📄 prom.c
字号:
unsigned int va, unsigned int pa, int mode){ unsigned int *pteg; unsigned int hash, i; hash = ((va >> 5) ^ (va >> 21)) & 0x7fff80; pteg = (unsigned int *)(htab + (hash & (hsize - 1))); for (i = 0; i < 8; ++i, pteg += 4) { if ((pteg[1] & 1) == 0) { pteg[1] = ((va >> 16) & 0xff80) | 1; pteg[3] = pa | mode; break; } }}extern unsigned long _SDR1;extern PTE *Hash;extern unsigned long Hash_size;voidprom_alloc_htab(void){ unsigned int hsize; unsigned long htab; unsigned int addr; unsigned long offset = reloc_offset(); /* * Because of OF bugs we can't use the "claim" client * interface to allocate memory for the hash table. * This code is only used on 64-bit PPCs, and the only * 64-bit PPCs at the moment are RS/6000s, and their * OF is based at 0xc00000 (the 12M point), so we just * arbitrarily use the 0x800000 - 0xc00000 region for the * hash table. * -- paulus. */#ifdef CONFIG_POWER4 hsize = 4 << 20; /* POWER4 has no BATs */#else hsize = 2 << 20;#endif /* CONFIG_POWER4 */ htab = (8 << 20); RELOC(Hash) = (void *)(htab + KERNELBASE); RELOC(Hash_size) = hsize; RELOC(_SDR1) = htab + __ilog2(hsize) - 18; /* * Put in PTEs for the first 64MB of RAM */ cacheable_memzero((void *)htab, hsize); for (addr = 0; addr < 0x4000000; addr += 0x1000) make_pte(htab, hsize, addr + KERNELBASE, addr, _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);}#endif /* CONFIG_PPC64BRIDGE */static __init voidprom_instantiate_rtas(void){ ihandle prom_rtas; unsigned int i; struct prom_args prom_args; unsigned long offset = reloc_offset(); prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); if (prom_rtas == (void *) -1) return; RELOC(rtas_size) = 0; call_prom(RELOC("getprop"), 4, 1, prom_rtas, RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); prom_print(RELOC("instantiating rtas")); if (RELOC(rtas_size) == 0) { RELOC(rtas_data) = 0; } else { /* * Ask OF for some space for RTAS. * Actually OF has bugs so we just arbitrarily * use memory at the 6MB point. */ RELOC(rtas_data) = 6 << 20; prom_print(RELOC(" at ")); prom_print_hex(RELOC(rtas_data)); } prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); prom_print(RELOC("...")); prom_args.service = RELOC("call-method"); prom_args.nargs = 3; prom_args.nret = 2; prom_args.args[0] = RELOC("instantiate-rtas"); prom_args.args[1] = prom_rtas; prom_args.args[2] = (void *) RELOC(rtas_data); RELOC(prom)(&prom_args); i = 0; if (prom_args.args[3] == 0) i = (unsigned int)prom_args.args[4]; RELOC(rtas_entry) = i; if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) prom_print(RELOC(" failed\n")); else prom_print(RELOC(" done\n"));}/* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */__initunsigned longprom_init(int r3, int r4, prom_entry pp){ int chrp = 0; unsigned long mem; ihandle prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; int prom_version = 0; unsigned long phys; /* Default */ phys = offset + KERNELBASE; /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) return phys; /* If we came here from BootX, clear the screen, * set up some pointers and return. */ if (r3 == 0x426f6f58 && pp == NULL) { bootx_init(r4, phys); return phys; } /* check if we're prep, return if we are */ if ( *(unsigned long *)(0) == 0xdeadc0de ) return phys; /* First get a handle for the stdout device */ RELOC(prom) = pp; RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1, RELOC("/chosen")); if (RELOC(prom_chosen) == (void *)-1) prom_exit(); if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), RELOC("stdout"), &RELOC(prom_stdout), sizeof(prom_stdout)) <= 0) prom_exit(); /* Get the full OF pathname of the stdout device */ mem = (unsigned long) RELOC(klimit) + offset; p = (char *) mem; memset(p, 0, 256); call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255); RELOC(of_stdout_device) = PTRUNRELOC(p); mem += strlen(p) + 1; /* Find the OF version */ prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom")); prom_version = 0; if (prom_op != (void*)-1) { char model[64]; int sz; sz = (int)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")); /* Get the boot device and translate it to a full OF pathname. */ p = (char *) mem; l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(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 = ALIGN(mem + strlen(d) + 1); } prom_instantiate_rtas();#ifdef CONFIG_PPC64BRIDGE /* * Find out how much memory we have and allocate a * suitably-sized hash table. */ prom_alloc_htab();#endif#ifdef CONFIG_SMP prom_hold_cpus(mem);#endif mem = check_display(mem); prom_print(RELOC("copying OF device tree...")); mem = copy_device_tree(mem, mem + (1<<20)); prom_print(RELOC("done\n")); RELOC(klimit) = (char *) (mem - offset); /* If we are already running at 0xc0000000, we assume we were loaded by * an OF bootloader which did set a BAT for us. This breaks OF translate * so we force phys to be 0 */ if (offset == 0) phys = 0; else { if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { prom_print(RELOC(" no MMU found\n")); } else { int nargs; struct prom_args prom_args; nargs = 4; prom_args.service = RELOC("call-method"); prom_args.nargs = nargs; prom_args.nret = 4; prom_args.args[0] = RELOC("translate"); prom_args.args[1] = prom_mmu; prom_args.args[2] = (void *)(offset + KERNELBASE); prom_args.args[3] = (void *)1; RELOC(prom)(&prom_args); /* We assume the phys. address size is 3 cells */ if (prom_args.args[nargs] != 0) prom_print(RELOC(" (translate failed)\n")); else phys = (unsigned long)prom_args.args[nargs+3]; } }#ifdef CONFIG_BOOTX_TEXT if (RELOC(prom_disp_node) != 0) setup_disp_fake_bi(RELOC(prom_disp_node));#endif /* If OpenFirmware version >= 3, then use quiesce call */ if (prom_version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); }#ifdef CONFIG_BOOTX_TEXT if (!chrp && RELOC(disp_bi)) { RELOC(prom_stdout) = 0; /* stop OF output */ clearscreen(); prepare_disp_BAT(); prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); prom_drawstring(RELOC("booting...\n")); RELOC(bootx_text_mapped) = 1; } else { RELOC(bootx_text_mapped) = 0; }#endif prom_print(RELOC("returning ")); prom_print_hex(phys); prom_print(RELOC(" from prom_init\n")); RELOC(prom_stdout) = 0; return phys;}void phys_call_rtas(int service, int nargs, int nret, ...){ va_list list; union { unsigned long words[16]; double align; } u; unsigned long offset = reloc_offset(); void (*rtas)(void *, unsigned long); int i; u.words[0] = service; u.words[1] = nargs; u.words[2] = nret; va_start(list, nret); for (i = 0; i < nargs; ++i) u.words[i+3] = va_arg(list, unsigned long); va_end(list); rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry); rtas(&u, RELOC(rtas_data));}#ifdef CONFIG_BOOTX_TEXT__init static voidprom_welcome(boot_infos_t* bi, unsigned long phys){ unsigned long offset = reloc_offset(); unsigned long flags; unsigned long pvr; prom_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); prom_drawstring(RELOC("\nstarted at : 0x")); prom_drawhex(phys); prom_drawstring(RELOC("\nlinked at : 0x")); prom_drawhex(KERNELBASE); prom_drawstring(RELOC("\nframe buffer at : 0x")); prom_drawhex((unsigned long)bi->dispDeviceBase); prom_drawstring(RELOC(" (phys), 0x")); prom_drawhex((unsigned long)bi->logicalDisplayBase); prom_drawstring(RELOC(" (log)")); prom_drawstring(RELOC("\nklimit : 0x")); prom_drawhex((unsigned long)RELOC(klimit)); prom_drawstring(RELOC("\nMSR : 0x")); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); prom_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { prom_drawstring(RELOC("\nHID0 : 0x")); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); prom_drawhex(flags); } if (pvr == 8 || pvr == 12) { prom_drawstring(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); prom_drawhex(flags); } prom_drawstring(RELOC("\n\n"));}/* Calc BAT values for mapping the display and store them * in disp_BAT. Those values are then used from head.S to map * the display during identify_machine() and MMU_Init() * * For now, the display is mapped in place (1:1). This should * be changed if the display physical address overlaps * KERNELBASE, which is fortunately not the case on any machine * I know of. This mapping is temporary and will disappear as * soon as the setup done by MMU_Init() is applied * * For now, we align the BAT and then map 8Mb on 601 and 16Mb * on other PPCs. This may cause trouble if the framebuffer * is really badly aligned, but I didn't encounter this case * yet. */__initstatic voidprepare_disp_BAT(void){ unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long addr = (unsigned long)bi->dispDeviceBase; if ((_get_PVR() >> 16) != 1) { /* 603, 604, G3, G4, ... */ addr &= 0xFF000000UL; RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2; RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ addr &= 0xFF800000UL; RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; } bi->logicalDisplayBase = bi->dispDeviceBase;}#endifstatic int prom_set_color(ihandle ih, int i, int r, int g, int b){ struct prom_args prom_args; unsigned long offset = reloc_offset(); prom_args.service = RELOC("call-method"); prom_args.nargs = 6; prom_args.nret = 1; prom_args.args[0] = RELOC("color!"); prom_args.args[1] = ih; prom_args.args[2] = (void *) i; prom_args.args[3] = (void *) b; prom_args.args[4] = (void *) g; prom_args.args[5] = (void *) r; RELOC(prom)(&prom_args); return (int) prom_args.args[6];}/* * 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. */__initstatic unsigned longcheck_display(unsigned long mem){ phandle node; ihandle ih; int i; unsigned long offset = reloc_offset(); 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 }; RELOC(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 ((int) call_prom(RELOC("package-to-path"), 3, 1, node, path, 255) < 0) continue; prom_print(RELOC("opening display ")); prom_print(path); ih = call_prom(RELOC("open"), 1, 1, path); if (ih == 0 || ih == (ihandle) -1) { prom_print(RELOC("... failed\n")); continue; } prom_print(RELOC("... ok\n")); if (RELOC(prom_disp_node) == 0) RELOC(prom_disp_node) = 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 ALIGN(mem);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -