svn commit: r337331 - in head/sys: amd64/amd64 arm64/arm64 dev/efidev sys

Kyle Evans kevans at FreeBSD.org
Sat Aug 4 21:41:12 UTC 2018


Author: kevans
Date: Sat Aug  4 21:41:10 2018
New Revision: 337331
URL: https://svnweb.freebsd.org/changeset/base/337331

Log:
  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

Modified:
  head/sys/amd64/amd64/efirt_machdep.c
  head/sys/arm64/arm64/efirt_machdep.c
  head/sys/dev/efidev/efirt.c
  head/sys/sys/efi.h

Modified: head/sys/amd64/amd64/efirt_machdep.c
==============================================================================
--- head/sys/amd64/amd64/efirt_machdep.c	Sat Aug  4 20:45:43 2018	(r337330)
+++ head/sys/amd64/amd64/efirt_machdep.c	Sat Aug  4 21:41:10 2018	(r337331)
@@ -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)
 {

Modified: head/sys/arm64/arm64/efirt_machdep.c
==============================================================================
--- head/sys/arm64/arm64/efirt_machdep.c	Sat Aug  4 20:45:43 2018	(r337330)
+++ head/sys/arm64/arm64/efirt_machdep.c	Sat Aug  4 21:41:10 2018	(r337331)
@@ -143,6 +143,19 @@ efi_1t1_l3(vm_offset_t va)
 }
 
 /*
+ * 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
  */
 bool

Modified: head/sys/dev/efidev/efirt.c
==============================================================================
--- head/sys/dev/efidev/efirt.c	Sat Aug  4 20:45:43 2018	(r337330)
+++ head/sys/dev/efidev/efirt.c	Sat Aug  4 21:41:10 2018	(r337331)
@@ -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++;

Modified: head/sys/sys/efi.h
==============================================================================
--- head/sys/sys/efi.h	Sat Aug  4 20:45:43 2018	(r337330)
+++ head/sys/sys/efi.h	Sat Aug  4 21:41:10 2018	(r337331)
@@ -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);
 


More information about the svn-src-head mailing list