1 /*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9 #include <stdarg.h>
10 #include <linux/types.h>
11 #include <linux/string.h>
12 #include <linux/ctype.h>
13
14 #include <asm/div64.h>
15
16 int (*prom)(void *);
17
18 void *chosen_handle;
19 void *stdin;
20 void *stdout;
21 void *stderr;
22
23 void exit(void);
24 void *finddevice(const char *name);
25 int getprop(void *phandle, const char *name, void *buf, int buflen);
26 void chrpboot(int a1, int a2, void *prom); /* in main.c */
27
28 void printk(char *fmt, ...);
29
30 int
write(void * handle,void * ptr,int nb)31 write(void *handle, void *ptr, int nb)
32 {
33 struct prom_args {
34 char *service;
35 int nargs;
36 int nret;
37 void *ihandle;
38 void *addr;
39 int len;
40 int actual;
41 } args;
42
43 args.service = "write";
44 args.nargs = 3;
45 args.nret = 1;
46 args.ihandle = handle;
47 args.addr = ptr;
48 args.len = nb;
49 args.actual = -1;
50 (*prom)(&args);
51 return args.actual;
52 }
53
54 int
read(void * handle,void * ptr,int nb)55 read(void *handle, void *ptr, int nb)
56 {
57 struct prom_args {
58 char *service;
59 int nargs;
60 int nret;
61 void *ihandle;
62 void *addr;
63 int len;
64 int actual;
65 } args;
66
67 args.service = "read";
68 args.nargs = 3;
69 args.nret = 1;
70 args.ihandle = handle;
71 args.addr = ptr;
72 args.len = nb;
73 args.actual = -1;
74 (*prom)(&args);
75 return args.actual;
76 }
77
78 void
exit()79 exit()
80 {
81 struct prom_args {
82 char *service;
83 } args;
84
85 for (;;) {
86 args.service = "exit";
87 (*prom)(&args);
88 }
89 }
90
91 void
pause(void)92 pause(void)
93 {
94 struct prom_args {
95 char *service;
96 } args;
97
98 args.service = "enter";
99 (*prom)(&args);
100 }
101
102 void *
finddevice(const char * name)103 finddevice(const char *name)
104 {
105 struct prom_args {
106 char *service;
107 int nargs;
108 int nret;
109 const char *devspec;
110 void *phandle;
111 } args;
112
113 args.service = "finddevice";
114 args.nargs = 1;
115 args.nret = 1;
116 args.devspec = name;
117 args.phandle = (void *) -1;
118 (*prom)(&args);
119 return args.phandle;
120 }
121
122 void *
claim(unsigned long virt,unsigned long size,unsigned long align)123 claim(unsigned long virt, unsigned long size, unsigned long align)
124 {
125 struct prom_args {
126 char *service;
127 int nargs;
128 int nret;
129 unsigned int virt;
130 unsigned int size;
131 unsigned int align;
132 void *ret;
133 } args;
134
135 args.service = "claim";
136 args.nargs = 3;
137 args.nret = 1;
138 args.virt = virt;
139 args.size = size;
140 args.align = align;
141 (*prom)(&args);
142 return args.ret;
143 }
144
145 int
getprop(void * phandle,const char * name,void * buf,int buflen)146 getprop(void *phandle, const char *name, void *buf, int buflen)
147 {
148 struct prom_args {
149 char *service;
150 int nargs;
151 int nret;
152 void *phandle;
153 const char *name;
154 void *buf;
155 int buflen;
156 int size;
157 } args;
158
159 args.service = "getprop";
160 args.nargs = 4;
161 args.nret = 1;
162 args.phandle = phandle;
163 args.name = name;
164 args.buf = buf;
165 args.buflen = buflen;
166 args.size = -1;
167 (*prom)(&args);
168 return args.size;
169 }
170
171 int
putc(int c,void * f)172 putc(int c, void *f)
173 {
174 char ch = c;
175
176 if (c == '\n')
177 putc('\r', f);
178 return write(f, &ch, 1) == 1? c: -1;
179 }
180
181 int
putchar(int c)182 putchar(int c)
183 {
184 return putc(c, stdout);
185 }
186
187 int
fputs(char * str,void * f)188 fputs(char *str, void *f)
189 {
190 int n = strlen(str);
191
192 return write(f, str, n) == n? 0: -1;
193 }
194
195 int
readchar(void)196 readchar(void)
197 {
198 char ch;
199
200 for (;;) {
201 switch (read(stdin, &ch, 1)) {
202 case 1:
203 return ch;
204 case -1:
205 printk("read(stdin) returned -1\r\n");
206 return -1;
207 }
208 }
209 }
210
211 static char line[256];
212 static char *lineptr;
213 static int lineleft;
214
215 int
getchar(void)216 getchar(void)
217 {
218 int c;
219
220 if (lineleft == 0) {
221 lineptr = line;
222 for (;;) {
223 c = readchar();
224 if (c == -1 || c == 4)
225 break;
226 if (c == '\r' || c == '\n') {
227 *lineptr++ = '\n';
228 putchar('\n');
229 break;
230 }
231 switch (c) {
232 case 0177:
233 case '\b':
234 if (lineptr > line) {
235 putchar('\b');
236 putchar(' ');
237 putchar('\b');
238 --lineptr;
239 }
240 break;
241 case 'U' & 0x1F:
242 while (lineptr > line) {
243 putchar('\b');
244 putchar(' ');
245 putchar('\b');
246 --lineptr;
247 }
248 break;
249 default:
250 if (lineptr >= &line[sizeof(line) - 1])
251 putchar('\a');
252 else {
253 putchar(c);
254 *lineptr++ = c;
255 }
256 }
257 }
258 lineleft = lineptr - line;
259 lineptr = line;
260 }
261 if (lineleft == 0)
262 return -1;
263 --lineleft;
264 return *lineptr++;
265 }
266
267
268
269 /* String functions lifted from lib/vsprintf.c and lib/ctype.c */
270 unsigned char _ctype[] = {
271 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
272 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
273 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
274 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
275 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
276 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
277 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
278 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
279 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
280 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
281 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
282 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
283 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
284 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
285 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
286 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
287 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
288 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
289 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
290 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
291 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
292 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
293 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
294 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
295
strnlen(const char * s,size_t count)296 size_t strnlen(const char * s, size_t count)
297 {
298 const char *sc;
299
300 for (sc = s; count-- && *sc != '\0'; ++sc)
301 /* nothing */;
302 return sc - s;
303 }
304
simple_strtoul(const char * cp,char ** endp,unsigned int base)305 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
306 {
307 unsigned long result = 0,value;
308
309 if (!base) {
310 base = 10;
311 if (*cp == '0') {
312 base = 8;
313 cp++;
314 if ((*cp == 'x') && isxdigit(cp[1])) {
315 cp++;
316 base = 16;
317 }
318 }
319 }
320 while (isxdigit(*cp) &&
321 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
322 result = result*base + value;
323 cp++;
324 }
325 if (endp)
326 *endp = (char *)cp;
327 return result;
328 }
329
simple_strtol(const char * cp,char ** endp,unsigned int base)330 long simple_strtol(const char *cp,char **endp,unsigned int base)
331 {
332 if(*cp=='-')
333 return -simple_strtoul(cp+1,endp,base);
334 return simple_strtoul(cp,endp,base);
335 }
336
skip_atoi(const char ** s)337 static int skip_atoi(const char **s)
338 {
339 int i=0;
340
341 while (isdigit(**s))
342 i = i*10 + *((*s)++) - '0';
343 return i;
344 }
345
346 #define ZEROPAD 1 /* pad with zero */
347 #define SIGN 2 /* unsigned/signed long */
348 #define PLUS 4 /* show plus */
349 #define SPACE 8 /* space if plus */
350 #define LEFT 16 /* left justified */
351 #define SPECIAL 32 /* 0x */
352 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
353
number(char * str,long long num,int base,int size,int precision,int type)354 static char * number(char * str, long long num, int base, int size, int precision, int type)
355 {
356 char c,sign,tmp[66];
357 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
358 int i;
359
360 if (type & LARGE)
361 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
362 if (type & LEFT)
363 type &= ~ZEROPAD;
364 if (base < 2 || base > 36)
365 return 0;
366 c = (type & ZEROPAD) ? '0' : ' ';
367 sign = 0;
368 if (type & SIGN) {
369 if (num < 0) {
370 sign = '-';
371 num = -num;
372 size--;
373 } else if (type & PLUS) {
374 sign = '+';
375 size--;
376 } else if (type & SPACE) {
377 sign = ' ';
378 size--;
379 }
380 }
381 if (type & SPECIAL) {
382 if (base == 16)
383 size -= 2;
384 else if (base == 8)
385 size--;
386 }
387 i = 0;
388 if (num == 0)
389 tmp[i++]='0';
390 else while (num != 0)
391 tmp[i++] = digits[do_div(num,base)];
392 if (i > precision)
393 precision = i;
394 size -= precision;
395 if (!(type&(ZEROPAD+LEFT)))
396 while(size-->0)
397 *str++ = ' ';
398 if (sign)
399 *str++ = sign;
400 if (type & SPECIAL) {
401 if (base==8)
402 *str++ = '0';
403 else if (base==16) {
404 *str++ = '0';
405 *str++ = digits[33];
406 }
407 }
408 if (!(type & LEFT))
409 while (size-- > 0)
410 *str++ = c;
411 while (i < precision--)
412 *str++ = '0';
413 while (i-- > 0)
414 *str++ = tmp[i];
415 while (size-- > 0)
416 *str++ = ' ';
417 return str;
418 }
419
420 /* Forward decl. needed for IP address printing stuff... */
421 int sprintf(char * buf, const char *fmt, ...);
422
vsprintf(char * buf,const char * fmt,va_list args)423 int vsprintf(char *buf, const char *fmt, va_list args)
424 {
425 int len;
426 unsigned long long num;
427 int i, base;
428 char * str;
429 const char *s;
430
431 int flags; /* flags to number() */
432
433 int field_width; /* width of output field */
434 int precision; /* min. # of digits for integers; max
435 number of chars for from string */
436 int qualifier; /* 'h', 'l', or 'L' for integer fields */
437 /* 'z' support added 23/7/1999 S.H. */
438 /* 'z' changed to 'Z' --davidm 1/25/99 */
439
440
441 for (str=buf ; *fmt ; ++fmt) {
442 if (*fmt != '%') {
443 *str++ = *fmt;
444 continue;
445 }
446
447 /* process flags */
448 flags = 0;
449 repeat:
450 ++fmt; /* this also skips first '%' */
451 switch (*fmt) {
452 case '-': flags |= LEFT; goto repeat;
453 case '+': flags |= PLUS; goto repeat;
454 case ' ': flags |= SPACE; goto repeat;
455 case '#': flags |= SPECIAL; goto repeat;
456 case '0': flags |= ZEROPAD; goto repeat;
457 }
458
459 /* get field width */
460 field_width = -1;
461 if (isdigit(*fmt))
462 field_width = skip_atoi(&fmt);
463 else if (*fmt == '*') {
464 ++fmt;
465 /* it's the next argument */
466 field_width = va_arg(args, int);
467 if (field_width < 0) {
468 field_width = -field_width;
469 flags |= LEFT;
470 }
471 }
472
473 /* get the precision */
474 precision = -1;
475 if (*fmt == '.') {
476 ++fmt;
477 if (isdigit(*fmt))
478 precision = skip_atoi(&fmt);
479 else if (*fmt == '*') {
480 ++fmt;
481 /* it's the next argument */
482 precision = va_arg(args, int);
483 }
484 if (precision < 0)
485 precision = 0;
486 }
487
488 /* get the conversion qualifier */
489 qualifier = -1;
490 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
491 qualifier = *fmt;
492 ++fmt;
493 }
494
495 /* default base */
496 base = 10;
497
498 switch (*fmt) {
499 case 'c':
500 if (!(flags & LEFT))
501 while (--field_width > 0)
502 *str++ = ' ';
503 *str++ = (unsigned char) va_arg(args, int);
504 while (--field_width > 0)
505 *str++ = ' ';
506 continue;
507
508 case 's':
509 s = va_arg(args, char *);
510 if (!s)
511 s = "<NULL>";
512
513 len = strnlen(s, precision);
514
515 if (!(flags & LEFT))
516 while (len < field_width--)
517 *str++ = ' ';
518 for (i = 0; i < len; ++i)
519 *str++ = *s++;
520 while (len < field_width--)
521 *str++ = ' ';
522 continue;
523
524 case 'p':
525 if (field_width == -1) {
526 field_width = 2*sizeof(void *);
527 flags |= ZEROPAD;
528 }
529 str = number(str,
530 (unsigned long) va_arg(args, void *), 16,
531 field_width, precision, flags);
532 continue;
533
534
535 case 'n':
536 if (qualifier == 'l') {
537 long * ip = va_arg(args, long *);
538 *ip = (str - buf);
539 } else if (qualifier == 'Z') {
540 size_t * ip = va_arg(args, size_t *);
541 *ip = (str - buf);
542 } else {
543 int * ip = va_arg(args, int *);
544 *ip = (str - buf);
545 }
546 continue;
547
548 case '%':
549 *str++ = '%';
550 continue;
551
552 /* integer number formats - set up the flags and "break" */
553 case 'o':
554 base = 8;
555 break;
556
557 case 'X':
558 flags |= LARGE;
559 case 'x':
560 base = 16;
561 break;
562
563 case 'd':
564 case 'i':
565 flags |= SIGN;
566 case 'u':
567 break;
568
569 default:
570 *str++ = '%';
571 if (*fmt)
572 *str++ = *fmt;
573 else
574 --fmt;
575 continue;
576 }
577 if (qualifier == 'L')
578 num = va_arg(args, long long);
579 else if (qualifier == 'l') {
580 num = va_arg(args, unsigned long);
581 if (flags & SIGN)
582 num = (signed long) num;
583 } else if (qualifier == 'Z') {
584 num = va_arg(args, size_t);
585 } else if (qualifier == 'h') {
586 num = (unsigned short) va_arg(args, int);
587 if (flags & SIGN)
588 num = (signed short) num;
589 } else {
590 num = va_arg(args, unsigned int);
591 if (flags & SIGN)
592 num = (signed int) num;
593 }
594 str = number(str, num, base, field_width, precision, flags);
595 }
596 *str = '\0';
597 return str-buf;
598 }
599
sprintf(char * buf,const char * fmt,...)600 int sprintf(char * buf, const char *fmt, ...)
601 {
602 va_list args;
603 int i;
604
605 va_start(args, fmt);
606 i=vsprintf(buf,fmt,args);
607 va_end(args);
608 return i;
609 }
610
611 static char sprint_buf[1024];
612
613 void
printk(char * fmt,...)614 printk(char *fmt, ...)
615 {
616 va_list args;
617 int n;
618
619 va_start(args, fmt);
620 n = vsprintf(sprint_buf, fmt, args);
621 va_end(args);
622 write(stdout, sprint_buf, n);
623 }
624
625 int
printf(char * fmt,...)626 printf(char *fmt, ...)
627 {
628 va_list args;
629 int n;
630
631 va_start(args, fmt);
632 n = vsprintf(sprint_buf, fmt, args);
633 va_end(args);
634 write(stdout, sprint_buf, n);
635 return n;
636 }
637