|
|
1.1 ! root 1: /* ! 2: * PROM interface support ! 3: * Copyright 1996 The Australian National University. ! 4: * Copyright 1996 Fujitsu Laboratories Limited ! 5: * Copyright 1999 Pete A. Zaitcev ! 6: * This software may be distributed under the terms of the Gnu ! 7: * Public License version 2 or later ! 8: */ ! 9: ! 10: #include <stdarg.h> ! 11: ! 12: #include "openprom.h" ! 13: #include "config.h" ! 14: #include "libopenbios/bindings.h" ! 15: #include "drivers/drivers.h" ! 16: #include "libopenbios/sys_info.h" ! 17: #include "boot.h" ! 18: #include "romvec.h" ! 19: ! 20: #ifdef CONFIG_DEBUG_OBP ! 21: #define DPRINTF(fmt, args...) \ ! 22: do { printk(fmt , ##args); } while (0) ! 23: #else ! 24: #define DPRINTF(fmt, args...) ! 25: #endif ! 26: ! 27: char obp_stdin, obp_stdout; ! 28: static int obp_fd_stdin, obp_fd_stdout; ! 29: const char *obp_stdin_path, *obp_stdout_path; ! 30: ! 31: struct linux_arguments_v0 obp_arg; ! 32: const char *bootpath; ! 33: static const struct linux_arguments_v0 * const obp_argp = &obp_arg; ! 34: ! 35: static void (*sync_hook)(void); ! 36: ! 37: static struct linux_romvec romvec0; ! 38: ! 39: static void doublewalk(__attribute__((unused)) unsigned int ptab1, ! 40: __attribute__((unused)) unsigned int va) ! 41: { ! 42: } ! 43: ! 44: int obp_nextnode(int node) ! 45: { ! 46: int peer; ! 47: ! 48: PUSH(node); ! 49: fword("peer"); ! 50: peer = POP(); ! 51: DPRINTF("obp_nextnode(0x%x) = 0x%x\n", node, peer); ! 52: ! 53: return peer; ! 54: } ! 55: ! 56: int obp_child(int node) ! 57: { ! 58: int child; ! 59: ! 60: PUSH(node); ! 61: fword("child"); ! 62: child = POP(); ! 63: DPRINTF("obp_child(0x%x) = 0x%x\n", node, child); ! 64: ! 65: return child; ! 66: } ! 67: ! 68: int obp_proplen(int node, const char *name) ! 69: { ! 70: int notfound; ! 71: ! 72: if (!node) { ! 73: DPRINTF("obp_proplen(0x0, %s) = -1\n", name); ! 74: return -1; ! 75: } ! 76: ! 77: push_str(name); ! 78: PUSH(node); ! 79: fword("get-package-property"); ! 80: notfound = POP(); ! 81: ! 82: if (notfound) { ! 83: DPRINTF("obp_proplen(0x%x, %s) (not found)\n", node, name); ! 84: ! 85: return -1; ! 86: } else { ! 87: int len; ! 88: ! 89: len = POP(); ! 90: (void) POP(); ! 91: DPRINTF("obp_proplen(0x%x, %s) = %d\n", node, name, len); ! 92: ! 93: return len; ! 94: } ! 95: } ! 96: ! 97: #ifdef CONFIG_DEBUG_OBP ! 98: static int looks_like_string(const char *str, int len) ! 99: { ! 100: int i; ! 101: int ret = (str[len-1] == '\0'); ! 102: for (i = 0; i < len-1 && ret; i++) ! 103: { ! 104: int ch = str[i] & 0xFF; ! 105: if (ch < 0x20 || ch > 0x7F) ! 106: ret = 0; ! 107: } ! 108: return ret; ! 109: } ! 110: #endif ! 111: ! 112: int obp_getprop(int node, const char *name, char *value) ! 113: { ! 114: int notfound, found; ! 115: int len; ! 116: const char *str; ! 117: ! 118: if (!node) { ! 119: DPRINTF("obp_getprop(0x0, %s) = -1\n", name); ! 120: return -1; ! 121: } ! 122: ! 123: if (!name) { ! 124: // NULL name means get first property ! 125: push_str(""); ! 126: PUSH(node); ! 127: fword("next-property"); ! 128: found = POP(); ! 129: if (found) { ! 130: len = POP(); ! 131: str = (char *) POP(); ! 132: DPRINTF("obp_getprop(0x%x, NULL) = %s\n", node, str); ! 133: ! 134: return (int)str; ! 135: } ! 136: DPRINTF("obp_getprop(0x%x, NULL) (not found)\n", node); ! 137: ! 138: return -1; ! 139: } else { ! 140: push_str(name); ! 141: PUSH(node); ! 142: fword("get-package-property"); ! 143: notfound = POP(); ! 144: } ! 145: if (notfound) { ! 146: DPRINTF("obp_getprop(0x%x, %s) (not found)\n", node, name); ! 147: ! 148: return -1; ! 149: } else { ! 150: len = POP(); ! 151: str = (char *) POP(); ! 152: if (len > 0) ! 153: memcpy(value, str, len); ! 154: else ! 155: str = "NULL"; ! 156: ! 157: #ifdef CONFIG_DEBUG_OBP ! 158: if (looks_like_string(str, len)) { ! 159: DPRINTF("obp_getprop(0x%x, %s) = %s\n", node, name, str); ! 160: } else { ! 161: int i; ! 162: DPRINTF("obp_getprop(0x%x, %s) = ", node, name); ! 163: for (i = 0; i < len; i++) { ! 164: DPRINTF("%02x%s", str[i] & 0xFF, ! 165: (len == 4 || i == len-1) ? "" : " "); ! 166: } ! 167: DPRINTF("\n"); ! 168: } ! 169: #endif ! 170: ! 171: return len; ! 172: } ! 173: } ! 174: ! 175: const char *obp_nextprop(int node, const char *name) ! 176: { ! 177: int found; ! 178: ! 179: if (!name || *name == '\0') { ! 180: // NULL name means get first property ! 181: push_str(""); ! 182: name = "NULL"; ! 183: } else { ! 184: push_str(name); ! 185: } ! 186: PUSH(node); ! 187: fword("next-property"); ! 188: found = POP(); ! 189: if (!found) { ! 190: DPRINTF("obp_nextprop(0x%x, %s) (not found)\n", node, name); ! 191: ! 192: return ""; ! 193: } else { ! 194: char *str; ! 195: ! 196: POP(); /* len */ ! 197: str = (char *) POP(); ! 198: ! 199: DPRINTF("obp_nextprop(0x%x, %s) = %s\n", node, name, str); ! 200: ! 201: return str; ! 202: } ! 203: } ! 204: ! 205: int obp_setprop(__attribute__((unused)) int node, ! 206: __attribute__((unused)) const char *name, ! 207: __attribute__((unused)) char *value, ! 208: __attribute__((unused)) int len) ! 209: { ! 210: DPRINTF("obp_setprop(0x%x, %s) = %s (%d)\n", node, name, value, len); ! 211: ! 212: return -1; ! 213: } ! 214: ! 215: static const struct linux_nodeops nodeops0 = { ! 216: obp_nextnode_handler, /* int (*no_nextnode)(int node); */ ! 217: obp_child_handler, /* int (*no_child)(int node); */ ! 218: obp_proplen_handler, /* int (*no_proplen)(int node, char *name); */ ! 219: obp_getprop_handler, /* int (*no_getprop)(int node,char *name,char *val); */ ! 220: obp_setprop_handler, /* int (*no_setprop)(int node, char *name, ! 221: char *val, int len); */ ! 222: obp_nextprop_handler /* char * (*no_nextprop)(int node, char *name); */ ! 223: }; ! 224: ! 225: int obp_nbgetchar(void) ! 226: { ! 227: return getchar(); ! 228: } ! 229: ! 230: int obp_nbputchar(int ch) ! 231: { ! 232: putchar(ch); ! 233: ! 234: return 0; ! 235: } ! 236: ! 237: void obp_putstr(char *str, int len) ! 238: { ! 239: PUSH(pointer2cell(str)); ! 240: PUSH(len); ! 241: fword("type"); ! 242: } ! 243: ! 244: void obp_printf(const char *fmt, ...) ! 245: { ! 246: va_list ap; ! 247: ! 248: va_start(ap, fmt); ! 249: printk(fmt, ap); ! 250: va_end(ap); ! 251: } ! 252: ! 253: void obp_reboot(char *str) ! 254: { ! 255: printk("rebooting (%s)\n", str); ! 256: *reset_reg = 1; ! 257: printk("reboot failed\n"); ! 258: for (;;) {} ! 259: } ! 260: ! 261: void obp_abort(void) ! 262: { ! 263: printk("abort, power off\n"); ! 264: *power_reg = 1; ! 265: printk("power off failed\n"); ! 266: for (;;) {} ! 267: } ! 268: ! 269: void obp_halt(void) ! 270: { ! 271: printk("halt, power off\n"); ! 272: *power_reg = 1; ! 273: printk("power off failed\n"); ! 274: for (;;) {} ! 275: } ! 276: ! 277: int obp_devopen(char *str) ! 278: { ! 279: int ret; ! 280: ! 281: push_str(str); ! 282: fword("open-dev"); ! 283: ret = POP(); ! 284: DPRINTF("obp_devopen(%s) = 0x%x\n", str, ret); ! 285: ! 286: return ret; ! 287: } ! 288: ! 289: int obp_devclose(int dev_desc) ! 290: { ! 291: int ret = 1; ! 292: ! 293: PUSH(dev_desc); ! 294: fword("close-dev"); ! 295: ! 296: DPRINTF("obp_devclose(0x%x) = %d\n", dev_desc, ret); ! 297: ! 298: return ret; ! 299: } ! 300: ! 301: int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) ! 302: { ! 303: int ret, hi, lo, bs; ! 304: ! 305: bs = 512; ! 306: hi = ((uint64_t)offset * bs) >> 32; ! 307: lo = ((uint64_t)offset * bs) & 0xffffffff; ! 308: ! 309: ret = obp_devseek(dev_desc, hi, lo); ! 310: ! 311: ret = obp_devread(dev_desc, buf, num_blks * bs) / bs; ! 312: ! 313: DPRINTF("obp_rdblkdev(fd 0x%x, num_blks %d, offset %d (hi %d lo %d), buf 0x%x) = %d\n", dev_desc, num_blks, offset, hi, lo, (int)buf, ret); ! 314: ! 315: return ret; ! 316: } ! 317: ! 318: int obp_devread(int dev_desc, char *buf, int nbytes) ! 319: { ! 320: int ret; ! 321: ! 322: PUSH((int)buf); ! 323: PUSH(nbytes); ! 324: push_str("read"); ! 325: PUSH(dev_desc); ! 326: fword("$call-method"); ! 327: ret = POP(); ! 328: ! 329: DPRINTF("obp_devread(fd 0x%x, buf 0x%x, nbytes %d) = %d\n", dev_desc, (int)buf, nbytes, ret); ! 330: ! 331: return ret; ! 332: } ! 333: ! 334: int obp_devwrite(int dev_desc, char *buf, int nbytes) ! 335: { ! 336: #ifdef CONFIG_DEBUG_OBP_DEVWRITE /* disabled, makes too much noise */ ! 337: int ret; ! 338: #endif ! 339: ! 340: PUSH((int)buf); ! 341: PUSH(nbytes); ! 342: push_str("write"); ! 343: PUSH(dev_desc); ! 344: fword("$call-method"); ! 345: #ifdef CONFIG_DEBUG_OBP_DEVWRITE ! 346: ret = POP(); ! 347: DPRINTF("obp_devwrite(fd 0x%x, buf %s, nbytes %d) = %d\n", dev_desc, buf, nbytes, ret); ! 348: #else ! 349: POP(); ! 350: #endif ! 351: ! 352: return nbytes; ! 353: } ! 354: ! 355: int obp_devseek(int dev_desc, int hi, int lo) ! 356: { ! 357: int ret; ! 358: ! 359: PUSH(lo); ! 360: PUSH(hi); ! 361: push_str("seek"); ! 362: PUSH(dev_desc); ! 363: fword("$call-method"); ! 364: ret = POP(); ! 365: ! 366: DPRINTF("obp_devseek(fd 0x%x, hi %d, lo %d) = %d\n", dev_desc, hi, lo, ret); ! 367: ! 368: return ret; ! 369: } ! 370: ! 371: int obp_inst2pkg(int dev_desc) ! 372: { ! 373: int ret; ! 374: ! 375: PUSH(dev_desc); ! 376: fword("ihandle>non-interposed-phandle"); ! 377: ret = POP(); ! 378: ! 379: DPRINTF("obp_inst2pkg(fd 0x%x) = 0x%x\n", dev_desc, ret); ! 380: ! 381: return ret; ! 382: } ! 383: ! 384: int obp_cpustart(__attribute__((unused))unsigned int whichcpu, ! 385: __attribute__((unused))int ctxtbl_ptr, ! 386: __attribute__((unused))int thiscontext, ! 387: __attribute__((unused))char *prog_counter) ! 388: { ! 389: int cpu, found; ! 390: struct linux_prom_registers *smp_ctable = (void *)ctxtbl_ptr; ! 391: ! 392: DPRINTF("obp_cpustart: cpu %d, ctxptr 0x%x, ctx %d, pc 0x%x\n", whichcpu, ! 393: smp_ctable->phys_addr, thiscontext, (unsigned int)prog_counter); ! 394: ! 395: found = obp_getprop(whichcpu, "mid", (char *)&cpu); ! 396: if (found == -1) ! 397: return -1; ! 398: DPRINTF("cpu found, id %d -> cpu %d\n", whichcpu, cpu); ! 399: ! 400: return start_cpu((unsigned int)prog_counter, ((unsigned int)smp_ctable->phys_addr) >> 4, ! 401: thiscontext, cpu); ! 402: } ! 403: ! 404: int obp_cpustop(__attribute__((unused)) unsigned int whichcpu) ! 405: { ! 406: DPRINTF("obp_cpustop: cpu %d\n", whichcpu); ! 407: ! 408: return 0; ! 409: } ! 410: ! 411: int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu) ! 412: { ! 413: DPRINTF("obp_cpuidle: cpu %d\n", whichcpu); ! 414: ! 415: return 0; ! 416: } ! 417: ! 418: int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu) ! 419: { ! 420: DPRINTF("obp_cpuresume: cpu %d\n", whichcpu); ! 421: ! 422: return 0; ! 423: } ! 424: ! 425: void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4) ! 426: { ! 427: int dstacktmp = 0; ! 428: ! 429: // It seems Solaris passes up to 5 arguments which should be pushed onto the Forth ! 430: // stack for execution. However the API doesn't provide for a way to specify the number ! 431: // of arguments actually being passed. Hence we preserve the state of the Forth stack ! 432: // before, push all the arguments, execute the Forth, then restore the stack to its ! 433: // previous state. This enables us to have a variable number of arguments and still ! 434: // preserve stack state between subsequent calls. ! 435: ! 436: // Preserve stack state ! 437: dstacktmp = dstackcnt; ! 438: ! 439: PUSH(arg4); ! 440: PUSH(arg3); ! 441: PUSH(arg2); ! 442: PUSH(arg1); ! 443: PUSH(arg0); ! 444: ! 445: DPRINTF("obp_fortheval_v2(%x %x %x %x %x %s)\n", arg4, arg3, arg2, arg1, arg0, str); ! 446: push_str(str); ! 447: fword("eval"); ! 448: ! 449: // Restore stack state ! 450: dstackcnt = dstacktmp; ! 451: } ! 452: ! 453: void * ! 454: init_openprom(void) ! 455: { ! 456: /* Setup the openprom vector. Note that all functions should be invoked ! 457: via their handler (see call-romvec.S) which acts as a proxy to save ! 458: the globals and setup the stack correctly */ ! 459: ! 460: // Linux wants a R/W romvec table ! 461: romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; ! 462: romvec0.pv_romvers = 3; ! 463: romvec0.pv_plugin_revision = 2; ! 464: romvec0.pv_printrev = 0x20019; ! 465: romvec0.pv_v0mem.v0_totphys = &ptphys; ! 466: romvec0.pv_v0mem.v0_prommap = &ptmap; ! 467: romvec0.pv_v0mem.v0_available = &ptavail; ! 468: romvec0.pv_nodeops = &nodeops0; ! 469: romvec0.pv_bootstr = (void *)doublewalk; ! 470: romvec0.pv_v0devops.v0_devopen = &obp_devopen_handler; ! 471: romvec0.pv_v0devops.v0_devclose = &obp_devclose_handler; ! 472: romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev_handler; ! 473: romvec0.pv_stdin = &obp_stdin; ! 474: romvec0.pv_stdout = &obp_stdout; ! 475: romvec0.pv_getchar = obp_nbgetchar_handler; ! 476: romvec0.pv_putchar = (void (*)(int))obp_nbputchar_handler; ! 477: romvec0.pv_nbgetchar = obp_nbgetchar_handler; ! 478: romvec0.pv_nbputchar = obp_nbputchar_handler; ! 479: romvec0.pv_putstr = obp_putstr_handler; ! 480: romvec0.pv_reboot = obp_reboot_handler; ! 481: romvec0.pv_printf = obp_printf_handler; ! 482: romvec0.pv_abort = obp_abort_handler; ! 483: romvec0.pv_halt = obp_halt_handler; ! 484: romvec0.pv_synchook = &sync_hook; ! 485: romvec0.pv_v0bootargs = &obp_argp; ! 486: romvec0.pv_fortheval.v2_eval = obp_fortheval_v2_handler; ! 487: romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg_handler; ! 488: romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc_handler; ! 489: romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree_handler; ! 490: romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap_handler; ! 491: romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap_handler; ! 492: romvec0.pv_v2devops.v2_dev_open = obp_devopen_handler; ! 493: romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose_handler; ! 494: romvec0.pv_v2devops.v2_dev_read = obp_devread_handler; ! 495: romvec0.pv_v2devops.v2_dev_write = obp_devwrite_handler; ! 496: romvec0.pv_v2devops.v2_dev_seek = obp_devseek_handler; ! 497: ! 498: romvec0.pv_v2bootargs.bootpath = &bootpath; ! 499: ! 500: romvec0.pv_v2bootargs.bootargs = &obp_arg.argv[1]; ! 501: romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin; ! 502: romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout; ! 503: ! 504: push_str(obp_stdin_path); ! 505: fword("open-dev"); ! 506: obp_fd_stdin = POP(); ! 507: push_str(obp_stdout_path); ! 508: fword("open-dev"); ! 509: obp_fd_stdout = POP(); ! 510: ! 511: romvec0.v3_memalloc = obp_memalloc_handler; ! 512: ! 513: romvec0.v3_cpustart = obp_cpustart_handler; ! 514: romvec0.v3_cpustop = obp_cpustop_handler; ! 515: romvec0.v3_cpuidle = obp_cpuidle_handler; ! 516: romvec0.v3_cpuresume = obp_cpuresume_handler; ! 517: ! 518: return &romvec0; ! 519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.