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.
thorpej-futex
jmcneill 2020-12-06 02:57:29 +00:00
parent f9f4337ba5
commit 161b30af53
12 changed files with 304 additions and 29 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
;;

View File

@ -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 ,

View File

@ -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

220
sys/dev/acpi/acpi_dev.c Normal file
View File

@ -0,0 +1,220 @@
/* $NetBSD: acpi_dev.c,v 1.1 2020/12/06 02:57:30 jmcneill Exp $ */
/*-
* Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca>
* 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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_dev.c,v 1.1 2020/12/06 02:57:30 jmcneill Exp $");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/mman.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#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;
}

View File

@ -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

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/mman.h>
@ -39,6 +39,7 @@ __RCSID("$NetBSD: acpi_user.c,v 1.5 2020/08/20 15:54:12 riastradh Exp $");
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
@ -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;

View File

@ -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 <dfr@FreeBSD.org>
@ -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

View File

@ -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 <iwasaki@FreeBSD.org>
@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
__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 <sys/param.h>
@ -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");