Add support for decoding Buffer objects that contain PnP/ACPI resource

streams.  Since the output is bulky, it's controlled by the '-r'
option.

Document this in the manpage, and clean up some awkward English a
little.
This commit is contained in:
Mike Smith 2002-01-02 07:01:34 +00:00
parent fbeabbfad6
commit add420aa72
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88802
4 changed files with 406 additions and 28 deletions

View File

@ -37,9 +37,12 @@
.Nd dump ACPI tables
.Sh SYNOPSIS
.Nm
.Op Fl r
.Nm
.Op Fl r
.Op Fl o Ar dsdt_file_for_output
.Nm
.Op Fl r
.Op Fl f Ar dsdt_file_for_input
.Sh DESCRIPTION
The
@ -47,65 +50,68 @@ The
command analyzes ACPI tables in physical memory and dumps them to standard output.
In addition,
.Nm
can disassemble some contents of the tables in AML
can disassemble AML
(ACPI Machine Language)
and dump them in ASL
found in these tables and dump them as ASL
(ACPI Source Language).
.Pp
ACPI tables have an notably essential data block called DSDT
(Differentiated System Description Table),
ACPI tables have an essential data block (the DSDT,
Differentiated System Description Table),
that includes information used on the kernel side such as
detail information about PnP hardware, procedures for controlling
a power management support and so on.
detailed information about PnP hardware, procedures for controlling
power management support and so on.
.Nm
can extract a DSDT data block from physical memory and store it into
can extract the DSDT data block from physical memory and store it into
a DSDT data file, and also can generate an output in ASL
from a given DSDT data file.
.Pp
When
.Nm
is invoked with no option, it will search ACPI tables from physical
is invoked without the
.Fl f
option, it will read ACPI tables from physical
memory via a special file
.Pa /dev/mem
and dump them. First, it searches Root System Description Pointer,
that has a signature
and dump them. First it searches for the RSDP
(Root System Description Pointer),
which has the signature
.Qq RSD PTR\ \& ,
and then gets RSDT
and then gets the RSDT
(Root System Description Table),
which includes a list of pointers to physical memory addresses
for other tables.
RSDT itself and all other tables linked from RSDT are generically
called SDT
(System Description Table)
and their header has the common format which consists of items
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.
.Nm
dumps contents of these SDTs.
For further information about formats of each table,
see chapter 5: ACPI Software Programming Model,
.Dq Advanced Configuration and Power Interface Specification Revision 1.0b
from Intel/Microsoft/Toshiba.
see chapter 5:
.Dq ACPI Software Programming Model
from the ACPI specifications referenced below.
.Pp
There is always a pointer to a physical memory address in RSDT for FACP
(Fixed ACPI Description Table).
FACP defines static system information about power management support
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 location of ACPI registers.
FACP also has a pointer to a physical memory address for DSDT,
The FACP also has a pointer to a physical memory address for DSDT,
which includes information used on the kernel side such as
PnP, power management support and so on.
While the other tables are described in fixed format,
DSDT consists of AML data which compiled from sources
written in free formated ASL, description language for ACPI.
the DSDT consists of AML data which is compiled from sources
written in free formated ASL, which is the description language for ACPI.
When
.Nm
outputs DSDT, it disassembles the AML data and
translates them into ASL.
formats it as ASL.
.Sh OPTIONS
The following options are supported by
.Nm :
@ -118,6 +124,11 @@ in addition to behavior with no option.
Interprets AML data in DSDT from a file specified in
.Ar dsdt_file_for_input
and dumps them in ASL to standard output.
.It Fl r
Additionally outputs commented ResourceTemplate() macros for Buffer
objects that contain valid resource streams.
These macros are defined in the ACPI 2.0 specification section
16.2.4.
.It Fl h
Displays usage and exit.
.El
@ -148,7 +159,7 @@ specified by a pointer in FACP.
Intel
Microsoft
Toshiba
Revision 1.0b
Revision 1.0b, 2.0
.Ed
<URL:http://www.teleport.com/~acpi/>
.Sh AUTHORS
@ -161,8 +172,9 @@ Some contributions made by
.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 Lucas Aq mwlucas@blackhelicopters.org .
.An Michael Smith Aq msmith@freebsd.org .
.Sh HISTORY
The
.Nm

View File

