Use the SMAP data from the loader if it is provided instead of using
virtual 86 mode to query the BIOS directly. This is needed for certain HP machines whose BIOS only provide an SMAP when invoked from real mode. On such machines the loader will be able to query the SMAP successfully due to the recent BTX changes, but the kernel will not. One thing I'm not sure of is if we can skip the INT 12h probe altogether if we have the SMAP from the loader as it seems that we do the INT 12h probe to setup enough state so we can use vm86 to call the BIOS. MFC after: 1 week
This commit is contained in:
parent
858a959376
commit
d0234f752f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=177155
@ -115,6 +115,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>
|
||||||
@ -1648,6 +1649,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
|
||||||
@ -1672,8 +1724,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;
|
||||||
|
|
||||||
has_smap = 0;
|
has_smap = 0;
|
||||||
#ifdef XBOX
|
#ifdef XBOX
|
||||||
@ -1751,69 +1805,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-monotonic 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
|
||||||
|
Loading…
Reference in New Issue
Block a user