code: plan9front

Download patch

ref: d67e83ed27fbb11ad21880352e706e095ecc0dfb
parent: 12ccc63ec3d72d1ef5b591c7f50534ac3b1e890b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Dec 2 15:08:36 EST 2022

9boot: delay GetMemoryMap until right before ExitBootServices (thanks michael forney!)

Michael Forney reported the following:

The UEFI specification suggests calling GetMemoryMap immediately
before ExitBootServices to ensure that the loader has the current
memory map. The firmware is able to enforce this since we have to
pass a "MapKey" from the last GetMemoryMap to ExitBootServices.

The T14 AMD gen 1 firmware is quite strict about this, and even a call
to OutputString will invalidate the MapKey. This causes
ExitBootServices to fail, and we enter 9front with boot services still
running. This causes all sorts of problems including leaving the
IOMMU enabled, breaking 9front's PCI drivers.

---

Michael sent a patch that moves memconf() to unload(), but i prefer
to make this explicit by calling memconf() before and keep unload() as
just that, not touching the configuration.

--- a/sys/src/boot/efi/efi.c
+++ b/sys/src/boot/efi/efi.c
@@ -42,7 +42,7 @@
 	eficall(ST->BootServices->ExitBootServices, IH, MK);
 }
 
-static void
+void
 memconf(char **cfg)
 {
 	static uchar memtype[EfiMaxMemoryType] = {
@@ -73,6 +73,10 @@
 	if(eficall(ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers))
 		return;
 
+	/* only called to get MK for ExitBootServices() */
+	if(cfg == nil)
+		return;
+
 	s = *cfg;
 	for(p = mapbuf; mapsize >= entsize; p += entsize, mapsize -= entsize){
 		t = (EFI_MEMORY_DESCRIPTOR*)p;
@@ -93,7 +97,7 @@
 	*s = '\0';
 	if(s > *cfg){
 		s[-1] = '\n';
-		print(*cfg);
+		/* print(*cfg); -- no printing allowed, can change MK */
 		*cfg = s;
 	}
 }
@@ -276,7 +280,7 @@
 void
 eficonfig(char **cfg)
 {
-	memconf(cfg);
+	/* memconf(cfg); -- must be called right before unload() */
 	acpiconf(cfg);
 	screenconf(cfg);
 }
--- a/sys/src/boot/efi/fns.h
+++ b/sys/src/boot/efi/fns.h
@@ -37,3 +37,4 @@
 
 uintptr eficall(void *proc, ...);
 void eficonfig(char **cfg);
+void memconf(char**);
--- a/sys/src/boot/efi/sub.c
+++ b/sys/src/boot/efi/sub.c
@@ -154,50 +154,53 @@
 #define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
 #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
 
-char *confend;
+static char *confend;
 
 static char*
-getconf(char *s, char *buf)
+findconf(char *s)
 {
 	char *p, *e;
-	int n;
-
-	n = strlen(s);
+	int n = strlen(s);
 	for(p = BOOTARGS; p < confend; p = e+1){
-		for(e = p+1; e < confend; e++)
-			if(*e == '\n')
-				break;
-		if(memcmp(p, s, n) == 0){
-			p += n;
-			n = e - p;
-			buf[n] = 0;
-			memmove(buf, p, n);
-			return buf;
+		for(e = p; e < confend && *e != '\n'; e++){
+			if(*e == '\0')
+				return nil;
 		}
+		if(e - p >= n && memcmp(p, s, n) == 0)
+			return p;
 	}
 	return nil;
 }
 
+static char*
+getconf(char *s, char *buf)
+{
+	char *p, *e;
+
+	if((p = findconf(s)) == nil)
+		return nil;
+	p += strlen(s);
+	for(e = p; *e != '\n'; e++)
+		;
+	memmove(buf, p, e - p);
+	buf[e - p] = '\0';
+	return buf;
+}
+
 static int
 delconf(char *s)
 {
 	char *p, *e;
 
-	for(p = BOOTARGS; p < confend; p = e){
-		for(e = p+1; e < confend; e++){
-			if(*e == '\n'){
-				e++;
-				break;
-			}
-		}
-		if(memcmp(p, s, strlen(s)) == 0){
-			memmove(p, e, confend - e);
-			confend -= e - p;
-			*confend = 0;
-			return 1;
-		}
-	}
-	return 0;
+	if((p = findconf(s)) == nil)
+		return 0;
+	for(e = p; *e != '\n'; e++)
+		;
+	e++;
+	memmove(p, e, confend - e);
+	confend -= e - p;
+	*confend = '\0';
+	return 1;
 }
 
 char*
@@ -364,6 +367,8 @@
 
 	close(f);
 	print("boot\n");
+
+	memconf(findconf("*e820=")?nil:&confend);
 	unload();
 
 	jump(e);