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