prom.c
字号:
__make_room(startp, endp, sizeof(type), __alignof__(type))static void __initinspect_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(); phandle ibm_phandle; np = make_room(mem_start, mem_end, 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 (;;) { /* 32 is max len of name including nul. */ namep = make_room(mem_start, mem_end, char[32]); if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; } /* Trim off some if we can */ *mem_start = DOUBLEWORD_ALIGN((unsigned long)namep + strlen(namep) + 1); pp = make_room(mem_start, mem_end, struct property); pp->name = PTRUNRELOC(namep); prev_name = namep; pp->length = call_prom("getproplen", 2, 1, node, namep); if (pp->length < 0) continue; if (pp->length > MAX_PROPERTY_LENGTH) { char path[128]; prom_printf("WARNING: ignoring large property "); /* It seems OF doesn't null-terminate the path :-( */ memset(path, 0, sizeof(path)); if (call_prom("package-to-path", 3, 1, node, path, sizeof(path)-1) > 0) prom_printf("[%s] ", path); prom_printf("%s length 0x%x\n", namep, pp->length); continue; } valp = __make_room(mem_start, mem_end, pp->length, 1); pp->value = PTRUNRELOC(valp); call_prom("getprop", 4, 1, node, namep, valp, pp->length); *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } /* Add a "linux,phandle" property. */ namep = make_room(mem_start, mem_end, char[16]); strcpy(namep, RELOC("linux,phandle")); pp = make_room(mem_start, mem_end, struct property); pp->name = PTRUNRELOC(namep); pp->length = sizeof(phandle); valp = make_room(mem_start, mem_end, phandle); pp->value = PTRUNRELOC(valp); *(phandle *)valp = node; *prev_propp = PTRUNRELOC(pp); pp->next = NULL; /* Set np->linux_phandle to the value of the ibm,phandle property if it exists, otherwise to the phandle for this node. */ np->linux_phandle = node; if (prom_getprop(node, "ibm,phandle", &ibm_phandle, sizeof(ibm_phandle)) > 0) np->linux_phandle = ibm_phandle; /* get the node's full name */ namep = (char *)*mem_start; l = call_prom("package-to-path", 3, 1, node, namep, *mem_end - *mem_start); if (l >= 0) { /* Didn't fit? Get more room. */ if (l+1 > *mem_end - *mem_start) { namep = __make_room(mem_start, mem_end, l+1, 1); call_prom("package-to-path", 3, 1, node, namep, l); } np->full_name = PTRUNRELOC(namep); namep[l] = '\0'; *mem_start = DOUBLEWORD_ALIGN(*mem_start + l + 1); } /* do all our children */ child = call_prom("child", 1, 1, node); while (child != (phandle)0) { inspect_node(child, np, mem_start, mem_end, allnextpp); child = call_prom("peer", 1, 1, child); }}/* * Make a copy of the device tree from the PROM. */static unsigned long __initcopy_device_tree(unsigned long mem_start){ phandle root; struct device_node **allnextp; unsigned long offset = reloc_offset(); unsigned long mem_end; /* We pass mem_end-mem_start to OF: keep it well under 32-bit */ mem_end = mem_start + 1024*1024*1024;#ifdef CONFIG_BLK_DEV_INITRD if (RELOC(initrd_start) && RELOC(initrd_start) > mem_start) mem_end = RELOC(initrd_start);#endif /* CONFIG_BLK_DEV_INITRD */ root = call_prom("peer", 1, 1, (phandle)0); if (root == (phandle)0) { prom_panic("couldn't get device tree root\n"); } allnextp = &RELOC(allnodes); inspect_node(root, NULL, &mem_start, &mem_end, &allnextp); *allnextp = NULL; return mem_start;}/* Verify bi_recs are good */static struct bi_record * __init prom_bi_rec_verify(struct bi_record *bi_recs){ struct bi_record *first, *last; prom_debug("birec_verify: r6=0x%x\n", (unsigned long)bi_recs); if (bi_recs != NULL) prom_debug(" tag=0x%x\n", bi_recs->tag); if ( bi_recs == NULL || bi_recs->tag != BI_FIRST ) return NULL; last = (struct bi_record *)(long)bi_recs->data[0]; prom_debug(" last=0x%x\n", (unsigned long)last); if (last != NULL) prom_debug(" last_tag=0x%x\n", last->tag); if ( last == NULL || last->tag != BI_LAST ) return NULL; first = (struct bi_record *)(long)last->data[0]; prom_debug(" first=0x%x\n", (unsigned long)first); if ( first == NULL || first != bi_recs ) return NULL; return bi_recs;}static void __init prom_bi_rec_reserve(void){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct bi_record *rec; if ( _prom->bi_recs != NULL) { for ( rec=_prom->bi_recs; rec->tag != BI_LAST; rec=bi_rec_next(rec) ) { prom_debug("bi: 0x%x\n", rec->tag); switch (rec->tag) {#ifdef CONFIG_BLK_DEV_INITRD case BI_INITRD: RELOC(initrd_start) = (unsigned long)(rec->data[0]); RELOC(initrd_end) = RELOC(initrd_start) + rec->data[1]; break;#endif /* CONFIG_BLK_DEV_INITRD */ } } /* The next use of this field will be after relocation * is enabled, so convert this physical address into a * virtual address. */ _prom->bi_recs = PTRUNRELOC(_prom->bi_recs); }}/* * 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){ unsigned long mem; ihandle prom_cpu; phandle cpu_pkg; unsigned long offset = reloc_offset(); long l; char *p, *d; unsigned long phys; u32 getprop_rval; struct systemcfg *_systemcfg; struct paca_struct *lpaca = PTRRELOC(&paca[0]); struct prom_t *_prom = PTRRELOC(&prom); /* First zero the BSS -- use memset, some arches don't have * caches on yet */ memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); /* Setup systemcfg and NACA pointers now */ RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset); RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset); /* Init interface to Open Firmware and pickup bi-recs */ prom_init_client_services(pp); /* Init prom stdout device */ prom_init_stdout(); prom_debug("klimit=0x%x\n", RELOC(klimit)); prom_debug("offset=0x%x\n", offset); prom_debug("->mem=0x%x\n", RELOC(klimit) - offset); /* check out if we have bi_recs */ _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]); prom_debug("bi_recs=0x%x\n", (unsigned long)_prom->bi_recs); prom_debug("new mem=0x%x\n", RELOC(klimit) - offset); } /* If we don't have birec's or didn't find them, check for an initrd * using the "yaboot" way */#ifdef CONFIG_BLK_DEV_INITRD if ( _prom->bi_recs == NULL && r3 && r4 && r4 != 0xdeadbeef) { RELOC(initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; RELOC(initrd_end) = RELOC(initrd_start) + r4; RELOC(initrd_below_start_ok) = 1; }#endif /* CONFIG_BLK_DEV_INITRD */ /* Default machine type. */ _systemcfg->platform = prom_find_machine_type(); /* On pSeries, copy the CPU hold code */ if (_systemcfg->platform == PLATFORM_PSERIES) copy_and_flush(0, KERNELBASE - offset, 0x100, 0); /* Start storing things at klimit */ mem = RELOC(klimit) - offset; /* Get the full OF pathname of the stdout device */ p = (char *) mem; memset(p, 0, 256); call_prom("instance-to-path", 3, 1, _prom->stdout, p, 255); RELOC(of_stdout_device) = PTRUNRELOC(p); mem += strlen(p) + 1; getprop_rval = 1; prom_getprop(_prom->root, "#size-cells", &getprop_rval, sizeof(getprop_rval)); _prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64; /* Determine which cpu is actually running right _now_ */ if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) prom_panic("cannot find boot cpu"); cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); _prom->cpu = getprop_rval; lpaca[0].hw_cpu_id = _prom->cpu; RELOC(boot_cpuid) = 0; prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); /* Get the boot device and translate it to a full OF pathname. */ p = (char *) mem; l = prom_getprop(_prom->chosen, "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("canon", 3, 1, p, d, 1<<20); RELOC(bootdevice) = PTRUNRELOC(d); mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); } RELOC(cmd_line[0]) = 0; if ((long)_prom->chosen > 0) { prom_getprop(_prom->chosen, "bootargs", p, sizeof(cmd_line)); if (p != NULL && p[0] != 0) strlcpy(RELOC(cmd_line), p, sizeof(cmd_line)); } early_cmdline_parse(); prom_initialize_lmb(); prom_bi_rec_reserve(); mem = check_display(mem); if (_systemcfg->platform != PLATFORM_POWERMAC) prom_instantiate_rtas(); /* Initialize some system info into the Naca early... */ prom_initialize_naca(); 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); prom_debug("after basic inits, mem=0x%x\n", mem);#ifdef CONFIG_BLK_DEV_INITRD prom_debug("initrd_start=0x%x\n", RELOC(initrd_start)); prom_debug("initrd_end=0x%x\n", RELOC(initrd_end));#endif /* CONFIG_BLK_DEV_INITRD */ prom_debug("copying OF device tree...\n"); mem = copy_device_tree(mem); RELOC(klimit) = mem + offset; prom_debug("new klimit is\n"); prom_debug("klimit=0x%x\n", RELOC(klimit)); prom_debug(" ->mem=0x%x\n", mem); lmb_reserve(0, __pa(RELOC(klimit)));#ifdef CONFIG_BLK_DEV_INITRD if (RELOC(initrd_start)) { unsigned long initrd_len; initrd_len = RELOC(initrd_end) - RELOC(initrd_start); /* Move initrd if it's where we're going to copy kernel. */ if (RELOC(initrd_start) < __pa(RELOC(klimit))) { memmove((void *)mem, (void *)RELOC(initrd_start), initrd_len); RELOC(initrd_start) = mem; RELOC(initrd_end) = mem + initrd_len; } lmb_reserve(RELOC(initrd_start), initrd_len); }#endif /* CONFIG_BLK_DEV_INITRD */ if (_systemcfg->platform == PLATFORM_PSERIES) prom_initialize_tce_table();#ifdef CONFIG_PMAC_DART if (_systemcfg->platform == PLATFORM_POWERMAC) prom_initialize_dart_table();#endif#ifdef CONFIG_BOOTX_TEXT if (_prom->disp_node) { prom_printf("Setting up bi display...\n"); setup_disp_fake_bi(_prom->disp_node); }#endif /* CONFIG_BOOTX_TEXT */ prom_printf("Calling quiesce ...\n"); call_prom("quiesce", 0, 0); phys = KERNELBASE - offset;#ifdef CONFIG_BLK_DEV_INITRD /* If we had an initrd, we convert its address to virtual */ if (RELOC(initrd_start)) { RELOC(initrd_start) = (unsigned long)__va(RELOC(initrd_start)); RELOC(initrd_end) = (unsigned long)__va(RELOC(initrd_end)); }#endif /* CONFIG_BLK_DEV_INITRD */ prom_printf("returning from prom_init\n"); return phys;}/* * Find the device_node with a given phandle. */static struct device_node * __devinitfind_phandle(phandle ph){ struct device_node *np; for (np = allnodes; np != 0; np = np->allnext) if (np->linux_phandle == ph) return np; return NULL;}/* * Find the interrupt parent of a node. */static struct device_node * __devinitintr_parent(struct device_node *p){ phandle *parp; parp = (phandle *) get_property(p, "interrupt-parent", NULL); if (parp == NULL) return p->parent; return find_phandle(*parp);}/* * Find out the size of each entry of the interrupts property * for a node. */int __devinit prom_n_intr_cells(struct device_node *np){ struct device_node *p; unsigned int *icp; for (p = np; (p = intr_parent(p)) != NULL; ) { icp = (unsigned int *) get_property(p, "#interrupt-cells", NULL); if (icp != NULL) return *icp; if (get_property(p, "interrupt-controller", NULL) != NULL || get_property(p, "interrupt-map", NULL) != NULL) { printk("oops, node %s doesn't have #interrupt-cells\n", p->full_name); return 1; } }#ifdef DEBUG_IRQ printk("prom_n_intr_cells failed for %s\n", np->full_name);#endif return 1;}/* * Map an interrupt from a device up to the platform interrupt * descriptor. */static int __devinitmap_interrupt(unsigned int **irq, struct device_node **ictrler, struct device_node *np, unsigned int *ints, int nintrc){ struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; int newintrc, newaddrc; unsigned int *reg; int naddrc; reg = (unsigned int *) get_property(np, "reg", NULL); naddrc = prom_n_addr_cells(np); p = intr_parent(np); while (p != NULL) { if (get_property(p, "interrupt-controller", NULL) != NULL) /* this node is an interrupt controller, stop here */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -