svn commit: r330868 - in head: stand/efi/loader sys/amd64/amd64 sys/arm64/arm64

Kyle Evans kevans at FreeBSD.org
Tue Mar 13 17:10:53 UTC 2018


Author: kevans
Date: Tue Mar 13 17:10:52 2018
New Revision: 330868
URL: https://svnweb.freebsd.org/changeset/base/330868

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

Modified:
  head/stand/efi/loader/bootinfo.c
  head/sys/amd64/amd64/efirt_machdep.c
  head/sys/arm64/arm64/efirt_machdep.c

Modified: head/stand/efi/loader/bootinfo.c
==============================================================================
--- head/stand/efi/loader/bootinfo.c	Tue Mar 13 17:04:14 2018	(r330867)
+++ head/stand/efi/loader/bootinfo.c	Tue Mar 13 17:10:52 2018	(r330868)
@@ -236,17 +236,48 @@ bi_copymodules(vm_offset_t 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
 bi_load_efi_data(struct preloaded_file *kfp)
 {
 	EFI_MEMORY_DESCRIPTOR *mm;
 	EFI_PHYSICAL_ADDRESS addr;
 	EFI_STATUS status;
+	const char *efi_novmap;
 	size_t efisz;
 	UINTN efi_mapkey;
 	UINTN mmsz, pages, retry, sz;
 	UINT32 mmver;
 	struct efi_map_header *efihdr;
+	bool do_vmap;
 
 #if defined(__amd64__) || defined(__aarch64__)
 	struct efi_fb efifb;
@@ -266,6 +297,11 @@ bi_load_efi_data(struct preloaded_file *kfp)
 	}
 #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;
 
 	/*
@@ -321,6 +357,13 @@ bi_load_efi_data(struct preloaded_file *kfp)
 		}
 		status = BS->ExitBootServices(IH, efi_mapkey);
 		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->descriptor_size = mmsz;
 			efihdr->descriptor_version = mmver;

Modified: head/sys/amd64/amd64/efirt_machdep.c
==============================================================================
--- head/sys/amd64/amd64/efirt_machdep.c	Tue Mar 13 17:04:14 2018	(r330867)
+++ head/sys/amd64/amd64/efirt_machdep.c	Tue Mar 13 17:10:52 2018	(r330868)
@@ -165,7 +165,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int 
 	    descsz)) {
 		if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
 			continue;
-		if (p->md_virt != NULL) {
+		if (p->md_virt != NULL && (uint64_t)p->md_virt != p->md_phys) {
 			if (bootverbose)
 				printf("EFI Runtime entry %d is mapped\n", i);
 			goto fail;

Modified: head/sys/arm64/arm64/efirt_machdep.c
==============================================================================
--- head/sys/arm64/arm64/efirt_machdep.c	Tue Mar 13 17:04:14 2018	(r330867)
+++ head/sys/arm64/arm64/efirt_machdep.c	Tue Mar 13 17:10:52 2018	(r330868)
@@ -169,7 +169,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int 
 	    descsz)) {
 		if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
 			continue;
-		if (p->md_virt != NULL) {
+		if (p->md_virt != NULL && (uint64_t)p->md_virt != p->md_phys) {
 			if (bootverbose)
 				printf("EFI Runtime entry %d is mapped\n", i);
 			goto fail;


More information about the svn-src-head mailing list