Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107536271
D30104.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D30104.diff
View Options
diff --git a/share/man/man4/efidev.4 b/share/man/man4/efidev.4
--- a/share/man/man4/efidev.4
+++ b/share/man/man4/efidev.4
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 12, 2018
+.Dd June 18, 2021
.Dt EFIDEV 4
.Os
.Sh NAME
@@ -71,11 +71,28 @@
.In sys/efi.h :
.Bl -tag -width indent
.It Dv EFIIOC_GET_TABLE Pq Vt "struct efi_get_table_ioc"
-Get a table by uuid from the UEFI system table.
+Copy the UEFI table specified by the
+.Va uuid
+field of the
+.Vt struct efi_get_table_ioc
+into the
+.Va buf
+field.
+The memory size for the buf field can be queried by passing
+.Dv NULL
+pointer as a buf value.
+The required size will be stored in the
+.Va table_len
+field.
+The size of the allocated memory must be specified in the
+.Va buf_len
+field.
.Bd -literal -offset indent
struct efi_get_table_ioc {
+ void *buf;
struct uuid uuid;
- void *ptr;
+ size_t table_len;
+ size_t buf_len;
};
.Ed
.It Dv EFIIOC_GET_TIME Pq Vt "struct efi_tm"
diff --git a/sys/dev/efidev/efidev.c b/sys/dev/efidev/efidev.c
--- a/sys/dev/efidev/efidev.c
+++ b/sys/dev/efidev/efidev.c
@@ -53,6 +53,29 @@
int error;
switch (cmd) {
+ case EFIIOC_GET_TABLE:
+ {
+ struct efi_get_table_ioc *egtioc =
+ (struct efi_get_table_ioc *)addr;
+ void *buf = NULL;
+
+ error = efi_copy_table(&egtioc->uuid, egtioc->buf ? &buf : NULL,
+ egtioc->buf_len, &egtioc->table_len);
+
+ if (error != 0 || egtioc->buf == NULL)
+ break;
+
+ if (egtioc->buf_len < egtioc->table_len) {
+ error = EINVAL;
+ free(buf, M_TEMP);
+ break;
+ }
+
+ error = copyout(buf, egtioc->buf, egtioc->buf_len);
+ free(buf, M_TEMP);
+
+ break;
+ }
case EFIIOC_GET_TIME:
{
struct efi_tm *tm = (struct efi_tm *)addr;
diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
@@ -38,6 +38,7 @@
#include <sys/kernel.h>
#include <sys/linker.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/clock.h>
@@ -47,6 +48,7 @@
#include <sys/sched.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <sys/uio.h>
#include <sys/vmmeter.h>
#include <machine/fpu.h>
@@ -58,6 +60,8 @@
#include <vm/pmap.h>
#include <vm/vm_map.h>
+#define EFI_TABLE_ALLOC_MAX 0x800000
+
static struct efi_systbl *efi_systbl;
static eventhandler_tag efi_shutdown_tag;
/*
@@ -96,6 +100,11 @@
EPROTO /* EFI_PROTOCOL_ERROR */
};
+enum efi_table_type {
+ TYPE_ESRT = 0,
+ TYPE_PROP
+};
+
static int efi_enter(void);
static void efi_leave(void);
@@ -336,6 +345,124 @@
return (ENOENT);
}
+static int
+get_table_length(enum efi_table_type type, size_t *table_len, void **taddr)
+{
+ switch (type) {
+ case TYPE_ESRT:
+ {
+ struct efi_esrt_table *esrt = NULL;
+ struct uuid uuid = EFI_TABLE_ESRT;
+ uint32_t fw_resource_count = 0;
+ size_t len = sizeof(*esrt);
+ int error;
+ void *buf;
+
+ error = efi_get_table(&uuid, (void **)&esrt);
+ if (error != 0)
+ return (error);
+
+ buf = malloc(len, M_TEMP, M_WAITOK);
+ error = physcopyout((vm_paddr_t)esrt, buf, len);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ /* Check ESRT version */
+ if (((struct efi_esrt_table *)buf)->fw_resource_version !=
+ ESRT_FIRMWARE_RESOURCE_VERSION) {
+ free(buf, M_TEMP);
+ return (ENODEV);
+ }
+
+ fw_resource_count = ((struct efi_esrt_table *)buf)->
+ fw_resource_count;
+ if (fw_resource_count > EFI_TABLE_ALLOC_MAX /
+ sizeof(struct efi_esrt_entry_v1)) {
+ free(buf, M_TEMP);
+ return (ENOMEM);
+ }
+
+ len += fw_resource_count * sizeof(struct efi_esrt_entry_v1);
+ *table_len = len;
+
+ if (taddr != NULL)
+ *taddr = esrt;
+ free(buf, M_TEMP);
+ return (0);
+ }
+ case TYPE_PROP:
+ {
+ struct uuid uuid = EFI_PROPERTIES_TABLE;
+ struct efi_prop_table *prop;
+ size_t len = sizeof(*prop);
+ uint32_t prop_len;
+ int error;
+ void *buf;
+
+ error = efi_get_table(&uuid, (void **)&prop);
+ if (error != 0)
+ return (error);
+
+ buf = malloc(len, M_TEMP, M_WAITOK);
+ error = physcopyout((vm_paddr_t)prop, buf, len);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ prop_len = ((struct efi_prop_table *)buf)->length;
+ if (prop_len > EFI_TABLE_ALLOC_MAX) {
+ free(buf, M_TEMP);
+ return (ENOMEM);
+ }
+ *table_len = prop_len;
+
+ if (taddr != NULL)
+ *taddr = prop;
+ free(buf, M_TEMP);
+ return (0);
+ }
+ }
+ return (ENOENT);
+}
+
+static int
+copy_table(struct uuid *uuid, void **buf, size_t buf_len, size_t *table_len)
+{
+ static const struct known_table {
+ struct uuid uuid;
+ enum efi_table_type type;
+ } tables[] = {
+ { EFI_TABLE_ESRT, TYPE_ESRT },
+ { EFI_PROPERTIES_TABLE, TYPE_PROP }
+ };
+ size_t table_idx;
+ void *taddr;
+ int rc;
+
+ for (table_idx = 0; table_idx < nitems(tables); table_idx++) {
+ if (!bcmp(&tables[table_idx].uuid, uuid, sizeof(*uuid)))
+ break;
+ }
+
+ if (table_idx == nitems(tables))
+ return (EINVAL);
+
+ rc = get_table_length(tables[table_idx].type, table_len, &taddr);
+ if (rc != 0)
+ return rc;
+
+ /* return table length to userspace */
+ if (buf == NULL)
+ return (0);
+
+ *buf = malloc(*table_len, M_TEMP, M_WAITOK);
+ rc = physcopyout((vm_paddr_t)taddr, *buf, *table_len);
+ return (rc);
+}
+
static int efi_rt_handle_faults = EFI_RT_HANDLE_FAULTS_DEFAULT;
SYSCTL_INT(_machdep, OID_AUTO, efi_rt_handle_faults, CTLFLAG_RWTUN,
&efi_rt_handle_faults, 0,
@@ -568,6 +695,7 @@
const static struct efi_ops efi_ops = {
.rt_ok = rt_ok,
.get_table = get_table,
+ .copy_table = copy_table,
.get_time = get_time,
.get_time_capabilities = get_time_capabilities,
.reset_system = reset_system,
diff --git a/sys/sys/efi.h b/sys/sys/efi.h
--- a/sys/sys/efi.h
+++ b/sys/sys/efi.h
@@ -40,6 +40,10 @@
{0xeb9d2d31,0x2d88,0x11d3,0x9a,0x16,{0x00,0x90,0x27,0x3f,0xc1,0x4d}}
#define EFI_TABLE_SMBIOS3 \
{0xf2fd1544,0x9794,0x4a2c,0x99,0x2e,{0xe5,0xbb,0xcf,0x20,0xe3,0x94}}
+#define EFI_TABLE_ESRT \
+ {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}}
enum efi_reset {
EFI_RESET_COLD = 0,
@@ -123,6 +127,31 @@
uint32_t __res;
};
+#define ESRT_FIRMWARE_RESOURCE_VERSION 1
+
+struct efi_esrt_table {
+ uint32_t fw_resource_count;
+ uint32_t fw_resource_count_max;
+ uint64_t fw_resource_version;
+ uint8_t entries[];
+};
+
+struct efi_esrt_entry_v1 {
+ struct uuid fw_class;
+ uint32_t fw_type;
+ uint32_t fw_version;
+ uint32_t lowest_supported_fw_version;
+ uint32_t capsule_flags;
+ uint32_t last_attempt_version;
+ uint32_t last_attempt_status;
+};
+
+struct efi_prop_table {
+ uint32_t version;
+ uint32_t length;
+ uint64_t memory_protection_attribute;
+};
+
#ifdef _KERNEL
#ifdef EFIABI_ATTR
@@ -188,6 +217,7 @@
*/
int (*rt_ok)(void);
int (*get_table)(struct uuid *, void **);
+ int (*copy_table)(struct uuid *, void **, size_t, size_t *);
int (*get_time)(struct efi_tm *);
int (*get_time_capabilities)(struct efi_tmcap *);
int (*reset_system)(enum efi_reset);
@@ -216,6 +246,15 @@
return (active_efi_ops->get_table(uuid, ptr));
}
+static inline int efi_copy_table(struct uuid *uuid, void **buf,
+ size_t buf_len, size_t *table_len)
+{
+
+ if (active_efi_ops->copy_table == NULL)
+ return (ENXIO);
+ return (active_efi_ops->copy_table(uuid, buf, buf_len, table_len));
+}
+
static inline int efi_get_time(struct efi_tm *tm)
{
diff --git a/sys/sys/efiio.h b/sys/sys/efiio.h
--- a/sys/sys/efiio.h
+++ b/sys/sys/efiio.h
@@ -32,6 +32,14 @@
#include <sys/uuid.h>
#include <sys/efi.h>
+struct efi_get_table_ioc
+{
+ void *buf; /* Pointer to userspace buffer */
+ struct uuid uuid; /* UUID to look up */
+ size_t table_len; /* Table size */
+ size_t buf_len; /* Size of the buffer */
+};
+
struct efi_var_ioc
{
efi_char *name; /* User pointer to name, in wide chars */
@@ -42,6 +50,7 @@
size_t datasize; /* Number of *bytes* in the data */
};
+#define EFIIOC_GET_TABLE _IOWR('E', 1, struct efi_get_table_ioc)
#define EFIIOC_GET_TIME _IOR('E', 2, struct efi_tm)
#define EFIIOC_SET_TIME _IOW('E', 3, struct efi_tm)
#define EFIIOC_VAR_GET _IOWR('E', 4, struct efi_var_ioc)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 16, 2:04 PM (20 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15826329
Default Alt Text
D30104.diff (8 KB)
Attached To
Mode
D30104: efirt: add ESRT table support
Attached
Detach File
Event Timeline
Log In to Comment