Author: jhb
Date: Tue Oct 12 19:28:20 2010
New Revision: 213745
URL: http://svn.freebsd.org/changeset/base/213745

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/8/sys/i386/i386/machdep.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/i386/i386/machdep.c
==============================================================================
--- stable/8/sys/i386/i386/machdep.c    Tue Oct 12 19:24:41 2010        
(r213744)
+++ stable/8/sys/i386/i386/machdep.c    Tue Oct 12 19:28:20 2010        
(r213745)
@@ -1938,6 +1938,7 @@ sdtossd(sd, ssd)
        ssd->ssd_gran  = sd->sd_gran;
 }
 
+#ifndef XEN
 static int
 add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
 {
@@ -2017,78 +2018,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
-#if defined(XEN)
-       has_smap = 0;
-       Maxmem = xen_start_info->nr_pages - init_first;
-       physmem = Maxmem;
-       basemem = 0;
-       physmap[0] = init_first << PAGE_SHIFT;
-       physmap[1] = ptoa(Maxmem) - round_page(MSGBUF_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);
@@ -2128,12 +2064,69 @@ 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;
+}
+#endif
+
+/*
+ * 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;
+#ifndef XEN
+       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;
+#endif
+
+       has_smap = 0;
+#if defined(XEN)
+       Maxmem = xen_start_info->nr_pages - init_first;
+       physmem = Maxmem;
+       basemem = 0;
+       physmap[0] = init_first << PAGE_SHIFT;
+       physmap[1] = ptoa(Maxmem) - round_page(MSGBUF_SIZE);
+       physmap_idx = 0;
+#else
+#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;
@@ -2144,9 +2137,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);
@@ -2155,33 +2149,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;
        }
 
        /*
-        * Perform "base memory" related probes & setup based on 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();
+       }
+
+       /*
+        * 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) {
@@ -2191,49 +2202,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;
-#elif !defined(XEN)
-               /*
-                * Prefer the RTC value for extended memory.
-                */
+#else
                extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8);
 #endif
        }
@@ -2258,6 +2259,7 @@ int15e820:
        physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024;
 
 physmap_done:
+#endif 
        /*
         * Now, physmap contains a map of physical memory.
         */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to