git: f840492b5b0d - main - efidev: add support for memory attribute

From: ShengYi Hung <aokblast_at_FreeBSD.org>
Date: Tue, 22 Jul 2025 04:45:52 UTC
The branch main has been updated by aokblast:

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

commit f840492b5b0d5c9e7d6d7d7dc25c260bc4d63ba2
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2025-07-19 17:07:27 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2025-07-22 04:45:29 +0000

    efidev: add support for memory attribute
    
    The EFI_PROPERTIES_TABLE has been deprecated in the UEFI specification.
    It is now replaced by the EFI_MEMORY_ATTRIBUTES_TABLE, which provides
    a new header and data format for describing memory region attributes.
    
    Reviewed by:    imp
    Approved by:    markj (mentor)
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D49998
---
 sys/dev/efidev/efirt.c       | 42 +++++++++++++++++++++++++++++++++++--
 sys/modules/efirt/Makefile   |  2 +-
 sys/sys/efi.h                | 18 ++++++++++++++++
 usr.sbin/efitable/efitable.8 |  2 ++
 usr.sbin/efitable/efitable.c | 50 +++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 110 insertions(+), 4 deletions(-)

diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
index b0fa33daeca7..b55c1c191077 100644
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
@@ -107,7 +107,8 @@ static int efi_status2err[25] = {
 
 enum efi_table_type {
 	TYPE_ESRT = 0,
-	TYPE_PROP
+	TYPE_PROP,
+	TYPE_MEMORY_ATTR
 };
 
 static int efi_enter(void);
@@ -445,6 +446,42 @@ get_table_length(enum efi_table_type type, size_t *table_len, void **taddr)
 		free(buf, M_TEMP);
 		return (0);
 	}
+	case TYPE_MEMORY_ATTR:
+	{
+		efi_guid_t guid = EFI_MEMORY_ATTRIBUTES_TABLE;
+		struct efi_memory_attribute_table *tbl_addr, *mem_addr;
+		int error;
+		void *buf;
+		size_t len = sizeof(struct efi_memory_attribute_table);
+
+		error = efi_get_table(&guid, (void **)&tbl_addr);
+		if (error)
+			return (error);
+
+		buf = malloc(len, M_TEMP, M_WAITOK);
+		error = physcopyout((vm_paddr_t)tbl_addr, buf, len);
+		if (error) {
+			free(buf, M_TEMP);
+			return (error);
+		}
+
+		mem_addr = (struct efi_memory_attribute_table *)buf;
+		if (mem_addr->version != 2) {
+			free(buf, M_TEMP);
+			return (EINVAL);
+		}
+		len += mem_addr->descriptor_size * mem_addr->num_ents;
+		if (len > EFI_TABLE_ALLOC_MAX) {
+			free(buf, M_TEMP);
+			return (ENOMEM);
+		}
+
+		*table_len = len;
+		if (taddr != NULL)
+			*taddr = tbl_addr;
+		free(buf, M_TEMP);
+		return (0);
+	}
 	}
 	return (ENOENT);
 }
@@ -457,7 +494,8 @@ copy_table(efi_guid_t *guid, void **buf, size_t buf_len, size_t *table_len)
 		enum efi_table_type type;
 	} tables[] = {
 		{ EFI_TABLE_ESRT,       TYPE_ESRT },
-		{ EFI_PROPERTIES_TABLE, TYPE_PROP }
+		{ EFI_PROPERTIES_TABLE, TYPE_PROP },
+		{ EFI_MEMORY_ATTRIBUTES_TABLE, TYPE_MEMORY_ATTR }
 	};
 	size_t table_idx;
 	void *taddr;
diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile
index 4738996fd4e6..c46484465b68 100644
--- a/sys/modules/efirt/Makefile
+++ b/sys/modules/efirt/Makefile
@@ -9,7 +9,7 @@ SRCS+=  device_if.h bus_if.h clock_if.h
 DPSRCS+= assym.inc
 
 .if ${MACHINE_CPUARCH} == "amd64"
-SRCS+=	opt_hwpmc_hooks.h opt_kstack_pages.h
+SRCS+=	opt_acpi.h opt_hwpmc_hooks.h opt_kstack_pages.h
 .endif
 
 efirt_support.o:	efirt_support.S assym.inc
diff --git a/sys/sys/efi.h b/sys/sys/efi.h
index 95a433a950db..89c8b15519de 100644
--- a/sys/sys/efi.h
+++ b/sys/sys/efi.h
@@ -42,6 +42,8 @@
 	{0xb122a263,0x3661,0x4f68,{0x99,0x29,0x78,0xf8,0xb0,0xd6,0x21,0x80}}
 #define	EFI_PROPERTIES_TABLE			\
 	{0x880aaca3,0x4adc,0x4a04,{0x90,0x79,0xb7,0x47,0x34,0x08,0x25,0xe5}}
+#define	EFI_MEMORY_ATTRIBUTES_TABLE		\
+	{0xdcfa911d,0x26eb,0x469f,{0xa2,0x20,0x38,0xb7,0xdc,0x46,0x12,0x20}}
 #define LINUX_EFI_MEMRESERVE_TABLE			\
 	{0x888eb0c6,0x8ede,0x4ff5,{0xa8,0xf0,0x9a,0xee,0x5c,0xb9,0x77,0xc2}}
 
@@ -166,6 +168,22 @@ struct efi_prop_table {
 	uint64_t	memory_protection_attribute;
 };
 
+struct efi_memory_descriptor {
+	uint32_t	type;
+	caddr_t		phy_addr;
+	caddr_t		virt_addr;
+	uint64_t	pages;
+	uint64_t	attrs;
+};
+
+struct efi_memory_attribute_table {
+	uint32_t	version;
+	uint32_t	num_ents;
+	uint32_t	descriptor_size;
+	uint32_t	flags;
+	struct efi_memory_descriptor tables[];
+};
+
 #ifdef _KERNEL
 
 #ifdef EFIABI_ATTR
diff --git a/usr.sbin/efitable/efitable.8 b/usr.sbin/efitable/efitable.8
index bb8a9cc3d0e1..4d174b7d9514 100644
--- a/usr.sbin/efitable/efitable.8
+++ b/usr.sbin/efitable/efitable.8
@@ -54,6 +54,8 @@ Currently supported tables:
 .Bl -tag -width indent -compact
 .It Cm esrt
 EFI System Resource Table
+.It Cm memory
+EFI Memory Attributes Table
 .It Cm prop
 EFI Properties Table
 .El
diff --git a/usr.sbin/efitable/efitable.c b/usr.sbin/efitable/efitable.c
index 0eee72801592..a506b4dea311 100644
--- a/usr.sbin/efitable/efitable.c
+++ b/usr.sbin/efitable/efitable.c
@@ -44,6 +44,7 @@
 
 static void efi_table_print_esrt(const void *data);
 static void efi_table_print_prop(const void *data);
+static void efi_table_print_memory(const void *data);
 static void usage(void) __dead2;
 
 struct efi_table_op {
@@ -56,7 +57,9 @@ static const struct efi_table_op efi_table_ops[] = {
 	{ .name = "esrt", .parse = efi_table_print_esrt,
 	    .guid = EFI_TABLE_ESRT },
 	{ .name = "prop", .parse = efi_table_print_prop,
-	    .guid = EFI_PROPERTIES_TABLE }
+	    .guid = EFI_PROPERTIES_TABLE },
+	{ .name = "memory", .parse = efi_table_print_memory,
+	    .guid = EFI_MEMORY_ATTRIBUTES_TABLE }
 };
 
 int
@@ -239,6 +242,51 @@ efi_table_print_prop(const void *data)
 		xo_err(EX_IOERR, "stdout");
 }
 
+static void
+efi_table_print_memory(const void *data)
+{
+	const struct efi_memory_attribute_table *attr =
+	    (const struct efi_memory_attribute_table *)data;
+	const struct efi_memory_descriptor *desc;
+	int i, nentries;
+
+	nentries = attr->num_ents;
+	desc = attr->tables;
+
+	xo_set_version(EFITABLE_XO_VERSION);
+
+	xo_open_container("memory");
+	xo_emit("{Lwc:Version}{:version/%#x}\n", attr->version);
+	xo_emit("{Lwc:Length}{:length/%u}\n", attr->descriptor_size);
+	xo_emit("{Lwc:Entries}{:entries/%u}\n", attr->num_ents);
+
+	xo_open_container("attributes");
+
+	/*
+	 * According to https://forum.osdev.org/viewtopic.php?t=32953, the size
+	 * of records into the attribute table never equals to
+	 * sizeof(efi_memory_descriptor). The correct one for indexing the array
+	 * resides in the attributet table.
+	 */
+	for (i = 0; i < nentries; i++) {
+		xo_emit("{Lwc:ID}{:id/%#x}\n", i);
+		xo_emit("{Lwc:Attributes}{:attributes/%#x}\n", desc->attrs);
+		xo_emit("{Lwc:Type}{:type/%#x}\n", desc->type);
+		xo_emit("{Lwc:Pages}{:pages/%#x}\n", desc->pages);
+		xo_emit("{Lwc:Phyaddr}{:phyaddr/%#p}\n", desc->phy_addr);
+		xo_emit("{Lwc:Virtaddr}{:virtaddr/%#p}\n", desc->virt_addr);
+		desc = (const struct efi_memory_descriptor *)(const void *)
+		    ((const char *)desc + attr->descriptor_size);
+	}
+
+	xo_close_container("attributes");
+
+	xo_close_container("memory");
+
+	if (xo_finish() < 0)
+		xo_err(EX_IOERR, "stdout");
+}
+
 static void usage(void)
 {
 	xo_error("usage: efitable [-g guid | -t name] [--libxo]\n");