📄 prom_init.c
字号:
s = os = (char *)RELOC(dt_string_start); s += 4; while (s < (char *)RELOC(dt_string_end)) { if (strcmp(s, str) == 0) return s - os; s += strlen(s) + 1; } return 0;}/* * The Open Firmware 1275 specification states properties must be 31 bytes or * less, however not all firmwares obey this. Make it 64 bytes to be safe. */#define MAX_PROPERTY_NAME 64static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, unsigned long *mem_end){ char *prev_name, *namep, *sstart; unsigned long soff; phandle child; sstart = (char *)RELOC(dt_string_start); /* get and store all property names */ prev_name = RELOC(""); for (;;) { /* 64 is max len of name including nul. */ namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { /* No more nodes: unwind alloc */ *mem_start = (unsigned long)namep; break; } /* skip "name" */ if (strcmp(namep, RELOC("name")) == 0) { *mem_start = (unsigned long)namep; prev_name = RELOC("name"); continue; } /* get/create string entry */ soff = dt_find_string(namep); if (soff != 0) { *mem_start = (unsigned long)namep; namep = sstart + soff; } else { /* Trim off some if we can */ *mem_start = (unsigned long)namep + strlen(namep) + 1; RELOC(dt_string_end) = *mem_start; } prev_name = namep; } /* do all our children */ child = call_prom("child", 1, 1, node); while (child != 0) { scan_dt_build_strings(child, mem_start, mem_end); child = call_prom("peer", 1, 1, child); }}static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long *mem_end){ phandle child; char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; unsigned long soff; unsigned char *valp; static char pname[MAX_PROPERTY_NAME]; int l, room; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); /* get the node's full name */ namep = (char *)*mem_start; room = *mem_end - *mem_start; if (room > 255) room = 255; l = call_prom("package-to-path", 3, 1, node, namep, room); if (l >= 0) { /* Didn't fit? Get more room. */ if (l >= room) { if (l >= *mem_end - *mem_start) namep = make_room(mem_start, mem_end, l+1, 1); call_prom("package-to-path", 3, 1, node, namep, l); } namep[l] = '\0'; /* Fixup an Apple bug where they have bogus \0 chars in the * middle of the path in some properties, and extract * the unit name (everything after the last '/'). */ for (lp = p = namep, ep = namep + l; p < ep; p++) { if (*p == '/') lp = namep; else if (*p != 0) *lp++ = *p; } *lp = 0; *mem_start = _ALIGN((unsigned long)lp + 1, 4); } /* get it again for debugging */ path = RELOC(prom_scratch); memset(path, 0, PROM_SCRATCH_SIZE); call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); /* get and store all properties */ prev_name = RELOC(""); sstart = (char *)RELOC(dt_string_start); for (;;) { if (call_prom("nextprop", 3, 1, node, prev_name, RELOC(pname)) != 1) break; /* skip "name" */ if (strcmp(RELOC(pname), RELOC("name")) == 0) { prev_name = RELOC("name"); continue; } /* find string offset */ soff = dt_find_string(RELOC(pname)); if (soff == 0) { prom_printf("WARNING: Can't find string index for" " <%s>, node %s\n", RELOC(pname), path); break; } prev_name = sstart + soff; /* get length */ l = call_prom("getproplen", 2, 1, node, RELOC(pname)); /* sanity checks */ if (l == PROM_ERROR) continue; if (l > MAX_PROPERTY_LENGTH) { prom_printf("WARNING: ignoring large property "); /* It seems OF doesn't null-terminate the path :-( */ prom_printf("[%s] ", path); prom_printf("%s length 0x%x\n", RELOC(pname), l); continue; } /* push property head */ dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(l, mem_start, mem_end); dt_push_token(soff, mem_start, mem_end); /* push property content */ valp = make_room(mem_start, mem_end, l, 4); call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); *mem_start = _ALIGN(*mem_start, 4); } /* Add a "linux,phandle" property. */ soff = dt_find_string(RELOC("linux,phandle")); if (soff == 0) prom_printf("WARNING: Can't find string index for" " <linux-phandle> node %s\n", path); else { dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(4, mem_start, mem_end); dt_push_token(soff, mem_start, mem_end); valp = make_room(mem_start, mem_end, 4, 4); *(u32 *)valp = node; } /* do all our children */ child = call_prom("child", 1, 1, node); while (child != 0) { scan_dt_build_struct(child, mem_start, mem_end); child = call_prom("peer", 1, 1, child); } dt_push_token(OF_DT_END_NODE, mem_start, mem_end);}static void __init flatten_device_tree(void){ phandle root; unsigned long mem_start, mem_end, room; struct boot_param_header *hdr; struct prom_t *_prom = &RELOC(prom); char *namep; u64 *rsvmap; /* * Check how much room we have between alloc top & bottom (+/- a * few pages), crop to 4Mb, as this is our "chuck" size */ room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; if (room > DEVTREE_CHUNK_SIZE) room = DEVTREE_CHUNK_SIZE; prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); /* Now try to claim that */ mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); if (mem_start == 0) prom_panic("Can't allocate initial device-tree chunk\n"); mem_end = RELOC(alloc_top); /* Get root of tree */ root = call_prom("peer", 1, 1, (phandle)0); if (root == (phandle)0) prom_panic ("couldn't get device tree root\n"); /* Build header and make room for mem rsv map */ mem_start = _ALIGN(mem_start, 4); hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); RELOC(dt_header_start) = (unsigned long)hdr; rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); /* Start of strings */ mem_start = PAGE_ALIGN(mem_start); RELOC(dt_string_start) = mem_start; mem_start += 4; /* hole */ /* Add "linux,phandle" in there, we'll need it */ namep = make_room(&mem_start, &mem_end, 16, 1); strcpy(namep, RELOC("linux,phandle")); mem_start = (unsigned long)namep + strlen(namep) + 1; /* Build string array */ prom_printf("Building dt strings...\n"); scan_dt_build_strings(root, &mem_start, &mem_end); RELOC(dt_string_end) = mem_start; /* Build structure */ mem_start = PAGE_ALIGN(mem_start); RELOC(dt_struct_start) = mem_start; prom_printf("Building dt structure...\n"); scan_dt_build_struct(root, &mem_start, &mem_end); dt_push_token(OF_DT_END, &mem_start, &mem_end); RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); /* Finish header */ hdr->boot_cpuid_phys = _prom->cpu; hdr->magic = OF_DT_HEADER; hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); hdr->version = OF_DT_VERSION; /* Version 16 is not backward compatible */ hdr->last_comp_version = 0x10; /* Reserve the whole thing and copy the reserve map in, we * also bump mem_reserve_cnt to cause further reservations to * fail since it's too late. */ reserve_mem(RELOC(dt_header_start), hdr->totalsize); memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));#ifdef DEBUG_PROM { int i; prom_printf("reserved memory map:\n"); for (i = 0; i < RELOC(mem_reserve_cnt); i++) prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, RELOC(mem_reserve_map)[i].size); }#endif RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; prom_printf("Device tree strings 0x%x -> 0x%x\n", RELOC(dt_string_start), RELOC(dt_string_end)); prom_printf("Device tree struct 0x%x -> 0x%x\n", RELOC(dt_struct_start), RELOC(dt_struct_end));}static void __init fixup_device_tree(void){#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC) phandle u3, i2c, mpic; u32 u3_rev; u32 interrupts[2]; u32 parent; /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); if (!PHANDLE_VALID(u3)) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); if (!PHANDLE_VALID(i2c)) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); if (!PHANDLE_VALID(mpic)) return; /* check if proper rev of u3 */ if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) == PROM_ERROR) return; if (u3_rev < 0x35 || u3_rev > 0x39) return; /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) return; prom_printf("fixing up bogus interrupts for u3 i2c...\n"); /* interrupt on this revision of u3 is number 0 and level */ interrupts[0] = 0; interrupts[1] = 1; prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts", &interrupts, sizeof(interrupts)); parent = (u32)mpic; prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent", &parent, sizeof(parent));#endif}static void __init prom_find_boot_cpu(void){ struct prom_t *_prom = &RELOC(prom); u32 getprop_rval; ihandle prom_cpu; phandle cpu_pkg; _prom->cpu = 0; if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) return; 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; prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);}static void __init prom_check_initrd(unsigned long r3, unsigned long r4){#ifdef CONFIG_BLK_DEV_INITRD struct prom_t *_prom = &RELOC(prom); if (r3 && r4 && r4 != 0xdeadbeef) { unsigned long val; RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; val = RELOC(prom_initrd_start); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", &val, sizeof(val)); val = RELOC(prom_initrd_end); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", &val, sizeof(val)); reserve_mem(RELOC(prom_initrd_start), RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); }#endif /* CONFIG_BLK_DEV_INITRD */}/* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, unsigned long r6, unsigned long r7){ struct prom_t *_prom; unsigned long hdr; u32 getprop_rval; unsigned long offset = reloc_offset();#ifdef CONFIG_PPC32 reloc_got2(offset);#endif _prom = &RELOC(prom); /* * First zero the BSS */ memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start); /* * Init interface to Open Firmware, get some node references, * like /chosen */ prom_init_client_services(pp); /* * See if this OF is old enough that we need to do explicit maps * and other workarounds */ prom_find_mmu(); /* * Init prom stdout device */ prom_init_stdout(); /* * Check for an initrd */ prom_check_initrd(r3, r4); /* * Get default machine type. At this point, we do not differentiate * between pSeries SMP and pSeries LPAR */ RELOC(of_platform) = prom_find_machine_type(); getprop_rval = RELOC(of_platform); prom_setprop(_prom->chosen, "/chosen", "linux,platform", &getprop_rval, sizeof(getprop_rval));#ifdef CONFIG_PPC_PSERIES /* * On pSeries, inform the firmware about our capabilities */ if (RELOC(of_platform) == PLATFORM_PSERIES || RELOC(of_platform) == PLATFORM_PSERIES_LPAR) prom_send_capabilities();#endif /* * Copy the CPU hold code */ if (RELOC(of_platform) != PLATFORM_POWERMAC) copy_and_flush(0, KERNELBASE + offset, 0x100, 0); /* * Do early parsing of command line */ early_cmdline_parse(); /* * Initialize memory management within prom_init */ prom_init_mem(); /* * Determine which cpu is actually running right _now_ */ prom_find_boot_cpu(); /* * Initialize display devices */ prom_check_displays();#ifdef CONFIG_PPC64 /* * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else * that uses the allocator, we need to make sure we get the top of memory * available for us here... */ if (RELOC(of_platform) == PLATFORM_PSERIES) prom_initialize_tce_table();#endif /* * On non-powermacs, try to instantiate RTAS and puts all CPUs * in spin-loops. PowerMacs don't have a working RTAS and use * a different way to spin CPUs */ if (RELOC(of_platform) != PLATFORM_POWERMAC) { prom_instantiate_rtas(); prom_hold_cpus(); } /* * Fill in some infos for use by the kernel later on */ if (RELOC(prom_memory_limit)) prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit", &RELOC(prom_memory_limit), sizeof(prom_memory_limit));#ifdef CONFIG_PPC64 if (RELOC(ppc64_iommu_off)) prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", NULL, 0); if (RELOC(iommu_force_on)) prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", NULL, 0); if (RELOC(prom_tce_alloc_start)) { prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start", &RELOC(prom_tce_alloc_start), sizeof(prom_tce_alloc_start)); prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end", &RELOC(prom_tce_alloc_end), sizeof(prom_tce_alloc_end)); }#endif /* * Fixup any known bugs in the device-tree */ fixup_device_tree(); /* * Now finally create the flattened device-tree */ prom_printf("copying OF device tree ...\n"); flatten_device_tree(); /* * in case stdin is USB and still active on IBM machines... * Unfortunately quiesce crashes on some powermacs if we have * closed stdin already (in particular the powerbook 101). */ if (RELOC(of_platform) != PLATFORM_POWERMAC) prom_close_stdin(); /* * Call OF "quiesce" method to shut down pending DMA's from * devices etc... */ prom_printf("Calling quiesce ...\n"); call_prom("quiesce", 0, 0); /* * And finally, call the kernel passing it the flattened device * tree and NULL as r5, thus triggering the new entry point which * is common to us and kexec */ hdr = RELOC(dt_header_start); prom_printf("returning from prom_init\n"); prom_debug("->dt_header_start=0x%x\n", hdr);#ifdef CONFIG_PPC32 reloc_got2(-offset);#endif __start(hdr, KERNELBASE + offset, 0); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -