📄 prom.c
字号:
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'; 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); prom_instantiate_rtas(); /* Initialize some system info into the Naca early... */ mem = prom_initialize_naca(mem); /* If we are on an SMP machine, then we *MUST* do the * following, regardless of whether we have an SMP * kernel or not. */ if ( _naca->processorCount > 1 ) prom_hold_cpus(mem); mem = check_display(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 (_naca->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 */ RELOC(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);}voidvirt_irq_init(void){ int i; for (i = 0; i < NR_IRQS; i++) virt_irq_to_real_map[i] = UNDEFINED_IRQ; for (i = 0; i < NR_HW_IRQS; i++) real_irq_to_virt_map[i] = UNDEFINED_IRQ;}/* Create a mapping for a real_irq if it doesn't already exist. * Return the virtual irq as a convenience. */unsigned longvirt_irq_create_mapping(unsigned long real_irq){ unsigned long virq; if (naca->interrupt_controller == IC_OPEN_PIC) return real_irq; /* no mapping for openpic (for now) */ virq = real_irq_to_virt(real_irq); if (virq == UNDEFINED_IRQ) { /* Assign a virtual IRQ number */ if (real_irq < NR_IRQS && virt_irq_to_real(real_irq) == UNDEFINED_IRQ) { /* A 1-1 mapping will work. */ virq = real_irq; } else { while (last_virt_irq < NR_IRQS && virt_irq_to_real(++last_virt_irq) != UNDEFINED_IRQ) /* skip irq's in use */; if (last_virt_irq >= NR_IRQS) panic("Too many IRQs are required on this system. NR_IRQS=%d\n", NR_IRQS); virq = last_virt_irq; } virt_irq_to_real_map[virq] = real_irq; real_irq_to_virt_map[real_irq] = virq; } return virq;}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 (;;) { pp = (struct property *) mem_start; namep = (char *) (pp + 1); pp->name = PTRUNRELOC(namep); if ((long) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, namep) <= 0) break; mem_start = DOUBLEWORD_ALIGN((unsigned long)namep + strlen(namep) + 1); prev_name = namep; valp = (unsigned char *) mem_start; pp->value = PTRUNRELOC(valp); pp->length = (int)(long) call_prom(RELOC("getprop"), 4, 1, node, namep, valp, mem_end - mem_start); if (pp->length < 0) continue; mem_start = DOUBLEWORD_ALIGN(mem_start + pp->length); *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } *prev_propp = 0; /* get the node's full name */ l = (long) call_prom(RELOC("package-to-path"), 3, 1, node, (char *) mem_start, mem_end - mem_start); if (l >= 0) { np->full_name = PTRUNRELOC((char *) mem_start); *(char *)(mem_start + l) = 0; mem_start = DOUBLEWORD_ALIGN(mem_start + l + 1); } /* do all our children */ child = call_prom(RELOC("child"), 1, 1, node); while (child != (phandle)0) { mem_start = inspect_node(child, np, mem_start, mem_end, allnextpp); child = call_prom(RELOC("peer"), 1, 1, child); } return mem_start;}/* * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). * It traverses the device tree and fills in the name, type, * {n_}addrs and {n_}intrs fields of each node. */void __initfinish_device_tree(void){ unsigned long mem = klimit; virt_irq_init(); mem = finish_node(allnodes, mem, NULL, 0, 0); dev_tree_size = mem - (unsigned long) allnodes; mem = _ALIGN(mem, PAGE_SIZE); lmb_reserve(__pa(klimit), mem-klimit); klimit = mem; rtas.dev = find_devices("rtas");}static unsigned long __initfinish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec){ struct device_node *child; int *ip; np->name = get_property(np, "name", 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -