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
This commit is contained in:
ShengYi Hung
2025-07-19 13:07:27 -04:00
parent 386960a880
commit f840492b5b
5 changed files with 110 additions and 4 deletions
+40 -2
View File
@@ -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;
+1 -1
View File
@@ -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
+18
View File
@@ -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
+2
View File
@@ -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
+49 -1
View File
@@ -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");