📄 prom.c
字号:
* and each option may be preceeded by a + or - to force on or off state. * The special option "all" may also be used. They are processed strictly * left to right. Multiple ppcdbg= options are the command line are treated * as a single option list. * * Examples: ppcdbg=phb_init,buswalk * ppcdbg=all,-mm,-tce * * ToDo: add "group" names that map to common combinations of flags. */void parse_ppcdbg_cmd_line(const char *line){ unsigned long offset = reloc_offset(); const char *ppcdbgopt = RELOC("ppcdbg="); struct naca_struct *_naca = RELOC(naca); const char *cmd, *end; _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */ cmd = line; while (cmd && (cmd = strstr(cmd, ppcdbgopt)) != NULL) { cmd += 7; /* skip ppcdbg= */ for (end = cmd; *end != '\0' && *end != '\t' && *end != ' '; end++) ; /* scan to whitespace or end */ parse_ppcdbg_optionlist(cmd, end); }}#endif /* CONFIG_PPCDBG *//* * Do minimal cmd_line parsing for early boot options. */static void __initprom_parse_cmd_line(char *line){#ifdef CONFIG_PPCDBG parse_ppcdbg_cmd_line(line);#endif}/* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */unsigned long __initprom_init(unsigned long r3, unsigned long r4, unsigned long pp, unsigned long r6, unsigned long r7, yaboot_debug_t *yaboot){ int chrp = 0; unsigned long mem; ihandle prom_mmu, prom_op, prom_root, prom_cpu; phandle cpu_pkg; unsigned long offset = reloc_offset(); long l, sz; char *p, *d; unsigned long phys; u32 getprop_rval; struct systemcfg *_systemcfg = RELOC(systemcfg); struct paca_struct *_xPaca = PTRRELOC(&paca[0]); struct prom_t *_prom = PTRRELOC(&prom); char *_cmd_line = PTRRELOC(&cmd_line[0]); /* Default machine type. */ _systemcfg->platform = PLATFORM_PSERIES; /* Get a handle to the prom entry point before anything else */ _prom->entry = pp; _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6); if ( _prom->bi_recs != NULL ) { RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + _prom->bi_recs->data[1]); }#ifdef DEBUG_YABOOT call_yaboot(yaboot->dummy,offset>>32,offset&0xffffffff); call_yaboot(yaboot->printf, RELOC("offset = 0x%08x%08x\n"), LONG_MSW(offset), LONG_LSW(offset));#endif /* Default */ phys = KERNELBASE - offset;#ifdef DEBUG_YABOOT call_yaboot(yaboot->printf, RELOC("phys = 0x%08x%08x\n"), LONG_MSW(phys), LONG_LSW(phys));#endif#ifdef DEBUG_YABOOT _prom->yaboot = yaboot; call_yaboot(yaboot->printf, RELOC("pp = 0x%08x%08x\n"), LONG_MSW(pp), LONG_LSW(pp)); call_yaboot(yaboot->printf, RELOC("prom = 0x%08x%08x\n"), LONG_MSW(_prom->entry), LONG_LSW(_prom->entry));#endif /* First get a handle for the stdout device */ _prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/chosen"));#ifdef DEBUG_YABOOT call_yaboot(yaboot->printf, RELOC("prom->chosen = 0x%08x%08x\n"), LONG_MSW(_prom->chosen), LONG_LSW(_prom->chosen));#endif if ((long)_prom->chosen <= 0) prom_exit(); if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen, RELOC("stdout"), &getprop_rval, sizeof(getprop_rval)) <= 0) prom_exit(); _prom->stdout = (ihandle)(unsigned long)getprop_rval;#ifdef DEBUG_YABOOT if (_prom->stdout == 0) { call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout)); } call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout));#endif#ifdef DEBUG_YABOOT call_yaboot(yaboot->printf, RELOC("Location: 0x11\n"));#endif mem = RELOC(klimit) - offset; #ifdef DEBUG_YABOOT call_yaboot(yaboot->printf, RELOC("Location: 0x11b\n"));#endif /* Get the full OF pathname of the stdout device */ p = (char *) mem; memset(p, 0, 256); call_prom(RELOC("instance-to-path"), 3, 1, _prom->stdout, p, 255); RELOC(of_stdout_device) = PTRUNRELOC(p); mem += strlen(p) + 1; getprop_rval = 1; prom_root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); if (prom_root != (ihandle)-1) { call_prom(RELOC("getprop"), 4, 1, prom_root, RELOC("#size-cells"), &getprop_rval, sizeof(getprop_rval)); } _prom->encode_phys_size = (getprop_rval==1) ? 32 : 64; /* Fetch the cmd_line */ sz = (long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen, RELOC("bootargs"), _cmd_line, sizeof(cmd_line)-1); if (sz > 0) _cmd_line[sz] = '\0'; if (sz <=1 ) strcpy(_cmd_line,RELOC(CONFIG_CMDLINE)); prom_parse_cmd_line(_cmd_line);#ifdef DEBUG_PROM prom_print(RELOC("DRENG: Detect OF version...\n"));#endif /* Find the OF version */ prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom")); if (prom_op != (ihandle)-1) { char model[64]; sz = (long)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64); if (sz > 0) { char *c; /* hack to skip the ibm chrp firmware # */ if ( strncmp(model,RELOC("IBM"),3) ) { for (c = model; *c; c++) if (*c >= '0' && *c <= '9') { _prom->version = *c - '0'; break; } } else chrp = 1; } } if (_prom->version >= 3) prom_print(RELOC("OF Version 3 detected.\n")); /* Determine which cpu is actually running right _now_ */ if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen, RELOC("cpu"), &getprop_rval, sizeof(getprop_rval)) <= 0) prom_exit(); prom_cpu = (ihandle)(unsigned long)getprop_rval; cpu_pkg = call_prom(RELOC("instance-to-package"), 1, 1, prom_cpu); call_prom(RELOC("getprop"), 4, 1, cpu_pkg, RELOC("reg"), &getprop_rval, sizeof(getprop_rval)); _prom->cpu = (int)(unsigned long)getprop_rval; _xPaca[0].xHwProcNum = _prom->cpu;#ifdef DEBUG_PROM prom_print(RELOC("Booting CPU hw index = 0x")); prom_print_hex(_prom->cpu); prom_print_nl();#endif /* Get the boot device and translate it to a full OF pathname. */ p = (char *) mem; l = (long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen, RELOC("bootpath"), p, 1<<20); if (l > 0) { p[l] = 0; /* should already be null-terminated */ RELOC(bootpath) = PTRUNRELOC(p); mem += l + 1; d = (char *) mem; *d = 0; call_prom(RELOC("canon"), 3, 1, p, d, 1<<20); RELOC(bootdevice) = PTRUNRELOC(d); mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); } mem = prom_initialize_lmb(mem); mem = prom_bi_rec_reserve(mem); mem = check_display(mem); prom_instantiate_rtas(); /* Initialize some system info into the Naca early... */ mem = prom_initialize_naca(mem); smt_setup(); /* If we are on an SMP machine, then we *MUST* do the * following, regardless of whether we have an SMP * kernel or not. */ prom_hold_cpus(mem);#ifdef DEBUG_PROM prom_print(RELOC("copying OF device tree...\n"));#endif mem = copy_device_tree(mem); RELOC(klimit) = mem + offset; lmb_reserve(0, __pa(RELOC(klimit))); if (_systemcfg->platform == PLATFORM_PSERIES) prom_initialize_tce_table(); if ((long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen, RELOC("mmu"), &getprop_rval, sizeof(getprop_rval)) <= 0) { prom_print(RELOC(" no MMU found\n")); prom_exit(); } /* We assume the phys. address size is 3 cells */ prom_mmu = (ihandle)(unsigned long)getprop_rval; if ((long)call_prom(RELOC("call-method"), 4, 4, RELOC("translate"), prom_mmu, (void *)(KERNELBASE - offset), (void *)1) != 0) { prom_print(RELOC(" (translate failed) ")); } else { prom_print(RELOC(" (translate ok) ")); phys = (unsigned long)_prom->args.rets[3]; } /* If OpenFirmware version >= 3, then use quiesce call */ if (_prom->version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); phys = KERNELBASE - offset; } prom_print(RELOC("returning from prom_init\n")); return phys;}static intprom_set_color(ihandle ih, int i, int r, int g, int b){ unsigned long offset = reloc_offset(); return (int)(long)call_prom(RELOC("call-method"), 6, 1, RELOC("color!"), ih, (void *)(long) i, (void *)(long) b, (void *)(long) g, (void *)(long) r );}/* * If we have a display that we don't know how to drive, * we will want to try to execute OF's open method for it * later. However, OF will probably fall over if we do that * we've taken over the MMU. * So we check whether we will need to open the display, * and if so, open it now. */static unsigned long __initcheck_display(unsigned long mem){ phandle node; ihandle ih; int i; unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); char type[64], *path; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0x55, 0xff, 0x55, 0xff, 0x55, 0x55, 0xff, 0xff, 0xff, 0x55, 0x55, 0xff, 0x55, 0xff, 0xff, 0xff, 0x55, 0xff, 0xff, 0xff }; _prom->disp_node = 0; for (node = 0; prom_next_node(&node); ) { type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), type, sizeof(type)); if (strcmp(type, RELOC("display")) != 0) continue; /* It seems OF doesn't null-terminate the path :-( */ path = (char *) mem; memset(path, 0, 256); if ((long) call_prom(RELOC("package-to-path"), 3, 1, node, path, 255) < 0) continue; prom_print(RELOC("opening display ")); prom_print(path); ih = (ihandle)call_prom(RELOC("open"), 1, 1, path); if (ih == (ihandle)0 || ih == (ihandle)-1) { prom_print(RELOC("... failed\n")); continue; } prom_print(RELOC("... ok\n")); if (_prom->disp_node == 0) _prom->disp_node = (ihandle)(unsigned long)node; /* Setup a useable color table when the appropriate * method is available. Should update this to set-colors */ for (i = 0; i < 32; i++) if (prom_set_color(ih, i, RELOC(default_colors)[i*3], RELOC(default_colors)[i*3+1], RELOC(default_colors)[i*3+2]) != 0) break;#ifdef CONFIG_FB for (i = 0; i < LINUX_LOGO_COLORS; i++) if (prom_set_color(ih, i + 32, RELOC(linux_logo_red)[i], RELOC(linux_logo_green)[i], RELOC(linux_logo_blue)[i]) != 0) break;#endif /* CONFIG_FB */ /* * If this display is the device that OF is using for stdout, * move it to the front of the list. */ mem += strlen(path) + 1; i = RELOC(prom_num_displays)++; if (RELOC(of_stdout_device) != 0 && i > 0 && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { for (; i > 0; --i) RELOC(prom_display_paths[i]) = RELOC(prom_display_paths[i-1]); } RELOC(prom_display_paths[i]) = PTRUNRELOC(path); if (RELOC(prom_num_displays) >= FB_MAX) break; } return DOUBLEWORD_ALIGN(mem);}static int __initprom_next_node(phandle *nodep){ phandle node; unsigned long offset = reloc_offset(); if ((node = *nodep) != 0 && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) return 1; if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; for (;;) { if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) return 0; if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; }}/* * Make a copy of the device tree from the PROM. */static unsigned long __initcopy_device_tree(unsigned long mem_start){ phandle root; unsigned long new_start; struct device_node **allnextp; unsigned long offset = reloc_offset(); unsigned long mem_end = mem_start + (8<<20); root = call_prom(RELOC("peer"), 1, 1, (phandle)0); if (root == (phandle)0) { prom_print(RELOC("couldn't get device tree root\n")); prom_exit(); } allnextp = &RELOC(allnodes); mem_start = DOUBLEWORD_ALIGN(mem_start); new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); *allnextp = 0; return new_start;}__initstatic unsigned longinspect_node(phandle node, struct device_node *dad, unsigned long mem_start, unsigned long mem_end, struct device_node ***allnextpp){ int l; phandle child; struct device_node *np; struct property *pp, **prev_propp; char *prev_name, *namep; unsigned char *valp; unsigned long offset = reloc_offset(); np = (struct device_node *) mem_start; mem_start += sizeof(struct device_node); memset(np, 0, sizeof(*np)); np->node = node; **allnextpp = PTRUNRELOC(np); *allnextpp = &np->allnext; if (dad != 0) { np->parent = PTRUNRELOC(dad); /* we temporarily use the `next' field as `last_child'. */ if (dad->next == 0) dad->child = PTRUNRELOC(np); else dad->next->sibling = PTRUNRELOC(np); dad->next = np; } /* get and store all properties */ prev_propp = &np->properties; prev_name = RELOC(""); for (;;) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -