git: 8937bd37d07c - main - arm64: limit EFI excluded regions to physical memory types

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Wed, 15 Mar 2023 15:44:44 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=8937bd37d07c5c75995e01457aec00fb0a05c462

commit 8937bd37d07c5c75995e01457aec00fb0a05c462
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2023-03-15 15:26:57 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-03-15 15:28:35 +0000

    arm64: limit EFI excluded regions to physical memory types
    
    Consolidate add_efi_map_entry() and exclude_efi_map_entry() into a
    single function, handle_efi_map_entry(), so that the exact set of entry
    types handled is the same in the addition or exclusion cases. Before,
    exclude_efi_map_entry() had a 'default' case that would exclude all
    entry types that were not listed explicitly in the switch statement.
    
    Logically, we do not need to exclude a range that could not possibly be
    added to physmem, and we do not need to exclude bus ranges that are not
    physical memory, for example EFI_MD_TYPE_IOMEM.
    
    Since physmem's ram0 device will reserve bus memory resources for its
    owned ranges, this was preventing attachment of the watchdog device on
    the RPI4B. For some reason its region of memory-mapped I/O appeared in
    the EFI memory map (with the aforementioned EFI_MD_TYPE_IOMEM type).
    This change fixes the attachment issue, as we prevent the physmem API
    from messing with this range of bus space.
    
    PR:             270044
    Reported by:    karels, Mark Millard
    Reviewed by:    andrew, karels, imp
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D39003
---
 sys/arm64/arm64/machdep.c | 71 ++++++++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 32 deletions(-)

diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index a076bd0a046a..0659602a9ded 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -455,36 +455,25 @@ foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *
 	}
 }
 
+/*
+ * Handle the EFI memory map list.
+ *
+ * We will make two passes at this, the first (exclude == false) to populate
+ * physmem with valid physical memory ranges from recognized map entry types.
+ * In the second pass we will exclude memory ranges from physmem which must not
+ * be used for general allocations, either because they are used by runtime
+ * firmware or otherwise reserved.
+ *
+ * Adding the runtime-reserved memory ranges to physmem and excluding them
+ * later ensures that they are included in the DMAP, but excluded from
+ * phys_avail[].
+ *
+ * Entry types not explicitly listed here are ignored and not mapped.
+ */
 static void
-exclude_efi_map_entry(struct efi_md *p, void *argp __unused)
-{
-
-	switch (p->md_type) {
-	case EFI_MD_TYPE_CODE:
-	case EFI_MD_TYPE_DATA:
-	case EFI_MD_TYPE_BS_CODE:
-	case EFI_MD_TYPE_BS_DATA:
-	case EFI_MD_TYPE_FREE:
-		/*
-		 * We're allowed to use any entry with these types.
-		 */
-		break;
-	default:
-		physmem_exclude_region(p->md_phys, p->md_pages * EFI_PAGE_SIZE,
-		    EXFLAG_NOALLOC);
-	}
-}
-
-static void
-exclude_efi_map_entries(struct efi_map_header *efihdr)
-{
-
-	foreach_efi_map_entry(efihdr, exclude_efi_map_entry, NULL);
-}
-
-static void
-add_efi_map_entry(struct efi_md *p, void *argp __unused)
+handle_efi_map_entry(struct efi_md *p, void *argp)
 {
+	bool exclude = *(bool *)argp;
 
 	switch (p->md_type) {
 	case EFI_MD_TYPE_RECLAIM:
@@ -496,7 +485,7 @@ add_efi_map_entry(struct efi_md *p, void *argp __unused)
 		/*
 		 * Some UEFI implementations put the system table in the
 		 * runtime code section. Include it in the DMAP, but will
-		 * be excluded from phys_avail later.
+		 * be excluded from phys_avail.
 		 */
 	case EFI_MD_TYPE_RT_DATA:
 		/*
@@ -504,6 +493,12 @@ add_efi_map_entry(struct efi_md *p, void *argp __unused)
 		 * region is created to stop it from being added
 		 * to phys_avail.
 		 */
+		if (exclude) {
+			physmem_exclude_region(p->md_phys,
+			    p->md_pages * EFI_PAGE_SIZE, EXFLAG_NOALLOC);
+			break;
+		}
+		/* FALLTHROUGH */
 	case EFI_MD_TYPE_CODE:
 	case EFI_MD_TYPE_DATA:
 	case EFI_MD_TYPE_BS_CODE:
@@ -512,8 +507,12 @@ add_efi_map_entry(struct efi_md *p, void *argp __unused)
 		/*
 		 * We're allowed to use any entry with these types.
 		 */
-		physmem_hardware_region(p->md_phys,
-		    p->md_pages * EFI_PAGE_SIZE);
+		if (!exclude)
+			physmem_hardware_region(p->md_phys,
+			    p->md_pages * EFI_PAGE_SIZE);
+		break;
+	default:
+		/* Other types shall not be handled by physmem. */
 		break;
 	}
 }
@@ -521,7 +520,15 @@ add_efi_map_entry(struct efi_md *p, void *argp __unused)
 static void
 add_efi_map_entries(struct efi_map_header *efihdr)
 {
-	foreach_efi_map_entry(efihdr, add_efi_map_entry, NULL);
+	bool exclude = false;
+	foreach_efi_map_entry(efihdr, handle_efi_map_entry, &exclude);
+}
+
+static void
+exclude_efi_map_entries(struct efi_map_header *efihdr)
+{
+	bool exclude = true;
+	foreach_efi_map_entry(efihdr, handle_efi_map_entry, &exclude);
 }
 
 static void