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/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h>
#include <machine/pcb.h>
#include <machine/pcb_ext.h>
@ -1640,6 +1641,57 @@ sdtossd(sd, ssd)
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
* available physical memory in the system, then test this memory and
@ -1664,8 +1716,10 @@ getmemsize(int first)
struct vm86context vmc;
vm_paddr_t pa, physmap[PHYSMAP_SIZE];
pt_entry_t *pte;
struct bios_smap *smap;
struct bios_smap *smap, *smapbase, *smapend;
u_int32_t smapsize;
quad_t dcons_addr, dcons_size;
caddr_t kmdp;
#ifdef XBOX
if (arch_i386_is_xbox) {
@ -1744,69 +1798,54 @@ getmemsize(int first)
int15e820:
/*
* 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.
* 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.
*/
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;
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;
if (boothowto & RB_VERBOSE)
printf("SMAP type=%02x base=%016llx len=%016llx\n",
smap->type, smap->base, smap->length);
smapbase = NULL;
kmdp = preload_search_by_type("elf kernel");
if (kmdp == NULL)
kmdp = preload_search_by_type("elf32 kernel");
if (kmdp != NULL)
smapbase = (struct bios_smap *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_SMAP);
if (smapbase != NULL) {
/* subr_module.c says:
* "Consumer may safely assume that size value precedes data."
* ie: an int32_t immediately precedes smap.
*/
smapsize = *((u_int32_t *)smapbase - 1);
smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
has_smap = 1;
if (smap->type != SMAP_TYPE_MEMORY)
continue;
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);
if (smap->length == 0)
continue;
#ifndef PAE
if (smap->base >= 0xffffffff) {
printf("%uK of memory above 4GB ignored\n",
(u_int)(smap->length / 1024));
continue;
}
#endif
for (i = 0; i <= physmap_idx; i += 2) {
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);
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);
}
/*
* Perform "base memory" related probes & setup based on SMAP