From 161b30af53dfaf1375e7d54bc282eb25c6a2f685 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sun, 6 Dec 2020 02:57:29 +0000 Subject: [PATCH] acpi: add character device for accessing ACPI tables The /dev/acpi character device gives an aperture into physical memory that allows only read access to known ACPI tables: RSDP, XSDT/RSDT, and the root tables. Adapt acpidump(8) to use this interface by default, falling back to the old /dev/mem method if it is not available or if ACPIDUMP_USE_DEVMEM=1 is set in the environment. The user visible benefit of this change is that "options INSECURE" is no longer required to dump ACPI tables. --- etc/MAKEDEV.tmpl | 6 +- etc/etc.aarch64/MAKEDEV.conf | 3 +- etc/etc.amd64/MAKEDEV.conf | 3 +- etc/etc.i386/MAKEDEV.conf | 3 +- etc/etc.ia64/MAKEDEV.conf | 3 +- share/man/man4/acpi.4 | 8 +- sys/conf/majors | 3 +- sys/dev/acpi/acpi_dev.c | 220 ++++++++++++++++++++++++ sys/dev/acpi/files.acpi | 3 +- usr.sbin/acpitools/acpidump/acpi_user.c | 61 +++++-- usr.sbin/acpitools/acpidump/acpidump.8 | 10 +- usr.sbin/acpitools/acpidump/acpidump.c | 10 +- 12 files changed, 304 insertions(+), 29 deletions(-) create mode 100644 sys/dev/acpi/acpi_dev.c diff --git a/etc/MAKEDEV.tmpl b/etc/MAKEDEV.tmpl index 1ed2851d4a14..e35711ff5a2b 100644 --- a/etc/MAKEDEV.tmpl +++ b/etc/MAKEDEV.tmpl @@ -1,5 +1,5 @@ #!/bin/sh - -# $NetBSD: MAKEDEV.tmpl,v 1.221 2020/07/26 15:47:27 jdolecek Exp $ +# $NetBSD: MAKEDEV.tmpl,v 1.222 2020/12/06 02:57:29 jmcneill Exp $ # # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc. # All rights reserved. @@ -2243,6 +2243,10 @@ xmm[0-9]) mkdev ttyXMM${unit}1 c %wwanc_chr% $(($unit * 65536 + 4)) ;; +acpi) + mkdev acpi c %acpi_chr% 0 + ;; + midevend) %MI_DEVICES_END% local) diff --git a/etc/etc.aarch64/MAKEDEV.conf b/etc/etc.aarch64/MAKEDEV.conf index a0f0b062d96a..acd39e4d0a54 100644 --- a/etc/etc.aarch64/MAKEDEV.conf +++ b/etc/etc.aarch64/MAKEDEV.conf @@ -1,4 +1,4 @@ -# $NetBSD: MAKEDEV.conf,v 1.7 2018/12/15 01:02:58 jmcneill Exp $ +# $NetBSD: MAKEDEV.conf,v 1.8 2020/12/06 02:57:30 jmcneill Exp $ all_md) makedev wscons fd0 fd1 wd0 wd1 wd2 wd3 sd0 sd1 sd2 sd3 @@ -20,6 +20,7 @@ all_md) makedev spiflash0 makedev bpf makedev openfirm + makedev acpi ;; ramdisk|floppy) diff --git a/etc/etc.amd64/MAKEDEV.conf b/etc/etc.amd64/MAKEDEV.conf index 1033c4b8ff41..efd1896b30e4 100644 --- a/etc/etc.amd64/MAKEDEV.conf +++ b/etc/etc.amd64/MAKEDEV.conf @@ -1,4 +1,4 @@ -# $NetBSD: MAKEDEV.conf,v 1.31 2020/08/03 04:32:13 nia Exp $ +# $NetBSD: MAKEDEV.conf,v 1.32 2020/12/06 02:57:30 jmcneill Exp $ # As of 2003-04-17, the "init" case must not create more than 890 entries. all_md) @@ -45,6 +45,7 @@ all_md) makedev kttcp makedev bio makedev xmm0 + makedev acpi ;; xen) diff --git a/etc/etc.i386/MAKEDEV.conf b/etc/etc.i386/MAKEDEV.conf index c59a841c4e35..8ca795b0e16f 100644 --- a/etc/etc.i386/MAKEDEV.conf +++ b/etc/etc.i386/MAKEDEV.conf @@ -1,4 +1,4 @@ -# $NetBSD: MAKEDEV.conf,v 1.32 2020/08/03 04:32:13 nia Exp $ +# $NetBSD: MAKEDEV.conf,v 1.33 2020/12/06 02:57:30 jmcneill Exp $ # As of 2005-03-15, the "init" case must not create more than 1024 entries. all_md) @@ -49,6 +49,7 @@ all_md) makedev io makedev bio makedev cfs + makedev acpi ;; xen) diff --git a/etc/etc.ia64/MAKEDEV.conf b/etc/etc.ia64/MAKEDEV.conf index e9d765f208fe..dd357d6e54a6 100644 --- a/etc/etc.ia64/MAKEDEV.conf +++ b/etc/etc.ia64/MAKEDEV.conf @@ -1,4 +1,4 @@ -# $NetBSD: MAKEDEV.conf,v 1.4 2020/04/05 14:09:18 jdolecek Exp $ +# $NetBSD: MAKEDEV.conf,v 1.5 2020/12/06 02:57:30 jmcneill Exp $ # As of 2005-03-15, the "init" case must not create more than 1024 entries. all_md) @@ -43,4 +43,5 @@ all_md) makedev io makedev bio makedev cfs + makedev acpi ;; diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4 index e2ab1940b7c6..03c3ba1bfd0e 100644 --- a/share/man/man4/acpi.4 +++ b/share/man/man4/acpi.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: acpi.4,v 1.86 2018/03/04 02:10:26 pgoyette Exp $ +.\" $NetBSD: acpi.4,v 1.87 2020/12/06 02:57:30 jmcneill Exp $ .\" .\" Copyright (c) 2002, 2004, 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -24,7 +24,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 4, 2018 +.Dd December 5, 2020 .Dt ACPI 4 .Os .Sh NAME @@ -491,6 +491,10 @@ When .Ic hw.acpi.debug.object is set to 1, the message stored to the debug object is printed every time the method is called by the interpreter. +.Sh FILES +.Bl -tag -width /dev/acpi +.It Pa /dev/acpi +.El .Sh SEE ALSO .Xr ioapic 4 , .Xr acpidump 8 , diff --git a/sys/conf/majors b/sys/conf/majors index 1aeeb245c2cc..e403ae148778 100644 --- a/sys/conf/majors +++ b/sys/conf/majors @@ -1,4 +1,4 @@ -# $NetBSD: majors,v 1.96 2020/08/28 14:58:25 riastradh Exp $ +# $NetBSD: majors,v 1.97 2020/12/06 02:57:30 jmcneill Exp $ # # Device majors for Machine-Independent drivers. # @@ -90,3 +90,4 @@ device-major vhci char 355 vhci device-major vio9p char 356 vio9p device-major fault char 357 fault device-major wwanc char 358 wwanc +device-major acpi char 359 acpi diff --git a/sys/dev/acpi/acpi_dev.c b/sys/dev/acpi/acpi_dev.c new file mode 100644 index 000000000000..1fb6bb7001db --- /dev/null +++ b/sys/dev/acpi/acpi_dev.c @@ -0,0 +1,220 @@ +/* $NetBSD: acpi_dev.c,v 1.1 2020/12/06 02:57:30 jmcneill Exp $ */ + +/*- + * Copyright (c) 2020 Jared McNeill + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: acpi_dev.c,v 1.1 2020/12/06 02:57:30 jmcneill Exp $"); + +#include +#include +#include + +#include +#include + +#define _COMPONENT ACPI_BUS_COMPONENT +ACPI_MODULE_NAME ("acpi_dev") + +static dev_type_read(acpi_read); + +const struct cdevsw acpi_cdevsw = { + .d_open = nullopen, + .d_close = nullclose, + .d_read = acpi_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, +}; + +/* + * acpi_find_table_rsdp -- + * + * Returns true if the RSDP table is found and overlaps the specified + * physical address. The table's physical start address and length + * are placed in 'paddr' and 'plen' when found. + * + */ +static bool +acpi_find_table_rsdp(ACPI_PHYSICAL_ADDRESS pa, + ACPI_PHYSICAL_ADDRESS *paddr, uint32_t *plen) +{ + ACPI_PHYSICAL_ADDRESS table_pa; + + table_pa = AcpiOsGetRootPointer(); + if (table_pa == 0) { + return false; + } + if (pa >= table_pa && pa < table_pa + sizeof(ACPI_TABLE_RSDP)) { + *paddr = table_pa; + *plen = sizeof(ACPI_TABLE_RSDP); + return true; + } + + return false; +} + +/* + * acpi_find_table_sdt -- + * + * Returns true if the XSDT/RSDT table is found and overlaps the + * specified physical address. The table's physical start address + * and length are placed in 'paddr' and 'plen' when found. + * + */ +static bool +acpi_find_table_sdt(ACPI_PHYSICAL_ADDRESS pa, + ACPI_PHYSICAL_ADDRESS *paddr, uint32_t *plen) +{ + ACPI_PHYSICAL_ADDRESS table_pa; + ACPI_TABLE_RSDP *rsdp; + ACPI_TABLE_HEADER *thdr; + uint32_t table_len; + + table_pa = AcpiOsGetRootPointer(); + KASSERT(table_pa != 0); + + /* + * Find the XSDT/RSDT using the RSDP. + */ + rsdp = AcpiOsMapMemory(table_pa, sizeof(ACPI_TABLE_RSDP)); + if (rsdp == NULL) { + return false; + } + if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress) { + table_pa = rsdp->XsdtPhysicalAddress; + } else { + table_pa = rsdp->RsdtPhysicalAddress; + } + AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP)); + if (table_pa == 0) { + return false; + } + + /* + * Map the XSDT/RSDT and check access. + */ + thdr = AcpiOsMapMemory(table_pa, sizeof(ACPI_TABLE_HEADER)); + if (thdr == NULL) { + return false; + } + table_len = thdr->Length; + AcpiOsUnmapMemory(thdr, sizeof(ACPI_TABLE_HEADER)); + if (pa >= table_pa && pa < table_pa + table_len) { + *paddr = table_pa; + *plen = table_len; + return true; + } + + return false; +} + +/* + * acpi_find_table -- + * + * Find an ACPI table that overlaps the specified physical address. + * Returns true if the table is found and places the table start + * address into 'paddr' and the length into 'plen'. + * + */ +static bool +acpi_find_table(ACPI_PHYSICAL_ADDRESS pa, + ACPI_PHYSICAL_ADDRESS *paddr, uint32_t *plen) +{ + ACPI_TABLE_DESC *tdesc; + bool found_table; + uint32_t i; + + /* Check for RSDP access. */ + if (acpi_find_table_rsdp(pa, paddr, plen)) { + return true; + } + + /* Check for XSDT/RSDT access. */ + if (acpi_find_table_sdt(pa, paddr, plen)) { + return true; + } + + /* Check for root table access. */ + found_table = false; + AcpiUtAcquireMutex(ACPI_MTX_TABLES); + for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++) { + tdesc = &AcpiGbl_RootTableList.Tables[i]; + if (pa >= tdesc->Address && + pa < tdesc->Address + tdesc->Length) { + *paddr = tdesc->Address; + *plen = tdesc->Length; + found_table = true; + break; + } + } + AcpiUtReleaseMutex(ACPI_MTX_TABLES); + return found_table; +} + +/* + * acpi_read -- + * + * Read data from an ACPI configuration table that resides in + * physical memory. Only supports reading one table at a time. + * + */ +static int +acpi_read(dev_t dev, struct uio *uio, int flag) +{ + ACPI_PHYSICAL_ADDRESS pa, table_pa; + uint32_t table_len; + uint8_t *data; + int error; + size_t len; + + if (uio->uio_rw != UIO_READ) { + return EPERM; + } + + /* Make sure this is a read of a known table */ + if (!acpi_find_table(uio->uio_offset, &table_pa, &table_len)) { + return EIO; + } + + /* Copy the contents of the table to user-space */ + pa = uio->uio_offset; + len = uimin(pa - table_pa + table_len, uio->uio_resid); + data = AcpiOsMapMemory(pa, len); + if (data == NULL) { + return ENOMEM; + } + error = uiomove(data, len, uio); + AcpiOsUnmapMemory(data, len); + + return error; +} diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index 97a7285e2614..1dba413608aa 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $NetBSD: files.acpi,v 1.115 2020/02/22 02:28:06 jmcneill Exp $ +# $NetBSD: files.acpi,v 1.116 2020/12/06 02:57:30 jmcneill Exp $ include "dev/acpi/acpica/files.acpica" @@ -21,6 +21,7 @@ device acpi: acpica, acpiapmbus, acpinodebus, acpiecdtbus, acpisdtbus, acpigtdtb attach acpi at acpibus file dev/acpi/acpi.c acpi file dev/acpi/acpi_debug.c acpi +file dev/acpi/acpi_dev.c acpi file dev/acpi/acpi_event.c acpi file dev/acpi/acpi_i2c.c acpi file dev/acpi/acpi_mcfg.c acpi & pci diff --git a/usr.sbin/acpitools/acpidump/acpi_user.c b/usr.sbin/acpitools/acpidump/acpi_user.c index a392dd54ebb7..a498b9cc99cc 100644 --- a/usr.sbin/acpitools/acpidump/acpi_user.c +++ b/usr.sbin/acpitools/acpidump/acpi_user.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_user.c,v 1.5 2020/08/20 15:54:12 riastradh Exp $ */ +/* $NetBSD: acpi_user.c,v 1.6 2020/12/06 02:57:30 jmcneill Exp $ */ /*- * Copyright (c) 1999 Doug Rabson @@ -30,7 +30,7 @@ */ #include -__RCSID("$NetBSD: acpi_user.c,v 1.5 2020/08/20 15:54:12 riastradh Exp $"); +__RCSID("$NetBSD: acpi_user.c,v 1.6 2020/12/06 02:57:30 jmcneill Exp $"); #include #include @@ -39,6 +39,7 @@ __RCSID("$NetBSD: acpi_user.c,v 1.5 2020/08/20 15:54:12 riastradh Exp $"); #include #include +#include #include #include #include @@ -48,6 +49,7 @@ __RCSID("$NetBSD: acpi_user.c,v 1.5 2020/08/20 15:54:12 riastradh Exp $"); static char machdep_acpi_root[] = "hw.acpi.root"; static int acpi_mem_fd = -1; +static bool acpi_mem_mmap = false; struct acpi_user_mapping { LIST_ENTRY(acpi_user_mapping) link; @@ -61,15 +63,48 @@ static LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist; static void acpi_user_init(void) { + int saved_errno, use_devmem; + const char *s; if (acpi_mem_fd == -1) { - acpi_mem_fd = open("/dev/mem", O_RDONLY); - if (acpi_mem_fd == -1) - err(EXIT_FAILURE, "opening /dev/mem"); + s = getenv("ACPIDUMP_USE_DEVMEM"); + use_devmem = s != NULL && *s == '1'; + if (!use_devmem) { + acpi_mem_fd = open("/dev/acpi", O_RDONLY); + } + if (acpi_mem_fd == -1) { + saved_errno = errno; + acpi_mem_fd = open("/dev/mem", O_RDONLY); + if (acpi_mem_fd == -1) { + errno = saved_errno; + } else { + acpi_mem_mmap = true; + } + } + if (acpi_mem_fd == -1) { + err(EXIT_FAILURE, "opening /dev/acpi"); + } LIST_INIT(&maplist); } } +static void * +acpi_user_read_table(vm_offset_t pa, size_t psize) +{ + void *data; + ssize_t len; + + data = calloc(1, psize); + if (!data) + errx(EXIT_FAILURE, "out of memory"); + + len = pread(acpi_mem_fd, data, psize, pa); + if (len == -1) + errx(EXIT_FAILURE, "can't read table"); + + return data; +} + static struct acpi_user_mapping * acpi_user_find_mapping(vm_offset_t pa, size_t size) { @@ -82,16 +117,22 @@ acpi_user_find_mapping(vm_offset_t pa, size_t size) } /* Then create a new one */ - size = round_page(pa + size) - trunc_page(pa); - pa = trunc_page(pa); + if (acpi_mem_mmap) { + size = round_page(pa + size) - trunc_page(pa); + pa = trunc_page(pa); + } map = malloc(sizeof(struct acpi_user_mapping)); if (!map) errx(EXIT_FAILURE, "out of memory"); map->pa = pa; - map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); + if (acpi_mem_mmap) { + map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); + if ((intptr_t) map->va == -1) + err(EXIT_FAILURE, "can't map address"); + } else { + map->va = acpi_user_read_table(pa, size); + } map->size = size; - if ((intptr_t) map->va == -1) - err(EXIT_FAILURE, "can't map address"); LIST_INSERT_HEAD(&maplist, map, link); return map; diff --git a/usr.sbin/acpitools/acpidump/acpidump.8 b/usr.sbin/acpitools/acpidump/acpidump.8 index 664f17bede7b..8d4bc318915f 100644 --- a/usr.sbin/acpitools/acpidump/acpidump.8 +++ b/usr.sbin/acpitools/acpidump/acpidump.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: acpidump.8,v 1.16 2019/06/22 12:39:40 maxv Exp $ +.\" $NetBSD: acpidump.8,v 1.17 2020/12/06 02:57:30 jmcneill Exp $ .\" ACPI (ACPI Package) .\" .\" Copyright (c) 1999 Doug Rabson @@ -30,7 +30,7 @@ .\" .\" $FreeBSD: head/usr.sbin/acpi/acpidump/acpidump.8 267668 2014-06-20 09:57:27Z bapt $ .\" -.Dd June 22, 2019 +.Dd December 4, 2020 .Dt ACPIDUMP 8 .Os .Sh NAME @@ -73,7 +73,7 @@ When is invoked without the .Fl f option, it will read ACPI tables from physical memory via -.Pa /dev/mem . +.Pa /dev/acpi . First it searches for the RSDP (Root System Description Pointer), which has the signature @@ -173,8 +173,8 @@ Dump the contents of the various fixed tables listed above. Enable verbose messages. .El .Sh FILES -.Bl -tag -width /dev/mem -.It Pa /dev/mem +.Bl -tag -width /dev/acpi +.It Pa /dev/acpi .El .Sh EXAMPLES If a developer requests a copy of your ASL, please use the following diff --git a/usr.sbin/acpitools/acpidump/acpidump.c b/usr.sbin/acpitools/acpidump/acpidump.c index bb3bf3614f91..22a699f355da 100644 --- a/usr.sbin/acpitools/acpidump/acpidump.c +++ b/usr.sbin/acpitools/acpidump/acpidump.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpidump.c,v 1.7 2017/08/04 06:30:36 msaitoh Exp $ */ +/* $NetBSD: acpidump.c,v 1.8 2020/12/06 02:57:30 jmcneill Exp $ */ /*- * Copyright (c) 2000 Mitsuru IWASAKI @@ -29,7 +29,7 @@ */ #include -__RCSID("$NetBSD: acpidump.c,v 1.7 2017/08/04 06:30:36 msaitoh Exp $"); +__RCSID("$NetBSD: acpidump.c,v 1.8 2020/12/06 02:57:30 jmcneill Exp $"); #include @@ -104,7 +104,7 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - /* Get input either from file or /dev/mem */ + /* Get input either from file or /dev/acpi */ if (dsdt_input_file != NULL) { if (dflag == 0 && tflag == 0) { warnx("Need to specify -d or -t with DSDT input file"); @@ -118,11 +118,11 @@ main(int argc, char *argv[]) rsdt = dsdt_load_file(dsdt_input_file); } else { if (vflag) - warnx("loading RSD PTR from /dev/mem"); + warnx("loading RSD PTR from /dev/acpi"); rsdt = sdt_load_devmem(); } - /* Display misc. SDT tables (only available when using /dev/mem) */ + /* Display misc. SDT tables (only available when using /dev/acpi) */ if (tflag) { if (vflag) warnx("printing various SDT tables");