efirt: Don't enter EFI context early, convert addrs to KVA instead

efi_enter here was needed because efi_runtime dereference causes a fault
outside of EFI context, due to runtime table living in runtime service
space. This may cause problems early in boot, though, so instead access it
by converting paddr to KVA for access.

While here, remove the other direct PHYS_TO_DMAP calls and the explicit DMAP
requirement from efidev.

Reviewed by:	kib
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D16591
This commit is contained in:
kevans 2018-08-04 21:41:10 +00:00
parent 4d78ed404a
commit 7997bd2bb8
4 changed files with 40 additions and 19 deletions

View File

@ -84,6 +84,19 @@ efi_destroy_1t1_map(void)
efi_pml4_page = NULL;
}
/*
* Map a physical address from EFI runtime space into KVA space. Returns 0 to
* indicate a failed mapping so that the caller may handle error.
*/
vm_offset_t
efi_phys_to_kva(vm_paddr_t paddr)
{
if (paddr >= dmaplimit)
return (0);
return (PHYS_TO_DMAP(paddr));
}
static vm_page_t
efi_1t1_page(void)
{

View File

@ -142,6 +142,19 @@ efi_1t1_l3(vm_offset_t va)
return (l3);
}
/*
* Map a physical address from EFI runtime space into KVA space. Returns 0 to
* indicate a failed mapping so that the caller may handle error.
*/
vm_offset_t
efi_phys_to_kva(vm_paddr_t paddr)
{
if (!PHYS_IN_DMAP(paddr))
return (0);
return (PHYS_TO_DMAP(paddr));
}
/*
* Create the 1:1 virtual to physical map for EFI
*/

View File

@ -131,9 +131,10 @@ efi_init(void)
{
struct efi_map_header *efihdr;
struct efi_md *map;
struct efi_rt *rtdm;
caddr_t kmdp;
size_t efisz;
int rt_disabled;
int ndesc, rt_disabled;
rt_disabled = 0;
TUNABLE_INT_FETCH("efi.rt.disabled", &rt_disabled);
@ -146,13 +147,9 @@ efi_init(void)
printf("EFI systbl not available\n");
return (0);
}
if (!PMAP_HAS_DMAP) {
if (bootverbose)
printf("EFI systbl requires direct map\n");
return (0);
}
efi_systbl = (struct efi_systbl *)PHYS_TO_DMAP(efi_systbl_phys);
if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) {
efi_systbl = (struct efi_systbl *)efi_phys_to_kva(efi_systbl_phys);
if (efi_systbl == NULL || efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) {
efi_systbl = NULL;
if (bootverbose)
printf("EFI systbl signature invalid\n");
@ -180,8 +177,8 @@ efi_init(void)
if (efihdr->descriptor_size == 0)
return (ENOMEM);
if (!efi_create_1t1_map(map, efihdr->memory_size /
efihdr->descriptor_size, efihdr->descriptor_size)) {
ndesc = efihdr->memory_size / efihdr->descriptor_size;
if (!efi_create_1t1_map(map, ndesc, efihdr->descriptor_size)) {
if (bootverbose)
printf("EFI cannot create runtime map\n");
return (ENOMEM);
@ -196,6 +193,7 @@ efi_init(void)
return (ENXIO);
}
#if defined(__aarch64__) || defined(__amd64__)
/*
* Some UEFI implementations have multiple implementations of the
* RS->GetTime function. They switch from one we can only use early
@ -203,14 +201,10 @@ efi_init(void)
* call RS->SetVirtualAddressMap. As this is not always the case, e.g.
* with an old loader.efi, check if the RS->GetTime function is within
* the EFI map, and fail to attach if not.
*
* We need to enter into the EFI environment as efi_runtime may point
* to an EFI address.
*/
efi_enter();
if (!efi_is_in_map(map, efihdr->memory_size / efihdr->descriptor_size,
efihdr->descriptor_size, (vm_offset_t)efi_runtime->rt_gettime)) {
efi_leave();
rtdm = (struct efi_rt *)efi_phys_to_kva((uintptr_t)efi_runtime);
if (rtdm == NULL || !efi_is_in_map(map, ndesc, efihdr->descriptor_size,
(vm_offset_t)rtdm->rt_gettime)) {
if (bootverbose)
printf(
"EFI runtime services table has an invalid pointer\n");
@ -218,7 +212,7 @@ efi_init(void)
efi_destroy_1t1_map();
return (ENXIO);
}
efi_leave();
#endif
return (0);
}
@ -291,7 +285,7 @@ efi_get_table(struct uuid *uuid, void **ptr)
ct = efi_cfgtbl;
while (count--) {
if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) {
*ptr = (void *)PHYS_TO_DMAP(ct->ct_data);
*ptr = (void *)efi_phys_to_kva(ct->ct_data);
return (0);
}
ct++;

View File

@ -172,6 +172,7 @@ extern vm_paddr_t efi_systbl_phys;
/* Internal MD EFI functions */
int efi_arch_enter(void);
void efi_arch_leave(void);
vm_offset_t efi_phys_to_kva(vm_paddr_t);
bool efi_create_1t1_map(struct efi_md *, int, int);
void efi_destroy_1t1_map(void);