📄 prom_init.c
字号:
/* Primary Thread of non-boot cpu */ prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); call_prom("start-cpu", 3, 0, node, secondary_hold, reg); for (i = 0; (i < 100000000) && (*acknowledge == ((unsigned long)-1)); i++ ) mb(); if (*acknowledge == reg) prom_printf("done\n"); else prom_printf("failed: %x\n", *acknowledge); }#ifdef CONFIG_SMP else prom_printf("%x : boot cpu %x\n", cpuid, reg);#endif /* CONFIG_SMP */ /* Reserve cpu #s for secondary threads. They start later. */ cpuid += cpu_threads; } if (cpuid > NR_CPUS) prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) ") exceeded: ignoring extras\n"); prom_debug("prom_hold_cpus: end...\n");}static void __init prom_init_client_services(unsigned long pp){ struct prom_t *_prom = &RELOC(prom); /* Get a handle to the prom entry point before anything else */ RELOC(prom_entry) = pp; /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); if (!PHANDLE_VALID(_prom->chosen)) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); if (!PHANDLE_VALID(_prom->root)) prom_panic("cannot find device tree root"); /* msg won't be printed :( */ _prom->mmumap = 0;}#ifdef CONFIG_PPC32/* * For really old powermacs, we need to map things we claim. * For that, we need the ihandle of the mmu. * Also, on the longtrail, we need to work around other bugs. */static void __init prom_find_mmu(void){ struct prom_t *_prom = &RELOC(prom); phandle oprom; char version[64]; oprom = call_prom("finddevice", 1, 1, ADDR("/openprom")); if (!PHANDLE_VALID(oprom)) return; if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) return; version[sizeof(version) - 1] = 0; /* XXX might need to add other versions here */ if (strcmp(version, "Open Firmware, 1.0.5") == 0) of_workarounds = OF_WA_CLAIM; else if (strncmp(version, "FirmWorks,3.", 12) == 0) { of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL; call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim"); } else return; _prom->memory = call_prom("open", 1, 1, ADDR("/memory")); prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, sizeof(_prom->mmumap)); if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap)) of_workarounds &= ~OF_WA_CLAIM; /* hmmm */}#else#define prom_find_mmu()#endifstatic void __init prom_init_stdout(void){ struct prom_t *_prom = &RELOC(prom); char *path = RELOC(of_stdout_device); char type[16]; u32 val; if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) prom_panic("cannot find stdout"); _prom->stdout = val; /* Get the full OF pathname of the stdout device */ memset(path, 0, 256); call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); val = call_prom("instance-to-package", 1, 1, _prom->stdout); prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package", &val, sizeof(val)); prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path", path, strlen(path) + 1); /* If it's a display, note it */ memset(type, 0, sizeof(type)); prom_getprop(val, "device_type", type, sizeof(type)); if (strcmp(type, RELOC("display")) == 0) prom_setprop(val, path, "linux,boot-display", NULL, 0);}static void __init prom_close_stdin(void){ struct prom_t *_prom = &RELOC(prom); ihandle val; if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) call_prom("close", 1, 0, val);}static int __init prom_find_machine_type(void){ struct prom_t *_prom = &RELOC(prom); char compat[256]; int len, i = 0;#ifdef CONFIG_PPC64 phandle rtas; int x;#endif /* Look for a PowerMac */ len = prom_getprop(_prom->root, "compatible", compat, sizeof(compat)-1); if (len > 0) { compat[len] = 0; while (i < len) { char *p = &compat[i]; int sl = strlen(p); if (sl == 0) break; if (strstr(p, RELOC("Power Macintosh")) || strstr(p, RELOC("MacRISC"))) return PLATFORM_POWERMAC;#ifdef CONFIG_PPC64 /* We must make sure we don't detect the IBM Cell * blades as pSeries due to some firmware issues, * so we do it here. */ if (strstr(p, RELOC("IBM,CBEA")) || strstr(p, RELOC("IBM,CPBW-1.0"))) return PLATFORM_GENERIC;#endif /* CONFIG_PPC64 */ i += sl + 1; } }#ifdef CONFIG_PPC64 /* If not a mac, try to figure out if it's an IBM pSeries or any other * PAPR compliant platform. We assume it is if : * - /device_type is "chrp" (please, do NOT use that for future * non-IBM designs ! * - it has /rtas */ len = prom_getprop(_prom->root, "device_type", compat, sizeof(compat)-1); if (len <= 0) return PLATFORM_GENERIC; if (strcmp(compat, RELOC("chrp"))) return PLATFORM_GENERIC; /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); if (!PHANDLE_VALID(rtas)) return PLATFORM_GENERIC; x = prom_getproplen(rtas, "ibm,hypertas-functions"); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); return PLATFORM_PSERIES_LPAR; } return PLATFORM_PSERIES;#else return PLATFORM_GENERIC;#endif}static int __init prom_set_color(ihandle ih, int i, int r, int g, int b){ return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, 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 void __init prom_check_displays(void){ char type[16], *path; phandle node; ihandle ih; int i; 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 }; const unsigned char *clut; prom_printf("Looking for displays\n"); for (node = 0; prom_next_node(&node); ) { memset(type, 0, sizeof(type)); prom_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, RELOC("display")) != 0) continue; /* It seems OF doesn't null-terminate the path :-( */ path = RELOC(prom_scratch); memset(path, 0, PROM_SCRATCH_SIZE); /* * leave some room at the end of the path for appending extra * arguments */ if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) == PROM_ERROR) continue; prom_printf("found display : %s, opening ... ", path); ih = call_prom("open", 1, 1, path); if (ih == 0) { prom_printf("failed\n"); continue; } /* Success */ prom_printf("done\n"); prom_setprop(node, path, "linux,opened", NULL, 0); /* Setup a usable color table when the appropriate * method is available. Should update this to set-colors */ clut = RELOC(default_colors); for (i = 0; i < 32; i++, clut += 3) if (prom_set_color(ih, i, clut[0], clut[1], clut[2]) != 0) break;#ifdef CONFIG_LOGO_LINUX_CLUT224 clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) if (prom_set_color(ih, i + 32, clut[0], clut[1], clut[2]) != 0) break;#endif /* CONFIG_LOGO_LINUX_CLUT224 */ }}/* Return (relocated) pointer to this much memory: moves initrd if reqd. */static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, unsigned long needed, unsigned long align){ void *ret; *mem_start = _ALIGN(*mem_start, align); while ((*mem_start + needed) > *mem_end) { unsigned long room, chunk; prom_debug("Chunk exhausted, claiming more at %x...\n", RELOC(alloc_bottom)); room = RELOC(alloc_top) - RELOC(alloc_bottom); if (room > DEVTREE_CHUNK_SIZE) room = DEVTREE_CHUNK_SIZE; if (room < PAGE_SIZE) prom_panic("No memory for flatten_device_tree (no room)"); chunk = alloc_up(room, 0); if (chunk == 0) prom_panic("No memory for flatten_device_tree (claim failed)"); *mem_end = RELOC(alloc_top); } ret = (void *)*mem_start; *mem_start += needed; return ret;}#define dt_push_token(token, mem_start, mem_end) \ do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0)static unsigned long __init dt_find_string(char *str){ char *s, *os; 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -