diff options
Diffstat (limited to 'usr.sbin/acpi')
-rw-r--r-- | usr.sbin/acpi/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/acpi/Makefile.inc | 24 | ||||
-rw-r--r-- | usr.sbin/acpi/acpiconf/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/acpi/acpiconf/acpiconf.8 | 92 | ||||
-rw-r--r-- | usr.sbin/acpi/acpiconf/acpiconf.c | 228 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidb/Makefile | 67 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidb/acpidb.8 | 167 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidb/acpidb.c | 503 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/acpi.c | 1098 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/acpi_user.c | 222 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.8 | 199 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.c | 144 | ||||
-rw-r--r-- | usr.sbin/acpi/acpidump/acpidump.h | 86 | ||||
-rw-r--r-- | usr.sbin/acpi/iasl/Makefile | 79 | ||||
-rw-r--r-- | usr.sbin/acpi/iasl/iasl.8 | 179 |
16 files changed, 3109 insertions, 0 deletions
diff --git a/usr.sbin/acpi/Makefile b/usr.sbin/acpi/Makefile new file mode 100644 index 0000000..8190bc7 --- /dev/null +++ b/usr.sbin/acpi/Makefile @@ -0,0 +1,7 @@ +# Makefile for acpi tools +# $Id: Makefile,v 1.1 2000/07/14 18:16:22 iwasaki Exp $ +# $FreeBSD$ + +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 0000000..9d387bc --- /dev/null +++ b/usr.sbin/acpi/Makefile.inc @@ -0,0 +1,24 @@ +# $Id: Makefile.inc,v 1.1 2000/07/14 18:16:22 iwasaki Exp $ +# $FreeBSD$ + +ACPICA_DIR= ${.CURDIR}/../../../sys/contrib/dev/acpica +CFLAGS+= -I${.CURDIR}/../../../sys + +.if exists(${.CURDIR}/../../Makefile.inc) +.include "${.CURDIR}/../../Makefile.inc" +.endif + +.PATH: ${ACPICA_DIR} \ + ${ACPICA_DIR}/common \ + ${ACPICA_DIR}/compiler \ + ${ACPICA_DIR}/debugger \ + ${ACPICA_DIR}/disassembler \ + ${ACPICA_DIR}/dispatcher \ + ${ACPICA_DIR}/events \ + ${ACPICA_DIR}/executer \ + ${ACPICA_DIR}/hardware \ + ${ACPICA_DIR}/namespace \ + ${ACPICA_DIR}/parser \ + ${ACPICA_DIR}/resources \ + ${ACPICA_DIR}/tables \ + ${ACPICA_DIR}/utilities diff --git a/usr.sbin/acpi/acpiconf/Makefile b/usr.sbin/acpi/acpiconf/Makefile new file mode 100644 index 0000000..5f862a2 --- /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 $ +# $FreeBSD$ + +PROG= acpiconf +MAN= acpiconf.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/acpiconf/acpiconf.8 b/usr.sbin/acpi/acpiconf/acpiconf.8 new file mode 100644 index 0000000..05d3a5d --- /dev/null +++ b/usr.sbin/acpi/acpiconf/acpiconf.8 @@ -0,0 +1,92 @@ +.\"- +.\" Copyright (c) 2000 Dag-Erling Coïdan 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 16, 2004 +.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 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 about the specified battery. +.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), +.Cm 4 +(the CPU context is lost and memory context is stored to disk) +and +.Cm 5 +(soft off). +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 before and after entering +the given sleep state. +.El +.Sh SEE ALSO +.Xr acpi 4 , +.Xr acpidump 8 , +.Xr apm 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 iwasaki@FreeBSD.org . +This manual page was written by +.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . diff --git a/usr.sbin/acpi/acpiconf/acpiconf.c b/usr.sbin/acpi/acpiconf/acpiconf.c new file mode 100644 index 0000000..87f1c76 --- /dev/null +++ b/usr.sbin/acpi/acpiconf/acpiconf.c @@ -0,0 +1,228 @@ +/*- + * 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 $ + * $FreeBSD$ + */ + +#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; + + if (num < 0 || num > 64) + err(EX_USAGE, "invalid battery %d", num); + + /* Print battery design information. */ + battio.unit = num; + if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) == -1) + err(EX_IOERR, "get battery info (%d) failed", num); + if (battio.bif.units == 0) + pwr_units = "mW"; + else + pwr_units = "mA"; + + if (battio.bif.dcap == UNKNOWN_CAP) + printf("Design capacity:\tunknown\n"); + else + printf("Design capacity:\t%d %sh\n", battio.bif.dcap, + pwr_units); + if (battio.bif.lfcap == UNKNOWN_CAP) + printf("Last full capacity:\tunknown\n"); + else + printf("Last full capacity:\t%d %sh\n", battio.bif.lfcap, + pwr_units); + printf("Technology:\t\t%s\n", battio.bif.btech == 0 ? + "primary (non-rechargeable)" : "secondary (rechargeable)"); + if (battio.bif.dvol == UNKNOWN_CAP) + printf("Design voltage:\t\tunknown\n"); + else + printf("Design voltage:\t\t%d mV\n", battio.bif.dvol); + printf("Capacity (warn):\t%d %sh\n", battio.bif.wcap, pwr_units); + printf("Capacity (low):\t\t%d %sh\n", battio.bif.lcap, pwr_units); + printf("Low/warn granularity:\t%d %sh\n", battio.bif.gra1, pwr_units); + printf("Warn/full granularity:\t%d %sh\n", battio.bif.gra2, pwr_units); + printf("Model number:\t\t%s\n", battio.bif.model); + printf("Serial number:\t\t%s\n", battio.bif.serial); + printf("Type:\t\t\t%s\n", battio.bif.type); + printf("OEM info:\t\t%s\n", battio.bif.oeminfo); + + /* 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) { + printf("State:\t\t\t"); + if (battio.battinfo.state == 0) + printf("high "); + if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL) + printf("critical "); + if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG) + printf("discharging "); + if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING) + printf("charging "); + printf("\n"); + 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 + 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. */ + 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) { + if (battio.bst.volt == UNKNOWN_VOLTAGE) + printf("Voltage:\t\tunknown\n"); + else + printf("Voltage:\t\t%d mV\n", battio.bst.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 c, *prog; + int sleep_type; + + 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': + acpi_battinfo(atoi(optarg)); + break; + case 'k': + acpi_sleep_ack(atoi(optarg)); + break; + case 's': + if (optarg[0] == 'S') + sleep_type = optarg[1] - '0'; + else + sleep_type = optarg[0] - '0'; + 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 (sleep_type != -1) + 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 0000000..4d99abf --- /dev/null +++ b/usr.sbin/acpi/acpidb/Makefile @@ -0,0 +1,67 @@ +# $FreeBSD$ + +PROG= acpidb +SRCS= acpidb.c +SRCS+= osunixxf.c + +# debugger +SRCS+= dbcmds.c dbdisply.c dbexec.c dbfileio.c dbhistry.c \ + dbinput.c dbstats.c dbutils.c dbxface.c + +# disassembler +SRCS+= dmbuffer.c dmnames.c dmobject.c dmopcode.c dmresrc.c \ + dmresrcl.c dmresrcs.c dmutils.c dmwalk.c + +# events +SRCS+= evevent.c evgpe.c evgpeblk.c evgpeinit.c evgpeutil.c \ + evmisc.c evregion.c evrgnini.c evsci.c evxface.c \ + evxfevnt.c evxfregn.c + +# hardware +SRCS+= hwacpi.c hwgpe.c hwregs.c hwsleep.c hwvalid.c hwxface.c + +# interpreter/dispatcher +SRCS+= dsfield.c dsinit.c dsmethod.c dsmthdat.c dsobject.c \ + dsopcode.c dsutils.c dswexec.c dswload.c dswscope.c \ + dswstate.c + +# interpreter/executer +SRCS+= 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 exstore.c \ + exstoren.c exstorob.c exsystem.c exutils.c + +# interpreter/parser +SRCS+= psargs.c psloop.c psopcode.c psparse.c psscope.c \ + pstree.c psutils.c pswalk.c psxface.c + +# namespace +SRCS+= nsaccess.c nsalloc.c nsdump.c nseval.c nsinit.c \ + nsload.c nsnames.c nsobject.c nsparse.c nspredef.c \ + nsrepair.c nsrepair2.c nssearch.c nsutils.c nswalk.c \ + nsxfeval.c nsxfname.c nsxfobj.c + +# resources +SRCS+= rsaddr.c rscalc.c rscreate.c rsdump.c rsinfo.c \ + rsio.c rsirq.c rslist.c rsmemory.c rsmisc.c \ + rsutils.c rsxface.c + +# tables +SRCS+= tbfadt.c tbfind.c tbinstal.c tbutils.c tbxface.c \ + tbxfroot.c + +# utilities +SRCS+= utalloc.c utcache.c utcopy.c utdebug.c utdelete.c \ + uteval.c utglobal.c utids.c utinit.c utlock.c utmath.c \ + utmisc.c utmutex.c utobject.c utosi.c utresrc.c \ + utstate.c uttrack.c utxface.c + +MAN= acpidb.8 +WARNS?= 2 + +CFLAGS+= -DACPI_EXEC_APP -fno-strict-aliasing +DPADD= ${LIBPTHREAD} +LDADD= -lpthread + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/acpidb/acpidb.8 b/usr.sbin/acpi/acpidb/acpidb.8 new file mode 100644 index 0000000..4ed97a6 --- /dev/null +++ b/usr.sbin/acpi/acpidb/acpidb.8 @@ -0,0 +1,167 @@ +.\"- +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.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 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 0000000..325dfae --- /dev/null +++ b/usr.sbin/acpi/acpidb/acpidb.c @@ -0,0 +1,503 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#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/tools/acpiexec/aecommon.h> + +/* + * Dummy DSDT Table Header + */ + +ACPI_TABLE_HEADER dummy_dsdt_table = { + "DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1 +}; + +/* + * Region space I/O routines on virtual machine + */ + +int aml_debug_prompt = 1; + +struct ACPIRegionContent { + TAILQ_ENTRY(ACPIRegionContent) links; + int regtype; + ACPI_PHYSICAL_ADDRESS addr; + UINT8 value; +}; + +TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); +struct ACPIRegionContentList RegionContentList; + +static int aml_simulation_initialized = 0; + +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 ACPI CA core subsystem. */ +ACPI_STATUS +AeLocalGetRootPointer(void) +{ + + return (AE_ERROR); +} + +void +AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable) +{ +} + +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 ", val); + printf(" / %ju) >>", 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]; + u_int8_t *code; + struct stat sb; + int fd, fd2; + int error; + + fd = open(dsdtfile, O_RDONLY, 0); + if (fd == -1) { + perror("open"); + return (-1); + } + if (fstat(fd, &sb) == -1) { + perror("fstat"); + return (-1); + } + code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); + if (code == NULL) { + perror("mmap"); + return (-1); + } + if ((error = AcpiInitializeSubsystem()) != AE_OK) { + return (-1); + } + + /* + * make sure DSDT data contains table header or not. + */ + if (strncmp((char *)code, "DSDT", 4) == 0) { + strncpy(filetmp, dsdtfile, sizeof(filetmp)); + } else { + mode_t mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size; + snprintf(filetmp, sizeof(filetmp), "%s.tmp", dsdtfile); + fd2 = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd2 == -1) { + perror("open"); + return (-1); + } + write(fd2, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER)); + + write(fd2, code, sb.st_size); + close(fd2); + } + + /* + * 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); + } + + AcpiDbGetTableFromFile(filetmp, NULL); + + AcpiDbInitialize(); + AcpiGbl_DebuggerConfiguration = 0; + AcpiDbUserCommands(':', NULL); + + if (strcmp(dsdtfile, filetmp) != 0) { + 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 0000000..e004500 --- /dev/null +++ b/usr.sbin/acpi/acpidump/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= acpidump +MAN= acpidump.8 +SRCS= acpi.c acpi_user.c acpidump.c + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c new file mode 100644 index 0000000..8a89f10 --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpi.c @@ -0,0 +1,1098 @@ +/*- + * Copyright (c) 1998 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. + * + * $FreeBSD$ + */ + +#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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.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_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_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); +static void acpi_walk_subtables(ACPI_TABLE_HEADER *table, void *first, + void (*action)(ACPI_SUBTABLE_HEADER *)); + +/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */ +static int addr_size; + +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%08lx:%u[%u] (Memory)", (u_long)gas->Address, + gas->BitOffset, gas->BitWidth); + break; + case ACPI_GAS_IO: + printf("0x%02lx:%u[%u] (IO)", (u_long)gas->Address, + gas->BitOffset, gas->BitWidth); + break; + case ACPI_GAS_PCI: + printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->Address >> 32), + (uint16_t)((gas->Address >> 16) & 0xffff), + (uint16_t)gas->Address); + 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%08lx (?)", (u_long)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) +{ + int fadt_revision; + + /* Set the FADT revision separately from the RSDP version. */ + if (addr_size == 8) { + fadt_revision = 2; + + /* + * 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. + */ + if (fadt->Facs != 0 && + (fadt->XFacs & 0xffffffff) != fadt->Facs) + fadt_revision = 1; + } 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; + int fadt_revision; + + fadt = (ACPI_TABLE_FADT *)sdp; + acpi_print_fadt(sdp); + + fadt_revision = acpi_get_fadt_revision(fadt); + if (fadt_revision == 1) + facs = (ACPI_TABLE_FACS *)acpi_map_sdt(fadt->Facs); + else + facs = (ACPI_TABLE_FACS *)acpi_map_sdt(fadt->XFacs); + if (memcmp(facs->Signature, ACPI_SIG_FACS, 4) != 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"); + action(subtable); + subtable = (ACPI_SUBTABLE_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_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); +} + +const char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", + "Local APIC NMI", "Local APIC Override", + "IO SAPIC", "Local SAPIC", "Platform Interrupt", + "Local X2APIC", "Local X2APIC NMI" }; +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; + + if (mp->Type < sizeof(apic_types) / sizeof(apic_types[0])) + 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 < sizeof(platform_int_types) / + sizeof(platform_int_types[0])) + 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; + } +} + +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_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("\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(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", 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_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 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); +} + +const char *srat_types[] = { "CPU", "Memory", "X2APIC" }; + +static void +acpi_print_srat(ACPI_SUBTABLE_HEADER *srat) +{ + ACPI_SRAT_CPU_AFFINITY *cpu; + ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; + + if (srat->Type < sizeof(srat_types) / sizeof(srat_types[0])) + 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; + } +} + +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 void +acpi_print_sdt(ACPI_TABLE_HEADER *sdp) +{ + printf(" "); + acpi_print_string(sdp->Signature, ACPI_NAME_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_NAME_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; + u_long addr; + + 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(", "); + switch (addr_size) { + case 4: + addr = le32toh(rsdt->TableOffsetEntry[i]); + break; + case 8: + addr = le64toh(xsdt->TableOffsetEntry[i]); + break; + default: + addr = 0; + } + assert(addr != 0); + printf("0x%08lx", addr); + } + 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; + char sep; + + 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) do { \ + if ((var) & ACPI_FADT_## flag) { \ + printf("%c%s", sep, #flag); sep = ','; \ + } \ +} while (0) + + printf("\tIAPC_BOOT_ARCH="); + sep = '{'; + PRINTFLAG(fadt->BootFlags, LEGACY_DEVICES); + PRINTFLAG(fadt->BootFlags, 8042); + PRINTFLAG(fadt->BootFlags, NO_VGA); + PRINTFLAG(fadt->BootFlags, NO_MSI); + PRINTFLAG(fadt->BootFlags, NO_ASPM); + if (fadt->BootFlags != 0) + printf("}"); + printf("\n"); + + printf("\tFlags="); + sep = '{'; + 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); + if (fadt->Flags != 0) + printf("}\n"); + +#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%08lx, ", (u_long)fadt->XFacs); + printf("X_DSDT=0x%08lx\n", (u_long)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=%08lx\n", + (u_long)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%08lx, length=%u, cksum=%u\n", + (u_long)rp->XsdtPhysicalAddress, rp->Length, + rp->ExtendedChecksum); + } + printf(END_COMMENT); +} + +static void +acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp) +{ + ACPI_TABLE_HEADER *sdp; + ACPI_TABLE_RSDT *rsdt; + ACPI_TABLE_XSDT *xsdt; + vm_offset_t addr; + int entries, i; + + acpi_print_rsdt(rsdp); + 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++) { + switch (addr_size) { + case 4: + addr = le32toh(rsdt->TableOffsetEntry[i]); + break; + case 8: + addr = le64toh(xsdt->TableOffsetEntry[i]); + break; + default: + assert((addr = 0)); + } + + 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 (!memcmp(sdp->Signature, ACPI_SIG_FADT, 4)) + acpi_handle_fadt(sdp); + else if (!memcmp(sdp->Signature, ACPI_SIG_MADT, 4)) + acpi_handle_madt(sdp); + else if (!memcmp(sdp->Signature, ACPI_SIG_HPET, 4)) + acpi_handle_hpet(sdp); + else if (!memcmp(sdp->Signature, ACPI_SIG_ECDT, 4)) + acpi_handle_ecdt(sdp); + else if (!memcmp(sdp->Signature, ACPI_SIG_MCFG, 4)) + acpi_handle_mcfg(sdp); + else if (!memcmp(sdp->Signature, ACPI_SIG_SRAT, 4)) + acpi_handle_srat(sdp); + else { + printf(BEGIN_COMMENT); + acpi_print_sdt(sdp); + printf(END_COMMENT); + } + } +} + +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", 4) != 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", 4) != 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]; + const char *tmpdir; + char *tmpext; + FILE *fp; + size_t len; + int fd; + + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) + tmpdir = _PATH_TMP; + strncpy(tmpstr, tmpdir, sizeof(tmpstr)); + strncat(tmpstr, "/acpidump.", sizeof(tmpstr) - strlen(tmpdir)); + if (realpath(tmpstr, buf) == NULL) { + perror("realpath tmp file"); + return; + } + strncpy(tmpstr, buf, sizeof(tmpstr)); + len = strlen(buf); + tmpext = tmpstr + len; + strncpy(tmpext, "XXXXXX", sizeof(tmpstr) - len); + fd = mkstemp(tmpstr); + if (fd < 0) { + perror("iasl tmp file"); + return; + } + write_dsdt(fd, rsdt, dsdp); + close(fd); + + /* Run iasl -d on the temp file */ + if (fork() == 0) { + close(STDOUT_FILENO); + if (vflag == 0) + close(STDERR_FILENO); + execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, NULL); + err(1, "exec"); + } + + wait(NULL); + unlink(tmpstr); + + /* Dump iasl's output to stdout */ + strncpy(tmpext, "dsl", sizeof(tmpstr) - len); + fp = fopen(tmpstr, "r"); + unlink(tmpstr); + if (fp == NULL) { + perror("iasl tmp file (read)"); + return; + } + while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) + fwrite(buf, 1, len, stdout); + fclose(fp); +} + +void +sdt_print_all(ACPI_TABLE_HEADER *rsdp) +{ + acpi_handle_rsdt(rsdp); +} + +/* 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++) { + switch (addr_size) { + case 4: + addr = le32toh(rsdt->TableOffsetEntry[i]); + break; + case 8: + addr = le64toh(xsdt->TableOffsetEntry[i]); + break; + default: + assert((addr = 0)); + } + 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 0000000..86e581f --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpi_user.c @@ -0,0 +1,222 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#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 hint_acpi_0_rsdp[] = "hint.acpi.0.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; +}; + +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, hint_acpi_0_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 0000000..1401e38 --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.8 @@ -0,0 +1,199 @@ +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd February 14, 2005 +.Dt ACPIDUMP 8 +.Os +.Sh NAME +.Nm acpidump +.Nd dump ACPI tables and ASL +.Sh SYNOPSIS +.Nm +.Op Fl d +.Op Fl t +.Op Fl h +.Op Fl v +.Op Fl f Ar dsdt_input +.Op Fl o Ar dsdt_output +.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. +When invoked with the +.Fl t +flag, the +.Nm +utility dumps contents of the following tables: +.Pp +.Bl -tag -offset indent -width 12345 -compact +.It DSDT +.It ECDT +.It FACS +.It FADT +.It HPET +.It MADT +.It MCFG +.It RSD PTR +.It RSDT +.El +.Pp +The RSDT contains a pointer to the physical memory address of the FACP +(Fixed ACPI Description Table). +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 +Disassemble the DSDT 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 h +Displays usage and exit. +.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 dfr@FreeBSD.org +.An Mitsuru IWASAKI Aq iwasaki@FreeBSD.org +.An Yasuo YOKOYAMA Aq yokoyama@jp.FreeBSD.org +.An Nate Lawson Aq njl@FreeBSD.org +.Pp +.An -nosplit +Some contributions made by +.An Chitoshi Ohsawa Aq ohsawa@catv1.ccn-net.ne.jp , +.An Takayasu IWANASHI Aq takayasu@wendy.a.perfect-liberty.or.jp , +.An Yoshihiko SARUMARU Aq mistral@imasy.or.jp , +.An Hiroki Sato Aq hrs@FreeBSD.org , +.An Michael Lucas Aq mwlucas@blackhelicopters.org +and +.An Michael Smith Aq 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 0000000..38844b6 --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.c @@ -0,0 +1,144 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#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]\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; + char c, *progname; + char *dsdt_input_file, *dsdt_output_file; + + dsdt_input_file = dsdt_output_file = NULL; + progname = argv[0]; + + if (argc < 2) + usage(progname); + + while ((c = getopt(argc, argv, "dhtvf:o:")) != -1) { + switch (c) { + case 'd': + dflag = 1; + 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 '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) { + if (vflag) + warnx("printing various SDT tables"); + sdt_print_all(rsdt); + } + + /* 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"); + aml_disassemble(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 0000000..c75cabd --- /dev/null +++ b/usr.sbin/acpi/acpidump/acpidump.h @@ -0,0 +1,86 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _ACPIDUMP_H_ +#define _ACPIDUMP_H_ + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/acconfig.h> +#include <contrib/dev/acpica/include/actbl1.h> + +/* 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); + +/* + * 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 *); + +/* Disassemble the AML in the DSDT */ +void aml_disassemble(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 0000000..7459e48 --- /dev/null +++ b/usr.sbin/acpi/iasl/Makefile @@ -0,0 +1,79 @@ +# $FreeBSD$ + +PROG= iasl +SRCS= adfile.c adisasm.c adwalk.c +SRCS+= osunixxf.c + +# common +SRCS+= dmextern.c dmrestag.c dmtable.c dmtbdump.c dmtbinfo.c \ + getopt.c + +# compiler +SRCS+= aslanalyze.c aslcodegen.c aslcompile.c aslcompiler.y.h \ + aslcompilerlex.l aslcompilerparse.y aslerror.c \ + aslfiles.c aslfold.c asllength.c asllisting.c \ + aslload.c asllookup.c aslmain.c aslmap.c aslopcodes.c \ + asloperands.c aslopt.c aslpredef.c aslresource.c \ + aslrestype1.c aslrestype1i.c aslrestype2.c \ + aslrestype2d.c aslrestype2e.c aslrestype2q.c \ + aslrestype2w.c aslstartup.c aslstubs.c asltransform.c \ + asltree.c aslutils.c dtcompile.c dtfield.c dtio.c \ + dtsubtable.c dttable.c dttemplate.c dtutils.c + +# debugger +SRCS+= dbfileio.c + +# disassembler +SRCS+= dmbuffer.c dmnames.c dmobject.c dmopcode.c dmresrc.c \ + dmresrcl.c dmresrcs.c dmutils.c dmwalk.c + +# interpreter/dispatcher +SRCS+= dsfield.c dsobject.c dsopcode.c dsutils.c dswexec.c \ + dswload.c dswscope.c dswstate.c + +# interpreter/executer +SRCS+= exconvrt.c excreate.c exdump.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 \ + exstore.c exstoren.c exstorob.c exsystem.c exutils.c + +# interpreter/parser +SRCS+= psargs.c psloop.c psopcode.c psparse.c psscope.c \ + pstree.c psutils.c pswalk.c + +# namespace +SRCS+= nsaccess.c nsalloc.c nsdump.c nsnames.c nsobject.c \ + nsparse.c nssearch.c nsutils.c nswalk.c nsxfobj.c + +# tables +SRCS+= tbfadt.c tbinstal.c tbutils.c tbxface.c + +# utilities +SRCS+= utalloc.c utcache.c utcopy.c utdebug.c utdelete.c \ + utglobal.c utinit.c utlock.c utmath.c utmisc.c \ + utmutex.c utobject.c utosi.c utresrc.c utstate.c \ + utxface.c + +WARNS?= 2 + +MAN= iasl.8 + +CFLAGS+= -DACPI_ASL_COMPILER -I. +CFLAGS+= -D_USE_BERKELEY_YACC +LFLAGS= -i -PAslCompiler +YFLAGS= -d -pAslCompiler +DPADD= ${LIBPTHREAD} +LDADD= -lpthread + +CLEANFILES= aslcompiler.y.h aslcompilerlex.l aslcompilerparse.y + +aslcompiler.y.h: aslcompilerparse.h + cat ${.ALLSRC} > ${.TARGET} + +aslcompilerlex.l: aslcompiler.l + cat ${.ALLSRC} > ${.TARGET} + +aslcompilerparse.y: aslcompiler.y + cat ${.ALLSRC} > ${.TARGET} + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpi/iasl/iasl.8 b/usr.sbin/acpi/iasl/iasl.8 new file mode 100644 index 0000000..bf16c8c --- /dev/null +++ b/usr.sbin/acpi/iasl/iasl.8 @@ -0,0 +1,179 @@ +.\"- +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.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 . |