diff options
Diffstat (limited to 'usr.sbin/acpi')
| -rw-r--r-- | usr.sbin/acpi/Makefile | 6 | ||||
| -rw-r--r-- | usr.sbin/acpi/Makefile.inc | 26 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpiconf/Makefile | 7 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpiconf/Makefile.depend | 15 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpiconf/acpiconf.8 | 119 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpiconf/acpiconf.c | 302 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidb/Makefile | 94 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidb/Makefile.depend | 16 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidb/acpidb.8 | 165 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidb/acpidb.c | 540 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/Makefile | 5 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/Makefile.depend | 15 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/acpi.c | 2875 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/acpi_user.c | 222 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.8 | 262 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.c | 160 | ||||
| -rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.h | 162 | ||||
| -rw-r--r-- | usr.sbin/acpi/iasl/Makefile | 154 | ||||
| -rw-r--r-- | usr.sbin/acpi/iasl/Makefile.depend | 16 | ||||
| -rw-r--r-- | usr.sbin/acpi/iasl/iasl.8 | 177 | 
20 files changed, 5338 insertions, 0 deletions
| diff --git a/usr.sbin/acpi/Makefile b/usr.sbin/acpi/Makefile new file mode 100644 index 000000000000..c44a4146f44b --- /dev/null +++ b/usr.sbin/acpi/Makefile @@ -0,0 +1,6 @@ +# Makefile for acpi tools +# $Id: Makefile,v 1.1 2000/07/14 18:16:22 iwasaki Exp $ + +SUBDIR= acpiconf acpidb acpidump iasl + +.include <bsd.subdir.mk> diff --git a/usr.sbin/acpi/Makefile.inc b/usr.sbin/acpi/Makefile.inc new file mode 100644 index 000000000000..6bc7076909a2 --- /dev/null +++ b/usr.sbin/acpi/Makefile.inc @@ -0,0 +1,26 @@ +# $Id: Makefile.inc,v 1.1 2000/07/14 18:16:22 iwasaki Exp $ + +ACPICA_DIR= ${SRCTOP}/sys/contrib/dev/acpica +CFLAGS+= -I${SRCTOP}/sys + +PACKAGE=	acpi + +.if exists(${.CURDIR:H:H}/Makefile.inc) +.include "${.CURDIR:H:H}/Makefile.inc" +.endif + +.PATH:	${ACPICA_DIR}					\ +	${ACPICA_DIR}/common				\ +	${ACPICA_DIR}/compiler				\ +	${ACPICA_DIR}/components/debugger		\ +	${ACPICA_DIR}/components/disassembler		\ +	${ACPICA_DIR}/components/dispatcher		\ +	${ACPICA_DIR}/components/events			\ +	${ACPICA_DIR}/components/executer		\ +	${ACPICA_DIR}/components/hardware		\ +	${ACPICA_DIR}/components/namespace		\ +	${ACPICA_DIR}/components/parser			\ +	${ACPICA_DIR}/components/resources		\ +	${ACPICA_DIR}/components/tables			\ +	${ACPICA_DIR}/components/utilities		\ +	${ACPICA_DIR}/os_specific/service_layers diff --git a/usr.sbin/acpi/acpiconf/Makefile b/usr.sbin/acpi/acpiconf/Makefile new file mode 100644 index 000000000000..c9778bbc9032 --- /dev/null +++ b/usr.sbin/acpi/acpiconf/Makefile @@ -0,0 +1,7 @@ +# $Id: Makefile,v 1.2 2000/07/14 18:16:25 iwasaki Exp $ + +PROG=	acpiconf +MAN=	acpiconf.8 +WARNS?=	3 + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/acpiconf/Makefile.depend b/usr.sbin/acpi/acpiconf/Makefile.depend new file mode 100644 index 000000000000..6ef78fac5cbf --- /dev/null +++ b/usr.sbin/acpi/acpiconf/Makefile.depend @@ -0,0 +1,15 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/acpi/acpiconf/acpiconf.8 b/usr.sbin/acpi/acpiconf/acpiconf.8 new file mode 100644 index 000000000000..24af8b5c8719 --- /dev/null +++ b/usr.sbin/acpi/acpiconf/acpiconf.8 @@ -0,0 +1,119 @@ +.\"- +.\" Copyright (c) 2000 Dag-Erling Smørgrav +.\" 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 +.\"    in this position and unchanged. +.\" 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. +.\" 3. The name of the author may not be used to endorse or promote products +.\"    derived from this software without specific prior written permission. +.\" +.\" 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. +.\" +.Dd June 16, 2023 +.Dt ACPICONF 8 +.Os +.Sh NAME +.Nm acpiconf +.Nd control ACPI power management +.Sh SYNOPSIS +.Nm +.Op Fl h +.Op Fl i Ar batt +.Op Fl k Ar ack +.Op Fl s Ar type +.Sh DESCRIPTION +The +.Nm +utility allows the user control of the ACPI power management +functions. +The following command-line options are recognized: +.Bl -tag -width ".Fl s Ar type" +.It Fl h +Displays a summary of available options. +.It Fl i Ar batt +Get design information and current status of the battery specified +by its number, starting with +.Cm 0 . +.It Fl k Ar ack +Ack or abort a pending suspend request using the argument provided. +.Sy Most users should not use this option directly. +.It Fl s Ar type +Enters the specified sleep mode. +Recognized types are +.Cm 1 +(only the CPU clock is stopped), +.Cm 2 +(not implemented on most systems but similar to S1), +.Cm 3 +(the CPU context is lost and memory context is preserved), +and +.Cm 4 +(the CPU context is lost and memory context is stored to disk). +Sleep states may also be given as S1, S2, etc. +The supported states depend on BIOS implementation, including ACPI +byte code (AML). +If the +.Pa /etc/rc.suspend +and +.Pa /etc/rc.resume +scripts are executable, they will be run by +.Xr devd 8 +or +.Xr apmd 8 +before and after entering the given sleep state. +.Pp +The +.Pa /etc/rc.suspend +and +.Pa /etc/rc.resume +scripts use the +.Xr rcorder 8 +utility to call scripts in +.Pa /etc/rc.d/ +and the +.Va $local_startup +directories that have a "suspend" or "resume" KEYWORD, respectively. +Called scripts are supplied with a single "suspend" / "resume" +command line argument. +See +.Xr rc.conf 5 +for more information about +.Va $local_startup . +.El +.Sh SEE ALSO +.Xr acpi 4 , +.Xr rc.conf 5 , +.Xr acpidump 8 , +.Xr apm 8 , +.Xr apmd 8 , +.Xr devd 8 , +.Xr rcorder 8 +.Sh HISTORY +The +.Nm +utility appeared in +.Fx 5.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Mitsuru Iwasaki Aq Mt iwasaki@FreeBSD.org . +This manual page was written by +.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org . diff --git a/usr.sbin/acpi/acpiconf/acpiconf.c b/usr.sbin/acpi/acpiconf/acpiconf.c new file mode 100644 index 000000000000..4f5cb08325dc --- /dev/null +++ b/usr.sbin/acpi/acpiconf/acpiconf.c @@ -0,0 +1,302 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + *	$Id: acpiconf.c,v 1.5 2000/08/08 14:12:19 iwasaki Exp $ + */ + +#include <sys/param.h> + +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sysexits.h> +#include <unistd.h> + +#include <dev/acpica/acpiio.h> + +#include <contrib/dev/acpica/include/acpi.h> + +#define ACPIDEV		"/dev/acpi" + +static int	acpifd; + +static void +acpi_init(void) +{ +	acpifd = open(ACPIDEV, O_RDWR); +	if (acpifd == -1) +		acpifd = open(ACPIDEV, O_RDONLY); +	if (acpifd == -1) +		err(EX_OSFILE, ACPIDEV); +} + +/* Prepare to sleep and then wait for the signal that sleeping can occur. */ +static void +acpi_sleep(int sleep_type) +{ +	int ret; +   +	/* Notify OS that we want to sleep.  devd(8) gets this notify. */ +	ret = ioctl(acpifd, ACPIIO_REQSLPSTATE, &sleep_type); +	if (ret != 0) +		err(EX_IOERR, "request sleep type (%d) failed", sleep_type); +} + +/* Ack or abort a pending suspend request. */ +static void +acpi_sleep_ack(int err_val) +{ +	int ret; + +	ret = ioctl(acpifd, ACPIIO_ACKSLPSTATE, &err_val); +	if (ret != 0) +		err(EX_IOERR, "ack sleep type failed"); +} + +/* should be a acpi define, but doesn't appear to be */ +#define UNKNOWN_CAP 0xffffffff +#define UNKNOWN_VOLTAGE 0xffffffff + +static int +acpi_battinfo(int num) +{ +	union acpi_battery_ioctl_arg battio; +	const char *pwr_units; +	int hours, min, amp; +	uint32_t volt; + +	if (num < 0 || num > 64) +		errx(EX_USAGE, "invalid battery %d", num); + +	/* Print battery design information. */ +	battio.unit = num; +	if (ioctl(acpifd, ACPIIO_BATT_GET_BIX, &battio) == -1) +		err(EX_IOERR, "get battery info (%d) failed", num); +	amp = battio.bix.units; +	pwr_units = amp ? "mA" : "mW"; +	if (battio.bix.dcap == UNKNOWN_CAP) +		printf("Design capacity:\tunknown\n"); +	else +		printf("Design capacity:\t%d %sh\n", battio.bix.dcap, +		    pwr_units); +	if (battio.bix.lfcap == UNKNOWN_CAP) +		printf("Last full capacity:\tunknown\n"); +	else +		printf("Last full capacity:\t%d %sh\n", battio.bix.lfcap, +		    pwr_units); +	printf("Technology:\t\t%s\n", battio.bix.btech == 0 ? +	    "primary (non-rechargeable)" : "secondary (rechargeable)"); +	if (ACPI_BIX_REV_MIN_CHECK(battio.bix.rev, ACPI_BIX_REV_1)) { +		printf("Battery Swappable Capability:\t"); +		if (battio.bix.scap == ACPI_BIX_SCAP_NO) +			printf("Non-swappable\n"); +		else if (battio.bix.scap == ACPI_BIX_SCAP_COLD) +			printf("cold swap\n"); +		else if (battio.bix.scap == ACPI_BIX_SCAP_HOT) +			printf("hot swap\n"); +		else +			printf("unknown\n"); +	} +	if (battio.bix.dvol == UNKNOWN_CAP) +		printf("Design voltage:\t\tunknown\n"); +	else +		printf("Design voltage:\t\t%d mV\n", battio.bix.dvol); +	printf("Capacity (warn):\t%d %sh\n", battio.bix.wcap, pwr_units); +	printf("Capacity (low):\t\t%d %sh\n", battio.bix.lcap, pwr_units); +	if (ACPI_BIX_REV_MIN_CHECK(battio.bix.rev, ACPI_BIX_REV_0)) { +		if (battio.bix.cycles != ACPI_BATT_UNKNOWN) +			printf("Cycle Count:\t\t%d\n", battio.bix.cycles); +		printf("Measurement Accuracy:\t%d%%\n", +		    battio.bix.accuracy / 1000); +		if (battio.bix.stmax != ACPI_BATT_UNKNOWN) +			printf("Max Sampling Time:\t%d ms\n", +			    battio.bix.stmax); +		if (battio.bix.stmin != ACPI_BATT_UNKNOWN) +			printf("Min Sampling Time:\t%d ms\n", +			    battio.bix.stmin); +		printf("Max Average Interval:\t%d ms\n", +		    battio.bix.aimax); +		printf("Min Average Interval:\t%d ms\n", +		    battio.bix.aimin); +	} +	printf("Low/warn granularity:\t%d %sh\n", battio.bix.gra1, pwr_units); +	printf("Warn/full granularity:\t%d %sh\n", battio.bix.gra2, pwr_units); +	printf("Model number:\t\t%s\n", battio.bix.model); +	printf("Serial number:\t\t%s\n", battio.bix.serial); +	printf("Type:\t\t\t%s\n", battio.bix.type); +	printf("OEM info:\t\t%s\n", battio.bix.oeminfo); + +	/* Fetch battery voltage information. */ +	volt = UNKNOWN_VOLTAGE; +	battio.unit = num; +	if (ioctl(acpifd, ACPIIO_BATT_GET_BST, &battio) == -1) +		err(EX_IOERR, "get battery status (%d) failed", num); +	if (battio.bst.state != ACPI_BATT_STAT_NOT_PRESENT) +		volt = battio.bst.volt; + +	/* Print current battery state information. */ +	battio.unit = num; +	if (ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1) +		err(EX_IOERR, "get battery user info (%d) failed", num); +	if (battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) { +		const char *state; +		switch (battio.battinfo.state & ACPI_BATT_STAT_BST_MASK) { +		case 0: +			state = "high"; +			break; +		case ACPI_BATT_STAT_DISCHARG: +			state = "discharging"; +			break; +		case ACPI_BATT_STAT_CHARGING: +			state = "charging"; +			break; +		case ACPI_BATT_STAT_CRITICAL: +			state = "critical"; +			break; +		case ACPI_BATT_STAT_DISCHARG | ACPI_BATT_STAT_CRITICAL: +			state = "critical discharging"; +			break; +		case ACPI_BATT_STAT_CHARGING | ACPI_BATT_STAT_CRITICAL: +			state = "critical charging"; +			break; +		default: +			state = "invalid"; +		} +		printf("State:\t\t\t%s\n", state); +		if (battio.battinfo.cap == -1) +			printf("Remaining capacity:\tunknown\n"); +		else +			printf("Remaining capacity:\t%d%%\n", +			    battio.battinfo.cap); +		if (battio.battinfo.min == -1) +			printf("Remaining time:\t\tunknown\n"); +		else { +			hours = battio.battinfo.min / 60; +			min = battio.battinfo.min % 60; +			printf("Remaining time:\t\t%d:%02d\n", hours, min); +		} +		if (battio.battinfo.rate == -1) +			printf("Present rate:\t\tunknown\n"); +		else if (amp && volt != UNKNOWN_VOLTAGE) { +			printf("Present rate:\t\t%d mA (%d mW)\n", +			    battio.battinfo.rate, +			    battio.battinfo.rate * volt / 1000); +		} else +			printf("Present rate:\t\t%d %s\n", +			    battio.battinfo.rate, pwr_units); +	} else +		printf("State:\t\t\tnot present\n"); + +	/* Print battery voltage information. */ +	if (volt == UNKNOWN_VOLTAGE) +		printf("Present voltage:\tunknown\n"); +	else +		printf("Present voltage:\t%d mV\n", volt); + +	return (0); +} + +static void +usage(const char* prog) +{ +	printf("usage: %s [-h] [-i batt] [-k ack] [-s 1-4]\n", prog); +	exit(0); +} + +int +main(int argc, char *argv[]) +{ +	char	*prog, *end; +	int	c, sleep_type, battery, ack; +	int	iflag = 0, kflag = 0, sflag = 0; + +	prog = argv[0]; +	if (argc < 2) +		usage(prog); +		/* NOTREACHED */ + +	sleep_type = -1; +	acpi_init(); +	while ((c = getopt(argc, argv, "hi:k:s:")) != -1) { +		switch (c) { +		case 'i': +			iflag = 1; +			battery = strtol(optarg, &end, 10); +			if ((size_t)(end - optarg) != strlen(optarg)) +			    errx(EX_USAGE, "invalid battery"); +			break; +		case 'k': +			kflag = 1; +			ack = strtol(optarg, &end, 10); +			if ((size_t)(end - optarg) != strlen(optarg)) +			    errx(EX_USAGE, "invalid ack argument"); +			break; +		case 's': +			sflag = 1; +			if (optarg[0] == 'S') +				optarg++; +			sleep_type = strtol(optarg, &end, 10); +			if ((size_t)(end - optarg) != strlen(optarg)) +			    errx(EX_USAGE, "invalid sleep type"); +			if (sleep_type < 1 || sleep_type > 4) +				errx(EX_USAGE, "invalid sleep type (%d)", +				     sleep_type); +			break; +		case 'h': +		default: +			usage(prog); +			/* NOTREACHED */ +		} +	} +	argc -= optind; +	argv += optind; + +	if (iflag != 0 && kflag != 0 && sflag != 0) +			errx(EX_USAGE, "-i, -k and -s are mutually exclusive"); + +	if (iflag  != 0) { +		if (kflag != 0) +			errx(EX_USAGE, "-i and -k are mutually exclusive"); +		if (sflag != 0) +			errx(EX_USAGE, "-i and -s are mutually exclusive"); +		acpi_battinfo(battery); +	} + +	if (kflag != 0) { +		if (sflag != 0) +			errx(EX_USAGE, "-k and -s are mutually exclusive"); +		acpi_sleep_ack(ack); +	} + + +	if (sflag != 0) +		acpi_sleep(sleep_type); + +	close(acpifd); +	exit (0); +} diff --git a/usr.sbin/acpi/acpidb/Makefile b/usr.sbin/acpi/acpidb/Makefile new file mode 100644 index 000000000000..377846a016ae --- /dev/null +++ b/usr.sbin/acpi/acpidb/Makefile @@ -0,0 +1,94 @@ +PROG=	acpidb +SRCS=	acpidb.c + +# common +SRCS+=	acfileio.c acgetline.c ahids.c ahuuids.c cmfsize.c + +# components/debugger +SRCS+=	dbcmds.c dbconvert.c dbdisply.c dbexec.c dbfileio.c	\ +	dbhistry.c dbinput.c dbmethod.c dbnames.c dbobject.c	\ +	dbstats.c dbtest.c dbutils.c dbxface.c + +# components/disassembler +SRCS+=	dmbuffer.c dmcstyle.c dmdeferred.c dmnames.c dmopcode.c	\ +	dmresrc.c dmresrcl.c dmresrcl2.c dmresrcs.c dmutils.c	\ +	dmwalk.c + +# components/dispatcher +SRCS+=	dsargs.c dscontrol.c dsdebug.c dsfield.c dsinit.c	\ +	dsmethod.c dsmthdat.c dsobject.c dsopcode.c dspkginit.c	\ +	dsutils.c dswexec.c dswload.c dswload2.c dswscope.c	\ +	dswstate.c + +# components/events +SRCS+=	evevent.c evglock.c evgpe.c evgpeblk.c evgpeinit.c	\ +	evgpeutil.c evhandler.c evmisc.c evregion.c evrgnini.c	\ +	evsci.c evxface.c evxfevnt.c evxfregn.c + +# components/executer +SRCS+=	exconcat.c exconfig.c exconvrt.c excreate.c exdebug.c	\ +	exdump.c exfield.c exfldio.c exmisc.c exmutex.c		\ +	exnames.c exoparg1.c exoparg2.c exoparg3.c exoparg6.c	\ +	exprep.c exregion.c exresnte.c exresolv.c exresop.c	\ +	exserial.c exstore.c exstoren.c exstorob.c exsystem.c	\ +	extrace.c exutils.c + +# components/hardware +SRCS+=	hwacpi.c hwesleep.c hwgpe.c hwpci.c hwregs.c hwsleep.c	\ +	hwvalid.c hwxface.c hwxfsleep.c + +# components/namespace +SRCS+=	nsaccess.c nsalloc.c nsarguments.c nsconvert.c nsdump.c	\ +	nseval.c nsinit.c nsload.c nsnames.c nsobject.c		\ +	nsparse.c nspredef.c nsprepkg.c nsrepair.c nsrepair2.c	\ +	nssearch.c nsutils.c nswalk.c nsxfeval.c nsxfname.c	\ +	nsxfobj.c + +# components/parser +SRCS+=	psargs.c psloop.c psobject.c psopcode.c psopinfo.c	\ +	psparse.c psscope.c pstree.c psutils.c pswalk.c		\ +	psxface.c + +# components/resources +SRCS+=	rsaddr.c rscalc.c rscreate.c rsdump.c rsdumpinfo.c	\ +	rsinfo.c rsio.c rsirq.c rslist.c rsmemory.c rsmisc.c	\ +	rsserial.c rsutils.c rsxface.c + +# components/tables +SRCS+=	tbdata.c tbfadt.c tbfind.c tbinstal.c tbprint.c		\ +	tbutils.c tbxface.c tbxfload.c + +# components/utilities +SRCS+=	utaddress.c utalloc.c utascii.c utbuffer.c utcache.c	\ +	utcksum.c utcopy.c utdebug.c utdecode.c utdelete.c	\ +	uterror.c uteval.c utexcep.c utglobal.c uthex.c utids.c	\ +	utinit.c utlock.c utmath.c utmisc.c utmutex.c		\ +	utnonansi.c utobject.c utosi.c utownerid.c utpredef.c	\ +	utresdecode.c utresrc.c utstate.c utstring.c		\ +	utstrsuppt.c utstrtoul64.c uttrack.c utuuid.c utxface.c	\ +	utxferror.c utxfinit.c + +# os_specific/service_layers +SRCS+=	osgendbg.c osunixxf.c + +MAN=	acpidb.8 +WARNS?=	3 + +CFLAGS+= -DACPI_DB_APP -DACPI_EXEC_APP -fno-strict-aliasing +LIBADD=	pthread + +.include <bsd.prog.mk> + +# clang 6.0.0 and higher warn about the ACPI_ROOT_OBJECT and +# ACPI_TO_POINTER macros from sys/contrib/dev/acpica/include/actypes.h, +# that they use arithmetic on a null pointer treated as a cast from +# integer to pointer, which is a GNU extension. +# +# Turn off the warning, because this is in contributed code. +.if ${COMPILER_TYPE} == "clang" +CWARNFLAGS+=	-Wno-null-pointer-arithmetic +.endif + +# AcpiUtInitStackPtrTrace intentionally leaks a pointer to an +# on-stack variable. +CWARNFLAGS.utdebug.c+= ${NO_WDANGLING_POINTER} diff --git a/usr.sbin/acpi/acpidb/Makefile.depend b/usr.sbin/acpi/acpidb/Makefile.depend new file mode 100644 index 000000000000..577dc5747f1e --- /dev/null +++ b/usr.sbin/acpi/acpidb/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ +	lib/libthr \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/acpi/acpidb/acpidb.8 b/usr.sbin/acpi/acpidb/acpidb.8 new file mode 100644 index 000000000000..0b9163c5a010 --- /dev/null +++ b/usr.sbin/acpi/acpidb/acpidb.8 @@ -0,0 +1,165 @@ +.\"- +.\" Copyright (c) 2003 Nate Lawson +.\" 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 +.\"    in this position and unchanged. +.\" 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. +.\" 3. The name of the author may not be used to endorse or promote products +.\"    derived from this software without specific prior written permission. +.\" +.\" 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. +.\" +.Dd August 7, 2003 +.Dt ACPIDB 8 +.Os +.Sh NAME +.Nm acpidb +.Nd ACPI DSDT debugger +.Sh SYNOPSIS +.Nm +.Ar input-file +.Sh DESCRIPTION +The +.Nm +utility is a debugger for the ACPI DSDT. +It can parse and execute various +AML methods and display the result. +.Sh COMMANDS +.Ss General-Purpose Commands +.Bl -tag -width indent +.It Ic Allocations +Display list of current memory allocations +.It Ic Dump Ar Address | Namepath Op Cm Byte | Word | Dword | Qword +Display ACPI objects or memory +.It Ic EnableAcpi +Enable ACPI (hardware) mode +.It Ic Help +Show various help screens +.It Ic History +Display command history buffer +.It Ic Level Ar DebugLevel Op Cm console +Get/Set debug level for file or console +.It Ic Locks +Current status of internal mutexes +.It Ic Quit No or Ic Exit +Exit the debugger +.It Ic Stats Op Cm Allocations | Memory | Misc | Objects | Tables +Display namespace and memory statistics +.It Ic Tables +Display info about loaded ACPI tables +.It Ic Unload Ar TableSig Op Ar Instance +Unload an ACPI table +.It Ic !\& Ar CommandNumber +Execute command from history buffer +.It Ic !! +Execute last command again +.El +.Ss Namespace Access Commands +.Bl -tag -width indent +.It Ic Event Cm F | G Ar Value +Generate AcpiEvent (Fixed/GPE) +.It Ic Find Ar Name +Find ACPI name(s) with wildcards +.Ql ( ?\& +is wildcard) +.It Ic Method +Display list of loaded control methods +.It Ic Namespace Oo Ar Addr | Path Oc Op Ar Depth +Display loaded namespace tree/subtree +.It Ic Notify Ar NamePath Value +Send a notification +.It Ic Objects Ar ObjectType +Display all objects of the given type +.It Ic Owner Ar OwnerId Op Ar Depth +Display loaded namespace by object owner +.It Ic Prefix Op Ar NamePath +Set or Get current execution prefix +.It Ic References Ar Addr +Find all references to object at addr +.It Ic Resources +Get and display resources +.It Ic Terminate +Delete namespace and all internal objects +.It Ic Thread Ar Threads Loops NamePath +Spawn threads to execute method(s) +.El +.Ss Control Method Execution Commands +.Bl -tag -width indent +.It Ic Arguments +.Pq Ic Args +Display method arguments +.It Ic Breakpoint Ar AmlOffset +Set an AML execution breakpoint +.It Ic Call +Run to next control method invocation +.It Ic Debug Ar Namepath Op Ar Arguments +Single Step a control method +.It Ic Execute Ar Namepath Op Arguments +Execute control method +.It Ic Go +Allow method to run to completion +.It Ic Information +Display info about the current method +.It Ic Into +Step into (not over) a method call +.It Ic List Op OpcodeCount +Display method ASL statements +.It Ic Locals +Display method local variables +.It Ic Results +Display method result stack +.It Ic Set Cm A | L Ar # Value +Set method data (Arguments/Locals) +.It Ic Stop +Terminate control method +.It Ic Tree +Display control method calling tree +.It Ic <Enter> +Single step next AML opcode (over calls) +.El +.Ss File I/O Commands +.Bl -tag -width indent +.It Ic Close +Close debug output file +.It Ic Open Ar Filename +Open a file for debug output +.It Ic Load Ar Filename +Load ACPI table from a file +.El +.Sh SEE ALSO +.Xr acpi 4 , +.Xr acpidump 8 , +.Xr iasl 8 +.Sh HISTORY +The +.Nm +utility first appeared in the +.Nm acpicatools +port. +It was imported for +.Fx 5.2 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Mitsuru Iwasaki Aq Mt iwasaki@FreeBSD.org +and uses Intel ACPI-CA for the backend. +This manual page was written by +.An Nate Lawson . diff --git a/usr.sbin/acpi/acpidb/acpidb.c b/usr.sbin/acpi/acpidb/acpidb.c new file mode 100644 index 000000000000..efd8099f467e --- /dev/null +++ b/usr.sbin/acpi/acpidb/acpidb.c @@ -0,0 +1,540 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000-2002 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/param.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/stdint.h> +#include <sys/types.h> + +#include <assert.h> +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/accommon.h> +#include <contrib/dev/acpica/include/acapps.h> +#include <contrib/dev/acpica/include/acdebug.h> +#include <contrib/dev/acpica/include/amlresrc.h> + +/* + * Dummy DSDT Table Header + */ + +static ACPI_TABLE_HEADER dummy_dsdt_table = { +	"DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1 +}; + +/* + * Region space I/O routines on virtual machine + */ + +static int	aml_debug_prompt = 1; + +struct ACPIRegionContent { +	TAILQ_ENTRY(ACPIRegionContent) links; +	int			regtype; +	ACPI_PHYSICAL_ADDRESS	addr; +	UINT8			value; +}; + +TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); +static struct	ACPIRegionContentList RegionContentList; + +static int		 aml_simulation_initialized = 0; + +ACPI_PHYSICAL_ADDRESS	 AeLocalGetRootPointer(void); +void			 AeDoObjectOverrides(void); +void			 AeTableOverride(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER **); + +static void		 aml_simulation_init(void); +static int		 aml_simulate_regcontent_add(int regtype, +			     ACPI_PHYSICAL_ADDRESS addr, +			     UINT8 value); +static int		 aml_simulate_regcontent_read(int regtype, +			     ACPI_PHYSICAL_ADDRESS addr, +			     UINT8 *valuep);  +static int		 aml_simulate_regcontent_write(int regtype, +			     ACPI_PHYSICAL_ADDRESS addr, +			     UINT8 *valuep); +static UINT64		 aml_simulate_prompt(char *msg, UINT64 def_val); +static void		 aml_simulation_regload(const char *dumpfile); +static void		 aml_simulation_regdump(const char *dumpfile); + +/* Stubs to simplify linkage to the ACPICA core subsystem. */ +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer(void) +{ + +	return (0); +} + +void +AeDoObjectOverrides(void) +{ +} + +void +AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable) +{ +} + +void +MpSaveGpioInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, +    UINT32 PinCount, UINT16 *PinList, char *DeviceName) +{ +} + +void +MpSaveSerialInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, +    char *DeviceName) +{ +} + +static void +aml_simulation_init(void) +{ + +	aml_simulation_initialized = 1; +	TAILQ_INIT(&RegionContentList); +	aml_simulation_regload("region.ini"); +} + +static int +aml_simulate_regcontent_add(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 value) +{ +	struct	ACPIRegionContent *rc; + +	rc = malloc(sizeof(struct ACPIRegionContent)); +	if (rc == NULL) { +		return (-1);	/* malloc fail */ +	} +	rc->regtype = regtype; +	rc->addr = addr; +	rc->value = value; + +	TAILQ_INSERT_TAIL(&RegionContentList, rc, links); +	return (0); +} + +static int +aml_simulate_regcontent_read(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) +{ +	struct	ACPIRegionContent *rc; + +	if (!aml_simulation_initialized) { +		aml_simulation_init(); +	} +	TAILQ_FOREACH(rc, &RegionContentList, links) { +		if (rc->regtype == regtype && rc->addr == addr) { +			*valuep = rc->value; +			return (1);	/* found */ +		} +	} + +	*valuep = 0; +	return (aml_simulate_regcontent_add(regtype, addr, *valuep)); +} + +static int +aml_simulate_regcontent_write(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) +{ +	struct	ACPIRegionContent *rc; + +	if (!aml_simulation_initialized) { +		aml_simulation_init(); +	} +	TAILQ_FOREACH(rc, &RegionContentList, links) { +		if (rc->regtype == regtype && rc->addr == addr) { +			rc->value = *valuep; +			return (1);	/* exists */ +		} +	} + +	return (aml_simulate_regcontent_add(regtype, addr, *valuep)); +} + +static UINT64 +aml_simulate_prompt(char *msg, UINT64 def_val) +{ +	char		buf[16], *ep; +	UINT64		val; + +	val = def_val; +	printf("DEBUG"); +	if (msg != NULL) { +		printf("%s", msg); +	} +	printf("(default: 0x%jx ", (uintmax_t)val); +	printf(" / %ju) >>", (uintmax_t)val); +	fflush(stdout); + +	bzero(buf, sizeof buf); +	while (1) { +		if (read(0, buf, sizeof buf) == 0) { +			continue; +		} +		if (buf[0] == '\n') { +			break;	/* use default value */ +		} +		if (buf[0] == '0' && buf[1] == 'x') { +			val = strtoq(buf, &ep, 16); +		} else { +			val = strtoq(buf, &ep, 10); +		} +		break; +	} +	return (val); +} + +static void +aml_simulation_regload(const char *dumpfile) +{ +	char	buf[256], *np, *ep; +	struct	ACPIRegionContent rc; +	FILE	*fp; + +	if (!aml_simulation_initialized) { +		return; +	} + +	if ((fp = fopen(dumpfile, "r")) == NULL) { +		return; +	} + +	while (fgets(buf, sizeof buf, fp) != NULL) { +		np = buf; +		/* reading region type */ +		rc.regtype = strtoq(np, &ep, 10); +		if (np == ep) { +			continue; +		} +		np = ep; + +		/* reading address */ +		rc.addr = strtoq(np, &ep, 16); +		if (np == ep) { +			continue; +		} +		np = ep; + +		/* reading value */ +		rc.value = strtoq(np, &ep, 16); +		if (np == ep) { +			continue; +		} +		aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value); +	} + +	fclose(fp); +} + +static void +aml_simulation_regdump(const char *dumpfile) +{ +	struct	ACPIRegionContent *rc; +	FILE	*fp; + +	if (!aml_simulation_initialized) { +		return; +	} +	if ((fp = fopen(dumpfile, "w")) == NULL) { +		warn("%s", dumpfile); +		return; +	} +	while (!TAILQ_EMPTY(&RegionContentList)) { +		rc = TAILQ_FIRST(&RegionContentList); +		fprintf(fp, "%d	0x%jx	0x%x\n", +		    rc->regtype, (uintmax_t)rc->addr, rc->value); +		TAILQ_REMOVE(&RegionContentList, rc, links); +		free(rc); +	} + +	fclose(fp); +	TAILQ_INIT(&RegionContentList); +} + +/* + * Space handlers on virtual machine + */ + +static ACPI_STATUS +aml_vm_space_handler( +	UINT32			SpaceID, +	UINT32			Function, +	ACPI_PHYSICAL_ADDRESS	Address, +	UINT32			BitWidth, +	UINT64			*Value, +	int			Prompt) +{ +	int			state; +	UINT8			val; +	UINT64			value, i; +	char			msg[256]; +	static const char	*space_names[] = { +		"SYSTEM_MEMORY", "SYSTEM_IO", "PCI_CONFIG", +		"EC", "SMBUS", "CMOS", "PCI_BAR_TARGET"}; + +	switch (Function) { +	case ACPI_READ: +		value = 0; +		for (i = 0; (i * 8) < BitWidth; i++) { +			state = aml_simulate_regcontent_read(SpaceID, +							     Address + i, &val); +			if (state == -1) { +				return (AE_NO_MEMORY); +			} +			value |= val << (i * 8); +		} +		*Value = value; +		if (Prompt) { +			sprintf(msg, "[read (%s, %2d, 0x%jx)]", +				space_names[SpaceID], BitWidth, +				(uintmax_t)Address); +			*Value = aml_simulate_prompt(msg, value); +			if (*Value != value) { +				return(aml_vm_space_handler(SpaceID, +						ACPI_WRITE, +						Address, BitWidth, Value, 0)); +			} +		} +		break; + +	case ACPI_WRITE: +		value = *Value; +		if (Prompt) { +			sprintf(msg, "[write(%s, %2d, 0x%jx)]", +				space_names[SpaceID], BitWidth, +				(uintmax_t)Address); +			value = aml_simulate_prompt(msg, *Value); +		} +		*Value = value; +		for (i = 0; (i * 8) < BitWidth; i++) { +			val = value & 0xff; +			state = aml_simulate_regcontent_write(SpaceID, +							      Address + i, &val); +			if (state == -1) { +				return (AE_NO_MEMORY); +			} +			value = value >> 8; +		} +	} + +	return (AE_OK); +} + +#define DECLARE_VM_SPACE_HANDLER(name, id);			\ +static ACPI_STATUS						\ +aml_vm_space_handler_##name (					\ +	UINT32			Function,			\ +	ACPI_PHYSICAL_ADDRESS	Address,			\ +	UINT32			BitWidth,			\ +	UINT64			*Value)				\ +{								\ +	return (aml_vm_space_handler(id, Function, Address,	\ +		BitWidth, Value, aml_debug_prompt));		\ +} + +DECLARE_VM_SPACE_HANDLER(system_memory,	ACPI_ADR_SPACE_SYSTEM_MEMORY); +DECLARE_VM_SPACE_HANDLER(system_io,	ACPI_ADR_SPACE_SYSTEM_IO); +DECLARE_VM_SPACE_HANDLER(pci_config,	ACPI_ADR_SPACE_PCI_CONFIG); +DECLARE_VM_SPACE_HANDLER(ec,		ACPI_ADR_SPACE_EC); +DECLARE_VM_SPACE_HANDLER(smbus,		ACPI_ADR_SPACE_SMBUS); +DECLARE_VM_SPACE_HANDLER(cmos,		ACPI_ADR_SPACE_CMOS); +DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET); + +/* + * Load DSDT data file and invoke debugger + */ + +static int +load_dsdt(const char *dsdtfile) +{ +	char			filetmp[PATH_MAX]; +	ACPI_NEW_TABLE_DESC	*list; +	u_int8_t		*code; +	struct stat		sb; +	int			dounlink, error, fd; + +	fd = open(dsdtfile, O_RDONLY, 0); +	if (fd == -1) { +		perror("open"); +		return (-1); +	} +	if (fstat(fd, &sb) == -1) { +		perror("fstat"); +		close(fd); +		return (-1); +	} +	code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); +	close(fd); +	if (code == NULL) { +		perror("mmap"); +		return (-1); +	} +	if ((error = AcpiInitializeSubsystem()) != AE_OK) { +		munmap(code, (size_t)sb.st_size); +		return (-1); +	} + +	/* +	 * make sure DSDT data contains table header or not. +	 */ +	if (strncmp((char *)code, "DSDT", 4) == 0) { +		dounlink = 0; +		strlcpy(filetmp, dsdtfile, sizeof(filetmp)); +	} else { +		dounlink = 1; +		mode_t	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +		dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size; +		if ((size_t)snprintf(filetmp, sizeof(filetmp), "%s.tmp", +		    dsdtfile) > sizeof(filetmp) - 1) { +			fprintf(stderr, "file name too long\n"); +			munmap(code, (size_t)sb.st_size); +			return (-1); +		} +		fd = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode); +		if (fd == -1) { +			perror("open"); +			munmap(code, (size_t)sb.st_size); +			return (-1); +		} +		write(fd, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER)); + +		write(fd, code, sb.st_size); +		close(fd); +	} +	munmap(code, (size_t)sb.st_size); + +	/* +	 * Install the virtual machine version of address space handlers. +	 */ +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_SYSTEM_MEMORY, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_memory, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_SYSTEM_IO, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_io, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise SystemIO handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_PCI_CONFIG, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_config, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise PciConfig handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_EC, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_ec, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise EC handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_SMBUS, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_smbus, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise SMBUS handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_CMOS, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_cmos, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise CMOS handler: %d\n", error); +		return (-1); +	} +	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, +			ACPI_ADR_SPACE_PCI_BAR_TARGET, +			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_bar_target, +			NULL, NULL)) != AE_OK) { +		fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error); +		return (-1); +	} + +	list = NULL; +	AcGetAllTablesFromFile(filetmp, TRUE, &list); + +	AcpiInitializeDebugger(); +	AcpiGbl_DebuggerConfiguration = 0; +	AcpiDbUserCommands(); + +	if (dounlink) { +		unlink(filetmp); +	} + +	return (0); +} + +static void +usage(const char *progname) +{ + +	printf("usage: %s dsdt_file\n", progname); +	exit(1); +} + +int +main(int argc, char *argv[]) +{ +	char	*progname; + +	progname = argv[0]; + +	if (argc == 1) { +		usage(progname); +	} + +	AcpiDbgLevel = ACPI_DEBUG_DEFAULT; + +	/* +	 * Match kernel options for the interpreter.  Global variable names +	 * can be found in acglobal.h. +	 */ +	AcpiGbl_EnableInterpreterSlack = TRUE; + +	aml_simulation_regload("region.ini"); +	if (load_dsdt(argv[1]) == 0) { +		aml_simulation_regdump("region.dmp"); +	} + +	return (0); +} diff --git a/usr.sbin/acpi/acpidump/Makefile b/usr.sbin/acpi/acpidump/Makefile new file mode 100644 index 000000000000..0b4dd02d920c --- /dev/null +++ b/usr.sbin/acpi/acpidump/Makefile @@ -0,0 +1,5 @@ +PROG=	acpidump +MAN=	acpidump.8 +SRCS=	acpi.c acpi_user.c acpidump.c + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/acpidump/Makefile.depend b/usr.sbin/acpi/acpidump/Makefile.depend new file mode 100644 index 000000000000..6ef78fac5cbf --- /dev/null +++ b/usr.sbin/acpi/acpidump/Makefile.depend @@ -0,0 +1,15 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c new file mode 100644 index 000000000000..026795118832 --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpi.c @@ -0,0 +1,2875 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1998 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * Copyright (c) 2020 Alexander Motin <mav@FreeBSD.org> + * Copyright (c) 2024 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/param.h> +#include <sys/endian.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <paths.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <uuid.h> + +#include "acpidump.h" + +#define BEGIN_COMMENT	"/*\n" +#define END_COMMENT	" */\n" + +static void	acpi_print_string(char *s, size_t length); +static void	acpi_print_gas(ACPI_GENERIC_ADDRESS *gas); +static int	acpi_get_fadt_revision(ACPI_TABLE_FADT *fadt); +static void	acpi_handle_fadt(ACPI_TABLE_HEADER *fadt); +static void	acpi_print_cpu(u_char cpu_id); +static void	acpi_print_cpu_uid(uint32_t uid, char *uid_string); +static void	acpi_print_local_apic(uint32_t apic_id, uint32_t flags); +static void	acpi_print_io_apic(uint32_t apic_id, uint32_t int_base, +		    uint64_t apic_addr); +static void	acpi_print_mps_flags(uint16_t flags); +static void	acpi_print_intr(uint32_t intr, uint16_t mps_flags); +static void	acpi_print_local_nmi(u_int lint, uint16_t mps_flags); +static void	acpi_print_madt(ACPI_SUBTABLE_HEADER *mp); +static void	acpi_handle_madt(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_ecdt(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_hpet(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_mcfg(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_slit(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_wddt(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_lpit(ACPI_TABLE_HEADER *sdp); +static void	acpi_print_srat_cpu(uint32_t apic_id, uint32_t proximity_domain, +		    uint32_t flags); +static void	acpi_print_srat_memory(ACPI_SRAT_MEM_AFFINITY *mp); +static void	acpi_print_srat(ACPI_SUBTABLE_HEADER *srat); +static void	acpi_handle_srat(ACPI_TABLE_HEADER *sdp); +static void	acpi_handle_tcpa(ACPI_TABLE_HEADER *sdp); +static void	acpi_print_nfit(ACPI_NFIT_HEADER *nfit); +static void	acpi_handle_nfit(ACPI_TABLE_HEADER *sdp); +static void	acpi_print_sdt(ACPI_TABLE_HEADER *sdp); +static void	acpi_print_fadt(ACPI_TABLE_HEADER *sdp); +static void	acpi_print_facs(ACPI_TABLE_FACS *facs); +static void	acpi_print_dsdt(ACPI_TABLE_HEADER *dsdp); +static ACPI_TABLE_HEADER *acpi_map_sdt(vm_offset_t pa); +static void	acpi_print_rsd_ptr(ACPI_TABLE_RSDP *rp); +static void	acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp, const char *elm); +static void	acpi_walk_subtables(ACPI_TABLE_HEADER *table, void *first, +		    void (*action)(ACPI_SUBTABLE_HEADER *)); +static void	acpi_walk_nfit(ACPI_TABLE_HEADER *table, void *first, +		    void (*action)(ACPI_NFIT_HEADER *)); + +/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */ +static int addr_size; + +/* Strings used in the TCPA table */ +static const char *tcpa_event_type_strings[] = { +	"PREBOOT Certificate", +	"POST Code", +	"Unused", +	"No Action", +	"Separator", +	"Action", +	"Event Tag", +	"S-CRTM Contents", +	"S-CRTM Version", +	"CPU Microcode", +	"Platform Config Flags", +	"Table of Devices", +	"Compact Hash", +	"IPL", +	"IPL Partition Data", +	"Non-Host Code", +	"Non-Host Config", +	"Non-Host Info" +}; + +static const char *TCPA_pcclient_strings[] = { +	"<undefined>", +	"SMBIOS", +	"BIS Certificate", +	"POST BIOS ROM Strings", +	"ESCD", +	"CMOS", +	"NVRAM", +	"Option ROM Execute", +	"Option ROM Configurateion", +	"<undefined>", +	"Option ROM Microcode Update ", +	"S-CRTM Version String", +	"S-CRTM Contents", +	"POST Contents", +	"Table of Devices", +}; + +#define	PRINTFLAG_END()		printflag_end() + +static char pf_sep = '{'; + +static void +printflag_end(void) +{ + +	if (pf_sep != '{') { +		printf("}"); +		pf_sep = '{'; +	} +	printf("\n"); +} + +static void +printflag(uint64_t var, uint64_t mask, const char *name) +{ + +	if (var & mask) { +		printf("%c%s", pf_sep, name); +		pf_sep = ','; +	} +} + +static void +printfield(uint64_t var, int lbit, int hbit, const char *name) +{ +	uint64_t mask; +	int len; + +	len = hbit - lbit + 1; +	mask = ((1 << (len + 1)) - 1) << lbit; +	printf("%c%s=%#jx", pf_sep, name, (uintmax_t)((var & mask) >> lbit)); +	pf_sep = ','; +} + +static void +acpi_print_string(char *s, size_t length) +{ +	int	c; + +	/* Trim trailing spaces and NULLs */ +	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) +		length--; + +	while (length--) { +		c = *s++; +		putchar(c); +	} +} + +static void +acpi_print_gas(ACPI_GENERIC_ADDRESS *gas) +{ +	switch(gas->SpaceId) { +	case ACPI_GAS_MEMORY: +		printf("0x%016jx:%u[%u] (Memory)", (uintmax_t)gas->Address, +		    gas->BitOffset, gas->BitWidth); +		break; +	case ACPI_GAS_IO: +		printf("0x%02jx:%u[%u] (IO)", (uintmax_t)gas->Address, +		    gas->BitOffset, gas->BitWidth); +		break; +	case ACPI_GAS_PCI: +		printf("%x:%x+0x%x:%u[%u] (PCI)", (uint16_t)(gas->Address >> 32), +		       (uint16_t)((gas->Address >> 16) & 0xffff), +		       (uint16_t)gas->Address, gas->BitOffset, gas->BitWidth); +		break; +	/* XXX How to handle these below? */ +	case ACPI_GAS_EMBEDDED: +		printf("0x%x:%u[%u] (EC)", (uint16_t)gas->Address, +		       gas->BitOffset, gas->BitWidth); +		break; +	case ACPI_GAS_SMBUS: +		printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->Address, +		       gas->BitOffset, gas->BitWidth); +		break; +	case ACPI_GAS_CMOS: +	case ACPI_GAS_PCIBAR: +	case ACPI_GAS_DATATABLE: +	case ACPI_GAS_FIXED: +	default: +		printf("0x%016jx (?)", (uintmax_t)gas->Address); +		break; +	} +} + +/* The FADT revision indicates whether we use the DSDT or X_DSDT addresses. */ +static int +acpi_get_fadt_revision(ACPI_TABLE_FADT *fadt __unused) +{ +	int fadt_revision; + +	/* Set the FADT revision separately from the RSDP version. */ +	if (addr_size == 8) { +		fadt_revision = 2; + +#if defined(__i386__) +		/* +		 * A few systems (e.g., IBM T23) have an RSDP that claims +		 * revision 2 but the 64 bit addresses are invalid.  If +		 * revision 2 and the 32 bit address is non-zero but the +		 * 32 and 64 bit versions don't match, prefer the 32 bit +		 * version for all subsequent tables. +		 * +		 * The only known ACPI systems this affects are early +		 * implementations on 32-bit x86. Because of this limit the +		 * workaround to i386. +		 */ +		if (fadt->Facs != 0 && +		    (fadt->XFacs & 0xffffffff) != fadt->Facs) +			fadt_revision = 1; +#endif +	} else +		fadt_revision = 1; +	return (fadt_revision); +} + +static void +acpi_handle_fadt(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_HEADER *dsdp; +	ACPI_TABLE_FACS	*facs; +	ACPI_TABLE_FADT *fadt; +	vm_offset_t	addr; +	int		fadt_revision; + +	fadt = (ACPI_TABLE_FADT *)sdp; +	acpi_print_fadt(sdp); + +	fadt_revision = acpi_get_fadt_revision(fadt); +	if (fadt_revision == 1) +		addr = fadt->Facs; +	else +		addr = fadt->XFacs; +	if (addr != 0) { +		facs = (ACPI_TABLE_FACS *)acpi_map_sdt(addr); + +		if (memcmp(facs->Signature, ACPI_SIG_FACS, ACPI_NAMESEG_SIZE) != 0 || +		    facs->Length < 64) +			errx(1, "FACS is corrupt"); +		acpi_print_facs(facs); +	} + +	if (fadt_revision == 1) +		dsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->Dsdt); +	else +		dsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->XDsdt); +	if (acpi_checksum(dsdp, dsdp->Length)) +		errx(1, "DSDT is corrupt"); +	acpi_print_dsdt(dsdp); +} + +static void +acpi_walk_subtables(ACPI_TABLE_HEADER *table, void *first, +    void (*action)(ACPI_SUBTABLE_HEADER *)) +{ +	ACPI_SUBTABLE_HEADER *subtable; +	char *end; + +	subtable = first; +	end = (char *)table + table->Length; +	while ((char *)subtable < end) { +		printf("\n"); +		if (subtable->Length < sizeof(ACPI_SUBTABLE_HEADER)) { +			warnx("invalid subtable length %u", subtable->Length); +			return; +		} +		action(subtable); +		subtable = (ACPI_SUBTABLE_HEADER *)((char *)subtable + +		    subtable->Length); +	} +} + +static void +acpi_walk_nfit(ACPI_TABLE_HEADER *table, void *first, +    void (*action)(ACPI_NFIT_HEADER *)) +{ +	ACPI_NFIT_HEADER *subtable; +	char *end; + +	subtable = first; +	end = (char *)table + table->Length; +	while ((char *)subtable < end) { +		printf("\n"); +		if (subtable->Length < sizeof(ACPI_NFIT_HEADER)) { +			warnx("invalid subtable length %u", subtable->Length); +			return; +		} +		action(subtable); +		subtable = (ACPI_NFIT_HEADER *)((char *)subtable + +		    subtable->Length); +	} +} + +static void +acpi_print_cpu(u_char cpu_id) +{ + +	printf("\tACPI CPU="); +	if (cpu_id == 0xff) +		printf("ALL\n"); +	else +		printf("%d\n", (u_int)cpu_id); +} + +static void +acpi_print_cpu_uid(uint32_t uid, char *uid_string) +{ + +	printf("\tUID=%d", uid); +	if (uid_string != NULL) +		printf(" (%s)", uid_string); +	printf("\n"); +} + +static void +acpi_print_local_apic(uint32_t apic_id, uint32_t flags) +{ + +	printf("\tFlags={"); +	if (flags & ACPI_MADT_ENABLED) +		printf("ENABLED"); +	else +		printf("DISABLED"); +	printf("}\n"); +	printf("\tAPIC ID=%d\n", apic_id); +} + +static void +acpi_print_io_apic(uint32_t apic_id, uint32_t int_base, uint64_t apic_addr) +{ + +	printf("\tAPIC ID=%d\n", apic_id); +	printf("\tINT BASE=%d\n", int_base); +	printf("\tADDR=0x%016jx\n", (uintmax_t)apic_addr); +} + +static void +acpi_print_mps_flags(uint16_t flags) +{ + +	printf("\tFlags={Polarity="); +	switch (flags & ACPI_MADT_POLARITY_MASK) { +	case ACPI_MADT_POLARITY_CONFORMS: +		printf("conforming"); +		break; +	case ACPI_MADT_POLARITY_ACTIVE_HIGH: +		printf("active-hi"); +		break; +	case ACPI_MADT_POLARITY_ACTIVE_LOW: +		printf("active-lo"); +		break; +	default: +		printf("0x%x", flags & ACPI_MADT_POLARITY_MASK); +		break; +	} +	printf(", Trigger="); +	switch (flags & ACPI_MADT_TRIGGER_MASK) { +	case ACPI_MADT_TRIGGER_CONFORMS: +		printf("conforming"); +		break; +	case ACPI_MADT_TRIGGER_EDGE: +		printf("edge"); +		break; +	case ACPI_MADT_TRIGGER_LEVEL: +		printf("level"); +		break; +	default: +		printf("0x%x", (flags & ACPI_MADT_TRIGGER_MASK) >> 2); +	} +	printf("}\n"); +} + +static void +acpi_print_gicc_flags(uint32_t flags) +{ + +	printf("\tFlags={Performance intr="); +	if (flags & ACPI_MADT_PERFORMANCE_IRQ_MODE) +		printf("edge"); +	else +		printf("level"); +	printf(", VGIC intr="); +	if (flags & ACPI_MADT_VGIC_IRQ_MODE) +		printf("edge"); +	else +		printf("level"); +	printf("}\n"); +} + +static void +acpi_print_intr(uint32_t intr, uint16_t mps_flags) +{ + +	printf("\tINTR=%d\n", intr); +	acpi_print_mps_flags(mps_flags); +} + +static void +acpi_print_local_nmi(u_int lint, uint16_t mps_flags) +{ + +	printf("\tLINT Pin=%d\n", lint); +	acpi_print_mps_flags(mps_flags); +} + +static const char *apic_types[] = { +    [ACPI_MADT_TYPE_LOCAL_APIC] = "Local APIC", +    [ACPI_MADT_TYPE_IO_APIC] = "IO APIC", +    [ACPI_MADT_TYPE_INTERRUPT_OVERRIDE] = "INT Override", +    [ACPI_MADT_TYPE_NMI_SOURCE] = "NMI", +    [ACPI_MADT_TYPE_LOCAL_APIC_NMI] = "Local APIC NMI", +    [ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE] = "Local APIC Override", +    [ACPI_MADT_TYPE_IO_SAPIC] = "IO SAPIC", +    [ACPI_MADT_TYPE_LOCAL_SAPIC] = "Local SAPIC", +    [ACPI_MADT_TYPE_INTERRUPT_SOURCE] = "Platform Interrupt", +    [ACPI_MADT_TYPE_LOCAL_X2APIC] = "Local X2APIC", +    [ACPI_MADT_TYPE_LOCAL_X2APIC_NMI] = "Local X2APIC NMI", +    [ACPI_MADT_TYPE_GENERIC_INTERRUPT] = "GIC CPU Interface Structure", +    [ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR] = "GIC Distributor Structure", +    [ACPI_MADT_TYPE_GENERIC_MSI_FRAME] = "GICv2m MSI Frame", +    [ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR] = "GIC Redistributor Structure", +    [ACPI_MADT_TYPE_GENERIC_TRANSLATOR] = "GIC ITS Structure" +}; + +static const char *platform_int_types[] = { "0 (unknown)", "PMI", "INIT", +					    "Corrected Platform Error" }; + +static void +acpi_print_madt(ACPI_SUBTABLE_HEADER *mp) +{ +	ACPI_MADT_LOCAL_APIC *lapic; +	ACPI_MADT_IO_APIC *ioapic; +	ACPI_MADT_INTERRUPT_OVERRIDE *over; +	ACPI_MADT_NMI_SOURCE *nmi; +	ACPI_MADT_LOCAL_APIC_NMI *lapic_nmi; +	ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_over; +	ACPI_MADT_IO_SAPIC *iosapic; +	ACPI_MADT_LOCAL_SAPIC *lsapic; +	ACPI_MADT_INTERRUPT_SOURCE *isrc; +	ACPI_MADT_LOCAL_X2APIC *x2apic; +	ACPI_MADT_LOCAL_X2APIC_NMI *x2apic_nmi; +	ACPI_MADT_GENERIC_INTERRUPT *gicc; +	ACPI_MADT_GENERIC_DISTRIBUTOR *gicd; +	ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr; +	ACPI_MADT_GENERIC_TRANSLATOR *gict; + +	if (mp->Type < nitems(apic_types)) +		printf("\tType=%s\n", apic_types[mp->Type]); +	else +		printf("\tType=%d (unknown)\n", mp->Type); +	switch (mp->Type) { +	case ACPI_MADT_TYPE_LOCAL_APIC: +		lapic = (ACPI_MADT_LOCAL_APIC *)mp; +		acpi_print_cpu(lapic->ProcessorId); +		acpi_print_local_apic(lapic->Id, lapic->LapicFlags); +		break; +	case ACPI_MADT_TYPE_IO_APIC: +		ioapic = (ACPI_MADT_IO_APIC *)mp; +		acpi_print_io_apic(ioapic->Id, ioapic->GlobalIrqBase, +		    ioapic->Address); +		break; +	case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: +		over = (ACPI_MADT_INTERRUPT_OVERRIDE *)mp; +		printf("\tBUS=%d\n", (u_int)over->Bus); +		printf("\tIRQ=%d\n", (u_int)over->SourceIrq); +		acpi_print_intr(over->GlobalIrq, over->IntiFlags); +		break; +	case ACPI_MADT_TYPE_NMI_SOURCE: +		nmi = (ACPI_MADT_NMI_SOURCE *)mp; +		acpi_print_intr(nmi->GlobalIrq, nmi->IntiFlags); +		break; +	case ACPI_MADT_TYPE_LOCAL_APIC_NMI: +		lapic_nmi = (ACPI_MADT_LOCAL_APIC_NMI *)mp; +		acpi_print_cpu(lapic_nmi->ProcessorId); +		acpi_print_local_nmi(lapic_nmi->Lint, lapic_nmi->IntiFlags); +		break; +	case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: +		lapic_over = (ACPI_MADT_LOCAL_APIC_OVERRIDE *)mp; +		printf("\tLocal APIC ADDR=0x%016jx\n", +		    (uintmax_t)lapic_over->Address); +		break; +	case ACPI_MADT_TYPE_IO_SAPIC: +		iosapic = (ACPI_MADT_IO_SAPIC *)mp; +		acpi_print_io_apic(iosapic->Id, iosapic->GlobalIrqBase, +		    iosapic->Address); +		break; +	case ACPI_MADT_TYPE_LOCAL_SAPIC: +		lsapic = (ACPI_MADT_LOCAL_SAPIC *)mp; +		acpi_print_cpu(lsapic->ProcessorId); +		acpi_print_local_apic(lsapic->Id, lsapic->LapicFlags); +		printf("\tAPIC EID=%d\n", (u_int)lsapic->Eid); +		if (mp->Length > __offsetof(ACPI_MADT_LOCAL_SAPIC, Uid)) +			acpi_print_cpu_uid(lsapic->Uid, lsapic->UidString); +		break; +	case ACPI_MADT_TYPE_INTERRUPT_SOURCE: +		isrc = (ACPI_MADT_INTERRUPT_SOURCE *)mp; +		if (isrc->Type < nitems(platform_int_types)) +			printf("\tType=%s\n", platform_int_types[isrc->Type]); +		else +			printf("\tType=%d (unknown)\n", isrc->Type); +		printf("\tAPIC ID=%d\n", (u_int)isrc->Id); +		printf("\tAPIC EID=%d\n", (u_int)isrc->Eid); +		printf("\tSAPIC Vector=%d\n", (u_int)isrc->IoSapicVector); +		acpi_print_intr(isrc->GlobalIrq, isrc->IntiFlags); +		break; +	case ACPI_MADT_TYPE_LOCAL_X2APIC: +		x2apic = (ACPI_MADT_LOCAL_X2APIC *)mp; +		acpi_print_cpu_uid(x2apic->Uid, NULL); +		acpi_print_local_apic(x2apic->LocalApicId, x2apic->LapicFlags); +		break; +	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: +		x2apic_nmi = (ACPI_MADT_LOCAL_X2APIC_NMI *)mp; +		acpi_print_cpu_uid(x2apic_nmi->Uid, NULL); +		acpi_print_local_nmi(x2apic_nmi->Lint, x2apic_nmi->IntiFlags); +		break; +	case ACPI_MADT_TYPE_GENERIC_INTERRUPT: +		gicc = (ACPI_MADT_GENERIC_INTERRUPT *)mp; +		acpi_print_cpu_uid(gicc->Uid, NULL); +		printf("\tCPU INTERFACE=%x\n", gicc->CpuInterfaceNumber); +		acpi_print_gicc_flags(gicc->Flags); +		printf("\tParking Protocol Version=%x\n", gicc->ParkingVersion); +		printf("\tPERF INTR=%d\n", gicc->PerformanceInterrupt); +		printf("\tParked ADDR=%016jx\n", +		    (uintmax_t)gicc->ParkedAddress); +		printf("\tBase ADDR=%016jx\n", (uintmax_t)gicc->BaseAddress); +		printf("\tGICV=%016jx\n", (uintmax_t)gicc->GicvBaseAddress); +		printf("\tGICH=%016jx\n", (uintmax_t)gicc->GichBaseAddress); +		printf("\tVGIC INTR=%d\n", gicc->VgicInterrupt); +		printf("\tGICR ADDR=%016jx\n", +		    (uintmax_t)gicc->GicrBaseAddress); +		printf("\tMPIDR=%jx\n", (uintmax_t)gicc->ArmMpidr); +		printf("\tEfficiency Class=%d\n", (u_int)gicc->EfficiencyClass); +		printf("\tSPE INTR=%d\n", gicc->SpeInterrupt); +		break; +	case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: +		gicd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)mp; +		printf("\tGIC ID=%d\n", (u_int)gicd->GicId); +		printf("\tBase ADDR=%016jx\n", (uintmax_t)gicd->BaseAddress); +		printf("\tVector Base=%d\n", gicd->GlobalIrqBase); +		printf("\tGIC VERSION=%d\n", (u_int)gicd->Version); +		break; +	case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: +		gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)mp; +		printf("\tBase ADDR=%016jx\n", (uintmax_t)gicr->BaseAddress); +		printf("\tLength=%08x\n", gicr->Length); +		break; +	case ACPI_MADT_TYPE_GENERIC_TRANSLATOR: +		gict = (ACPI_MADT_GENERIC_TRANSLATOR *)mp; +		printf("\tGIC ITS ID=%d\n", gict->TranslationId); +		printf("\tBase ADDR=%016jx\n", (uintmax_t)gict->BaseAddress); +		break; +	} +} + +static void +acpi_handle_madt(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_MADT *madt; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	madt = (ACPI_TABLE_MADT *)sdp; +	printf("\tLocal APIC ADDR=0x%08x\n", madt->Address); +	printf("\tFlags={"); +	if (madt->Flags & ACPI_MADT_PCAT_COMPAT) +		printf("PC-AT"); +	printf("}\n"); +	acpi_walk_subtables(sdp, (madt + 1), acpi_print_madt); +	printf(END_COMMENT); +} + +static void +acpi_handle_bert(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_BERT *bert; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	bert = (ACPI_TABLE_BERT *)sdp; +	printf("\tRegionLength=%d\n", bert->RegionLength); +	printf("\tAddress=0x%016jx\n", bert->Address); +	printf(END_COMMENT); +} + +static void +acpi_print_whea(ACPI_WHEA_HEADER *w) +{ + +	printf("\n\tAction=%d\n", w->Action); +	printf("\tInstruction=%d\n", w->Instruction); +	printf("\tFlags=%02x\n", w->Flags); +	printf("\tRegisterRegion="); +	acpi_print_gas(&w->RegisterRegion); +	printf("\n\tValue=0x%016jx\n", w->Value); +	printf("\tMask=0x%016jx\n", w->Mask); +} + +static void +acpi_handle_einj(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_EINJ *einj; +	ACPI_WHEA_HEADER *w; +	u_int i; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	einj = (ACPI_TABLE_EINJ *)sdp; +	printf("\tHeaderLength=%d\n", einj->HeaderLength); +	printf("\tFlags=0x%02x\n", einj->Flags); +	printf("\tEntries=%d\n", einj->Entries); +	w = (ACPI_WHEA_HEADER *)(einj + 1); +	for (i = 0; i < MIN(einj->Entries, (sdp->Length - +	    sizeof(ACPI_TABLE_EINJ)) / sizeof(ACPI_WHEA_HEADER)); i++) +		acpi_print_whea(w + i); +	printf(END_COMMENT); +} + +static void +acpi_handle_erst(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_ERST *erst; +	ACPI_WHEA_HEADER *w; +	u_int i; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	erst = (ACPI_TABLE_ERST *)sdp; +	printf("\tHeaderLength=%d\n", erst->HeaderLength); +	printf("\tEntries=%d\n", erst->Entries); +	w = (ACPI_WHEA_HEADER *)(erst + 1); +	for (i = 0; i < MIN(erst->Entries, (sdp->Length - +	    sizeof(ACPI_TABLE_ERST)) / sizeof(ACPI_WHEA_HEADER)); i++) +		acpi_print_whea(w + i); +	printf(END_COMMENT); +} + +static void +acpi_print_hest_bank(ACPI_HEST_IA_ERROR_BANK *b) +{ + +	printf("\tBank:\n"); +	printf("\t\tBankNumber=%d\n", b->BankNumber); +	printf("\t\tClearStatusOnInit=%d\n", b->ClearStatusOnInit); +	printf("\t\tStatusFormat=%d\n", b->StatusFormat); +	printf("\t\tControlRegister=%x\n", b->ControlRegister); +	printf("\t\tControlData=%jx\n", b->ControlData); +	printf("\t\tStatusRegister=%x\n", b->StatusRegister); +	printf("\t\tAddressRegister=%x\n", b->AddressRegister); +	printf("\t\tMiscRegister=%x\n", b->MiscRegister); +} + +static void +acpi_print_hest_notify(ACPI_HEST_NOTIFY *n) +{ + +	printf("\t\tType=%d\n", n->Type); +	printf("\t\tLength=%d\n", n->Length); +	printf("\t\tConfigWriteEnable=%04x\n", n->ConfigWriteEnable); +	printf("\t\tPollInterval=%d\n", n->PollInterval); +	printf("\t\tVector=%d\n", n->Vector); +	printf("\t\tPollingThresholdValue=%d\n", n->PollingThresholdValue); +	printf("\t\tPollingThresholdWindow=%d\n", n->PollingThresholdWindow); +	printf("\t\tErrorThresholdValue=%d\n", n->ErrorThresholdValue); +	printf("\t\tErrorThresholdWindow=%d\n", n->ErrorThresholdWindow); +} + +static void +acpi_print_hest_aer(ACPI_HEST_AER_COMMON *a) +{ + +	printf("\tFlags=%02x\n", a->Flags); +	printf("\tEnabled=%d\n", a->Enabled); +	printf("\tRecordsToPreallocate=%d\n", a->RecordsToPreallocate); +	printf("\tMaxSectionsPerRecord=%d\n", a->MaxSectionsPerRecord); +	printf("\tBus=%d\n", a->Bus); +	printf("\tDevice=%d\n", a->Device); +	printf("\tFunction=%d\n", a->Function); +	printf("\tDeviceControl=%d\n", a->DeviceControl); +	printf("\tUncorrectableMask=%d\n", a->UncorrectableMask); +	printf("\tUncorrectableSeverity=%d\n", a->UncorrectableSeverity); +	printf("\tCorrectableMask=%d\n", a->CorrectableMask); +	printf("\tAdvancedCapabilities=%d\n", a->AdvancedCapabilities); +} + +static int +acpi_handle_hest_structure(void *addr, int remaining) +{ +	ACPI_HEST_HEADER *hdr = addr; +	int i; + +	if (remaining < (int)sizeof(ACPI_HEST_HEADER)) +		return (-1); + +	printf("\n\tType=%d\n", hdr->Type); +	printf("\tSourceId=%d\n", hdr->SourceId); +	switch (hdr->Type) { +	case ACPI_HEST_TYPE_IA32_CHECK: { +		ACPI_HEST_IA_MACHINE_CHECK *s = addr; +		printf("\tFlags=%02x\n", s->Flags); +		printf("\tEnabled=%d\n", s->Enabled); +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tGlobalCapabilityData=%jd\n", s->GlobalCapabilityData); +		printf("\tGlobalControlData=%jd\n", s->GlobalControlData); +		printf("\tNumHardwareBanks=%d\n", s->NumHardwareBanks); +		for (i = 0; i < s->NumHardwareBanks; i++) { +			acpi_print_hest_bank((ACPI_HEST_IA_ERROR_BANK *) +			    (s + 1) + i); +		} +		return (sizeof(*s) + s->NumHardwareBanks * +		    sizeof(ACPI_HEST_IA_ERROR_BANK)); +	} +	case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: { +		ACPI_HEST_IA_CORRECTED *s = addr; +		printf("\tFlags=%02x\n", s->Flags); +		printf("\tEnabled=%d\n", s->Enabled); +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tNotify:\n"); +		acpi_print_hest_notify(&s->Notify); +		printf("\tNumHardwareBanks=%d\n", s->NumHardwareBanks); +		for (i = 0; i < s->NumHardwareBanks; i++) { +			acpi_print_hest_bank((ACPI_HEST_IA_ERROR_BANK *) +			    (s + 1) + i); +		} +		return (sizeof(*s) + s->NumHardwareBanks * +		    sizeof(ACPI_HEST_IA_ERROR_BANK)); +	} +	case ACPI_HEST_TYPE_IA32_NMI: { +		ACPI_HEST_IA_NMI *s = addr; +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tMaxRawDataLength=%d\n", s->MaxRawDataLength); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_AER_ROOT_PORT: { +		ACPI_HEST_AER_ROOT *s = addr; +		acpi_print_hest_aer(&s->Aer); +		printf("\tRootErrorCommand=%d\n", s->RootErrorCommand); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_AER_ENDPOINT: { +		ACPI_HEST_AER *s = addr; +		acpi_print_hest_aer(&s->Aer); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_AER_BRIDGE: { +		ACPI_HEST_AER_BRIDGE *s = addr; +		acpi_print_hest_aer(&s->Aer); +		printf("\tUncorrectableMask2=%d\n", s->UncorrectableMask2); +		printf("\tUncorrectableSeverity2=%d\n", s->UncorrectableSeverity2); +		printf("\tAdvancedCapabilities2=%d\n", s->AdvancedCapabilities2); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_GENERIC_ERROR: { +		ACPI_HEST_GENERIC *s = addr; +		printf("\tRelatedSourceId=%d\n", s->RelatedSourceId); +		printf("\tEnabled=%d\n", s->Enabled); +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tMaxRawDataLength=%d\n", s->MaxRawDataLength); +		printf("\tErrorStatusAddress="); +		acpi_print_gas(&s->ErrorStatusAddress); +		printf("\n"); +		printf("\tNotify:\n"); +		acpi_print_hest_notify(&s->Notify); +		printf("\tErrorBlockLength=%d\n", s->ErrorBlockLength); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_GENERIC_ERROR_V2: { +		ACPI_HEST_GENERIC_V2 *s = addr; +		printf("\tRelatedSourceId=%d\n", s->RelatedSourceId); +		printf("\tEnabled=%d\n", s->Enabled); +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tMaxRawDataLength=%d\n", s->MaxRawDataLength); +		printf("\tErrorStatusAddress="); +		acpi_print_gas(&s->ErrorStatusAddress); +		printf("\n"); +		printf("\tNotify:\n"); +		acpi_print_hest_notify(&s->Notify); +		printf("\tErrorBlockLength=%d\n", s->ErrorBlockLength); +		printf("\tReadAckRegister="); +		acpi_print_gas(&s->ReadAckRegister); +		printf("\n"); +		printf("\tReadAckPreserve=%jd\n", s->ReadAckPreserve); +		printf("\tReadAckWrite=%jd\n", s->ReadAckWrite); +		return (sizeof(*s)); +	} +	case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: { +		ACPI_HEST_IA_DEFERRED_CHECK *s = addr; +		printf("\tFlags=%02x\n", s->Flags); +		printf("\tEnabled=%d\n", s->Enabled); +		printf("\tRecordsToPreallocate=%d\n", s->RecordsToPreallocate); +		printf("\tMaxSectionsPerRecord=%d\n", s->MaxSectionsPerRecord); +		printf("\tNotify:\n"); +		acpi_print_hest_notify(&s->Notify); +		printf("\tNumHardwareBanks=%d\n", s->NumHardwareBanks); +		for (i = 0; i < s->NumHardwareBanks; i++) { +			acpi_print_hest_bank((ACPI_HEST_IA_ERROR_BANK *) +			    (s + 1) + i); +		} +		return (sizeof(*s) + s->NumHardwareBanks * +		    sizeof(ACPI_HEST_IA_ERROR_BANK)); +	} +	default: +		return (-1); +	} +} + +static void +acpi_handle_hest(ACPI_TABLE_HEADER *sdp) +{ +	char *cp; +	int remaining, consumed; +	ACPI_TABLE_HEST *hest; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	hest = (ACPI_TABLE_HEST *)sdp; +	printf("\tErrorSourceCount=%d\n", hest->ErrorSourceCount); + +	remaining = sdp->Length - sizeof(ACPI_TABLE_HEST); +	while (remaining > 0) { +		cp = (char *)sdp + sdp->Length - remaining; +		consumed = acpi_handle_hest_structure(cp, remaining); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} +	printf(END_COMMENT); +} + +static void +acpi_handle_hpet(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_HPET *hpet; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	hpet = (ACPI_TABLE_HPET *)sdp; +	printf("\tHPET Number=%d\n", hpet->Sequence); +	printf("\tADDR="); +	acpi_print_gas(&hpet->Address); +	printf("\n\tHW Rev=0x%x\n", hpet->Id & ACPI_HPET_ID_HARDWARE_REV_ID); +	printf("\tComparators=%d\n", (hpet->Id & ACPI_HPET_ID_COMPARATORS) >> +	    8); +	printf("\tCounter Size=%d\n", hpet->Id & ACPI_HPET_ID_COUNT_SIZE_CAP ? +	    1 : 0); +	printf("\tLegacy IRQ routing capable={"); +	if (hpet->Id & ACPI_HPET_ID_LEGACY_CAPABLE) +		printf("TRUE}\n"); +	else +		printf("FALSE}\n"); +	printf("\tPCI Vendor ID=0x%04x\n", hpet->Id >> 16); +	printf("\tMinimal Tick=%d\n", hpet->MinimumTick); +	printf("\tFlags=0x%02x\n", hpet->Flags); +	printf(END_COMMENT); +} + +static void +acpi_handle_ecdt(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_ECDT *ecdt; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	ecdt = (ACPI_TABLE_ECDT *)sdp; +	printf("\tEC_CONTROL="); +	acpi_print_gas(&ecdt->Control); +	printf("\n\tEC_DATA="); +	acpi_print_gas(&ecdt->Data); +	printf("\n\tUID=%#x, ", ecdt->Uid); +	printf("GPE_BIT=%#x\n", ecdt->Gpe); +	printf("\tEC_ID=%s\n", ecdt->Id); +	printf(END_COMMENT); +} + +static void +acpi_handle_mcfg(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_MCFG *mcfg; +	ACPI_MCFG_ALLOCATION *alloc; +	u_int i, entries; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	mcfg = (ACPI_TABLE_MCFG *)sdp; +	entries = (sdp->Length - sizeof(ACPI_TABLE_MCFG)) / +	    sizeof(ACPI_MCFG_ALLOCATION); +	alloc = (ACPI_MCFG_ALLOCATION *)(mcfg + 1); +	for (i = 0; i < entries; i++, alloc++) { +		printf("\n"); +		printf("\tBase Address=0x%016jx\n", (uintmax_t)alloc->Address); +		printf("\tSegment Group=0x%04x\n", alloc->PciSegment); +		printf("\tStart Bus=%d\n", alloc->StartBusNumber); +		printf("\tEnd Bus=%d\n", alloc->EndBusNumber); +	} +	printf(END_COMMENT); +} + +static void +acpi_handle_slit(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_SLIT *slit; +	UINT64 i, j; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	slit = (ACPI_TABLE_SLIT *)sdp; +	printf("\tLocality Count=%ju\n", (uintmax_t)slit->LocalityCount); +	printf("\n\t      "); +	for (i = 0; i < slit->LocalityCount; i++) +		printf(" %3ju", (uintmax_t)i); +	printf("\n\t     +"); +	for (i = 0; i < slit->LocalityCount; i++) +		printf("----"); +	printf("\n"); +	for (i = 0; i < slit->LocalityCount; i++) { +		printf("\t %3ju |", (uintmax_t)i); +		for (j = 0; j < slit->LocalityCount; j++) +			printf(" %3d", +			    slit->Entry[i * slit->LocalityCount + j]); +		printf("\n"); +	} +	printf(END_COMMENT); +} + +static void +acpi_handle_wddt(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_WDDT *wddt; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	wddt = (ACPI_TABLE_WDDT *)sdp; +	printf("\tSpecVersion=0x%04x, TableVersion=0x%04x\n", +	    wddt->SpecVersion, wddt->TableVersion); +	printf("\tPciVendorId=0x%04x, Address=", wddt->PciVendorId); +	acpi_print_gas(&wddt->Address); +	printf("\n\tMaxCount=%u, MinCount=%u, Period=%ums\n", +	    wddt->MaxCount, wddt->MinCount, wddt->Period); + +#define	PRINTFLAG(var, flag)	printflag((var), ACPI_WDDT_## flag, #flag) +	printf("\tStatus="); +	PRINTFLAG(wddt->Status, AVAILABLE); +	PRINTFLAG(wddt->Status, ACTIVE); +	PRINTFLAG(wddt->Status, TCO_OS_OWNED); +	PRINTFLAG(wddt->Status, USER_RESET); +	PRINTFLAG(wddt->Status, WDT_RESET); +	PRINTFLAG(wddt->Status, POWER_FAIL); +	PRINTFLAG(wddt->Status, UNKNOWN_RESET); +	PRINTFLAG_END(); +	printf("\tCapability="); +	PRINTFLAG(wddt->Capability, AUTO_RESET); +	PRINTFLAG(wddt->Capability, ALERT_SUPPORT); +	PRINTFLAG_END(); +#undef PRINTFLAG + +	printf(END_COMMENT); +} + +static void +acpi_print_native_lpit(ACPI_LPIT_NATIVE *nl) +{ +	printf("\tEntryTrigger="); +	acpi_print_gas(&nl->EntryTrigger); +	printf("\n\tResidency=%u\n", nl->Residency); +	printf("\tLatency=%u\n", nl->Latency); +	if (nl->Header.Flags & ACPI_LPIT_NO_COUNTER) +		printf("\tResidencyCounter=Not Present"); +	else { +		printf("\tResidencyCounter="); +		acpi_print_gas(&nl->ResidencyCounter); +		printf("\n"); +	} +	if (nl->CounterFrequency) +		printf("\tCounterFrequency=%ju\n", nl->CounterFrequency); +	else +		printf("\tCounterFrequency=TSC\n"); +} + +static void +acpi_print_lpit(ACPI_LPIT_HEADER *lpit) +{ +	if (lpit->Type == ACPI_LPIT_TYPE_NATIVE_CSTATE) +		printf("\tType=ACPI_LPIT_TYPE_NATIVE_CSTATE\n"); +	else +		warnx("unknown LPIT type %u", lpit->Type); + +	printf("\tLength=%u\n", lpit->Length); +	printf("\tUniqueId=0x%04x\n", lpit->UniqueId); +#define	PRINTFLAG(var, flag)	printflag((var), ACPI_LPIT_## flag, #flag) +	printf("\tFlags="); +	PRINTFLAG(lpit->Flags, STATE_DISABLED); +	PRINTFLAG_END(); +#undef PRINTFLAG + +	if (lpit->Type == ACPI_LPIT_TYPE_NATIVE_CSTATE) +		return acpi_print_native_lpit((ACPI_LPIT_NATIVE *)lpit); +} + +static void +acpi_walk_lpit(ACPI_TABLE_HEADER *table, void *first, +    void (*action)(ACPI_LPIT_HEADER *)) +{ +	ACPI_LPIT_HEADER *subtable; +	char *end; + +	subtable = first; +	end = (char *)table + table->Length; +	while ((char *)subtable < end) { +		printf("\n"); +		if (subtable->Length < sizeof(ACPI_LPIT_HEADER)) { +			warnx("invalid subtable length %u", subtable->Length); +			return; +		} +		action(subtable); +		subtable = (ACPI_LPIT_HEADER *)((char *)subtable + +		    subtable->Length); +	} +} + +static void +acpi_handle_lpit(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_LPIT *lpit; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	lpit = (ACPI_TABLE_LPIT *)sdp; +	acpi_walk_lpit(sdp, (lpit + 1), acpi_print_lpit); + +	printf(END_COMMENT); +} + +static void +acpi_print_srat_cpu(uint32_t apic_id, uint32_t proximity_domain, +    uint32_t flags) +{ + +	printf("\tFlags={"); +	if (flags & ACPI_SRAT_CPU_ENABLED) +		printf("ENABLED"); +	else +		printf("DISABLED"); +	printf("}\n"); +	printf("\tAPIC ID=%d\n", apic_id); +	printf("\tProximity Domain=%d\n", proximity_domain); +} + +static char * +acpi_tcpa_evname(struct TCPAevent *event) +{ +	struct TCPApc_event *pc_event; +	char *eventname = NULL; + +	pc_event = (struct TCPApc_event *)(event + 1); + +	switch(event->event_type) { +	case PREBOOT: +	case POST_CODE: +	case UNUSED: +	case NO_ACTION: +	case SEPARATOR: +	case SCRTM_CONTENTS: +	case SCRTM_VERSION: +	case CPU_MICROCODE: +	case PLATFORM_CONFIG_FLAGS: +	case TABLE_OF_DEVICES: +	case COMPACT_HASH: +	case IPL: +	case IPL_PARTITION_DATA: +	case NONHOST_CODE: +	case NONHOST_CONFIG: +	case NONHOST_INFO: +		asprintf(&eventname, "%s", +		    tcpa_event_type_strings[event->event_type]); +		break; + +	case ACTION: +		eventname = calloc(event->event_size + 1, sizeof(char)); +		memcpy(eventname, pc_event, event->event_size); +		break; + +	case EVENT_TAG: +		switch (pc_event->event_id) { +		case SMBIOS: +		case BIS_CERT: +		case CMOS: +		case NVRAM: +		case OPTION_ROM_EXEC: +		case OPTION_ROM_CONFIG: +		case S_CRTM_VERSION: +		case POST_BIOS_ROM: +		case ESCD: +		case OPTION_ROM_MICROCODE: +		case S_CRTM_CONTENTS: +		case POST_CONTENTS: +			asprintf(&eventname, "%s", +			    TCPA_pcclient_strings[pc_event->event_id]); +			break; + +		default: +			asprintf(&eventname, "<unknown tag 0x%02x>", +			    pc_event->event_id); +			break; +		} +		break; + +	default: +		asprintf(&eventname, "<unknown 0x%02x>", event->event_type); +		break; +	} + +	return eventname; +} + +static void +acpi_print_tcpa(struct TCPAevent *event) +{ +	int i; +	char *eventname; + +	eventname = acpi_tcpa_evname(event); + +	printf("\t%d", event->pcr_index); +	printf(" 0x"); +	for (i = 0; i < 20; i++) +		printf("%02x", event->pcr_value[i]); +	printf(" [%s]\n", eventname ? eventname : "<unknown>"); + +	free(eventname); +} + +static void +acpi_handle_tcpa(ACPI_TABLE_HEADER *sdp) +{ +	struct TCPAbody *tcpa; +	struct TCPAevent *event; +	uintmax_t len, paddr; +	unsigned char *vaddr = NULL; +	unsigned char *vend = NULL; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	tcpa = (struct TCPAbody *) sdp; + +	switch (tcpa->platform_class) { +	case ACPI_TCPA_BIOS_CLIENT: +		len = tcpa->client.log_max_len; +		paddr = tcpa->client.log_start_addr; +		break; + +	case ACPI_TCPA_BIOS_SERVER: +		len = tcpa->server.log_max_len; +		paddr = tcpa->server.log_start_addr; +		break; + +	default: +		printf("XXX"); +		printf(END_COMMENT); +		return; +	} +	printf("\tClass %u Base Address 0x%jx Length %ju\n\n", +	    tcpa->platform_class, paddr, len); + +	if (len == 0) { +		printf("\tEmpty TCPA table\n"); +		printf(END_COMMENT); +		return; +	} +	if(sdp->Revision == 1){ +		printf("\tOLD TCPA spec log found. Dumping not supported.\n"); +		printf(END_COMMENT); +		return; +	} + +	vaddr = (unsigned char *)acpi_map_physical(paddr, len); +	vend = vaddr + len; + +	while (vaddr != NULL) { +		if ((uintptr_t)vaddr + sizeof(struct TCPAevent) >= +		    (uintptr_t)vend || (uintptr_t)vaddr + sizeof( +		    struct TCPAevent) < (uintptr_t)vaddr) +			break; +		event = (struct TCPAevent *)(void *)vaddr; +		if ((uintptr_t)vaddr + event->event_size >= (uintptr_t)vend) +			break; +		if ((uintptr_t)vaddr + event->event_size < (uintptr_t)vaddr) +			break; +		if (event->event_type == 0 && event->event_size == 0) +			break; +#if 0 +		{ +		unsigned int i, j, k; + +		printf("\n\tsize %d\n\t\t%p ", event->event_size, vaddr); +		for (j = 0, i = 0; i < +		    sizeof(struct TCPAevent) + event->event_size; i++) { +			printf("%02x ", vaddr[i]); +			if ((i+1) % 8 == 0) { +				for (k = 0; k < 8; k++) +					printf("%c", isprint(vaddr[j+k]) ? +					    vaddr[j+k] : '.'); +				printf("\n\t\t%p ", &vaddr[i + 1]); +				j = i + 1; +			} +		} +		printf("\n"); } +#endif +		acpi_print_tcpa(event); + +		vaddr += sizeof(struct TCPAevent) + event->event_size; +	} + +	printf(END_COMMENT); +} + +static void acpi_handle_tpm2(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_TPM2 *tpm2; +	 +	printf (BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	tpm2 = (ACPI_TABLE_TPM2 *) sdp; +	printf ("\t\tControlArea=%jx\n", tpm2->ControlAddress); +	printf ("\t\tStartMethod=%x\n", tpm2->StartMethod);	 +	printf (END_COMMENT); +} + +static int spcr_xlate_baud(uint8_t r) +{ +	static int rates[] = { 9600, 19200, -1, 57600, 115200 }; +	_Static_assert(nitems(rates) == 7 - 3 + 1, "rates array size incorrect"); + +	if (r == 0) +		return (0); + +	if (r < 3 || r > 7) +		return (-1); + +	return (rates[r - 3]); +} + +static const char *spcr_interface_type(int ift) +{ +	static const char *if_names[] = { +		[0x00] = "Fully 16550-compatible", +		[0x01] = "16550 subset compatible with DBGP Revision 1", +		[0x02] = "MAX311xE SPI UART", +		[0x03] = "Arm PL011 UART", +		[0x04] = "MSM8x60 (e.g. 8960)", +		[0x05] = "Nvidia 16550", +		[0x06] = "TI OMAP", +		[0x07] = "Reserved (Do Not Use)", +		[0x08] = "APM88xxxx", +		[0x09] = "MSM8974", +		[0x0a] = "SAM5250", +		[0x0b] = "Intel USIF", +		[0x0c] = "i.MX 6", +		[0x0d] = "(deprecated) Arm SBSA (2.x only) Generic UART supporting only 32-bit accesses", +		[0x0e] = "Arm SBSA Generic UART", +		[0x0f] = "Arm DCC", +		[0x10] = "BCM2835", +		[0x11] = "SDM845 with clock rate of 1.8432 MHz", +		[0x12] = "16550-compatible with parameters defined in Generic Address Structure", +		[0x13] = "SDM845 with clock rate of 7.372 MHz", +		[0x14] = "Intel LPSS", +		[0x15] = "RISC-V SBI console (any supported SBI mechanism)", +	}; + +	if (ift >= (int)nitems(if_names) || if_names[ift] == NULL) +		return ("Reserved"); +	return (if_names[ift]); +} + +static const char *spcr_interrupt_type(int ift) +{ +	static char buf[100]; + +#define APPEND(b,s) \ +	if ((ift & (b)) != 0) { \ +		if (strlen(buf) > 0) \ +			strlcat(buf, ",", sizeof(buf)); \ +		strlcat(buf, s, sizeof(buf)); \ +	} + +	*buf = '\0'; +	APPEND(0x01, "PC/AT IRQ"); +	APPEND(0x02, "I/O APIC"); +	APPEND(0x04, "I/O SAPIC"); +	APPEND(0x08, "ARMH GIC"); +	APPEND(0x10, "RISC-V PLIC/APLIC"); + +#undef APPEND + +	return (buf); +} + +static const char *spcr_terminal_type(int type) +{ +	static const char *term_names[] = { +		[0] = "VT100", +		[1] = "Extended VT100", +		[2] = "VT-UTF8", +		[3] = "ANSI", +	}; + +	if (type >= (int)nitems(term_names) || term_names[type] == NULL) +		return ("Reserved"); +	return (term_names[type]); +} + +static void acpi_handle_spcr(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_SPCR *spcr; + +	printf (BEGIN_COMMENT); +	acpi_print_sdt(sdp); + +	/* Rev 1 and 2 are the same size */ +	spcr = (ACPI_TABLE_SPCR *) sdp; +	printf ("\tInterfaceType=%d (%s)\n", spcr->InterfaceType, +	    spcr_interface_type(spcr->InterfaceType)); +	printf ("\tSerialPort="); +	acpi_print_gas(&spcr->SerialPort); +	printf ("\n\tInterruptType=%#x (%s)\n", spcr->InterruptType, +	    spcr_interrupt_type(spcr->InterruptType)); +	printf ("\tPcInterrupt=%d (%s)\n", spcr->PcInterrupt, +	    (spcr->InterruptType & 0x1) ? "Valid" : "Invalid"); +	printf ("\tInterrupt=%d\n", spcr->Interrupt); +	printf ("\tBaudRate=%d (%d)\n", spcr_xlate_baud(spcr->BaudRate), spcr->BaudRate); +	printf ("\tParity=%d\n", spcr->Parity); +	printf ("\tStopBits=%d\n", spcr->StopBits); +	printf ("\tFlowControl=%d\n", spcr->FlowControl); +	printf ("\tTerminalType=%d (%s)\n", spcr->TerminalType, +	    spcr_terminal_type(spcr->TerminalType)); +	printf ("\tPciDeviceId=%#04x\n", spcr->PciDeviceId); +	printf ("\tPciVendorId=%#04x\n", spcr->PciVendorId); +	printf ("\tPciBus=%d\n", spcr->PciBus); +	printf ("\tPciDevice=%d\n", spcr->PciDevice); +	printf ("\tPciFunction=%d\n", spcr->PciFunction); +	printf ("\tPciFlags=%d\n", spcr->PciFlags); +	printf ("\tPciSegment=%d\n", spcr->PciSegment); + +	/* Rev 3 added UartClkFrequency */ +	if (sdp->Revision >= 3) { +		printf("\tLanguage=%d\n", spcr->Language); +		printf("\tUartClkFreq=%jd", +		    (uintmax_t)spcr->UartClkFreq); +	} + +	/* Rev 4 added PreciseBaudrate and NameSpace* */ +	if (sdp->Revision >= 4) { +		printf("\tPreciseBaudrate=%jd", +		    (uintmax_t)spcr->PreciseBaudrate); +		if (spcr->NameSpaceStringLength > 0 && +		    spcr->NameSpaceStringOffset >= sizeof(*spcr) && +		    sdp->Length >= spcr->NameSpaceStringOffset + +		        spcr->NameSpaceStringLength) { +			printf ("\tNameSpaceString='%s'\n", +			    (char *)sdp + spcr->NameSpaceStringOffset); +		} +	} + +	printf (END_COMMENT); +} + +static const char * +devscope_type2str(int type) +{ +	static char typebuf[16]; + +	switch (type) { +	case ACPI_DMAR_SCOPE_TYPE_ENDPOINT: +		return ("PCI Endpoint Device"); +	case ACPI_DMAR_SCOPE_TYPE_BRIDGE: +		return ("PCI Sub-Hierarchy"); +	case ACPI_DMAR_SCOPE_TYPE_IOAPIC: +		return ("IOAPIC"); +	case ACPI_DMAR_SCOPE_TYPE_HPET: +		return ("HPET"); +	case ACPI_DMAR_SCOPE_TYPE_NAMESPACE: +		return ("ACPI NS DEV"); +	default: +		snprintf(typebuf, sizeof(typebuf), "%d", type); +		return (typebuf); +	} +} + +static int +acpi_handle_dmar_devscope(void *addr, int remaining) +{ +	char sep; +	int pathlen; +	ACPI_DMAR_PCI_PATH *path, *pathend; +	ACPI_DMAR_DEVICE_SCOPE *devscope = addr; + +	if (remaining < (int)sizeof(ACPI_DMAR_DEVICE_SCOPE)) +		return (-1); + +	if (remaining < devscope->Length) +		return (-1); + +	printf("\n"); +	printf("\t\tType=%s\n", devscope_type2str(devscope->EntryType)); +	printf("\t\tLength=%d\n", devscope->Length); +	printf("\t\tEnumerationId=%d\n", devscope->EnumerationId); +	printf("\t\tStartBusNumber=%d\n", devscope->Bus); + +	path = (ACPI_DMAR_PCI_PATH *)(devscope + 1); +	pathlen = devscope->Length - sizeof(ACPI_DMAR_DEVICE_SCOPE); +	pathend = path + pathlen / sizeof(ACPI_DMAR_PCI_PATH); +	if (path < pathend) { +		sep = '{'; +		printf("\t\tPath="); +		do { +			printf("%c%d:%d", sep, path->Device, path->Function); +			sep=','; +			path++; +		} while (path < pathend); +		printf("}\n"); +	} + +	return (devscope->Length); +} + +static void +acpi_handle_dmar_drhd(ACPI_DMAR_HARDWARE_UNIT *drhd) +{ +	char *cp; +	int remaining, consumed; + +	printf("\n"); +	printf("\tType=DRHD\n"); +	printf("\tLength=%d\n", drhd->Header.Length); + +#define	PRINTFLAG(var, flag)	printflag((var), ACPI_DMAR_## flag, #flag) + +	printf("\tFlags="); +	PRINTFLAG(drhd->Flags, INCLUDE_ALL); +	PRINTFLAG_END(); + +#undef PRINTFLAG + +	printf("\tSegment=%d\n", drhd->Segment); +	printf("\tAddress=0x%016jx\n", (uintmax_t)drhd->Address); + +	remaining = drhd->Header.Length - sizeof(ACPI_DMAR_HARDWARE_UNIT); +	if (remaining > 0) +		printf("\tDevice Scope:"); +	while (remaining > 0) { +		cp = (char *)drhd + drhd->Header.Length - remaining; +		consumed = acpi_handle_dmar_devscope(cp, remaining); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} +} + +static void +acpi_handle_dmar_rmrr(ACPI_DMAR_RESERVED_MEMORY *rmrr) +{ +	char *cp; +	int remaining, consumed; + +	printf("\n"); +	printf("\tType=RMRR\n"); +	printf("\tLength=%d\n", rmrr->Header.Length); +	printf("\tSegment=%d\n", rmrr->Segment); +	printf("\tBaseAddress=0x%016jx\n", (uintmax_t)rmrr->BaseAddress); +	printf("\tLimitAddress=0x%016jx\n", (uintmax_t)rmrr->EndAddress); + +	remaining = rmrr->Header.Length - sizeof(ACPI_DMAR_RESERVED_MEMORY); +	if (remaining > 0) +		printf("\tDevice Scope:"); +	while (remaining > 0) { +		cp = (char *)rmrr + rmrr->Header.Length - remaining; +		consumed = acpi_handle_dmar_devscope(cp, remaining); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} +} + +static void +acpi_handle_dmar_atsr(ACPI_DMAR_ATSR *atsr) +{ +	char *cp; +	int remaining, consumed; + +	printf("\n"); +	printf("\tType=ATSR\n"); +	printf("\tLength=%d\n", atsr->Header.Length); + +#define	PRINTFLAG(var, flag)	printflag((var), ACPI_DMAR_## flag, #flag) + +	printf("\tFlags="); +	PRINTFLAG(atsr->Flags, ALL_PORTS); +	PRINTFLAG_END(); + +#undef PRINTFLAG + +	printf("\tSegment=%d\n", atsr->Segment); + +	remaining = atsr->Header.Length - sizeof(ACPI_DMAR_ATSR); +	if (remaining > 0) +		printf("\tDevice Scope:"); +	while (remaining > 0) { +		cp = (char *)atsr + atsr->Header.Length - remaining; +		consumed = acpi_handle_dmar_devscope(cp, remaining); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} +} + +static void +acpi_handle_dmar_rhsa(ACPI_DMAR_RHSA *rhsa) +{ + +	printf("\n"); +	printf("\tType=RHSA\n"); +	printf("\tLength=%d\n", rhsa->Header.Length); +	printf("\tBaseAddress=0x%016jx\n", (uintmax_t)rhsa->BaseAddress); +	printf("\tProximityDomain=0x%08x\n", rhsa->ProximityDomain); +} + +static int +acpi_handle_dmar_remapping_structure(void *addr, int remaining) +{ +	ACPI_DMAR_HEADER *hdr = addr; + +	if (remaining < (int)sizeof(ACPI_DMAR_HEADER)) +		return (-1); + +	if (remaining < hdr->Length) +		return (-1); + +	switch (hdr->Type) { +	case ACPI_DMAR_TYPE_HARDWARE_UNIT: +		acpi_handle_dmar_drhd(addr); +		break; +	case ACPI_DMAR_TYPE_RESERVED_MEMORY: +		acpi_handle_dmar_rmrr(addr); +		break; +	case ACPI_DMAR_TYPE_ROOT_ATS: +		acpi_handle_dmar_atsr(addr); +		break; +	case ACPI_DMAR_TYPE_HARDWARE_AFFINITY: +		acpi_handle_dmar_rhsa(addr); +		break; +	default: +		printf("\n"); +		printf("\tType=%d\n", hdr->Type); +		printf("\tLength=%d\n", hdr->Length); +		break; +	} +	return (hdr->Length); +} + +#ifndef ACPI_DMAR_X2APIC_OPT_OUT +#define	ACPI_DMAR_X2APIC_OPT_OUT	(0x2) +#endif + +static void +acpi_handle_dmar(ACPI_TABLE_HEADER *sdp) +{ +	char *cp; +	int remaining, consumed; +	ACPI_TABLE_DMAR *dmar; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	dmar = (ACPI_TABLE_DMAR *)sdp; +	printf("\tHost Address Width=%d\n", dmar->Width + 1); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_DMAR_## flag, #flag) + +	printf("\tFlags="); +	PRINTFLAG(dmar->Flags, INTR_REMAP); +	PRINTFLAG(dmar->Flags, X2APIC_OPT_OUT); +	PRINTFLAG_END(); + +#undef PRINTFLAG + +	remaining = sdp->Length - sizeof(ACPI_TABLE_DMAR); +	while (remaining > 0) { +		cp = (char *)sdp + sdp->Length - remaining; +		consumed = acpi_handle_dmar_remapping_structure(cp, remaining); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} + +	printf(END_COMMENT); +} + +static void +acpi_handle_ivrs_ivhd_header(ACPI_IVRS_HEADER *addr) +{ +	printf("\n\tIVHD Type=%#x IOMMU DeviceId=%#06x\n\tFlags=", +	    addr->Type, addr->DeviceId); +#define PRINTFLAG(flag, name) printflag(addr->Flags, flag, #name) +	PRINTFLAG(ACPI_IVHD_TT_ENABLE, HtTunEn); +	PRINTFLAG(ACPI_IVHD_ISOC, PassPW); +	PRINTFLAG(ACPI_IVHD_RES_PASS_PW, ResPassPW); +	PRINTFLAG(ACPI_IVHD_ISOC, Isoc); +	PRINTFLAG(ACPI_IVHD_TT_ENABLE, IotlbSup); +	PRINTFLAG((1 << 5), Coherent); +	PRINTFLAG((1 << 6), PreFSup); +	PRINTFLAG((1 << 7), PPRSup); +#undef PRINTFLAG +	PRINTFLAG_END(); +} + +static void +acpi_handle_ivrs_ivhd_dte(UINT8 dte) +{ +	if (dte == 0) { +		printf("\n"); +		return; +	} +	printf(" DTE="); +#define PRINTFLAG(flag, name) printflag(dte, flag, #name) +	PRINTFLAG(ACPI_IVHD_INIT_PASS, INITPass); +	PRINTFLAG(ACPI_IVHD_EINT_PASS, EIntPass); +	PRINTFLAG(ACPI_IVHD_NMI_PASS, NMIPass); +	PRINTFLAG(ACPI_IVHD_SYSTEM_MGMT, SysMgtPass); +	PRINTFLAG(ACPI_IVHD_LINT0_PASS, Lint0Pass); +	PRINTFLAG(ACPI_IVHD_LINT1_PASS, Lint1Pass); +#undef PRINTFLAG +	PRINTFLAG_END(); +} + +static void +acpi_handle_ivrs_ivhd_edte(UINT32 edte) +{ +	if (edte == 0) +		return; +	printf("\t\t ExtDTE="); +#define PRINTFLAG(flag, name) printflag(edte, flag, #name) +	PRINTFLAG(ACPI_IVHD_ATS_DISABLED, AtsDisabled); +#undef PRINTFLAG +	PRINTFLAG_END(); +} + +static const char * +acpi_handle_ivrs_ivhd_variety(UINT8 v) +{ +	switch (v) { +	case ACPI_IVHD_IOAPIC: +		return ("IOAPIC"); +	case ACPI_IVHD_HPET: +		return ("HPET"); +	default: +		return ("UNKNOWN"); +	} +} + +static void +acpi_handle_ivrs_ivhd_devs(ACPI_IVRS_DE_HEADER *d, char *de) +{ +	char *db; +	ACPI_IVRS_DEVICE4 *d4; +	ACPI_IVRS_DEVICE8A *d8a; +	ACPI_IVRS_DEVICE8B *d8b; +	ACPI_IVRS_DEVICE8C *d8c; +	ACPI_IVRS_DEVICE_HID *dh; +	size_t len; +	UINT32 x32; + +	for (; (char *)d < de; d = (ACPI_IVRS_DE_HEADER *)(db + len)) { +		db = (char *)d; +		if (d->Type == ACPI_IVRS_TYPE_PAD4) { +			len = sizeof(*d4); +		} else if (d->Type == ACPI_IVRS_TYPE_ALL) { +			d4 = (ACPI_IVRS_DEVICE4 *)db; +			len = sizeof(*d4); +			printf("\t\tDev Type=%#x Id=ALL", d4->Header.Type); +			acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_SELECT) { +			d4 = (ACPI_IVRS_DEVICE4 *)db; +			len = sizeof(*d4); +			printf("\t\tDev Type=%#x Id=%#06x", d4->Header.Type, +			    d4->Header.Id); +			acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_START) { +			d4 = (ACPI_IVRS_DEVICE4 *)db; +			len = 2 * sizeof(*d4); +			printf("\t\tDev Type=%#x Id=%#06x-%#06x", +			    d4->Header.Type, +			    d4->Header.Id, (d4 + 1)->Header.Id); +			acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_END) { +			d4 = (ACPI_IVRS_DEVICE4 *)db; +			len = 2 * sizeof(*d4); +			printf("\t\tDev Type=%#x Id=%#06x BIOS BUG\n", +			    d4->Header.Type, d4->Header.Id); +		} else if (d->Type == ACPI_IVRS_TYPE_PAD8) { +			len = sizeof(*d8a); +		} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_SELECT) { +			d8a = (ACPI_IVRS_DEVICE8A *)db; +			len = sizeof(*d8a); +			printf("\t\tDev Type=%#x Id=%#06x AliasId=%#06x", +			    d8a->Header.Type, d8a->Header.Id, d8a->UsedId); +			acpi_handle_ivrs_ivhd_dte(d8a->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_START) { +			d8a = (ACPI_IVRS_DEVICE8A *)db; +			d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8a)); +			len = sizeof(*d8a) + sizeof(*d4); +			printf("\t\tDev Type=%#x Id=%#06x-%#06x AliasId=%#06x", +			    d8a->Header.Type, d8a->Header.Id, d4->Header.Id, +			    d8a->UsedId); +			acpi_handle_ivrs_ivhd_dte(d8a->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_EXT_SELECT) { +			d8b = (ACPI_IVRS_DEVICE8B *)db; +			len = sizeof(*d8b); +			printf("\t\tDev Type=%#x Id=%#06x", +			    d8b->Header.Type, d8b->Header.Id); +			acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting); +			printf("\t\t"); +			acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData); +		} else if (d->Type == ACPI_IVRS_TYPE_EXT_START) { +			d8b = (ACPI_IVRS_DEVICE8B *)db; +			len = sizeof(*d8b); +			d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8b)); +			len = sizeof(*d8b) + sizeof(*d4); +			printf("\t\tDev Type=%#x Id=%#06x-%#06x", +			    d8b->Header.Type, d8b->Header.Id, d4->Header.Id); +			acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting); +			acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData); +		} else if (d->Type == ACPI_IVRS_TYPE_SPECIAL) { +			d8c = (ACPI_IVRS_DEVICE8C *)db; +			len = sizeof(*d8c); +			printf("\t\tDev Type=%#x Id=%#06x Handle=%#x " +			    "Variety=%d(%s)", +			    d8c->Header.Type, d8c->UsedId, d8c->Handle, +			    d8c->Variety, +			    acpi_handle_ivrs_ivhd_variety(d8c->Variety)); +			acpi_handle_ivrs_ivhd_dte(d8c->Header.DataSetting); +		} else if (d->Type == ACPI_IVRS_TYPE_HID) { +			dh = (ACPI_IVRS_DEVICE_HID *)db; +			len = sizeof(*dh) + dh->UidLength; +			printf("\t\tDev Type=%#x Id=%#06x HID=", +			    dh->Header.Type, dh->Header.Id); +			acpi_print_string((char *)&dh->AcpiHid, +			    sizeof(dh->AcpiHid)); +			printf(" CID="); +			acpi_print_string((char *)&dh->AcpiCid, +			    sizeof(dh->AcpiCid)); +			printf(" UID="); +			switch (dh->UidType) { +			case ACPI_IVRS_UID_NOT_PRESENT: +			default: +				printf("none"); +				break; +			case ACPI_IVRS_UID_IS_INTEGER: +				memcpy(&x32, dh + 1, sizeof(x32)); +				printf("%#x", x32); +				break; +			case ACPI_IVRS_UID_IS_STRING: +				acpi_print_string((char *)(dh + 1), +				    dh->UidLength); +				break; +			} +			acpi_handle_ivrs_ivhd_dte(dh->Header.DataSetting); +		} else { +			printf("\t\tDev Type=%#x Unknown\n", d->Type); +			if (d->Type <= 63) +				len = sizeof(*d4); +			else if (d->Type <= 127) +				len = sizeof(*d8a); +			else { +				printf("Abort, cannot advance iterator.\n"); +				return; +			} +		} +	} +} + +static void +acpi_handle_ivrs_ivhd_10(ACPI_IVRS_HARDWARE1 *addr, bool efrsup) +{ +	acpi_handle_ivrs_ivhd_header(&addr->Header); +	printf("\tCapOffset=%#x Base=%#jx PCISeg=%#x Unit=%#x MSIlog=%d\n", +	    addr->CapabilityOffset, (uintmax_t)addr->BaseAddress, +	    addr->PciSegmentGroup, (addr->Info & ACPI_IVHD_UNIT_ID_MASK) >> 8, +	    addr->Info & ACPI_IVHD_MSI_NUMBER_MASK); +	if (efrsup) { +#define PRINTFLAG(flag, name) printflag(addr->FeatureReporting, flag, #name) +#define PRINTFIELD(lbit, hbit, name) \ +    printfield(addr->FeatureReporting, lbit, hbit, #name) +		PRINTFIELD(30, 31, HATS); +		PRINTFIELD(28, 29, GATS); +		PRINTFIELD(23, 27, MsiNumPPR); +		PRINTFIELD(17, 22, PNBanks); +		PRINTFIELD(13, 16, PNCounters); +		PRINTFIELD(8, 12, PASmax); +		PRINTFLAG(1 << 7, HESup); +		PRINTFLAG(1 << 6, GASup); +		PRINTFLAG(1 << 5, UASup); +		PRINTFIELD(3, 2, GLXSup); +		PRINTFLAG(1 << 1, NXSup); +		PRINTFLAG(1 << 0, XTSup); +#undef PRINTFLAG +#undef PRINTFIELD +		PRINTFLAG_END(); +	} +	acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1), +	    (char *)addr + addr->Header.Length); +} + +static void +acpi_handle_ivrs_ivhd_info_11(ACPI_IVRS_HARDWARE2 *addr) +{ +	acpi_handle_ivrs_ivhd_header(&addr->Header); +	printf("\tCapOffset=%#x Base=%#jx PCISeg=%#x Unit=%#x MSIlog=%d\n", +	    addr->CapabilityOffset, (uintmax_t)addr->BaseAddress, +	    addr->PciSegmentGroup, (addr->Info >> 8) & 0x1f, +	    addr->Info & 0x5); +	printf("\tAttr="); +#define PRINTFIELD(lbit, hbit, name) \ +    printfield(addr->Attributes, lbit, hbit, #name) +	PRINTFIELD(23, 27, MsiNumPPR); +	PRINTFIELD(17, 22, PNBanks); +	PRINTFIELD(13, 16, PNCounters); +#undef PRINTFIELD +	PRINTFLAG_END(); +} + +static void +acpi_handle_ivrs_ivhd_11(ACPI_IVRS_HARDWARE2 *addr) +{ +	acpi_handle_ivrs_ivhd_info_11(addr); +	printf("\tEFRreg=%#018jx\n", (uintmax_t)addr->EfrRegisterImage); +	acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1), +	    (char *)addr + addr->Header.Length); +} + +static void +acpi_handle_ivrs_ivhd_40(ACPI_IVRS_HARDWARE2 *addr) +{ +	acpi_handle_ivrs_ivhd_info_11(addr); +	printf("\tEFRreg=%#018jx EFR2reg=%#018jx\n", +	    (uintmax_t)addr->EfrRegisterImage, (uintmax_t)addr->Reserved); +	acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1), +	    (char *)addr + addr->Header.Length); +} + +static const char * +acpi_handle_ivrs_ivmd_type(ACPI_IVRS_MEMORY *addr) +{ +	switch (addr->Header.Type) { +	case ACPI_IVRS_TYPE_MEMORY1: +		return ("ALL"); +	case ACPI_IVRS_TYPE_MEMORY2: +		return ("specified"); +	case ACPI_IVRS_TYPE_MEMORY3: +		return ("range"); +	default: +		return ("unknown"); +	} +} + +static void +acpi_handle_ivrs_ivmd(ACPI_IVRS_MEMORY *addr) +{ +	UINT16 x16; + +	printf("\tMem Type=%#x(%s) ", +	    addr->Header.Type, acpi_handle_ivrs_ivmd_type(addr)); +	switch (addr->Header.Type) { +	case ACPI_IVRS_TYPE_MEMORY2: +		memcpy(&x16, &addr->Reserved, sizeof(x16)); +		printf("Id=%#06x PCISeg=%#x ", addr->Header.DeviceId, x16); +		break; +	case ACPI_IVRS_TYPE_MEMORY3: +		memcpy(&x16, &addr->Reserved, sizeof(x16)); +		printf("Id=%#06x-%#06x PCISeg=%#x", addr->Header.DeviceId, +		    addr->AuxData, x16); +		break; +	} +	printf("Start=%#18jx Length=%#jx Flags=", +	    (uintmax_t)addr->StartAddress, (uintmax_t)addr->MemoryLength); +#define PRINTFLAG(flag, name) printflag(addr->Header.Flags, flag, #name) +	PRINTFLAG(ACPI_IVMD_EXCLUSION_RANGE, ExclusionRange); +	PRINTFLAG(ACPI_IVMD_WRITE, IW); +	PRINTFLAG(ACPI_IVMD_READ, IR); +	PRINTFLAG(ACPI_IVMD_UNITY, Unity); +#undef PRINTFLAG +	PRINTFLAG_END(); +} + +static int +acpi_handle_ivrs_blocks(void *addr, int remaining, bool efrsup) +{ +	ACPI_IVRS_HEADER *hdr = addr; + +	if (remaining < (int)sizeof(ACPI_IVRS_HEADER)) +		return (-1); + +	if (remaining < hdr->Length) +		return (-1); + +	switch (hdr->Type) { +	case ACPI_IVRS_TYPE_HARDWARE1: +		acpi_handle_ivrs_ivhd_10(addr, efrsup); +		break; +	case ACPI_IVRS_TYPE_HARDWARE2: +		if (!efrsup) +			printf("\t!! Found IVHD block 0x11 but !EFRsup\n"); +		acpi_handle_ivrs_ivhd_11(addr); +		break; +	case ACPI_IVRS_TYPE_HARDWARE3: +		if (!efrsup) +			printf("\t!! Found IVHD block 0x40 but !EFRsup\n"); +		acpi_handle_ivrs_ivhd_40(addr); +		break; +	case ACPI_IVRS_TYPE_MEMORY1: +	case ACPI_IVRS_TYPE_MEMORY2: +	case ACPI_IVRS_TYPE_MEMORY3: +		acpi_handle_ivrs_ivmd(addr); +		break; +	default: +		printf("\n"); +		printf("\tType=%d\n", hdr->Type); +		printf("\tLength=%d\n", hdr->Length); +		break; +	} +	return (hdr->Length); +} + +#define	ACPI_IVRS_DMAREMAP	0x00000002 +#define	ACPI_IVRS_EFRSUP	0x00000001 +#define	ACPI_IVRS_GVA_SIZE	0x000000e0 + +static void +acpi_handle_ivrs(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_IVRS *ivrs; +	char *cp; +	int remaining, consumed; +	bool efrsup; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	ivrs = (ACPI_TABLE_IVRS *)sdp; +	efrsup = (ivrs->Info & ACPI_IVRS_EFRSUP) != 0; +	printf("\tVAsize=%d PAsize=%d GVAsize=%d\n", +	    (ivrs->Info & ACPI_IVRS_VIRTUAL_SIZE) >> 15, +	    (ivrs->Info & ACPI_IVRS_PHYSICAL_SIZE) >> 8, +	    (ivrs->Info & ACPI_IVRS_GVA_SIZE) >> 5); +	printf("\tATS_resp_res=%d DMA_preboot_remap=%d EFRsup=%d\n", +	    (ivrs->Info & ACPI_IVRS_ATS_RESERVED) != 0, +	    (ivrs->Info & ACPI_IVRS_DMAREMAP) != 0, efrsup); + +	remaining = sdp->Length - sizeof(ACPI_TABLE_IVRS); +	while (remaining > 0) { +		cp = (char *)sdp + sdp->Length - remaining; +		consumed = acpi_handle_ivrs_blocks(cp, remaining, efrsup); +		if (consumed <= 0) +			break; +		else +			remaining -= consumed; +	} + +	printf(END_COMMENT); +} + +static void +acpi_print_srat_memory(ACPI_SRAT_MEM_AFFINITY *mp) +{ + +	printf("\tFlags={"); +	if (mp->Flags & ACPI_SRAT_MEM_ENABLED) +		printf("ENABLED"); +	else +		printf("DISABLED"); +	if (mp->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) +		printf(",HOT_PLUGGABLE"); +	if (mp->Flags & ACPI_SRAT_MEM_NON_VOLATILE) +		printf(",NON_VOLATILE"); +	printf("}\n"); +	printf("\tBase Address=0x%016jx\n", (uintmax_t)mp->BaseAddress); +	printf("\tLength=0x%016jx\n", (uintmax_t)mp->Length); +	printf("\tProximity Domain=%d\n", mp->ProximityDomain); +} + +static const char *srat_types[] = { +    [ACPI_SRAT_TYPE_CPU_AFFINITY] = "CPU", +    [ACPI_SRAT_TYPE_MEMORY_AFFINITY] = "Memory", +    [ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY] = "X2APIC", +    [ACPI_SRAT_TYPE_GICC_AFFINITY] = "GICC", +    [ACPI_SRAT_TYPE_GIC_ITS_AFFINITY] = "GIC ITS", +}; + +static void +acpi_print_srat(ACPI_SUBTABLE_HEADER *srat) +{ +	ACPI_SRAT_CPU_AFFINITY *cpu; +	ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; +	ACPI_SRAT_GICC_AFFINITY *gic; + +	if (srat->Type < nitems(srat_types)) +		printf("\tType=%s\n", srat_types[srat->Type]); +	else +		printf("\tType=%d (unknown)\n", srat->Type); +	switch (srat->Type) { +	case ACPI_SRAT_TYPE_CPU_AFFINITY: +		cpu = (ACPI_SRAT_CPU_AFFINITY *)srat; +		acpi_print_srat_cpu(cpu->ApicId, +		    cpu->ProximityDomainHi[2] << 24 | +		    cpu->ProximityDomainHi[1] << 16 | +		    cpu->ProximityDomainHi[0] << 0 | +		    cpu->ProximityDomainLo, cpu->Flags); +		break; +	case ACPI_SRAT_TYPE_MEMORY_AFFINITY: +		acpi_print_srat_memory((ACPI_SRAT_MEM_AFFINITY *)srat); +		break; +	case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: +		x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)srat; +		acpi_print_srat_cpu(x2apic->ApicId, x2apic->ProximityDomain, +		    x2apic->Flags); +		break; +	case ACPI_SRAT_TYPE_GICC_AFFINITY: +		gic = (ACPI_SRAT_GICC_AFFINITY *)srat; +		acpi_print_srat_cpu(gic->AcpiProcessorUid, gic->ProximityDomain, +		    gic->Flags); +		break; +	} +} + +static void +acpi_handle_srat(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_SRAT *srat; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	srat = (ACPI_TABLE_SRAT *)sdp; +	printf("\tTable Revision=%d\n", srat->TableRevision); +	acpi_walk_subtables(sdp, (srat + 1), acpi_print_srat); +	printf(END_COMMENT); +} + +static const char *nfit_types[] = { +    [ACPI_NFIT_TYPE_SYSTEM_ADDRESS] = "System Address", +    [ACPI_NFIT_TYPE_MEMORY_MAP] = "Memory Map", +    [ACPI_NFIT_TYPE_INTERLEAVE] = "Interleave", +    [ACPI_NFIT_TYPE_SMBIOS] = "SMBIOS", +    [ACPI_NFIT_TYPE_CONTROL_REGION] = "Control Region", +    [ACPI_NFIT_TYPE_DATA_REGION] = "Data Region", +    [ACPI_NFIT_TYPE_FLUSH_ADDRESS] = "Flush Address", +    [ACPI_NFIT_TYPE_CAPABILITIES] = "Platform Capabilities" +}; + + +static void +acpi_print_nfit(ACPI_NFIT_HEADER *nfit) +{ +	char *uuidstr; +	uint32_t m, status; + +	ACPI_NFIT_SYSTEM_ADDRESS *sysaddr; +	ACPI_NFIT_MEMORY_MAP *mmap; +	ACPI_NFIT_INTERLEAVE *ileave; +	ACPI_NFIT_CONTROL_REGION *ctlreg; +	ACPI_NFIT_DATA_REGION *datareg; +	ACPI_NFIT_FLUSH_ADDRESS *fladdr; +	ACPI_NFIT_CAPABILITIES *caps; + +	if (nfit->Type < nitems(nfit_types)) +		printf("\tType=%s\n", nfit_types[nfit->Type]); +	else +		printf("\tType=%u (unknown)\n", nfit->Type); +	switch (nfit->Type) { +	case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: +		sysaddr = (ACPI_NFIT_SYSTEM_ADDRESS *)nfit; +		printf("\tRangeIndex=%u\n", (u_int)sysaddr->RangeIndex); +		printf("\tProximityDomain=%u\n", +		    (u_int)sysaddr->ProximityDomain); +		uuid_to_string((uuid_t *)(uintptr_t)(sysaddr->RangeGuid), +		    &uuidstr, &status); +		if (status != uuid_s_ok) +			errx(1, "uuid_to_string: status=%u", status); +		printf("\tRangeGuid=%s\n", uuidstr); +		free(uuidstr); +		printf("\tAddress=0x%016jx\n", (uintmax_t)sysaddr->Address); +		printf("\tLength=0x%016jx\n", (uintmax_t)sysaddr->Length); +		printf("\tMemoryMapping=0x%016jx\n", +		    (uintmax_t)sysaddr->MemoryMapping); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_NFIT_## flag, #flag) + +		printf("\tFlags="); +		PRINTFLAG(sysaddr->Flags, ADD_ONLINE_ONLY); +		PRINTFLAG(sysaddr->Flags, PROXIMITY_VALID); +		PRINTFLAG_END(); + +#undef PRINTFLAG + +		break; +	case ACPI_NFIT_TYPE_MEMORY_MAP: +		mmap = (ACPI_NFIT_MEMORY_MAP *)nfit; +		printf("\tDeviceHandle=0x%x\n", (u_int)mmap->DeviceHandle); +		printf("\tPhysicalId=0x%04x\n", (u_int)mmap->PhysicalId); +		printf("\tRegionId=%u\n", (u_int)mmap->RegionId); +		printf("\tRangeIndex=%u\n", (u_int)mmap->RangeIndex); +		printf("\tRegionIndex=%u\n", (u_int)mmap->RegionIndex); +		printf("\tRegionSize=0x%016jx\n", (uintmax_t)mmap->RegionSize); +		printf("\tRegionOffset=0x%016jx\n", +		    (uintmax_t)mmap->RegionOffset); +		printf("\tAddress=0x%016jx\n", (uintmax_t)mmap->Address); +		printf("\tInterleaveIndex=%u\n", (u_int)mmap->InterleaveIndex); +		printf("\tInterleaveWays=%u\n", (u_int)mmap->InterleaveWays); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_NFIT_MEM_## flag, #flag) + +		printf("\tFlags="); +		PRINTFLAG(mmap->Flags, SAVE_FAILED); +		PRINTFLAG(mmap->Flags, RESTORE_FAILED); +		PRINTFLAG(mmap->Flags, FLUSH_FAILED); +		PRINTFLAG(mmap->Flags, NOT_ARMED); +		PRINTFLAG(mmap->Flags, HEALTH_OBSERVED); +		PRINTFLAG(mmap->Flags, HEALTH_ENABLED); +		PRINTFLAG(mmap->Flags, MAP_FAILED); +		PRINTFLAG_END(); + +#undef PRINTFLAG + +		break; +	case ACPI_NFIT_TYPE_INTERLEAVE: +		ileave = (ACPI_NFIT_INTERLEAVE *)nfit; +		printf("\tInterleaveIndex=%u\n", +		    (u_int)ileave->InterleaveIndex); +		printf("\tLineCount=%u\n", (u_int)ileave->LineCount); +		printf("\tLineSize=%u\n", (u_int)ileave->LineSize); +		for (m = 0; m < ileave->LineCount; m++) { +			printf("\tLine%uOffset=0x%08x\n", (u_int)m + 1, +			    (u_int)ileave->LineOffset[m]); +		} +		break; +	case ACPI_NFIT_TYPE_SMBIOS: +		/* XXX smbios->Data[x] output is not supported */ +		break; +	case ACPI_NFIT_TYPE_CONTROL_REGION: +		ctlreg = (ACPI_NFIT_CONTROL_REGION *)nfit; +		printf("\tRegionIndex=%u\n", (u_int)ctlreg->RegionIndex); +		printf("\tVendorId=0x%04x\n", (u_int)ctlreg->VendorId); +		printf("\tDeviceId=0x%04x\n", (u_int)ctlreg->DeviceId); +		printf("\tRevisionId=0x%02x\n", (u_int)ctlreg->RevisionId); +		printf("\tSubsystemVendorId=0x%04x\n", +		    (u_int)ctlreg->SubsystemVendorId); +		printf("\tSubsystemDeviceId=0x%04x\n", +		    (u_int)ctlreg->SubsystemDeviceId); +		printf("\tSubsystemRevisionId=0x%02x\n", +		    (u_int)ctlreg->SubsystemRevisionId); +		printf("\tValidFields=0x%02x\n", (u_int)ctlreg->ValidFields); +		printf("\tManufacturingLocation=0x%02x\n", +		    (u_int)ctlreg->ManufacturingLocation); +		printf("\tManufacturingDate=%04x\n", +		    (u_int)be16toh(ctlreg->ManufacturingDate)); +		printf("\tSerialNumber=%08X\n", +		    (u_int)be32toh(ctlreg->SerialNumber)); +		printf("\tCode=0x%04x\n", (u_int)ctlreg->Code); +		printf("\tWindows=%u\n", (u_int)ctlreg->Windows); +		printf("\tWindowSize=0x%016jx\n", +		    (uintmax_t)ctlreg->WindowSize); +		printf("\tCommandOffset=0x%016jx\n", +		    (uintmax_t)ctlreg->CommandOffset); +		printf("\tCommandSize=0x%016jx\n", +		    (uintmax_t)ctlreg->CommandSize); +		printf("\tStatusOffset=0x%016jx\n", +		    (uintmax_t)ctlreg->StatusOffset); +		printf("\tStatusSize=0x%016jx\n", +		    (uintmax_t)ctlreg->StatusSize); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_NFIT_## flag, #flag) + +		printf("\tFlags="); +		PRINTFLAG(ctlreg->Flags, CONTROL_BUFFERED); +		PRINTFLAG_END(); + +#undef PRINTFLAG + +		break; +	case ACPI_NFIT_TYPE_DATA_REGION: +		datareg = (ACPI_NFIT_DATA_REGION *)nfit; +		printf("\tRegionIndex=%u\n", (u_int)datareg->RegionIndex); +		printf("\tWindows=%u\n", (u_int)datareg->Windows); +		printf("\tOffset=0x%016jx\n", (uintmax_t)datareg->Offset); +		printf("\tSize=0x%016jx\n", (uintmax_t)datareg->Size); +		printf("\tCapacity=0x%016jx\n", (uintmax_t)datareg->Capacity); +		printf("\tStartAddress=0x%016jx\n", +		    (uintmax_t)datareg->StartAddress); +		break; +	case ACPI_NFIT_TYPE_FLUSH_ADDRESS: +		fladdr = (ACPI_NFIT_FLUSH_ADDRESS *)nfit; +		printf("\tDeviceHandle=%u\n", (u_int)fladdr->DeviceHandle); +		printf("\tHintCount=%u\n", (u_int)fladdr->HintCount); +		for (m = 0; m < fladdr->HintCount; m++) { +			printf("\tHintAddress%u=0x%016jx\n", (u_int)m + 1, +			    (uintmax_t)fladdr->HintAddress[m]); +		} +		break; +	case ACPI_NFIT_TYPE_CAPABILITIES: +		caps = (ACPI_NFIT_CAPABILITIES *)nfit; +		printf("\tHighestCapability=%u\n", (u_int)caps->HighestCapability); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_NFIT_CAPABILITY_## flag, #flag) + +		printf("\tCapabilities="); +		PRINTFLAG(caps->Capabilities, CACHE_FLUSH); +		PRINTFLAG(caps->Capabilities, MEM_FLUSH); +		PRINTFLAG(caps->Capabilities, MEM_MIRRORING); +		PRINTFLAG_END(); + +#undef PRINTFLAG +		break; +	} +} + +static void +acpi_handle_nfit(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_NFIT *nfit; + +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	nfit = (ACPI_TABLE_NFIT *)sdp; +	acpi_walk_nfit(sdp, (nfit + 1), acpi_print_nfit); +	printf(END_COMMENT); +} + +static void +acpi_print_sdt(ACPI_TABLE_HEADER *sdp) +{ +	printf("  "); +	acpi_print_string(sdp->Signature, ACPI_NAMESEG_SIZE); +	printf(": Length=%d, Revision=%d, Checksum=%d,\n", +	       sdp->Length, sdp->Revision, sdp->Checksum); +	printf("\tOEMID="); +	acpi_print_string(sdp->OemId, ACPI_OEM_ID_SIZE); +	printf(", OEM Table ID="); +	acpi_print_string(sdp->OemTableId, ACPI_OEM_TABLE_ID_SIZE); +	printf(", OEM Revision=0x%x,\n", sdp->OemRevision); +	printf("\tCreator ID="); +	acpi_print_string(sdp->AslCompilerId, ACPI_NAMESEG_SIZE); +	printf(", Creator Revision=0x%x\n", sdp->AslCompilerRevision); +} + +static void +acpi_print_rsdt(ACPI_TABLE_HEADER *rsdp) +{ +	ACPI_TABLE_RSDT *rsdt; +	ACPI_TABLE_XSDT *xsdt; +	int	i, entries; + +	rsdt = (ACPI_TABLE_RSDT *)rsdp; +	xsdt = (ACPI_TABLE_XSDT *)rsdp; +	printf(BEGIN_COMMENT); +	acpi_print_sdt(rsdp); +	entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; +	printf("\tEntries={ "); +	for (i = 0; i < entries; i++) { +		if (i > 0) +			printf(", "); +		if (addr_size == 4) +			printf("0x%08x", le32toh(rsdt->TableOffsetEntry[i])); +		else +			printf("0x%016jx", +			    (uintmax_t)le64toh(xsdt->TableOffsetEntry[i])); +	} +	printf(" }\n"); +	printf(END_COMMENT); +} + +static const char *acpi_pm_profiles[] = { +	"Unspecified", "Desktop", "Mobile", "Workstation", +	"Enterprise Server", "SOHO Server", "Appliance PC" +}; + +static void +acpi_print_fadt(ACPI_TABLE_HEADER *sdp) +{ +	ACPI_TABLE_FADT *fadt; +	const char *pm; + +	fadt = (ACPI_TABLE_FADT *)sdp; +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->Facs, +	       fadt->Dsdt); +	printf("\tINT_MODEL=%s\n", fadt->Model ? "APIC" : "PIC"); +	if (fadt->PreferredProfile >= sizeof(acpi_pm_profiles) / sizeof(char *)) +		pm = "Reserved"; +	else +		pm = acpi_pm_profiles[fadt->PreferredProfile]; +	printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->PreferredProfile); +	printf("\tSCI_INT=%d\n", fadt->SciInterrupt); +	printf("\tSMI_CMD=0x%x, ", fadt->SmiCommand); +	printf("ACPI_ENABLE=0x%x, ", fadt->AcpiEnable); +	printf("ACPI_DISABLE=0x%x, ", fadt->AcpiDisable); +	printf("S4BIOS_REQ=0x%x\n", fadt->S4BiosRequest); +	printf("\tPSTATE_CNT=0x%x\n", fadt->PstateControl); +	printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", +	       fadt->Pm1aEventBlock, +	       fadt->Pm1aEventBlock + fadt->Pm1EventLength - 1); +	if (fadt->Pm1bEventBlock != 0) +		printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", +		       fadt->Pm1bEventBlock, +		       fadt->Pm1bEventBlock + fadt->Pm1EventLength - 1); +	printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", +	       fadt->Pm1aControlBlock, +	       fadt->Pm1aControlBlock + fadt->Pm1ControlLength - 1); +	if (fadt->Pm1bControlBlock != 0) +		printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", +		       fadt->Pm1bControlBlock, +		       fadt->Pm1bControlBlock + fadt->Pm1ControlLength - 1); +	if (fadt->Pm2ControlBlock != 0) +		printf("\tPM2_CNT_BLK=0x%x-0x%x\n", +		       fadt->Pm2ControlBlock, +		       fadt->Pm2ControlBlock + fadt->Pm2ControlLength - 1); +	printf("\tPM_TMR_BLK=0x%x-0x%x\n", +	       fadt->PmTimerBlock, +	       fadt->PmTimerBlock + fadt->PmTimerLength - 1); +	if (fadt->Gpe0Block != 0) +		printf("\tGPE0_BLK=0x%x-0x%x\n", +		       fadt->Gpe0Block, +		       fadt->Gpe0Block + fadt->Gpe0BlockLength - 1); +	if (fadt->Gpe1Block != 0) +		printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", +		       fadt->Gpe1Block, +		       fadt->Gpe1Block + fadt->Gpe1BlockLength - 1, +		       fadt->Gpe1Base); +	if (fadt->CstControl != 0) +		printf("\tCST_CNT=0x%x\n", fadt->CstControl); +	printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n", +	       fadt->C2Latency, fadt->C3Latency); +	printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", +	       fadt->FlushSize, fadt->FlushStride); +	printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", +	       fadt->DutyOffset, fadt->DutyWidth); +	printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", +	       fadt->DayAlarm, fadt->MonthAlarm, fadt->Century); + +#define PRINTFLAG(var, flag)	printflag((var), ACPI_FADT_## flag, #flag) + +	printf("\tIAPC_BOOT_ARCH="); +	PRINTFLAG(fadt->BootFlags, LEGACY_DEVICES); +	PRINTFLAG(fadt->BootFlags, 8042); +	PRINTFLAG(fadt->BootFlags, NO_VGA); +	PRINTFLAG(fadt->BootFlags, NO_MSI); +	PRINTFLAG(fadt->BootFlags, NO_ASPM); +	PRINTFLAG(fadt->BootFlags, NO_CMOS_RTC); +	PRINTFLAG_END(); + +	printf("\tFlags="); +	PRINTFLAG(fadt->Flags, WBINVD); +	PRINTFLAG(fadt->Flags, WBINVD_FLUSH); +	PRINTFLAG(fadt->Flags, C1_SUPPORTED); +	PRINTFLAG(fadt->Flags, C2_MP_SUPPORTED); +	PRINTFLAG(fadt->Flags, POWER_BUTTON); +	PRINTFLAG(fadt->Flags, SLEEP_BUTTON); +	PRINTFLAG(fadt->Flags, FIXED_RTC); +	PRINTFLAG(fadt->Flags, S4_RTC_WAKE); +	PRINTFLAG(fadt->Flags, 32BIT_TIMER); +	PRINTFLAG(fadt->Flags, DOCKING_SUPPORTED); +	PRINTFLAG(fadt->Flags, RESET_REGISTER); +	PRINTFLAG(fadt->Flags, SEALED_CASE); +	PRINTFLAG(fadt->Flags, HEADLESS); +	PRINTFLAG(fadt->Flags, SLEEP_TYPE); +	PRINTFLAG(fadt->Flags, PCI_EXPRESS_WAKE); +	PRINTFLAG(fadt->Flags, PLATFORM_CLOCK); +	PRINTFLAG(fadt->Flags, S4_RTC_VALID); +	PRINTFLAG(fadt->Flags, REMOTE_POWER_ON); +	PRINTFLAG(fadt->Flags, APIC_CLUSTER); +	PRINTFLAG(fadt->Flags, APIC_PHYSICAL); +	PRINTFLAG(fadt->Flags, HW_REDUCED); +	PRINTFLAG(fadt->Flags, LOW_POWER_S0); +	PRINTFLAG_END(); + +#undef PRINTFLAG + +	if (fadt->Flags & ACPI_FADT_RESET_REGISTER) { +		printf("\tRESET_REG="); +		acpi_print_gas(&fadt->ResetRegister); +		printf(", RESET_VALUE=%#x\n", fadt->ResetValue); +	} +	if (acpi_get_fadt_revision(fadt) > 1) { +		printf("\tX_FACS=0x%016jx, ", (uintmax_t)fadt->XFacs); +		printf("X_DSDT=0x%016jx\n", (uintmax_t)fadt->XDsdt); +		printf("\tX_PM1a_EVT_BLK="); +		acpi_print_gas(&fadt->XPm1aEventBlock); +		if (fadt->XPm1bEventBlock.Address != 0) { +			printf("\n\tX_PM1b_EVT_BLK="); +			acpi_print_gas(&fadt->XPm1bEventBlock); +		} +		printf("\n\tX_PM1a_CNT_BLK="); +		acpi_print_gas(&fadt->XPm1aControlBlock); +		if (fadt->XPm1bControlBlock.Address != 0) { +			printf("\n\tX_PM1b_CNT_BLK="); +			acpi_print_gas(&fadt->XPm1bControlBlock); +		} +		if (fadt->XPm2ControlBlock.Address != 0) { +			printf("\n\tX_PM2_CNT_BLK="); +			acpi_print_gas(&fadt->XPm2ControlBlock); +		} +		printf("\n\tX_PM_TMR_BLK="); +		acpi_print_gas(&fadt->XPmTimerBlock); +		if (fadt->XGpe0Block.Address != 0) { +			printf("\n\tX_GPE0_BLK="); +			acpi_print_gas(&fadt->XGpe0Block); +		} +		if (fadt->XGpe1Block.Address != 0) { +			printf("\n\tX_GPE1_BLK="); +			acpi_print_gas(&fadt->XGpe1Block); +		} +		printf("\n"); +	} + +	printf(END_COMMENT); +} + +static void +acpi_print_facs(ACPI_TABLE_FACS *facs) +{ +	printf(BEGIN_COMMENT); +	printf("  FACS:\tLength=%u, ", facs->Length); +	printf("HwSig=0x%08x, ", facs->HardwareSignature); +	printf("Firm_Wake_Vec=0x%08x\n", facs->FirmwareWakingVector); + +	printf("\tGlobal_Lock="); +	if (facs->GlobalLock != 0) { +		if (facs->GlobalLock & ACPI_GLOCK_PENDING) +			printf("PENDING,"); +		if (facs->GlobalLock & ACPI_GLOCK_OWNED) +			printf("OWNED"); +	} +	printf("\n"); + +	printf("\tFlags="); +	if (facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) +		printf("S4BIOS"); +	printf("\n"); + +	if (facs->XFirmwareWakingVector != 0) +		printf("\tX_Firm_Wake_Vec=%016jx\n", +		    (uintmax_t)facs->XFirmwareWakingVector); +	printf("\tVersion=%u\n", facs->Version); + +	printf(END_COMMENT); +} + +static void +acpi_print_dsdt(ACPI_TABLE_HEADER *dsdp) +{ +	printf(BEGIN_COMMENT); +	acpi_print_sdt(dsdp); +	printf(END_COMMENT); +} + +int +acpi_checksum(void *p, size_t length) +{ +	uint8_t *bp; +	uint8_t sum; + +	bp = p; +	sum = 0; +	while (length--) +		sum += *bp++; + +	return (sum); +} + +static ACPI_TABLE_HEADER * +acpi_map_sdt(vm_offset_t pa) +{ +	ACPI_TABLE_HEADER *sp; + +	sp = acpi_map_physical(pa, sizeof(ACPI_TABLE_HEADER)); +	sp = acpi_map_physical(pa, sp->Length); +	return (sp); +} + +static void +acpi_print_rsd_ptr(ACPI_TABLE_RSDP *rp) +{ +	printf(BEGIN_COMMENT); +	printf("  RSD PTR: OEM="); +	acpi_print_string(rp->OemId, ACPI_OEM_ID_SIZE); +	printf(", ACPI_Rev=%s (%d)\n", rp->Revision < 2 ? "1.0x" : "2.0x", +	       rp->Revision); +	if (rp->Revision < 2) { +		printf("\tRSDT=0x%08x, cksum=%u\n", rp->RsdtPhysicalAddress, +		    rp->Checksum); +	} else { +		printf("\tXSDT=0x%016jx, length=%u, cksum=%u\n", +		    (uintmax_t)rp->XsdtPhysicalAddress, rp->Length, +		    rp->ExtendedChecksum); +	} +	printf(END_COMMENT); +} + +static const struct { +	const char *sig; +	void (*fnp)(ACPI_TABLE_HEADER *); +} known[] = { +	{ ACPI_SIG_BERT, 	acpi_handle_bert }, +	{ ACPI_SIG_DMAR,	acpi_handle_dmar }, +	{ ACPI_SIG_ECDT,	acpi_handle_ecdt }, +	{ ACPI_SIG_EINJ,	acpi_handle_einj }, +	{ ACPI_SIG_ERST,	acpi_handle_erst }, +	{ ACPI_SIG_FADT,	acpi_handle_fadt }, +	{ ACPI_SIG_HEST,	acpi_handle_hest }, +	{ ACPI_SIG_HPET,	acpi_handle_hpet }, +	{ ACPI_SIG_IVRS,	acpi_handle_ivrs }, +	{ ACPI_SIG_LPIT,	acpi_handle_lpit }, +	{ ACPI_SIG_MADT,	acpi_handle_madt }, +	{ ACPI_SIG_MCFG,	acpi_handle_mcfg }, +	{ ACPI_SIG_NFIT,	acpi_handle_nfit }, +	{ ACPI_SIG_SLIT,	acpi_handle_slit }, +	{ ACPI_SIG_SPCR,	acpi_handle_spcr }, +	{ ACPI_SIG_SRAT,	acpi_handle_srat }, +	{ ACPI_SIG_TCPA,	acpi_handle_tcpa }, +	{ ACPI_SIG_TPM2,	acpi_handle_tpm2 }, +	{ ACPI_SIG_WDDT,	acpi_handle_wddt }, +}; + +static void +acpi_report_sdp(ACPI_TABLE_HEADER *sdp) +{ +	for (u_int i = 0; i < nitems(known); i++) { +		if (memcmp(sdp->Signature, known[i].sig, ACPI_NAMESEG_SIZE) +		    == 0) { +			known[i].fnp(sdp); +			return; +		} +	} + +	/* +	 * Otherwise, do a generic thing. +	 */ +	printf(BEGIN_COMMENT); +	acpi_print_sdt(sdp); +	printf(END_COMMENT); +} + +static void +acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp, const char *tbl) +{ +	ACPI_TABLE_HEADER *sdp; +	ACPI_TABLE_RSDT *rsdt; +	ACPI_TABLE_XSDT *xsdt; +	vm_offset_t addr; +	int entries, i; + +	if (tbl == NULL) { +		acpi_print_rsdt(rsdp); +	} else { +		if (memcmp(tbl, rsdp->Signature, ACPI_NAMESEG_SIZE) == 0) { +			acpi_print_rsdt(rsdp); +			return; +		} +	} +	rsdt = (ACPI_TABLE_RSDT *)rsdp; +	xsdt = (ACPI_TABLE_XSDT *)rsdp; +	entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; +	for (i = 0; i < entries; i++) { +		if (addr_size == 4) +			addr = le32toh(rsdt->TableOffsetEntry[i]); +		else +			addr = le64toh(xsdt->TableOffsetEntry[i]); +		if (addr == 0) +			continue; +		sdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr); +		if (acpi_checksum(sdp, sdp->Length)) { +			warnx("RSDT entry %d (sig %.4s) is corrupt", i, +			    sdp->Signature); +			continue; +		} +		if (tbl != NULL && memcmp(sdp->Signature, tbl, ACPI_NAMESEG_SIZE) != 0) +			continue; +		acpi_report_sdp(sdp); +	} +} + +ACPI_TABLE_HEADER * +sdt_load_devmem(void) +{ +	ACPI_TABLE_RSDP *rp; +	ACPI_TABLE_HEADER *rsdp; + +	rp = acpi_find_rsd_ptr(); +	if (!rp) +		errx(1, "Can't find ACPI information"); + +	if (tflag) +		acpi_print_rsd_ptr(rp); +	if (rp->Revision < 2) { +		rsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(rp->RsdtPhysicalAddress); +		if (memcmp(rsdp->Signature, "RSDT", ACPI_NAMESEG_SIZE) != 0 || +		    acpi_checksum(rsdp, rsdp->Length) != 0) +			errx(1, "RSDT is corrupted"); +		addr_size = sizeof(uint32_t); +	} else { +		rsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(rp->XsdtPhysicalAddress); +		if (memcmp(rsdp->Signature, "XSDT", ACPI_NAMESEG_SIZE) != 0 || +		    acpi_checksum(rsdp, rsdp->Length) != 0) +			errx(1, "XSDT is corrupted"); +		addr_size = sizeof(uint64_t); +	} +	return (rsdp); +} + +/* Write the DSDT to a file, concatenating any SSDTs (if present). */ +static int +write_dsdt(int fd, ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdt) +{ +	ACPI_TABLE_HEADER sdt; +	ACPI_TABLE_HEADER *ssdt; +	uint8_t sum; + +	/* Create a new checksum to account for the DSDT and any SSDTs. */ +	sdt = *dsdt; +	if (rsdt != NULL) { +		sdt.Checksum = 0; +		sum = acpi_checksum(dsdt + 1, dsdt->Length - +		    sizeof(ACPI_TABLE_HEADER)); +		ssdt = sdt_from_rsdt(rsdt, ACPI_SIG_SSDT, NULL); +		while (ssdt != NULL) { +			sdt.Length += ssdt->Length - sizeof(ACPI_TABLE_HEADER); +			sum += acpi_checksum(ssdt + 1, +			    ssdt->Length - sizeof(ACPI_TABLE_HEADER)); +			ssdt = sdt_from_rsdt(rsdt, ACPI_SIG_SSDT, ssdt); +		} +		sum += acpi_checksum(&sdt, sizeof(ACPI_TABLE_HEADER)); +		sdt.Checksum -= sum; +	} + +	/* Write out the DSDT header and body. */ +	write(fd, &sdt, sizeof(ACPI_TABLE_HEADER)); +	write(fd, dsdt + 1, dsdt->Length - sizeof(ACPI_TABLE_HEADER)); + +	/* Write out any SSDTs (if present.) */ +	if (rsdt != NULL) { +		ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL); +		while (ssdt != NULL) { +			write(fd, ssdt + 1, ssdt->Length - +			    sizeof(ACPI_TABLE_HEADER)); +			ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt); +		} +	} +	return (0); +} + +void +dsdt_save_file(char *outfile, ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdp) +{ +	int	fd; +	mode_t	mode; + +	assert(outfile != NULL); +	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; +	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode); +	if (fd == -1) { +		perror("dsdt_save_file"); +		return; +	} +	write_dsdt(fd, rsdt, dsdp); +	close(fd); +} + +void +aml_disassemble(ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdp) +{ +	char buf[PATH_MAX], tmpstr[PATH_MAX], wrkdir[PATH_MAX]; +	const char *iname = "/acpdump.din"; +	const char *oname = "/acpdump.dsl"; +	const char *tmpdir; +	FILE *fp; +	size_t len; +	int fd, status; +	pid_t pid; + +	tmpdir = getenv("TMPDIR"); +	if (tmpdir == NULL) +		tmpdir = _PATH_TMP; +	if (realpath(tmpdir, buf) == NULL) { +		perror("realpath tmp dir"); +		return; +	} +	len = sizeof(wrkdir) - strlen(iname); +	if ((size_t)snprintf(wrkdir, len, "%s/acpidump.XXXXXX", buf) > len-1 ) { +		fprintf(stderr, "$TMPDIR too long\n"); +		return; +	} +	if  (mkdtemp(wrkdir) == NULL) { +		perror("mkdtemp tmp working dir"); +		return; +	} +	len = (size_t)snprintf(tmpstr, sizeof(tmpstr), "%s%s", wrkdir, iname); +	assert(len <= sizeof(tmpstr) - 1); +	fd = open(tmpstr, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); +	if (fd < 0) { +		perror("iasl tmp file"); +		return; +	} +	write_dsdt(fd, rsdt, dsdp); +	close(fd); + +	/* Run iasl -d on the temp file */ +	if ((pid = fork()) == 0) { +		close(STDOUT_FILENO); +		if (vflag == 0) +			close(STDERR_FILENO); +		execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, NULL); +		err(1, "exec"); +	} +	if (pid > 0) +		wait(&status); +	if (unlink(tmpstr) < 0) { +		perror("unlink"); +		goto out; +	} +	if (pid < 0) { +		perror("fork"); +		goto out; +	} +	if (status != 0) { +		fprintf(stderr, "iasl exit status = %d\n", status); +	} + +	/* Dump iasl's output to stdout */ +	len = (size_t)snprintf(tmpstr, sizeof(tmpstr), "%s%s", wrkdir, oname); +	assert(len <= sizeof(tmpstr) - 1); +	fp = fopen(tmpstr, "r"); +	if (unlink(tmpstr) < 0) { +		perror("unlink"); +		goto out; +	} +	if (fp == NULL) { +		perror("iasl tmp file (read)"); +		goto out; +	} +	while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) +		fwrite(buf, 1, len, stdout); +	fclose(fp); + +    out: +	if (rmdir(wrkdir) < 0) +		perror("rmdir"); +} + +void +aml_disassemble_separate(ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdp) +{ +	ACPI_TABLE_HEADER *ssdt = NULL; + +	aml_disassemble(NULL, dsdp); +	if (rsdt != NULL) { +		for (;;) { +			ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt); +			if (ssdt == NULL) +				break; +			aml_disassemble(NULL, ssdt); +		} +	} +} + +void +sdt_print_all(ACPI_TABLE_HEADER *rsdp, const char *tbl) +{ +	acpi_handle_rsdt(rsdp, tbl); +} + +/* Fetch a table matching the given signature via the RSDT. */ +ACPI_TABLE_HEADER * +sdt_from_rsdt(ACPI_TABLE_HEADER *rsdp, const char *sig, ACPI_TABLE_HEADER *last) +{ +	ACPI_TABLE_HEADER *sdt; +	ACPI_TABLE_RSDT *rsdt; +	ACPI_TABLE_XSDT *xsdt; +	vm_offset_t addr; +	int entries, i; + +	rsdt = (ACPI_TABLE_RSDT *)rsdp; +	xsdt = (ACPI_TABLE_XSDT *)rsdp; +	entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; +	for (i = 0; i < entries; i++) { +		if (addr_size == 4) +			addr = le32toh(rsdt->TableOffsetEntry[i]); +		else +			addr = le64toh(xsdt->TableOffsetEntry[i]); +		if (addr == 0) +			continue; +		sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr); +		if (last != NULL) { +			if (sdt == last) +				last = NULL; +			continue; +		} +		if (memcmp(sdt->Signature, sig, strlen(sig))) +			continue; +		if (acpi_checksum(sdt, sdt->Length)) +			errx(1, "RSDT entry %d is corrupt", i); +		return (sdt); +	} + +	return (NULL); +} + +ACPI_TABLE_HEADER * +dsdt_from_fadt(ACPI_TABLE_FADT *fadt) +{ +	ACPI_TABLE_HEADER	*sdt; + +	/* Use the DSDT address if it is version 1, otherwise use XDSDT. */ +	if (acpi_get_fadt_revision(fadt) == 1) +		sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->Dsdt); +	else +		sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->XDsdt); +	if (acpi_checksum(sdt, sdt->Length)) +		errx(1, "DSDT is corrupt\n"); +	return (sdt); +} diff --git a/usr.sbin/acpi/acpidump/acpi_user.c b/usr.sbin/acpi/acpidump/acpi_user.c new file mode 100644 index 000000000000..daa4118089cf --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpi_user.c @@ -0,0 +1,222 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/param.h> +#include <sys/mman.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#include <err.h> +#include <fcntl.h> +#include <kenv.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "acpidump.h" + +static char	acpi_rsdp[] = "acpi.rsdp"; +static char	machdep_acpi_root[] = "machdep.acpi_root"; +static int      acpi_mem_fd = -1; + +struct acpi_user_mapping { +	LIST_ENTRY(acpi_user_mapping) link; +	vm_offset_t     pa; +	caddr_t         va; +	size_t          size; +}; + +static LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist; + +static void +acpi_user_init(void) +{ + +	if (acpi_mem_fd == -1) { +		acpi_mem_fd = open("/dev/mem", O_RDONLY); +		if (acpi_mem_fd == -1) +			err(1, "opening /dev/mem"); +		LIST_INIT(&maplist); +	} +} + +static struct acpi_user_mapping * +acpi_user_find_mapping(vm_offset_t pa, size_t size) +{ +	struct	acpi_user_mapping *map; + +	/* First search for an existing mapping */ +	for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) { +		if (map->pa <= pa && map->size >= pa + size - map->pa) +			return (map); +	} + +	/* Then create a new one */ +	size = round_page(pa + size) - trunc_page(pa); +	pa = trunc_page(pa); +	map = malloc(sizeof(struct acpi_user_mapping)); +	if (!map) +		errx(1, "out of memory"); +	map->pa = pa; +	map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); +	map->size = size; +	if ((intptr_t) map->va == -1) +		err(1, "can't map address"); +	LIST_INSERT_HEAD(&maplist, map, link); + +	return (map); +} + +static ACPI_TABLE_RSDP * +acpi_get_rsdp(u_long addr) +{ +	ACPI_TABLE_RSDP rsdp; +	size_t len; + +	/* Read in the table signature and check it. */ +	pread(acpi_mem_fd, &rsdp, 8, addr); +	if (memcmp(rsdp.Signature, "RSD PTR ", 8)) +		return (NULL); + +	/* Read the entire table. */ +	pread(acpi_mem_fd, &rsdp, sizeof(rsdp), addr); + +	/* Check the standard checksum. */ +	if (acpi_checksum(&rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) +		return (NULL); + +	/* Check extended checksum if table version >= 2. */ +	if (rsdp.Revision >= 2 && +	    acpi_checksum(&rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) +		return (NULL); + +	/* If the revision is 0, assume a version 1 length. */ +	if (rsdp.Revision == 0) +		len = sizeof(ACPI_RSDP_COMMON); +	else +		len = rsdp.Length; + +	return (acpi_map_physical(addr, len)); +} + +static ACPI_TABLE_RSDP * +acpi_scan_rsd_ptr(void) +{ +#if defined(__amd64__) || defined(__i386__) +	ACPI_TABLE_RSDP *rsdp; +	u_long		addr, end; + +	/* +	 * On ia32, scan physical memory for the RSD PTR if above failed. +	 * According to section 5.2.2 of the ACPI spec, we only consider +	 * two regions for the base address: +	 * 1. EBDA (1 KB area addressed by the 16 bit pointer at 0x40E +	 * 2. High memory (0xE0000 - 0xFFFFF) +	 */ +	addr = ACPI_EBDA_PTR_LOCATION; +	pread(acpi_mem_fd, &addr, sizeof(uint16_t), addr); +	addr <<= 4; +	end = addr + ACPI_EBDA_WINDOW_SIZE; +	for (; addr < end; addr += 16) +		if ((rsdp = acpi_get_rsdp(addr)) != NULL) +			return (rsdp); +	addr = ACPI_HI_RSDP_WINDOW_BASE; +	end = addr + ACPI_HI_RSDP_WINDOW_SIZE; +	for (; addr < end; addr += 16) +		if ((rsdp = acpi_get_rsdp(addr)) != NULL) +			return (rsdp); +#endif /* __amd64__ || __i386__ */ +	return (NULL); +} + +/* + * Public interfaces + */ +ACPI_TABLE_RSDP * +acpi_find_rsd_ptr(void) +{ +	ACPI_TABLE_RSDP *rsdp; +	char		buf[20]; +	u_long		addr; +	size_t		len; + +	acpi_user_init(); + +	addr = 0; + +	/* Attempt to use kenv or sysctl to find RSD PTR record. */ +	if (kenv(KENV_GET, acpi_rsdp, buf, 20) > 0) +		addr = strtoul(buf, NULL, 0); +	if (addr == 0) { +		len = sizeof(addr); +		if (sysctlbyname(machdep_acpi_root, &addr, &len, NULL, 0) != 0) +			addr = 0; +	} +	if (addr != 0 && (rsdp = acpi_get_rsdp(addr)) != NULL) +		return (rsdp); + +	return (acpi_scan_rsd_ptr()); +} + +void * +acpi_map_physical(vm_offset_t pa, size_t size) +{ +	struct	acpi_user_mapping *map; + +	map = acpi_user_find_mapping(pa, size); +	return (map->va + (pa - map->pa)); +} + +ACPI_TABLE_HEADER * +dsdt_load_file(char *infile) +{ +	ACPI_TABLE_HEADER *sdt; +	uint8_t		*dp; +	struct stat	 sb; + +	if ((acpi_mem_fd = open(infile, O_RDONLY)) == -1) +		errx(1, "opening %s", infile); + +	LIST_INIT(&maplist); + +	if (fstat(acpi_mem_fd, &sb) == -1) +		errx(1, "fstat %s", infile); + +	dp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, acpi_mem_fd, 0); +	if (dp == NULL) +		errx(1, "mmap %s", infile); + +	sdt = (ACPI_TABLE_HEADER *)dp; +	if (strncmp(dp, ACPI_SIG_DSDT, 4) != 0 || +	    acpi_checksum(sdt, sdt->Length) != 0) +		return (NULL); + +	return (sdt); +} diff --git a/usr.sbin/acpi/acpidump/acpidump.8 b/usr.sbin/acpi/acpidump/acpidump.8 new file mode 100644 index 000000000000..70a53b479fc4 --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.8 @@ -0,0 +1,262 @@ +.\" ACPI (ACPI Package) +.\" +.\" Copyright (c) 1999 Doug Rabson <dfr@FreeBSD.org> +.\" Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> +.\" Copyright (c) 2000 Yasuo YOKOYAMA <yokoyama@jp.FreeBSD.org> +.\" Copyright (c) 2000 Hiroki Sato <hrs@FreeBSD.org> +.\" 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. +.\" +.Dd October 5, 2024 +.Dt ACPIDUMP 8 +.Os +.Sh NAME +.Nm acpidump +.Nd dump ACPI tables and ASL +.Sh SYNOPSIS +.Nm +.Op Fl d +.Op Fl f Ar dsdt_input +.Op Fl h +.Op Fl o Ar dsdt_output +.Op Fl t +.Op Fl T Ar table_name +.Op Fl v +.Sh DESCRIPTION +The +.Nm +utility analyzes ACPI tables in physical memory and can dump them to a file. +In addition, +.Nm +can call +.Xr iasl 8 +to disassemble AML +(ACPI Machine Language) +found in these tables and dump them as ASL +(ACPI Source Language) +to stdout. +.Pp +ACPI tables have an essential data block (the DSDT, +Differentiated System Description Table) +that includes information used on the kernel side such as +detailed information about PnP hardware, procedures for controlling +power management support, and so on. +The +.Nm +utility can extract the DSDT data block from physical memory and store it into +an output file and optionally also disassemble it. +If any Secondary System Description Table +(SSDT) +entries exist, they will also be included in the output file and disassembly. +.Pp +When +.Nm +is invoked without the +.Fl f +option, it will read ACPI tables from physical memory via +.Pa /dev/mem . +First it searches for the RSDP +(Root System Description Pointer), +which has the signature +.Qq RSD PTR\ \& , +and then gets the RSDT +(Root System Description Table), +which includes a list of pointers to physical memory addresses +for other tables. +The RSDT itself and all other tables linked from RSDT are generically +called SDTs +(System Description Tables) +and their header has a common format which consists of items +such as Signature, Length, Revision, Checksum, OEMID, OEM Table ID, +OEM Revision, Creator ID and Creator Revision. +.Pp +When invoked with the +.Fl t +flag, the +.Nm +utility dumps contents of all the ACPI tables, except the DSDT and SSDT. +The following SDTs are reported in detail, while the remainder will only report +the common header information: +.Pp +.Bl -tag -offset indent -width 12345 -compact +.It BERT Boot Error Record Table +Reports any previous boot errors. +.It DMAR DMA Remapping Table +Contains information about the DMA remapping necessary for the system +for I/O virtualization on Intel CPUS. +.It DSDT Differentiated System Description Table +Contains the main AML for the system. +.It ECDT Embedded Controller Boot Resources Table +Contains information about accessing the embedded controller +prior to the OS decoding the DSDT for all its details. +.It EINJ Error Injection Table +Use to inject hardware errors to the error reporting mechanisms. +.It ERST Error Record Serialization Table +Information to retrieve and manage errors reported from the hardware. +.It FACS Firmware ACPI Control Structure +Information for the OS to interact with the firmware for things +like suspend / resume and prevent mutual access to resources +shared between the OS and the firmware. +.It FACP Fixed ACPI Description Table (FADT) +Information related to power management, and other CPU related data. +.It HEST Hardware Error Source Table +Describes the possible sources of hardware errors to the OS. +.It HPET High Precision Event Timer Table +Describes the high precision timers in the system. +.It IVRS I/O Virtualization Reporting Structure +Information for hypvervisors to use to share I/O resources on AMD +processors. +.It LPIT Low Power Idle Table +Power management information for reducing power usage of the system. +.It MADT Multiple APIC Description Table +Describes all the Advanced Programmable Interrupt Controllers and +Intel Streamlined Advanced Programmable Interrupt Controller present +in the system. +.It MCFG PCI Express Memory-mapped Configuration +PCI config space base address register. +.It NFIT NVDIMM Firmware Interface Table +NVDIMM information in the system. +.It RSD PTR +Pointer to the RSDT. +.It RSDT Root System Description Table +An array of physical pointers to other system description tables, +the FACP (Fixed ACPI Description Table). +.It SLIT System Locality Distance Information Table +Provides information about the cost of communicating between different +parts of the system (NUMA). +.It SPCR Serial Port Console Redirection +Contains informatiom about any serial port that the firmware used as +a reporting console. +.It SRAT System Resource Affinity Table +Defines the domains of locality in the system for processors, memory +and generic initiators (eg PCIe root complexes). +.It TCPA Trusted Computing Platform Alliance +Information about the TPM elements of the system. +.It TPM2 Trusted Platform Module 2 +Additional information about newer TPM hardware. +.It WDDT Watchdog Timer Description Table +Information about how to manage watchdog timers in the system. +.El +.Pp +The FACP defines static system information about power management support +(ACPI Hardware Register Implementation) +such as interrupt mode (INT_MODEL), +SCI interrupt number, SMI command port (SMI_CMD) +and the location of ACPI registers. +The FACP also has a pointer to a physical memory address for the DSDT. +While the other tables are fixed format, +the DSDT consists of free-formatted AML data. +.Sh OPTIONS +The following options are supported by +.Nm : +.Bl -tag -width indent +.It Fl d +Concatenate the DSDT and the SSDT's into single image and disassemble the image into ASL using +.Xr iasl 8 +and print the results to stdout. +.It Fl t +Dump the contents of the various fixed tables listed above. +.It Fl T ar table_name +Dump the contents of the specific table. +All ACPI tables are exactly 4 characters long. +.It Fl h +Displays usage and exit. +.It Fl s +Disassemble each of the DSDT and the SSDT's into ASL using +.Xr iasl 8 +and print the results to stdout. +This will avoid +.Xr iasl 8 +error on disassembling concatenated image. +If both +.Fl d +and +.Fl s +are specified, the last option is effective. +.It Fl v +Enable verbose messages. +.It Fl f Ar dsdt_input +Load the DSDT from the specified file instead of physical memory. +Since only the DSDT is stored in the file, the +.Fl t +flag may not be used with this option. +.It Fl o Ar dsdt_output +Store the DSDT data block from physical memory into the specified file. +.El +.Sh FILES +.Bl -tag -width /dev/mem +.It Pa /dev/mem +.El +.Sh EXAMPLES +If a developer requests a copy of your ASL, please use the following +command to dump all tables and compress the result. +.Bd -literal -offset indent +# acpidump -dt | gzip -c9 > my_computer.asl.gz +.Ed +.Pp +This example dumps the DSDT from physical memory to foo.dsdt. +It also prints the contents of various system tables and disassembles +the AML contained in the DSDT to stdout, redirecting the output +to foo.asl. +.Bd -literal -offset indent +# acpidump -t -d -o foo.dsdt > foo.asl +.Ed +.Pp +This example reads a DSDT file and disassembles it to stdout. +Verbose messages are enabled. +.Bd -literal -offset indent +# acpidump -v -d -f foo.dsdt +.Ed +.Sh SEE ALSO +.Xr acpi 4 , +.Xr mem 4 , +.Xr acpiconf 8 , +.Xr acpidb 8 , +.Xr iasl 8 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.0 +and was rewritten to use +.Xr iasl 8 +for +.Fx 5.2 . +.Sh AUTHORS +.An Doug Rabson Aq Mt dfr@FreeBSD.org +.An Mitsuru IWASAKI Aq Mt iwasaki@FreeBSD.org +.An Yasuo YOKOYAMA Aq Mt yokoyama@jp.FreeBSD.org +.An Nate Lawson Aq Mt njl@FreeBSD.org +.Pp +.An -nosplit +Some contributions made by +.An Chitoshi Ohsawa Aq Mt ohsawa@catv1.ccn-net.ne.jp , +.An Takayasu IWANASHI Aq Mt takayasu@wendy.a.perfect-liberty.or.jp , +.An Yoshihiko SARUMARU Aq Mt mistral@imasy.or.jp , +.An Hiroki Sato Aq Mt hrs@FreeBSD.org , +.An Michael Lucas Aq Mt mwlucas@blackhelicopters.org +and +.An Michael Smith Aq Mt msmith@FreeBSD.org . +.Sh BUGS +The current implementation does not dump the BOOT structure or +other miscellaneous tables. diff --git a/usr.sbin/acpi/acpidump/acpidump.c b/usr.sbin/acpi/acpidump/acpidump.c new file mode 100644 index 000000000000..477b56958d1f --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.c @@ -0,0 +1,160 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/param.h> +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "acpidump.h" + +int	dflag;	/* Disassemble AML using iasl(8) */ +int	tflag;	/* Dump contents of SDT tables */ +int	vflag;	/* Use verbose messages */ + +static void +usage(const char *progname) +{ + +	fprintf(stderr, "usage: %s [-d] [-t] [-h] [-v] [-f dsdt_input] " +			"[-o dsdt_output] [-T table_name]\n", progname); +	fprintf(stderr, "To send ASL:\n\t%s -dt | gzip -c9 > foo.asl.gz\n", +	    progname); +	exit(1); +} + +int +main(int argc, char *argv[]) +{ +	ACPI_TABLE_HEADER *rsdt, *sdt; +	int	c; +	char	*progname; +	char	*dsdt_input_file, *dsdt_output_file; +	char	*tbl = NULL; + +	dsdt_input_file = dsdt_output_file = NULL; +	progname = argv[0]; + +	if (argc < 2) +		usage(progname); + +	while ((c = getopt(argc, argv, "df:ho:tT:vs")) != -1) { +		switch (c) { +		case 'd': +			dflag = 1; +			break; +		case 'T': +			tbl = optarg; +			if (strlen(tbl) != 4) { +				warnx("Illegal table name %s", tbl); +				usage(progname); +			} +			break; +		case 't': +			tflag = 1; +			break; +		case 'v': +			vflag = 1; +			break; +		case 'f': +			dsdt_input_file = optarg; +			break; +		case 'o': +			dsdt_output_file = optarg; +			break; +		case 's': +			dflag = 2; +			break; +		case 'h': +		default: +			usage(progname); +			/* NOTREACHED */ +		} +	} +	argc -= optind; +	argv += optind; + +	/* Get input either from file or /dev/mem */ +	if (dsdt_input_file != NULL) { +		if (dflag == 0 && tflag == 0) { +			warnx("Need to specify -d or -t with DSDT input file"); +			usage(progname); +		} else if (tflag != 0) { +			warnx("Can't use -t with DSDT input file"); +			usage(progname); +		} +		if (vflag) +			warnx("loading DSDT file: %s", dsdt_input_file); +		rsdt = dsdt_load_file(dsdt_input_file); +	} else { +		if (vflag) +			warnx("loading RSD PTR from /dev/mem"); +		rsdt = sdt_load_devmem(); +	} + +	/* Display misc. SDT tables (only available when using /dev/mem) */ +	if (tflag || tbl != NULL) { +		if (vflag) +			warnx("printing various SDT tables"); +		sdt_print_all(rsdt, tbl); +	} + +	/* Translate RSDT to DSDT pointer */ +	if (dsdt_input_file == NULL) { +		sdt = sdt_from_rsdt(rsdt, ACPI_SIG_FADT, NULL); +		sdt = dsdt_from_fadt((ACPI_TABLE_FADT *)sdt); +	} else { +		sdt = rsdt; +		rsdt = NULL; +	} + +	/* Dump the DSDT and SSDTs to a file */ +	if (dsdt_output_file != NULL) { +		if (vflag) +			warnx("saving DSDT file: %s", dsdt_output_file); +		dsdt_save_file(dsdt_output_file, rsdt, sdt); +	} + +	/* Disassemble the DSDT into ASL */ +	if (dflag) { +		if (vflag) +			warnx("disassembling DSDT, iasl messages follow"); +		if (dflag == 1) { +			aml_disassemble(rsdt, sdt); +		} else { +			aml_disassemble_separate(rsdt, sdt); +		} +		if (vflag) +			warnx("iasl processing complete"); +	} + +	exit(0); +} diff --git a/usr.sbin/acpi/acpidump/acpidump.h b/usr.sbin/acpi/acpidump/acpidump.h new file mode 100644 index 000000000000..8755a96dd8af --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.h @@ -0,0 +1,162 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#ifndef _ACPIDUMP_H_ +#define	_ACPIDUMP_H_ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/acconfig.h> +#include <contrib/dev/acpica/include/actbl1.h> +#pragma GCC diagnostic pop + +/* GAS address space ID constants. */ +#define	ACPI_GAS_MEMORY		0 +#define	ACPI_GAS_IO		1 +#define	ACPI_GAS_PCI		2 +#define	ACPI_GAS_EMBEDDED	3 +#define	ACPI_GAS_SMBUS		4 +#define	ACPI_GAS_CMOS		5 +#define	ACPI_GAS_PCIBAR		6 +#define	ACPI_GAS_DATATABLE	7 +#define	ACPI_GAS_FIXED		0x7f + +/* Subfields in the HPET Id member. */ +#define	ACPI_HPET_ID_HARDWARE_REV_ID	0x000000ff +#define	ACPI_HPET_ID_COMPARATORS	0x00001f00 +#define	ACPI_HPET_ID_COUNT_SIZE_CAP	0x00002000 +#define	ACPI_HPET_ID_LEGACY_CAPABLE	0x00008000 +#define	ACPI_HPET_ID_PCI_VENDOR_ID	0xffff0000 + +/* Find and map the RSD PTR structure and return it for parsing */ +ACPI_TABLE_HEADER *sdt_load_devmem(void); + +/* TCPA */ +struct TCPAbody { +	ACPI_TABLE_HEADER header; +	uint16_t	platform_class; +#define ACPI_TCPA_BIOS_CLIENT	0x00 +#define ACPI_TCPA_BIOS_SERVER	0x01 +	union { +		struct client_hdr { +			uint32_t	log_max_len __packed; +			uint64_t	log_start_addr __packed; +		} client; +		struct server_hdr { +			uint16_t	reserved; +			uint64_t	log_max_len __packed; +			uint64_t	log_start_addr __packed; +		} server; +	}; +} __packed; + +struct TCPAevent { +	u_int32_t	pcr_index; +	u_int32_t	event_type; +	u_int8_t	pcr_value[20]; +	u_int32_t	event_size; +	u_int8_t	event_data[0]; +}; + +struct TCPApc_event { +	u_int32_t	event_id; +	u_int32_t	event_size; +	u_int8_t	event_data[0]; +}; + +enum TCPAevent_types { +	PREBOOT = 0, +	POST_CODE, +	UNUSED, +	NO_ACTION, +	SEPARATOR, +	ACTION, +	EVENT_TAG, +	SCRTM_CONTENTS, +	SCRTM_VERSION, +	CPU_MICROCODE, +	PLATFORM_CONFIG_FLAGS, +	TABLE_OF_DEVICES, +	COMPACT_HASH, +	IPL, +	IPL_PARTITION_DATA, +	NONHOST_CODE, +	NONHOST_CONFIG, +	NONHOST_INFO, +	EVENT_TYPE_MAX, +}; + +enum TCPApcclient_ids { +	SMBIOS = 1, +	BIS_CERT, +	POST_BIOS_ROM, +	ESCD, +	CMOS, +	NVRAM, +	OPTION_ROM_EXEC, +	OPTION_ROM_CONFIG, +	OPTION_ROM_MICROCODE = 10, +	S_CRTM_VERSION, +	S_CRTM_CONTENTS, +	POST_CONTENTS, +	HOST_TABLE_OF_DEVICES, +	PCCLIENT_ID_MAX, +}; + +/* + * Load the DSDT from a previous save file.  Note that other tables are + * not saved (i.e. FADT) + */ +ACPI_TABLE_HEADER *dsdt_load_file(char *); + +/* Save the DSDT to a file */ +void	 dsdt_save_file(char *, ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER *); + +/* Print out as many fixed tables as possible, given the RSD PTR */ +void	 sdt_print_all(ACPI_TABLE_HEADER *, const char *); + +/* Disassemble the AML in the DSDT */ +void	 aml_disassemble(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER *); +void	 aml_disassemble_separate(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER *); + +/* Routines for accessing tables in physical memory */ +ACPI_TABLE_RSDP *acpi_find_rsd_ptr(void); +void	*acpi_map_physical(vm_offset_t, size_t); +ACPI_TABLE_HEADER *sdt_from_rsdt(ACPI_TABLE_HEADER *, const char *, +	    ACPI_TABLE_HEADER *); +ACPI_TABLE_HEADER *dsdt_from_fadt(ACPI_TABLE_FADT *); +int	 acpi_checksum(void *, size_t); + +/* Command line flags */ +extern int	dflag; +extern int	tflag; +extern int	vflag; + +#endif	/* !_ACPIDUMP_H_ */ diff --git a/usr.sbin/acpi/iasl/Makefile b/usr.sbin/acpi/iasl/Makefile new file mode 100644 index 000000000000..5b163b9d8885 --- /dev/null +++ b/usr.sbin/acpi/iasl/Makefile @@ -0,0 +1,154 @@ +PROG=	iasl + +# common +SRCS=	acfileio.c adfile.c adisasm.c adwalk.c ahids.c		\ +	ahpredef.c ahtable.c ahuuids.c cmfsize.c dmextern.c	\ +	dmrestag.c dmswitch.c dmtable.c dmtables.c dmtbdump.c	\ +	dmtbdump1.c dmtbdump2.c dmtbdump3.c dmtbinfo.c		\ +	dmtbinfo1.c dmtbinfo2.c dmtbinfo3.c getopt.c + +# compiler +SRCS+=	aslallocate.c aslanalyze.c aslascii.c aslbtypes.c	\ +	aslcache.c aslcodegen.c aslcompile.c aslcompiler.y.h	\ +	aslcompilerlex.c aslcompilerparse.c asldebug.c		\ +	aslerror.c aslexternal.c aslfileio.c aslfiles.c		\ +	aslfold.c aslhelp.c aslhex.c asllength.c asllisting.c	\ +	asllistsup.c aslload.c asllookup.c aslmain.c aslmap.c	\ +	aslmapenter.c aslmapoutput.c aslmaputils.c		\ +	aslmessages.c aslmethod.c aslnamesp.c asloffset.c	\ +	aslopcodes.c asloperands.c aslopt.c asloptions.c	\ +	aslparseop.c aslpld.c aslpredef.c aslprepkg.c		\ +	aslprintf.c aslprune.c aslresource.c aslrestype1.c	\ +	aslrestype1i.c aslrestype2.c aslrestype2d.c		\ +	aslrestype2e.c aslrestype2q.c aslrestype2s.c		\ +	aslrestype2w.c aslstartup.c aslstubs.c asltransform.c	\ +	asltree.c aslutils.c asluuid.c aslwalks.c aslxref.c	\ +	aslxrefout.c cvcompiler.c cvdisasm.c cvparser.c		\ +	dtcompile.c dtcompilerparser.y.h dtcompilerparserlex.c	\ +	dtcompilerparserparse.c dtexpress.c dtfield.c dtio.c	\ +	dtparser.y.h dtparserlex.c dtparserparse.c dtsubtable.c	\ +	dttable.c dttable1.c dttable2.c dttemplate.c dtutils.c	\ +	prexpress.c prmacros.c prparser.y.h prparserlex.c	\ +	prparserparse.c prscan.c prutils.c + +# components/debugger +SRCS+=	dbfileio.c + +# components/disassembler +SRCS+=	dmbuffer.c dmcstyle.c dmdeferred.c dmnames.c dmopcode.c	\ +	dmresrc.c dmresrcl.c dmresrcl2.c dmresrcs.c dmutils.c	\ +	dmwalk.c + +# components/dispatcher +SRCS+=	dsargs.c dscontrol.c dsfield.c dsobject.c dsopcode.c	\ +	dspkginit.c dsutils.c dswexec.c dswload.c dswload2.c	\ +	dswscope.c dswstate.c + +# components/executer +SRCS+=	exconcat.c exconvrt.c excreate.c exdump.c exmisc.c	\ +	exmutex.c exnames.c exoparg1.c exoparg2.c exoparg3.c	\ +	exoparg6.c exprep.c exresnte.c exresolv.c exresop.c	\ +	exstore.c exstoren.c exstorob.c exsystem.c exutils.c + +# components/parser +SRCS+=	psargs.c psloop.c psobject.c psopcode.c psopinfo.c	\ +	psparse.c psscope.c pstree.c psutils.c pswalk.c + +# components/namespace +SRCS+=	nsaccess.c nsalloc.c nsdump.c nsnames.c nsobject.c	\ +	nsparse.c nssearch.c nsutils.c nswalk.c + +# components/tables +SRCS+=	tbdata.c tbfadt.c tbinstal.c tbprint.c tbutils.c	\ +	tbxface.c tbxfload.c + +# components/utilities +SRCS+=	utaddress.c utalloc.c utascii.c utbuffer.c utcache.c	\ +	utcksum.c utcopy.c utdebug.c utdecode.c utdelete.c	\ +	uterror.c utexcep.c utglobal.c uthex.c utinit.c		\ +	utlock.c utmath.c utmisc.c utmutex.c utnonansi.c	\ +	utobject.c utownerid.c utpredef.c utresdecode.c		\ +	utresrc.c utstate.c utstring.c utstrsuppt.c		\ +	utstrtoul64.c utuuid.c utxface.c utxferror.c + +# os_specific/service_layers +SRCS+=	osunixxf.c + +WARNS?=	2 + +MAN=	iasl.8 + +CFLAGS+= -DACPI_ASL_COMPILER -I. +CWARNFLAGS.aslrestype2s.c= ${NO_WUNUSED_BUT_SET_VARIABLE} +CWARNFLAGS.dmextern.c= ${NO_WUNUSED_BUT_SET_VARIABLE} +LFLAGS= -i -s +DLFLAGS=-i +YFLAGS= -d + +CLEANFILES= aslcompiler.y aslcompiler.y.h aslcompilerlex.c	\ +	aslcompilerparse.c aslcompilerparse.h			\ +	dtcompilerparser.y.h dtcompilerparserlex.c		\ +	dtcompilerparserparse.c	dtcompilerparserparse.h		\ +	dtparser.y.h dtparserlex.c dtparserparse.c		\ +	dtparserparse.h prparser.y.h prparserlex.c		\ +	prparserparse.c prparserparse.h + +PARSER=	aslcstyle.y aslhelpers.y aslkeywords.y aslparser.y	\ +	aslprimaries.y aslresources.y aslrules.y aslsupport.y	\ +	asltokens.y asltypes.y + +aslcompilerlex.c: aslcompiler.l aslsupport.l +	${LEX} ${LFLAGS} -PAslCompiler -o${.TARGET} \ +	    ${ACPICA_DIR}/compiler/aslcompiler.l + +aslcompiler.y: ${PARSER} +	m4 -P -I${ACPICA_DIR}/compiler \ +	    ${ACPICA_DIR}/compiler/aslparser.y > ${.TARGET} + +.ORDER: aslcompilerparse.c aslcompilerparse.h +aslcompilerparse.h: .NOMETA +aslcompilerparse.c aslcompilerparse.h: aslcompiler.y +	${YACC} ${YFLAGS} -pAslCompiler -oaslcompilerparse.c ${.ALLSRC} + +aslcompiler.y.h: aslcompilerparse.h .NOMETA +	ln -f ${.ALLSRC} ${.TARGET} + +dtcompilerparserlex.c: dtcompilerparser.l +	${LEX} ${DLFLAGS} -PDtCompilerParser -o${.TARGET} ${.ALLSRC} + +.ORDER: dtcompilerparserparse.c dtcompilerparserparse.h +dtcompilerparserparse.h: .NOMETA +dtcompilerparserparse.c dtcompilerparserparse.h: dtcompilerparser.y +	${YACC} ${YFLAGS} -pDtCompilerParser -odtcompilerparserparse.c \ +	    ${.ALLSRC} + +dtcompilerparser.y.h: dtcompilerparserparse.h .NOMETA +	ln -f ${.ALLSRC} ${.TARGET} + +dtparserlex.c: dtparser.l +	${LEX} ${DLFLAGS} -PDtParser -o${.TARGET} ${.ALLSRC} + +.ORDER: dtparserparse.c dtparserparse.h +dtparserparse.h: .NOMETA +dtparserparse.c dtparserparse.h: dtparser.y +	${YACC} ${YFLAGS} -pDtParser -odtparserparse.c ${.ALLSRC} + +dtparser.y.h: dtparserparse.h .NOMETA +	ln -f ${.ALLSRC} ${.TARGET} + +prparserlex.c: prparser.l +	${LEX} ${LFLAGS} -PPrParser -o${.TARGET} ${.ALLSRC} + +.ORDER: prparserparse.c prparserparse.h +prparserparse.h: .NOMETA +prparserparse.c prparserparse.h: prparser.y +	${YACC} ${YFLAGS} -pPrParser -oprparserparse.c ${.ALLSRC} + +prparser.y.h: prparserparse.h .NOMETA +	ln -f ${.ALLSRC} ${.TARGET} + +# AcpiUtInitStackPtrTrace intentionally leaks a pointer to an +# on-stack variable. +CWARNFLAGS.utdebug.c+= ${NO_WDANGLING_POINTER} + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/iasl/Makefile.depend b/usr.sbin/acpi/iasl/Makefile.depend new file mode 100644 index 000000000000..c2fea3d32305 --- /dev/null +++ b/usr.sbin/acpi/iasl/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ +	usr.bin/yacc.host \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/acpi/iasl/iasl.8 b/usr.sbin/acpi/iasl/iasl.8 new file mode 100644 index 000000000000..3f096ebc0635 --- /dev/null +++ b/usr.sbin/acpi/iasl/iasl.8 @@ -0,0 +1,177 @@ +.\"- +.\" Copyright (c) 2003 Nate Lawson +.\" 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 +.\"    in this position and unchanged. +.\" 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. +.\" 3. The name of the author may not be used to endorse or promote products +.\"    derived from this software without specific prior written permission. +.\" +.\" 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. +.\" +.Dd May 20, 2008 +.Dt IASL 8 +.Os +.Sh NAME +.Nm iasl +.Nd Intel ACPI compiler/decompiler +.Sh SYNOPSIS +.Nm +.Op Fl 2cefghl +.Op Fl b Ar type +.Op Fl d Ar file +.Op Fl dc Ar file +.Op Fl hc +.Op Fl hr +.Op Fl i Ar type +.Op Fl ln +.Op Fl ls +.Op Fl oa +.Op Fl of +.Op Fl oi +.Op Fl on +.Op Fl ot +.Op Fl p Ar prefix +.Op Fl s Ar type +.Op Fl t Ar type +.Op Fl vi +.Op Fl vo +.Op Fl vr +.Op Fl vs +.Op Fl x Ar level +.Op Fl w Ar level +.Ar input-file +.Sh DESCRIPTION +The +.Nm +utility is a compiler/decompiler for ACPI Source Language (ASL) +and ACPI Machine Language (AML). +Major features of +.Nm +include: +.Bl -bullet -offset indent +.It +Full support for the ACPI 3.0b Specification including ASL grammar +elements and operators. +.It +Extensive compiler syntax and semantic error checking, especially in +the area of control methods. +This reduces the number of errors that are +not discovered until the AML code is actually interpreted (i.e., the +compile-time error checking reduces the number of run-time errors). +.It +Multiple types of output files, including formatted listing files with +intermixed source, several types of AML files, and error messages. +.El +.Sh OPTIONS +.Bl -tag -width indent +.It Fl 2 +Emit ACPI 2.0 compatible ASL code. +.It Fl b Sm Cm p | t | b Sm +Create compiler debug/trace file +.Pq Pa *.txt . +Types: Parse/Tree/Both. +.It Fl c +Parse only, no output generation. +.It Fl d Ar file +Disassemble AML to ASL source code file +.Pq Pa *.dsl . +.It Fl dc Ar file +Disassemble AML and immediately compile it. +(Obtain DSDT from current system if no input file.) +.It Fl e +Generate +.Fn External +statements for unresolved symbols. +.It Fl f +Ignore errors, force creation of AML output file(s). +.It Fl g +Get ACPI tables and write to files +.Pq Pa *.dat . +.It Fl h +Additional help and compiler debug options. +.It Fl hc +Display operators allowed in constant expressions. +.It Fl hr +Display ACPI reserved method names. +.It Fl i Sm Cm a | c Sm +Create assembler or C include file +.Pa ( *.inc +or +.Pa *.h ) . +.It Fl l +Create mixed listing file (ASL source and AML) +.Pq Pa *.lst . +.It Fl ln +Create namespace file +.Pq Pa *.nsp . +.It Fl ls +Create combined source file (expanded includes) +.Pq Pa *.src . +.It Fl oa +Disable all optimizations (compatibility mode). +.It Fl of +Disable constant folding. +.It Fl oi +Disable integer optimization to Zero/One/Ones. +.It Fl on +Disable named reference string optimization. +.It Fl ot +Display compile times. +.It Fl p Ar prefix +Specify filename prefix for all output files (including +.Pa .aml ) . +.It Fl s Sm Cm a | c Sm +Create AML in assembler or C source file +.Pa ( *.asm +or +.Pa *.c ) . +.It Fl t Ar a|c +Create AML in assembler or C hex table +.Pq Pa *.hex . +.It Fl vi +Less verbose errors and warnings for use with IDEs. +.It Fl vo +Enable optimization comments. +.It Fl vr +Disable remarks. +.It Fl vs +Disable signon. +.It Fl x Ar level +Set debug level for trace output. +.It Fl w Ar level +Set warning level. +.El +.Sh SEE ALSO +.Xr acpi 4 , +.Xr acpidump 8 +.Sh HISTORY +The +.Nm +utility is provided with Intel ACPI-CA. +It first appeared in +.Fx 5.2 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Intel . +This manual page was written by +.An Nate Lawson . | 
