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