summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjmcneill <jmcneill@NetBSD.org>2021-07-24 11:39:18 +0000
committerjmcneill <jmcneill@NetBSD.org>2021-07-24 11:39:18 +0000
commit06e2ed96e086b43a50d2b22b60ce6959498744bd (patch)
treef602b8b6be107f5ca4b72794170d6da22f7b76d6 /sys/dev
parente13db1d72249ae962d454180af75a2879e0d25c9 (diff)
smbios: Add character device for accessing SMBIOS tables
The /dev/smbios character device gives an aperture into physical memory that allows read-only access to the SMBIOS header and tables.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/smbios.c105
-rw-r--r--sys/dev/smbiosvar.h4
2 files changed, 106 insertions, 3 deletions
diff --git a/sys/dev/smbios.c b/sys/dev/smbios.c
index c3a95402fb7..008b8177f7c 100644
--- a/sys/dev/smbios.c
+++ b/sys/dev/smbios.c
@@ -1,4 +1,4 @@
-/* $NetBSD: smbios.c,v 1.1 2021/07/21 23:16:09 jmcneill Exp $ */
+/* $NetBSD: smbios.c,v 1.2 2021/07/24 11:39:19 jmcneill Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -86,12 +86,15 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.1 2021/07/21 23:16:09 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.2 2021/07/24 11:39:19 jmcneill Exp $");
#include <sys/param.h>
+#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <uvm/uvm_extern.h>
+
#include <dev/smbiosvar.h>
#define SMBIOS_MAKESIG(a, b, c, d) \
@@ -99,6 +102,104 @@ __KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.1 2021/07/21 23:16:09 jmcneill Exp $");
struct smbios_entry smbios_entry;
+static dev_type_read(smbios_read);
+
+const struct cdevsw smbios_cdevsw = {
+ .d_open = nullopen,
+ .d_close = nullclose,
+ .d_read = smbios_read,
+ .d_write = nowrite,
+ .d_ioctl = noioctl,
+ .d_stop = nostop,
+ .d_tty = notty,
+ .d_poll = nopoll,
+ .d_mmap = nommap,
+ .d_kqfilter = nokqfilter,
+ .d_discard = nodiscard,
+ .d_flag = D_OTHER | D_MPSAFE,
+};
+
+static void *
+smbios_map_memory(paddr_t pa, size_t size)
+{
+ paddr_t spa, epa, curpa;
+ vaddr_t va, curva;
+
+ spa = trunc_page(pa);
+ epa = round_page(pa + size);
+
+ va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY);
+ if (va == 0) {
+ return NULL;
+ }
+
+ for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) {
+ pmap_kenter_pa(curva, curpa, VM_PROT_READ, PMAP_WRITE_BACK);
+ }
+ pmap_update(pmap_kernel());
+
+ return (void *)(va + (pa - spa));
+}
+
+static void
+smbios_unmap_memory(void *va, size_t size)
+{
+ vaddr_t ova;
+ vsize_t osz;
+
+ ova = trunc_page((vaddr_t)va);
+ osz = round_page((vaddr_t)va + size) - ova;
+
+ pmap_kremove(ova, osz);
+ pmap_update(pmap_kernel());
+ uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY);
+}
+
+/*
+ * smbios_read --
+ *
+ * Read data from an SMBIOS table that resides in physical memory.
+ */
+static int
+smbios_read(dev_t dev, struct uio *uio, int flag)
+{
+ paddr_t pa;
+ uint8_t *data;
+ size_t len;
+ int error;
+
+ if (smbios_entry.addr == NULL) {
+ return EIO;
+ }
+ if (uio->uio_rw != UIO_READ) {
+ return EPERM;
+ }
+
+ pa = uio->uio_offset;
+ if (pa == smbios_entry.hdrphys) {
+ /* SMBIOS header */
+ len = uimin(0x20, uio->uio_resid);
+
+ } else {
+ /* Table data */
+ if (pa < smbios_entry.tabphys ||
+ pa >= smbios_entry.tabphys + smbios_entry.len) {
+ return EFAULT;
+ }
+ len = uimin(smbios_entry.len - (pa - smbios_entry.tabphys),
+ uio->uio_resid);
+ }
+
+ data = smbios_map_memory(pa, len);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+ error = uiomove(data, len, uio);
+ smbios_unmap_memory(data, len);
+
+ return error;
+}
+
int
smbios2_check_header(const uint8_t *p)
{
diff --git a/sys/dev/smbiosvar.h b/sys/dev/smbiosvar.h
index 39441bd8c13..adef800b0d4 100644
--- a/sys/dev/smbiosvar.h
+++ b/sys/dev/smbiosvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: smbiosvar.h,v 1.1 2021/07/21 23:16:09 jmcneill Exp $ */
+/* $NetBSD: smbiosvar.h,v 1.2 2021/07/24 11:39:19 jmcneill Exp $ */
/*
* Copyright (c) 2006 Gordon Willem Klok <gklok@cogeco.ca>
* Copyright (c) 2005 Jordan Hargrave
@@ -41,6 +41,8 @@
#define SMBIOS_UUID_REPLEN 37 /* 16 zero padded values, 4 hyphens, 1 null */
struct smbios_entry {
+ paddr_t hdrphys;
+ paddr_t tabphys;
uint8_t rev;
uint8_t mjr;
uint8_t min;