Date: Tue, 12 Oct 2010 19:28:33 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r213746 - stable/7/sys/i386/i386 Message-ID: <201010121928.o9CJSXKu059664@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Tue Oct 12 19:28:33 2010 New Revision: 213746 URL: http://svn.freebsd.org/changeset/base/213746 Log: MFC 213226: Rewrite the i386 memory probe: - Check for SMAP data from the loader first. If it exists, don't bother doing any VM86 calls at all. This will be more friendly for non-BIOS boot environments such as EFI, etc. - Move the base memory setup into a new basemem_setup() routine instead of duplicating it. - Simplify the XEN case by removing all of the VM86/SMAP parsing code rather than just jumping over it. - Adjust some comments to better explain the code flow. Modified: stable/7/sys/i386/i386/machdep.c Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/sys/i386/i386/machdep.c ============================================================================== --- stable/7/sys/i386/i386/machdep.c Tue Oct 12 19:28:20 2010 (r213745) +++ stable/7/sys/i386/i386/machdep.c Tue Oct 12 19:28:33 2010 (r213746) @@ -1730,69 +1730,13 @@ add_smap_entry(struct bios_smap *smap, v return (1); } -/* - * Populate the (physmap) array with base/bound pairs describing the - * available physical memory in the system, then test this memory and - * build the phys_avail array describing the actually-available memory. - * - * If we cannot accurately determine the physical memory map, then use - * value from the 0xE801 call, and failing that, the RTC. - * - * Total memory size may be set by the kernel environment variable - * hw.physmem or the compile-time define MAXMEM. - * - * XXX first should be vm_paddr_t. - */ static void -getmemsize(int first) +basemem_setup(void) { - int i, off, physmap_idx, pa_indx, da_indx; - int hasbrokenint12, has_smap; - u_long physmem_tunable; - u_int extmem; - struct vm86frame vmf; - struct vm86context vmc; - vm_paddr_t pa, physmap[PHYSMAP_SIZE]; + vm_paddr_t pa; pt_entry_t *pte; - struct bios_smap *smap, *smapbase, *smapend; - u_int32_t smapsize; - quad_t dcons_addr, dcons_size; - caddr_t kmdp; - - has_smap = 0; -#ifdef XBOX - if (arch_i386_is_xbox) { - /* - * We queried the memory size before, so chop off 4MB for - * the framebuffer and inform the OS of this. - */ - physmap[0] = 0; - physmap[1] = (arch_i386_xbox_memsize * 1024 * 1024) - XBOX_FB_SIZE; - physmap_idx = 0; - goto physmap_done; - } -#endif - - hasbrokenint12 = 0; - TUNABLE_INT_FETCH("hw.hasbrokenint12", &hasbrokenint12); - bzero(&vmf, sizeof(vmf)); - bzero(physmap, sizeof(physmap)); - basemem = 0; - - /* - * Some newer BIOSes has broken INT 12H implementation which cause - * kernel panic immediately. In this case, we need to scan SMAP - * with INT 15:E820 first, then determine base memory size. - */ - if (hasbrokenint12) { - goto int15e820; - } + int i; - /* - * Perform "base memory" related probes & setup - */ - vm86_intcall(0x12, &vmf); - basemem = vmf.vmf_ax; if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); @@ -1832,12 +1776,58 @@ getmemsize(int first) pte = (pt_entry_t *)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; +} + +/* + * Populate the (physmap) array with base/bound pairs describing the + * available physical memory in the system, then test this memory and + * build the phys_avail array describing the actually-available memory. + * + * If we cannot accurately determine the physical memory map, then use + * value from the 0xE801 call, and failing that, the RTC. + * + * Total memory size may be set by the kernel environment variable + * hw.physmem or the compile-time define MAXMEM. + * + * XXX first should be vm_paddr_t. + */ +static void +getmemsize(int first) +{ + int has_smap, off, physmap_idx, pa_indx, da_indx; + u_long physmem_tunable; + vm_paddr_t physmap[PHYSMAP_SIZE]; + pt_entry_t *pte; + quad_t dcons_addr, dcons_size; + int hasbrokenint12, i; + u_int extmem; + struct vm86frame vmf; + struct vm86context vmc; + vm_paddr_t pa; + struct bios_smap *smap, *smapbase, *smapend; + u_int32_t smapsize; + caddr_t kmdp; + + has_smap = 0; +#ifdef XBOX + if (arch_i386_is_xbox) { + /* + * We queried the memory size before, so chop off 4MB for + * the framebuffer and inform the OS of this. + */ + physmap[0] = 0; + physmap[1] = (arch_i386_xbox_memsize * 1024 * 1024) - XBOX_FB_SIZE; + physmap_idx = 0; + goto physmap_done; + } +#endif + bzero(&vmf, sizeof(vmf)); + bzero(physmap, sizeof(physmap)); + basemem = 0; -int15e820: /* - * Fetch the memory map with INT 15:E820. First, check to see - * if the loader supplied it and use that if so. Otherwise, - * use vm86 to invoke the BIOS call directly. + * Check if the loader supplied an SMAP memory map. If so, + * use that and do not make any VM86 calls. */ physmap_idx = 0; smapbase = NULL; @@ -1848,9 +1838,10 @@ int15e820: smapbase = (struct bios_smap *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_SMAP); if (smapbase != NULL) { - /* subr_module.c says: + /* + * subr_module.c says: * "Consumer may safely assume that size value precedes data." - * ie: an int32_t immediately precedes smap. + * ie: an int32_t immediately precedes SMAP. */ smapsize = *((u_int32_t *)smapbase - 1); smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize); @@ -1859,33 +1850,50 @@ int15e820: for (smap = smapbase; smap < smapend; smap++) if (!add_smap_entry(smap, physmap, &physmap_idx)) break; - } else { - /* - * map page 1 R/W into the kernel page table so we can use it - * as a buffer. The kernel will unmap this page later. - */ - pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT); - vmc.npages = 0; - smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + - (1 << PAGE_SHIFT)); - vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); - - vmf.vmf_ebx = 0; - do { - vmf.vmf_eax = 0xE820; - vmf.vmf_edx = SMAP_SIG; - vmf.vmf_ecx = sizeof(struct bios_smap); - i = vm86_datacall(0x15, &vmf, &vmc); - if (i || vmf.vmf_eax != SMAP_SIG) - break; - has_smap = 1; - if (!add_smap_entry(smap, physmap, &physmap_idx)) - break; - } while (vmf.vmf_ebx != 0); + goto have_smap; + } + + /* + * Some newer BIOSes have a broken INT 12H implementation + * which causes a kernel panic immediately. In this case, we + * need use the SMAP to determine the base memory size. + */ + hasbrokenint12 = 0; + TUNABLE_INT_FETCH("hw.hasbrokenint12", &hasbrokenint12); + if (hasbrokenint12 == 0) { + /* Use INT12 to determine base memory size. */ + vm86_intcall(0x12, &vmf); + basemem = vmf.vmf_ax; + basemem_setup(); } /* - * Perform "base memory" related probes & setup based on SMAP + * Fetch the memory map with INT 15:E820. Map page 1 R/W into + * the kernel page table so we can use it as a buffer. The + * kernel will unmap this page later. + */ + pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT); + vmc.npages = 0; + smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); + vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); + + vmf.vmf_ebx = 0; + do { + vmf.vmf_eax = 0xE820; + vmf.vmf_edx = SMAP_SIG; + vmf.vmf_ecx = sizeof(struct bios_smap); + i = vm86_datacall(0x15, &vmf, &vmc); + if (i || vmf.vmf_eax != SMAP_SIG) + break; + has_smap = 1; + if (!add_smap_entry(smap, physmap, &physmap_idx)) + break; + } while (vmf.vmf_ebx != 0); + +have_smap: + /* + * If we didn't fetch the "base memory" size from INT12, + * figure it out from the SMAP (or just guess). */ if (basemem == 0) { for (i = 0; i <= physmap_idx; i += 2) { @@ -1895,49 +1903,39 @@ int15e820: } } - /* - * XXX this function is horribly organized and has to the same - * things that it does above here. - */ + /* XXX: If we couldn't find basemem from SMAP, just guess. */ if (basemem == 0) basemem = 640; - if (basemem > 640) { - printf( - "Preposterous BIOS basemem of %uK, truncating to 640K\n", - basemem); - basemem = 640; - } - - /* - * Let vm86 scribble on pages between basemem and - * ISA_HOLE_START, as above. - */ - for (pa = trunc_page(basemem * 1024); - pa < ISA_HOLE_START; pa += PAGE_SIZE) - pmap_kenter(KERNBASE + pa, pa); - pte = (pt_entry_t *)vm86paddr; - for (i = basemem / 4; i < 160; i++) - pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; + basemem_setup(); } if (physmap[1] != 0) goto physmap_done; /* - * If we failed above, try memory map with INT 15:E801 + * If we failed to find an SMAP, figure out the extended + * memory size. We will then build a simple memory map with + * two segments, one for "base memory" and the second for + * "extended memory". Note that "extended memory" starts at a + * physical address of 1MB and that both basemem and extmem + * are in units of 1KB. + * + * First, try to fetch the extended memory size via INT 15:E801. */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { + /* + * If INT15:E801 fails, this is our last ditch effort + * to determine the extended memory size. Currently + * we prefer the RTC value over INT15:88. + */ #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; #else - /* - * Prefer the RTC value for extended memory. - */ extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010121928.o9CJSXKu059664>