mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-11 09:50:12 +00:00
EFIRT: SetVirtualAddressMap with 1:1 mapping after exiting boot services
This fixes a problem encountered on the Lenovo Thinkpad X220/Yoga 11e where runtime services would try to inexplicably jump to other parts of memory where it shouldn't be when attempting to enumerate EFI vars, causing a panic. The virtual mapping is enabled by default and can be disabled by setting efi_disable_vmap in loader.conf(5). Reviewed by: kib (earlier version) MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D14677
This commit is contained in:
parent
a95659f75f
commit
63ee68c220
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=330868
@ -236,17 +236,48 @@ bi_copymodules(vm_offset_t addr)
|
|||||||
return(addr);
|
return(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
efi_do_vmap(EFI_MEMORY_DESCRIPTOR *mm, UINTN sz, UINTN mmsz, UINT32 mmver)
|
||||||
|
{
|
||||||
|
EFI_MEMORY_DESCRIPTOR *desc, *viter, *vmap;
|
||||||
|
EFI_STATUS ret;
|
||||||
|
int curr, ndesc, nset;
|
||||||
|
|
||||||
|
nset = 0;
|
||||||
|
desc = mm;
|
||||||
|
ndesc = sz / mmsz;
|
||||||
|
vmap = malloc(sz);
|
||||||
|
if (vmap == NULL)
|
||||||
|
/* This isn't really an EFI error case, but pretend it is */
|
||||||
|
return (EFI_OUT_OF_RESOURCES);
|
||||||
|
viter = vmap;
|
||||||
|
for (curr = 0; curr < ndesc;
|
||||||
|
curr++, desc = NextMemoryDescriptor(desc, mmsz)) {
|
||||||
|
if ((desc->Attribute & EFI_MEMORY_RUNTIME) != 0) {
|
||||||
|
++nset;
|
||||||
|
desc->VirtualStart = desc->PhysicalStart;
|
||||||
|
*viter = *desc;
|
||||||
|
viter = NextMemoryDescriptor(viter, mmsz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = RS->SetVirtualAddressMap(nset * mmsz, mmsz, mmver, vmap);
|
||||||
|
free(vmap);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bi_load_efi_data(struct preloaded_file *kfp)
|
bi_load_efi_data(struct preloaded_file *kfp)
|
||||||
{
|
{
|
||||||
EFI_MEMORY_DESCRIPTOR *mm;
|
EFI_MEMORY_DESCRIPTOR *mm;
|
||||||
EFI_PHYSICAL_ADDRESS addr;
|
EFI_PHYSICAL_ADDRESS addr;
|
||||||
EFI_STATUS status;
|
EFI_STATUS status;
|
||||||
|
const char *efi_novmap;
|
||||||
size_t efisz;
|
size_t efisz;
|
||||||
UINTN efi_mapkey;
|
UINTN efi_mapkey;
|
||||||
UINTN mmsz, pages, retry, sz;
|
UINTN mmsz, pages, retry, sz;
|
||||||
UINT32 mmver;
|
UINT32 mmver;
|
||||||
struct efi_map_header *efihdr;
|
struct efi_map_header *efihdr;
|
||||||
|
bool do_vmap;
|
||||||
|
|
||||||
#if defined(__amd64__) || defined(__aarch64__)
|
#if defined(__amd64__) || defined(__aarch64__)
|
||||||
struct efi_fb efifb;
|
struct efi_fb efifb;
|
||||||
@ -266,6 +297,11 @@ bi_load_efi_data(struct preloaded_file *kfp)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
do_vmap = true;
|
||||||
|
efi_novmap = getenv("efi_disable_vmap");
|
||||||
|
if (efi_novmap != NULL)
|
||||||
|
do_vmap = strcasecmp(efi_novmap, "YES") != 0;
|
||||||
|
|
||||||
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
|
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -321,6 +357,13 @@ bi_load_efi_data(struct preloaded_file *kfp)
|
|||||||
}
|
}
|
||||||
status = BS->ExitBootServices(IH, efi_mapkey);
|
status = BS->ExitBootServices(IH, efi_mapkey);
|
||||||
if (EFI_ERROR(status) == 0) {
|
if (EFI_ERROR(status) == 0) {
|
||||||
|
/*
|
||||||
|
* This may be disabled by setting efi_disable_vmap in
|
||||||
|
* loader.conf(5). By default we will setup the virtual
|
||||||
|
* map entries.
|
||||||
|
*/
|
||||||
|
if (do_vmap)
|
||||||
|
efi_do_vmap(mm, sz, mmsz, mmver);
|
||||||
efihdr->memory_size = sz;
|
efihdr->memory_size = sz;
|
||||||
efihdr->descriptor_size = mmsz;
|
efihdr->descriptor_size = mmsz;
|
||||||
efihdr->descriptor_version = mmver;
|
efihdr->descriptor_version = mmver;
|
||||||
|
@ -165,7 +165,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
|
|||||||
descsz)) {
|
descsz)) {
|
||||||
if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
|
if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (p->md_virt != NULL) {
|
if (p->md_virt != NULL && (uint64_t)p->md_virt != p->md_phys) {
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
printf("EFI Runtime entry %d is mapped\n", i);
|
printf("EFI Runtime entry %d is mapped\n", i);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -169,7 +169,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
|
|||||||
descsz)) {
|
descsz)) {
|
||||||
if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
|
if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (p->md_virt != NULL) {
|
if (p->md_virt != NULL && (uint64_t)p->md_virt != p->md_phys) {
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
printf("EFI Runtime entry %d is mapped\n", i);
|
printf("EFI Runtime entry %d is mapped\n", i);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
Loading…
Reference in New Issue
Block a user