@ -70,8 +70,8 @@ static void
usage(const char *progname)
{
printf("usage:\t%s [-o dsdt_file_for_output]\n", progname);
printf("\t%s [-f dsdt_file_for_input]\n", progname);
printf("usage:\t%s [-r] [-o dsdt_file_for_output]\n", progname);
printf("\t%s [-r] [-f dsdt_file_for_input]\n", progname);
printf("\t%s [-h]\n", progname);
exit(1);
}
@ -82,7 +82,7 @@ main(int argc, char *argv[])
char c, *progname;
progname = argv[0];
while ((c = getopt(argc, argv, "f:o:h")) != -1) {
while ((c = getopt(argc, argv, "f:o:hr")) != -1) {
switch (c) {
case 'f':
asl_dump_from_file(optarg);
@ -93,6 +93,9 @@ main(int argc, char *argv[])
case 'h':
usage(progname);
break;
case 'r':
rflag++;
break;
default:
argc -= optind;
argv += optind;

View File

@ -176,5 +176,6 @@ void acpi_load_dsdt(char *, u_int8_t **, u_int8_t **);
void acpi_dump_dsdt(u_int8_t *, u_int8_t *);
extern char *aml_dumpfile;
extern struct ACPIsdt dsdt_header;
extern int rflag;
#endif /* !_ACPIDUMP_H_ */

View File

@ -39,6 +39,7 @@
#include "aml/aml_env.h"
struct aml_environ asl_env;
int rflag;
static u_int32_t
asl_dump_pkglength(u_int8_t **dpp)
@ -228,6 +229,364 @@ asl_dump_defscope(u_int8_t **dpp, int indent)
*dpp = dp;
}
static void
asl_dump_resourcebuffer(u_int8_t *dp, u_int8_t *end, int indent)
{
u_int8_t *p;
int print, len, name, indep, i, ofs;
print = 0;
indep = 0;
restart:
if (print) {
printf("\n");
print_indent(indent);
printf("/* ResourceTemplate() {\n");
}
for (p = dp; p < end; ) {
ofs = p - dp;
if (*p & 0x80) { /* large resource */
if ((end - p) < 3) {
return;
}
name = *p;
len = ((int)*(p + 2) << 8) + *(p + 1);
p += 3;
} else { /* small resource */
name = (*p >> 3) & 0x0f;
len = *p & 0x7;
p++;
}
if (name == 0xf) { /* end tag */
if (print == 0) {
print = 1;
goto restart;
} else {
print_indent(indent);
printf("} */\n");
print_indent(indent);
break;
}
}
if (print) {
print_indent(indent);
switch (name) {
case 0x06:
if (indep) {
printf(" }\n");
print_indent(indent);
}
printf(" StartDependentFn(");
if (len == 1)
printf("%d, %d",
*p & 0x3,
(*p >> 2) & 0x3);
printf(") {\n");
indep = 1;
continue;
case 0x07:
if (indep)
printf(" }\n");
print_indent(indent);
printf(" EndDependentFn() {}\n");
indep = 0;
continue;
}
printf("%s 0x%-04.4x ", indep ? " " : "", ofs);
switch (name) {
case 0x04: /* IRQ() { } */
{
int i, first;
printf("IRQ(");
if (len == 3) {
printf("%s, Active%s, %s",
*(p + 2) & 0x01 ? "Edge" : "Level",
*(p + 2) & 0x08 ? "Low" : "High",
*(p + 2) & 0x10 ? "Shared" :
"Exclusive");
}
printf(")");
first = 1;
for (i = 0; i < 16; i++) {
if (*(p + (i / 8)) & (1 << (i % 8))) {
if (first) {
printf(" {");
first = 0;
} else {
printf(", ");
}
printf("%d", i);
}
}
if (!first)
printf("}");
printf("\n");
break;
}
case 0x05: /* DMA() { } */
{
int i, first;
printf("DMA(%s, %sBusMaster, Transfer%s)",
(*(p + 1) & 0x60) == 0 ? "Compatibility" :
(*(p + 1) & 0x60) == 1 ? "TypeA" :
(*(p + 1) & 0x60) == 2 ? "TypeB" : "TypeF",
*(p + 1) & 0x04 ? "" : "Not",
(*(p + 1) & 0x03) == 0 ? "8" :
(*(p + 1) & 0x03) == 1 ? "8_16" : "16");
first = 1;
for (i = 0; i < 8; i++) {
if (*p & (1 << i)) {
if (first) {
printf(" {");
first = 0;
} else {
printf(", ");
}
printf("%d", i);
}
}
if (!first)
printf("}");
printf("\n");
break;
}
case 0x08: /* IO() */
printf("IO(Decode%s, 0x%x, 0x%x, 0x%x, 0x%x)\n",
*p & 0x01 ? "16" : "10",
(int)*(u_int16_t *)(p + 1),
(int)*(u_int16_t *)(p + 3),
*(p + 5),
*(p + 6));
break;
case 0x09: /* FixedIO() */
printf("FixedIO(0x%x, 0x%x)\n",
*p + ((int)*(p + 1) << 8),
*(p + 2));
break;
case 0x0e: /* VendorShort() { }*/
case 0x84: /* VendorLong() { } */
{
int i, first;
printf("Vendor%s()", name == 0x0e ? "Short" : "Long");
first = 0;
for (i = 0; i < len; i++) {
if (first) {
printf(" {");
first = 0;
} else {
printf(", ");
}
printf("0x%02x", *(p + i));
}
if (!first)
printf("}");
printf("\n");
break;
}
case 0x81: /* Memory24() */
printf("Memory24(Read%s, 0x%06x, 0x%06x, 0x%x, 0x%x)\n",
*p & 0x01 ? "Write" : "Only",
(u_int32_t)*(u_int16_t *)(p + 1) << 8,
(u_int32_t)*(u_int16_t *)(p + 3) << 8,
(int)*(u_int16_t *)(p + 5),
(int)*(u_int16_t *)(p + 7));
break;
case 0x82: /* Register() */
printf("Register(%s, %d, %d, 0x%016llx)\n",
*p == 0x00 ? "SystemMemory" :
*p == 0x01 ? "SystemIO" :
*p == 0x02 ? "PCIConfigSpace" :
*p == 0x03 ? "EmbeddedController" :
*p == 0x04 ? "SMBus" :
*p == 0x7f ? "FunctionalFixedHardware" : "Unknown",
*(p + 1),
*(p + 2),
*(u_int64_t *)(p + 3));
break;
case 0x85: /* Memory32() */
printf("Memory32(Read%s, 0x%08x, 0x%08x, 0x%x, 0x%x)\n",
*p & 0x01 ? "Write" : "Only",
*(u_int32_t *)(p + 1),
*(u_int32_t *)(p + 5),
*(u_int32_t *)(p + 9),
*(u_int32_t *)(p + 13));
break;
case 0x86: /* Memory32Fixed() */
printf("Memory32Fixed(Read%s, 0x%08x, 0x%x)\n",
*p & 0x01 ? "Write" : "Only",
*(u_int32_t *)(p + 1),
*(u_int32_t *)(p + 5));
break;
case 0x87: /* DWordMemory() / DWordIO() */
case 0x88: /* WordMemory() / WordIO() */
case 0x8a: /* QWordMemory() / QWordIO() */
{
u_int64_t granularity, minimum, maximum, translation, length;
char *size, *source;
int index, slen;
switch (name) {
case 0x87:
size = "D";
granularity = *(u_int32_t *)(p + 3);
minimum = *(u_int32_t *)(p + 7);
maximum = *(u_int32_t *)(p + 11);
translation = *(u_int32_t *)(p + 15);
length = *(u_int32_t *)(p + 19);
index = *(p + 23);
source = p + 24;
slen = len - 24;
break;
case 0x88:
size = "";
granularity = *(u_int16_t *)(p + 3);
minimum = *(u_int16_t *)(p + 5);
maximum = *(u_int16_t *)(p + 7);
translation = *(u_int16_t *)(p + 9);
length = *(u_int16_t *)(p + 11);
index = *(p + 13);
source = p + 14;
slen = len - 14;
break;
case 0x8a:
size = "Q";
granularity = *(u_int64_t *)(p + 3);
minimum = *(u_int64_t *)(p + 11);
maximum = *(u_int64_t *)(p + 19);
translation = *(u_int64_t *)(p + 27);
length = *(u_int64_t *)(p + 35);
index = *(p + 43);
source = p + 44;
slen = len - 44;
break;
}
switch(*p) {
case 0:
printf("%sWordMemory("
"Resource%s, "
"%sDecode, "
"Min%sFixed, "
"Max%sFixed, "
"%s, "
"Read%s, "
"0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx, "
"%d, '%.*s', "
"AddressRange%s, "
"Type%s)\n",
size,
*(p + 1) & 0x01 ? "Consumer" : "Producer",
*(p + 1) & 0x02 ? "Sub" : "Pos",
*(p + 1) & 0x04 ? "" : "Not",
*(p + 1) & 0x08 ? "" : "Not",
(*(p + 2) >> 1) == 0 ? "NonCacheable" :
(*(p + 2) >> 1) == 1 ? "Cacheable" :
(*(p + 2) >> 1) == 2 ? "WriteCombining" :
"Prefetchable",
*(p + 2) & 0x01 ? "Write" : "Only",
granularity, minimum, maximum, translation, length,
index, slen, source,
((*(p + 2) >> 3) & 0x03) == 0 ? "Memory" :
((*(p + 2) >> 3) & 0x03) == 1 ? "Reserved" :
((*(p + 2) >> 3) & 0x03) == 2 ? "ACPI" : "NVS",
*(p + 2) & 0x20 ? "Translation" : "Static");
break;
case 1:
printf("%sWordIO("
"Resource%s, "
"Min%sFixed, "
"Max%sFixed, "
"%sDecode, "
"%s, "
"0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx, "
"%d, '%.*s', "
"Type%s, "
"%sTranslation)\n",
size,
*(p + 1) & 0x01 ? "Consumer" : "Producer",
*(p + 1) & 0x04 ? "" : "Not",
*(p + 1) & 0x08 ? "" : "Not",
*(p + 1) & 0x02 ? "Sub" : "Pos",
(*(p + 2) & 0x03) == 0 ? "EntireRange" :
(*(p + 2) & 0x03) == 1 ? "NonISAOnlyRanges" :
(*(p + 2) & 0x03) == 2 ? "ISAOnlyRanges" : "EntireRange",
granularity, minimum, maximum, translation, length,
index, slen, source,
*(p + 2) & 0x10 ? "Translation" : "Static",
*(p + 2) & 0x20 ? "Sparse" : "Dense");
break;
case 2:
printf("%sWordBus("
"Resource%s, "
"%sDecode, "
"Min%sFixed, "
"Max%sFixed, "
"0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx, "
"%d, '%.*s')\n",
size,
*(p + 1) & 0x01 ? "Consumer" : "Producer",
*(p + 1) & 0x02 ? "Sub" : "Pos",
*(p + 1) & 0x04 ? "" : "Not",
*(p + 1) & 0x08 ? "" : "Not",
granularity, minimum, maximum, translation, length,
index, slen, source);
break;
default:
printf("%sWordUnknown()\n", size);
}
break;
}
case 0x89: /* Interrupt() { } */
{
int i, first, pad, sl;
char *rp;
pad = *(p + 1) * 4;
rp = p + 1 + pad;
sl = len - pad - 3;
printf("Interrupt(Resource%s, %s, Active%s, %s, %d, %.*s)",
*p & 0x01 ? "Producer" : "Consumer",
*p & 0x02 ? "Edge" : "Level",
*p & 0x04 ? "Low" : "High",
*p & 0x08 ? "Shared" : "Exclusive",
(int)*(p + 1 + pad),
sl,
rp);
first = 1;
for (i = 0; i < *(p + 1); i++) {
if (first) {
printf(" {");
first = 0;
} else {
printf(", ");
}
printf("%u", *(u_int32_t *)(p + 2 + (i * 4)));
}
if (!first)
printf("}");
printf("\n");
break;
}
default:
printf("Unknown(0x%x, %d)\n", name, len);
break;
}
}
p += len;
}
}
static void
asl_dump_defbuffer(u_int8_t **dpp, int indent)
{
@ -242,12 +601,15 @@ asl_dump_defbuffer(u_int8_t **dpp, int indent)
end = start + pkglength;
printf("Buffer(");
asl_dump_termobj(&dp, indent);
start = dp;
printf(") {");
while (dp < end) {
printf("0x%x", *dp++);
if (dp < end)
printf(", ");
}
if (rflag)
asl_dump_resourcebuffer(start, end, indent);
printf(" }");
*dpp = dp;