diff options
| author | jmcneill <jmcneill@NetBSD.org> | 2021-07-24 11:39:18 +0000 |
|---|---|---|
| committer | jmcneill <jmcneill@NetBSD.org> | 2021-07-24 11:39:18 +0000 |
| commit | 06e2ed96e086b43a50d2b22b60ce6959498744bd (patch) | |
| tree | f602b8b6be107f5ca4b72794170d6da22f7b76d6 /sys/dev | |
| parent | e13db1d72249ae962d454180af75a2879e0d25c9 (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.c | 105 | ||||
| -rw-r--r-- | sys/dev/smbiosvar.h | 4 |
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; |
