prom.c
字号:
/* Set the common spinloop variable, so all of the secondary cpus * will block when they are awakened from their OF spinloop. * This must occur for both SMP and non SMP kernels, since OF will * be trashed when we move the kernel. */ *spinloop = 0;#ifdef CONFIG_HMT for (i=0; i < NR_CPUS; i++) { RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; }#endif /* look for cpus */ for (node = 0; prom_next_node(&node); ) { type[0] = 0; prom_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, RELOC("cpu")) != 0) continue; /* Skip non-configured cpus. */ prom_getprop(node, "status", type, sizeof(type)); if (strcmp(type, RELOC("okay")) != 0) continue; reg = -1; prom_getprop(node, "reg", ®, sizeof(reg)); path = (char *) mem; memset(path, 0, 256); if (call_prom("package-to-path", 3, 1, node, path, 255) == PROM_ERROR) continue; prom_debug("\ncpuid = 0x%x\n", cpuid); prom_debug("cpu hw idx = 0x%x\n", reg); lpaca[cpuid].hw_cpu_id = reg; /* Init the acknowledge var which will be reset by * the secondary cpu when it awakens from its OF * spinloop. */ *acknowledge = (unsigned long)-1; propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", &interrupt_server, sizeof(interrupt_server)); if (propsize < 0) { /* no property. old hardware has no SMT */ cpu_threads = 1; interrupt_server[0] = reg; /* fake it with phys id */ } else { /* We have a threaded processor */ cpu_threads = propsize / sizeof(u32); if (cpu_threads > MAX_CPU_THREADS) { prom_printf("SMT: too many threads!\n" "SMT: found %x, max is %x\n", cpu_threads, MAX_CPU_THREADS); cpu_threads = 1; /* ToDo: panic? */ } } hw_cpu_num = interrupt_server[0]; if (hw_cpu_num != _prom->cpu) { /* Primary Thread of non-boot cpu */ prom_printf("%x : starting cpu %s... ", cpuid, path); call_prom("start-cpu", 3, 0, node, secondary_hold, cpuid); for ( i = 0 ; (i < 100000000) && (*acknowledge == ((unsigned long)-1)); i++ ) ; if (*acknowledge == cpuid) { prom_printf("... done\n"); /* We have to get every CPU out of OF, * even if we never start it. */ if (cpuid >= NR_CPUS) goto next;#ifdef CONFIG_SMP /* Set the number of active processors. */ _systemcfg->processorCount++; cpu_set(cpuid, RELOC(cpu_available_map)); cpu_set(cpuid, RELOC(cpu_possible_map)); cpu_set(cpuid, RELOC(cpu_present_at_boot));#endif } else { prom_printf("... failed: %x\n", *acknowledge); } }#ifdef CONFIG_SMP else { prom_printf("%x : booting cpu %s\n", cpuid, path); cpu_set(cpuid, RELOC(cpu_available_map)); cpu_set(cpuid, RELOC(cpu_possible_map)); cpu_set(cpuid, RELOC(cpu_online_map)); cpu_set(cpuid, RELOC(cpu_present_at_boot)); }#endifnext:#ifdef CONFIG_SMP /* Init paca for secondary threads. They start later. */ for (i=1; i < cpu_threads; i++) { cpuid++; if (cpuid >= NR_CPUS) continue; lpaca[cpuid].hw_cpu_id = interrupt_server[i]; prom_printf("%x : preparing thread ... ", interrupt_server[i]); if (_naca->smt_state) { cpu_set(cpuid, RELOC(cpu_available_map)); cpu_set(cpuid, RELOC(cpu_present_at_boot)); prom_printf("available\n"); } else { prom_printf("not available\n"); } }#endif cpuid++; }#ifdef CONFIG_HMT /* Only enable HMT on processors that provide support. */ if (__is_processor(PV_PULSAR) || __is_processor(PV_ICESTAR) || __is_processor(PV_SSTAR)) { prom_printf(" starting secondary threads\n"); for (i = 0; i < NR_CPUS; i += 2) { if (!cpu_online(i)) continue; if (i == 0) { unsigned long pir = _get_PIR(); if (__is_processor(PV_PULSAR)) { RELOC(hmt_thread_data)[i].pir = pir & 0x1f; } else { RELOC(hmt_thread_data)[i].pir = pir & 0x3ff; } }/* cpu_set(i+1, cpu_online_map); */ cpu_set(i+1, RELOC(cpu_possible_map)); } _systemcfg->processorCount *= 2; } else { prom_printf("Processor is not HMT capable\n"); }#endif 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 smt_setup(void){ char *p, *q; char my_smt_enabled = SMT_DYNAMIC; ihandle prom_options = 0; char option[9]; unsigned long offset = reloc_offset(); struct naca_struct *_naca = RELOC(naca); char found = 0; if (strstr(RELOC(cmd_line), RELOC("smt-enabled="))) { for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-enabled="))) != 0; ) { q = p + 12; if (p > RELOC(cmd_line) && p[-1] != ' ') continue; found = 1; if (q[0] == 'o' && q[1] == 'f' && q[2] == 'f' && (q[3] == ' ' || q[3] == '\0')) { my_smt_enabled = SMT_OFF; } else if (q[0]=='o' && q[1] == 'n' && (q[2] == ' ' || q[2] == '\0')) { my_smt_enabled = SMT_ON; } else { my_smt_enabled = SMT_DYNAMIC; } } } if (!found) { prom_options = call_prom("finddevice", 1, 1, ADDR("/options")); if (prom_options != (ihandle) -1) { prom_getprop(prom_options, "ibm,smt-enabled", option, sizeof(option)); if (option[0] != 0) { found = 1; if (!strcmp(option, RELOC("off"))) my_smt_enabled = SMT_OFF; else if (!strcmp(option, RELOC("on"))) my_smt_enabled = SMT_ON; else my_smt_enabled = SMT_DYNAMIC; } } } if (!found ) my_smt_enabled = SMT_DYNAMIC; /* default to on */ _naca->smt_state = my_smt_enabled;}#ifdef CONFIG_BOOTX_TEXT/* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too */static void __init setup_disp_fake_bi(ihandle dp){ int width = 640, height = 480, depth = 8, pitch; unsigned address; struct pci_reg_property addrs[8]; int i, naddrs; char name[64]; unsigned long offset = reloc_offset(); memset(name, 0, sizeof(name)); prom_getprop(dp, "name", name, sizeof(name)); name[sizeof(name)-1] = 0; prom_printf("Initializing fake screen: %s\n", name); prom_getprop(dp, "width", &width, sizeof(width)); prom_getprop(dp, "height", &height, sizeof(height)); prom_getprop(dp, "depth", &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); prom_getprop(dp, "linebytes", &pitch, sizeof(pitch)); if (pitch == 1) pitch = 0x1000; /* for strange IBM display */ address = 0; prom_printf("width %x height %x depth %x linebytes %x\n", width, height, depth, depth); prom_getprop(dp, "address", &address, sizeof(address)); if (address == 0) { /* look for an assigned address with a size of >= 1MB */ naddrs = prom_getprop(dp, "assigned-addresses", addrs, sizeof(addrs)); naddrs /= sizeof(struct pci_reg_property); for (i = 0; i < naddrs; ++i) { if (addrs[i].size_lo >= (1 << 20)) { address = addrs[i].addr.a_lo; /* use the BE aperture if possible */ if (addrs[i].size_lo >= (16 << 20)) address += (8 << 20); break; } } if (address == 0) { prom_printf("Failed to get address of frame buffer\n"); return; } } btext_setup_display(width, height, depth, pitch, address); prom_printf("Addr of fb: %x\n", address); RELOC(boot_text_mapped) = 0;}#endif /* CONFIG_BOOTX_TEXT */static void __init prom_init_client_services(unsigned long pp){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); /* Get a handle to the prom entry point before anything else */ _prom->entry = pp; /* Init default value for phys size */ _prom->encode_phys_size = 32; /* get a handle for the stdout device */ _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); if ((long)_prom->chosen <= 0) prom_panic("cannot find chosen"); /* msg won't be printed :( */ /* get device tree root */ _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); if ((long)_prom->root <= 0) prom_panic("cannot find device tree root"); /* msg won't be printed :( */}static void __init prom_init_stdout(void){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); u32 val; if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) prom_panic("cannot find stdout"); _prom->stdout = val;}static int __init prom_find_machine_type(void){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); char compat[256]; int len, i = 0; 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("MacRISC4"))) return PLATFORM_POWERMAC; i += sl + 1; } } /* Default to pSeries */ return PLATFORM_PSERIES;}static int __init prom_set_color(ihandle ih, int i, int r, int g, int b){ unsigned long offset = reloc_offset(); 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 unsigned long __init check_display(unsigned long mem){ phandle node; ihandle ih; int i, j; unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); char type[16], *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 }; const unsigned char *clut; _prom->disp_node = 0; prom_printf("Looking for displays\n"); if (RELOC(of_stdout_device) != 0) prom_printf("OF stdout is : %s\n", PTRRELOC(RELOC(of_stdout_device))); for (node = 0; prom_next_node(&node); ) { type[0] = 0; 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 = (char *) mem; memset(path, 0, 256); /* * leave some room at the end of the path for appending extra * arguments */ if (call_prom("package-to-path", 3, 1, node, path, 250) < 0) continue; prom_printf("found display : %s\n", path); /* * 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); RELOC(prom_num_displays) = i + 1; 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_nodes[i]) = RELOC(prom_display_nodes[i-1]); } _prom->disp_node = node; } RELOC(prom_display_paths[i]) = PTRUNRELOC(path); RELOC(prom_display_nodes[i]) = node; if (_prom->disp_node == 0) _prom->disp_node = node; if (RELOC(prom_num_displays) >= FB_MAX) break; } prom_printf("Opening displays...\n"); for (j = RELOC(prom_num_displays) - 1; j >= 0; j--) { path = PTRRELOC(RELOC(prom_display_paths[j])); prom_printf("opening display : %s", path); ih = call_prom("open", 1, 1, path); if (ih == (ihandle)0 || ih == (ihandle)-1) { prom_printf("... failed\n"); continue; } prom_printf("... done\n"); /* Setup a useable 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 DOUBLEWORD_ALIGN(mem);}/* 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); if (*mem_start + needed > *mem_end) {#ifdef CONFIG_BLK_DEV_INITRD unsigned long offset = reloc_offset(); /* FIXME: Apple OF doesn't map unclaimed mem. If this * ever happened on G5, we'd need to fix. */ unsigned long initrd_len; if (*mem_end != RELOC(initrd_start)) prom_panic("No memory for copy_device_tree"); prom_printf("Huge device_tree: moving initrd\n"); /* Move by 4M. */ initrd_len = RELOC(initrd_end) - RELOC(initrd_start); *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024; memmove((void *)*mem_end, (void *)RELOC(initrd_start), initrd_len); RELOC(initrd_start) = *mem_end; RELOC(initrd_end) = RELOC(initrd_start) + initrd_len;#else prom_panic("No memory for copy_device_tree");#endif } ret = (void *)*mem_start; *mem_start += needed; return ret;}#define make_room(startp, endp, type) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -