MFC: Use the SMAP data from the loader if it is provided.

This commit is contained in:
jhb 2008-03-21 15:40:33 +00:00
parent 303513927d
commit 664b0cf23f

View File

@ -114,6 +114,7 @@ __FBSDID("$FreeBSD$");
#include <machine/cputypes.h> #include <machine/cputypes.h>
#include <machine/intr_machdep.h> #include <machine/intr_machdep.h>
#include <machine/md_var.h> #include <machine/md_var.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h> #include <machine/pc/bios.h>
#include <machine/pcb.h> #include <machine/pcb.h>
#include <machine/pcb_ext.h> #include <machine/pcb_ext.h>
@ -1640,6 +1641,57 @@ sdtossd(sd, ssd)
ssd->ssd_gran = sd->sd_gran; ssd->ssd_gran = sd->sd_gran;
} }
static int
add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp)
{
int i, physmap_idx;
physmap_idx = *physmap_idxp;
if (boothowto & RB_VERBOSE)
printf("SMAP type=%02x base=%016llx len=%016llx\n",
smap->type, smap->base, smap->length);
if (smap->type != SMAP_TYPE_MEMORY)
return (1);
if (smap->length == 0)
return (1);
#ifndef PAE
if (smap->base >= 0xffffffff) {
printf("%uK of memory above 4GB ignored\n",
(u_int)(smap->length / 1024));
return (1);
}
#endif
for (i = 0; i <= physmap_idx; i += 2) {
if (smap->base < physmap[i + 1]) {
if (boothowto & RB_VERBOSE)
printf(
"Overlapping or non-monotonic memory region, ignoring second region\n");
return (1);
}
}
if (smap->base == physmap[physmap_idx + 1]) {
physmap[physmap_idx + 1] += smap->length;
return (1);
}
physmap_idx += 2;
*physmap_idxp = physmap_idx;
if (physmap_idx == PHYSMAP_SIZE) {
printf(
"Too many segments in the physical address map, giving up\n");
return (0);
}
physmap[physmap_idx] = smap->base;
physmap[physmap_idx + 1] = smap->base + smap->length;
return (1);
}
/* /*
* Populate the (physmap) array with base/bound pairs describing the * Populate the (physmap) array with base/bound pairs describing the
* available physical memory in the system, then test this memory and * available physical memory in the system, then test this memory and
@ -1664,8 +1716,10 @@ getmemsize(int first)
struct vm86context vmc; struct vm86context vmc;
vm_paddr_t pa, physmap[PHYSMAP_SIZE]; vm_paddr_t pa, physmap[PHYSMAP_SIZE];
pt_entry_t *pte; pt_entry_t *pte;
struct bios_smap *smap; struct bios_smap *smap, *smapbase, *smapend;
u_int32_t smapsize;
quad_t dcons_addr, dcons_size; quad_t dcons_addr, dcons_size;
caddr_t kmdp;
#ifdef XBOX #ifdef XBOX
if (arch_i386_is_xbox) { if (arch_i386_is_xbox) {
@ -1744,69 +1798,54 @@ getmemsize(int first)
int15e820: int15e820:
/* /*
* map page 1 R/W into the kernel page table so we can use it * Fetch the memory map with INT 15:E820. First, check to see
* as a buffer. The kernel will unmap this page later. * if the loader supplied it and use that if so. Otherwise,
* use vm86 to invoke the BIOS call directly.
*/ */
pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT);
/*
* get memory map with INT 15:E820
*/
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);
physmap_idx = 0; physmap_idx = 0;
vmf.vmf_ebx = 0; smapbase = NULL;
do { kmdp = preload_search_by_type("elf kernel");
vmf.vmf_eax = 0xE820; if (kmdp == NULL)
vmf.vmf_edx = SMAP_SIG; kmdp = preload_search_by_type("elf32 kernel");
vmf.vmf_ecx = sizeof(struct bios_smap); if (kmdp != NULL)
i = vm86_datacall(0x15, &vmf, &vmc); smapbase = (struct bios_smap *)preload_search_info(kmdp,
if (i || vmf.vmf_eax != SMAP_SIG) MODINFO_METADATA | MODINFOMD_SMAP);
break; if (smapbase != NULL) {
if (boothowto & RB_VERBOSE) /* subr_module.c says:
printf("SMAP type=%02x base=%016llx len=%016llx\n", * "Consumer may safely assume that size value precedes data."
smap->type, smap->base, smap->length); * ie: an int32_t immediately precedes smap.
*/
smapsize = *((u_int32_t *)smapbase - 1);
smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
has_smap = 1; has_smap = 1;
if (smap->type != SMAP_TYPE_MEMORY) for (smap = smapbase; smap < smapend; smap++)
continue; 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);
if (smap->length == 0) vmf.vmf_ebx = 0;
continue; do {
vmf.vmf_eax = 0xE820;
#ifndef PAE vmf.vmf_edx = SMAP_SIG;
if (smap->base >= 0xffffffff) { vmf.vmf_ecx = sizeof(struct bios_smap);
printf("%uK of memory above 4GB ignored\n", i = vm86_datacall(0x15, &vmf, &vmc);
(u_int)(smap->length / 1024)); if (i || vmf.vmf_eax != SMAP_SIG)
continue; break;
} has_smap = 1;
#endif if (!add_smap_entry(smap, physmap, &physmap_idx))
break;
for (i = 0; i <= physmap_idx; i += 2) { } while (vmf.vmf_ebx != 0);
if (smap->base < physmap[i + 1]) { }
if (boothowto & RB_VERBOSE)
printf(
"Overlapping or non-montonic memory region, ignoring second region\n");
continue;
}
}
if (smap->base == physmap[physmap_idx + 1]) {
physmap[physmap_idx + 1] += smap->length;
continue;
}
physmap_idx += 2;
if (physmap_idx == PHYSMAP_SIZE) {
printf(
"Too many segments in the physical address map, giving up\n");
break;
}
physmap[physmap_idx] = smap->base;
physmap[physmap_idx + 1] = smap->base + smap->length;
} while (vmf.vmf_ebx != 0);
/* /*
* Perform "base memory" related probes & setup based on SMAP * Perform "base memory" related probes & setup based on SMAP