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