PERFORCE change 184128 for review

John Baldwin jhb at FreeBSD.org
Thu Sep 23 21:37:14 UTC 2010


http://p4web.freebsd.org/@@184128?ac=10

Change 184128 by jhb at jhb_jhbbsd on 2010/09/23 21:36:15

	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 twice, and only call it once during
	  boot.
	- Adjust some comments to better explain the code flow.

Affected files ...

.. //depot/projects/smpng/sys/i386/i386/machdep.c#157 edit

Differences ...

==== //depot/projects/smpng/sys/i386/i386/machdep.c#157 (text+ko) ====

@@ -2029,6 +2029,52 @@
 	return (1);
 }
 
+static void
+basemem_setup(void)
+{
+	pt_entry_t *pte;
+
+	if (basemem > 640) {
+		printf("Preposterous BIOS basemem of %uK, truncating to 640K\n",
+			basemem);
+		basemem = 640;
+	}
+
+	/*
+	 * XXX if biosbasemem is now < 640, there is a `hole'
+	 * between the end of base memory and the start of
+	 * ISA memory.  The hole may be empty or it may
+	 * contain BIOS code or data.  Map it read/write so
+	 * that the BIOS can write to it.  (Memory from 0 to
+	 * the physical end of the kernel is mapped read-only
+	 * to begin with and then parts of it are remapped.
+	 * The parts that aren't remapped form holes that
+	 * remain read-only and are unused by the kernel.
+	 * The base memory area is below the physical end of
+	 * the kernel and right now forms a read-only hole.
+	 * The part of it from PAGE_SIZE to
+	 * (trunc_page(biosbasemem * 1024) - 1) will be
+	 * remapped and used by the kernel later.)
+	 *
+	 * This code is similar to the code used in
+	 * pmap_mapdev, but since no memory needs to be
+	 * allocated we simply change the mapping.
+	 */
+	for (pa = trunc_page(basemem * 1024);
+	     pa < ISA_HOLE_START; pa += PAGE_SIZE)
+		pmap_kenter(KERNBASE + pa, pa);
+
+	/*
+	 * Map pages between basemem and ISA_HOLE_START, if any, r/w into
+	 * the vm86 page table so that vm86 can scribble on them using
+	 * the vm86 map too.  XXX: why 2 ways for this and only 1 way for
+	 * page 0, at least as initialized here?
+	 */
+	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
@@ -2052,13 +2098,20 @@
 	struct vm86frame vmf;
 	struct vm86context vmc;
 	vm_paddr_t pa, physmap[PHYSMAP_SIZE];
-	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;
+#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) {
 		/*
@@ -2071,83 +2124,14 @@
 		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;
-	}
-
-	/*
-	 * 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);
-		basemem = 640;
-	}
-
-	/*
-	 * XXX if biosbasemem is now < 640, there is a `hole'
-	 * between the end of base memory and the start of
-	 * ISA memory.  The hole may be empty or it may
-	 * contain BIOS code or data.  Map it read/write so
-	 * that the BIOS can write to it.  (Memory from 0 to
-	 * the physical end of the kernel is mapped read-only
-	 * to begin with and then parts of it are remapped.
-	 * The parts that aren't remapped form holes that
-	 * remain read-only and are unused by the kernel.
-	 * The base memory area is below the physical end of
-	 * the kernel and right now forms a read-only hole.
-	 * The part of it from PAGE_SIZE to
-	 * (trunc_page(biosbasemem * 1024) - 1) will be
-	 * remapped and used by the kernel later.)
-	 *
-	 * This code is similar to the code used in
-	 * pmap_mapdev, but since no memory needs to be
-	 * allocated we simply change the mapping.
-	 */
-	for (pa = trunc_page(basemem * 1024);
-	     pa < ISA_HOLE_START; pa += PAGE_SIZE)
-		pmap_kenter(KERNBASE + pa, pa);
-
-	/*
-	 * Map pages between basemem and ISA_HOLE_START, if any, r/w into
-	 * the vm86 page table so that vm86 can scribble on them using
-	 * the vm86 map too.  XXX: why 2 ways for this and only 1 way for
-	 * page 0, at least as initialized here?
-	 */
-	pte = (pt_entry_t *)vm86paddr;
-	for (i = basemem / 4; i < 160; i++)
-		pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
-
-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;
 	kmdp = preload_search_by_type("elf kernel");
 	if (kmdp == NULL)
@@ -2156,9 +2140,10 @@
 		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);
@@ -2167,33 +2152,51 @@
 		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);
+		goto have_smap;
+	}
 
-		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);
+	/*
+	 * 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.
+	 */
+	physmap_idx = 0;
+	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) {
@@ -2203,49 +2206,39 @@
 			}
 		}
 
-		/*
-		 * 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
 	}
@@ -2270,6 +2263,7 @@
 	physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024;
 
 physmap_done:
+#endif	
 	/*
 	 * Now, physmap contains a map of physical memory.
 	 */


More information about the p4-projects mailing list