acpi.c revision 120309
1161475Sdelphij/*-
260786Sps * Copyright (c) 1998 Doug Rabson
360786Sps * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
460786Sps * All rights reserved.
5170256Sdelphij *
660786Sps * Redistribution and use in source and binary forms, with or without
760786Sps * modification, are permitted provided that the following conditions
8170256Sdelphij * are met:
9170256Sdelphij * 1. Redistributions of source code must retain the above copyright
10170256Sdelphij *    notice, this list of conditions and the following disclaimer.
11170256Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12170256Sdelphij *    notice, this list of conditions and the following disclaimer in the
13170256Sdelphij *    documentation and/or other materials provided with the distribution.
14170256Sdelphij *
15170256Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16170256Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17170256Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18161475Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19161475Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2060786Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2160786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22170256Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23170256Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24170256Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25161475Sdelphij * SUCH DAMAGE.
26170256Sdelphij *
27161475Sdelphij *	$FreeBSD: head/usr.sbin/acpi/acpidump/acpi.c 120309 2003-09-21 03:51:48Z njl $
28161475Sdelphij */
29161475Sdelphij
30161475Sdelphij#include <sys/param.h>
3160786Sps#include <sys/endian.h>
32170256Sdelphij#include <sys/stat.h>
33161475Sdelphij#include <sys/wait.h>
34161475Sdelphij#include <assert.h>
3560786Sps#include <err.h>
3660786Sps#include <fcntl.h>
37170256Sdelphij#include <stdio.h>
38161475Sdelphij#include <string.h>
39161475Sdelphij#include <unistd.h>
40161475Sdelphij
4160786Sps#include "acpidump.h"
42161475Sdelphij
43161475Sdelphij#define BEGIN_COMMENT	"/*\n"
4460786Sps#define END_COMMENT	" */\n"
4560786Sps
46161475Sdelphijstatic void	acpi_print_string(char *s, size_t length);
47161475Sdelphijstatic void	acpi_print_gas(struct ACPIgas *gas);
48161475Sdelphijstatic void	acpi_handle_fadt(struct FADTbody *fadt);
49161475Sdelphijstatic void	acpi_print_cpu(u_char cpu_id);
5060786Spsstatic void	acpi_print_local_apic(u_char cpu_id, u_char apic_id,
51161475Sdelphij				      u_int32_t flags);
52161475Sdelphijstatic void	acpi_print_io_apic(u_char apic_id, u_int32_t int_base,
5360786Sps				   u_int64_t apic_addr);
5460786Spsstatic void	acpi_print_mps_flags(u_int16_t flags);
55161475Sdelphijstatic void	acpi_print_intr(u_int32_t intr, u_int16_t mps_flags);
56161475Sdelphijstatic void	acpi_print_apic(struct MADT_APIC *mp);
5760786Spsstatic void	acpi_handle_apic(struct ACPIsdt *sdp);
5860786Spsstatic void	acpi_handle_hpet(struct ACPIsdt *sdp);
59161475Sdelphijstatic void	acpi_print_sdt(struct ACPIsdt *sdp);
60161475Sdelphijstatic void	acpi_print_fadt(struct FADTbody *fadt);
6160786Spsstatic void	acpi_print_facs(struct FACSbody *facs);
6260786Spsstatic void	acpi_print_dsdt(struct ACPIsdt *dsdp);
63161475Sdelphijstatic struct ACPIsdt *acpi_map_sdt(vm_offset_t pa);
64161475Sdelphijstatic void	acpi_print_rsd_ptr(struct ACPIrsdp *rp);
65161475Sdelphijstatic void	acpi_handle_rsdt(struct ACPIsdt *rsdp);
6660786Sps
6760786Sps/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */
68161475Sdelphijstatic int addr_size;
69161475Sdelphij
70161475Sdelphijstatic void
7160786Spsacpi_print_string(char *s, size_t length)
72161475Sdelphij{
73161475Sdelphij	int	c;
7460786Sps
7560786Sps	/* Trim trailing spaces and NULLs */
76161475Sdelphij	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
77161475Sdelphij		length--;
78161475Sdelphij
7960786Sps	while (length--) {
8060786Sps		c = *s++;
81161475Sdelphij		putchar(c);
82161475Sdelphij	}
83161475Sdelphij}
8460786Sps
8560786Spsstatic void
86161475Sdelphijacpi_print_gas(struct ACPIgas *gas)
87161475Sdelphij{
88161475Sdelphij	switch(gas->address_space_id) {
89161475Sdelphij	case ACPI_GAS_MEMORY:
9089019Sps		printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->address,
9160786Sps		       gas->bit_offset, gas->bit_width);
9260786Sps		break;
93161475Sdelphij	case ACPI_GAS_IO:
94161475Sdelphij		printf("0x%02lx:%u[%u] (IO)", (u_long)gas->address,
95161475Sdelphij		       gas->bit_offset, gas->bit_width);
96161475Sdelphij		break;
9760786Sps	case ACPI_GAS_PCI:
9860786Sps		printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->address >> 32),
9960786Sps		       (uint16_t)((gas->address >> 16) & 0xffff),
10060786Sps		       (uint16_t)gas->address);
101161475Sdelphij		break;
102161475Sdelphij	/* XXX How to handle these below? */
10360786Sps	case ACPI_GAS_EMBEDDED:
104161475Sdelphij		printf("0x%x:%u[%u] (EC)", (uint16_t)gas->address,
105161475Sdelphij		       gas->bit_offset, gas->bit_width);
106161475Sdelphij		break;
107161475Sdelphij	case ACPI_GAS_SMBUS:
10860786Sps		printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->address,
10960786Sps		       gas->bit_offset, gas->bit_width);
11060786Sps		break;
111161475Sdelphij	case ACPI_GAS_FIXED:
112161475Sdelphij	default:
11360786Sps		printf("0x%08lx (?)", (u_long)gas->address);
11460786Sps		break;
115161475Sdelphij	}
116161475Sdelphij}
117161475Sdelphij
11860786Spsstatic void
119161475Sdelphijacpi_handle_fadt(struct FADTbody *fadt)
120170256Sdelphij{
12160786Sps	struct ACPIsdt	*dsdp;
122170256Sdelphij	struct FACSbody	*facs;
123170256Sdelphij
124161475Sdelphij	acpi_print_fadt(fadt);
125161475Sdelphij
126161475Sdelphij	/*
127161475Sdelphij	 * My T23 is revision 2 but the 64 bit addresses are invalid.
128161475Sdelphij	 * If revision 2 and the 32 bit address is non-zero but the 32
129161475Sdelphij	 * and 64 bit versions don't match, prefer the 32 bit version.
13060786Sps	 */
131161475Sdelphij	if (addr_size == 4 ||
132161475Sdelphij	    (addr_size == 8 && fadt->facs_ptr != 0 &&
133161475Sdelphij	    (fadt->x_facs_ptr & 0xffffffff) != fadt->facs_ptr))
134161475Sdelphij		facs = (struct FACSbody *)acpi_map_sdt(fadt->facs_ptr);
135161475Sdelphij	else
136161475Sdelphij		facs = (struct FACSbody *)acpi_map_sdt(fadt->x_facs_ptr);
13760786Sps	if (memcmp(facs->signature, "FACS", 4) != 0 || facs->len < 64)
138161475Sdelphij		errx(1, "FACS is corrupt");
13960786Sps	acpi_print_facs(facs);
140161475Sdelphij
14160786Sps	if (addr_size == 4 ||
142161475Sdelphij	    (addr_size == 8 && fadt->dsdt_ptr != 0 &&
143161475Sdelphij	    (fadt->x_dsdt_ptr & 0xffffffff) != fadt->dsdt_ptr))
14460786Sps		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
145161475Sdelphij	else
146161475Sdelphij		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
14760786Sps	if (acpi_checksum(dsdp, dsdp->len))
148161475Sdelphij		errx(1, "DSDT is corrupt");
149161475Sdelphij	acpi_print_dsdt(dsdp);
150161475Sdelphij}
151161475Sdelphij
15260786Spsstatic void
153161475Sdelphijacpi_print_cpu(u_char cpu_id)
154161475Sdelphij{
155161475Sdelphij
156161475Sdelphij	printf("\tACPI CPU=");
15760786Sps	if (cpu_id == 0xff)
158161475Sdelphij		printf("ALL\n");
159161475Sdelphij	else
16060786Sps		printf("%d\n", (u_int)cpu_id);
161161475Sdelphij}
162161475Sdelphij
163161475Sdelphijstatic void
164161475Sdelphijacpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags)
165161475Sdelphij{
166161475Sdelphij	acpi_print_cpu(cpu_id);
167161475Sdelphij	printf("\tFlags={");
16860786Sps	if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
16960786Sps		printf("ENABLED");
17060786Sps	else
17160786Sps		printf("DISABLED");
172161475Sdelphij	printf("}\n");
173161475Sdelphij	printf("\tAPIC ID=%d\n", (u_int)apic_id);
174161475Sdelphij}
175161475Sdelphij
17660786Spsstatic void
17760786Spsacpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr)
178161475Sdelphij{
179161475Sdelphij	printf("\tAPIC ID=%d\n", (u_int)apic_id);
180161475Sdelphij	printf("\tINT BASE=%d\n", int_base);
18160786Sps	printf("\tADDR=0x%016jx\n", apic_addr);
18260786Sps}
183161475Sdelphij
18460786Spsstatic void
18560786Spsacpi_print_mps_flags(u_int16_t flags)
186161475Sdelphij{
187161475Sdelphij
188161475Sdelphij	printf("\tFlags={Polarity=");
18960786Sps	switch (flags & MPS_INT_FLAG_POLARITY_MASK) {
19060786Sps	case MPS_INT_FLAG_POLARITY_CONFORM:
19160786Sps		printf("conforming");
192161475Sdelphij		break;
193161475Sdelphij	case MPS_INT_FLAG_POLARITY_HIGH:
194161475Sdelphij		printf("active-hi");
19560786Sps		break;
19660786Sps	case MPS_INT_FLAG_POLARITY_LOW:
197161475Sdelphij		printf("active-lo");
198170256Sdelphij		break;
199170256Sdelphij	default:
20060786Sps		printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK);
201161475Sdelphij		break;
202161475Sdelphij	}
20360786Sps	printf(", Trigger=");
20463128Sps	switch (flags & MPS_INT_FLAG_TRIGGER_MASK) {
205161475Sdelphij	case MPS_INT_FLAG_TRIGGER_CONFORM:
206161475Sdelphij		printf("conforming");
207161475Sdelphij		break;
20863128Sps	case MPS_INT_FLAG_TRIGGER_EDGE:
20960786Sps		printf("edge");
21060786Sps		break;
21160786Sps	case MPS_INT_FLAG_TRIGGER_LEVEL:
212161475Sdelphij		printf("level");
21360786Sps		break;
21460786Sps	default:
215161475Sdelphij		printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2);
216161475Sdelphij	}
217161475Sdelphij	printf("}\n");
218161475Sdelphij}
21960786Sps
22060786Spsstatic void
221161475Sdelphijacpi_print_intr(u_int32_t intr, u_int16_t mps_flags)
222161475Sdelphij{
223161475Sdelphij
22460786Sps	printf("\tINTR=%d\n", (u_int)intr);
22560786Sps	acpi_print_mps_flags(mps_flags);
22660786Sps}
22760786Sps
22860786Spsconst char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI",
22960786Sps			     "Local NMI", "Local APIC Override", "IO SAPIC",
23060786Sps			     "Local SAPIC", "Platform Interrupt" };
23160786Spsconst char *platform_int_types[] = { "PMI", "INIT",
23260786Sps				     "Corrected Platform Error" };
23360786Sps
23460786Spsstatic void
23560786Spsacpi_print_apic(struct MADT_APIC *mp)
236161475Sdelphij{
237161475Sdelphij
238161475Sdelphij	printf("\tType=%s\n", apic_types[mp->type]);
239161475Sdelphij	switch (mp->type) {
240161475Sdelphij	case ACPI_MADT_APIC_TYPE_LOCAL_APIC:
241161475Sdelphij		acpi_print_local_apic(mp->body.local_apic.cpu_id,
242161475Sdelphij		    mp->body.local_apic.apic_id, mp->body.local_apic.flags);
243161475Sdelphij		break;
24460786Sps	case ACPI_MADT_APIC_TYPE_IO_APIC:
245161475Sdelphij		acpi_print_io_apic(mp->body.io_apic.apic_id,
24660786Sps		    mp->body.io_apic.int_base,
247161475Sdelphij		    mp->body.io_apic.apic_addr);
248161475Sdelphij		break;
24960786Sps	case ACPI_MADT_APIC_TYPE_INT_OVERRIDE:
250161475Sdelphij		printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus);
251161475Sdelphij		printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source);
25260786Sps		acpi_print_intr(mp->body.int_override.intr,
253161475Sdelphij		    mp->body.int_override.mps_flags);
254161475Sdelphij		break;
255161475Sdelphij	case ACPI_MADT_APIC_TYPE_NMI:
256161475Sdelphij		acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags);
257161475Sdelphij		break;
258161475Sdelphij	case ACPI_MADT_APIC_TYPE_LOCAL_NMI:
25960786Sps		acpi_print_cpu(mp->body.local_nmi.cpu_id);
26060786Sps		printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin);
261161475Sdelphij		acpi_print_mps_flags(mp->body.local_nmi.mps_flags);
262161475Sdelphij		break;
263161475Sdelphij	case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE:
264161475Sdelphij		printf("\tLocal APIC ADDR=0x%016jx\n",
265161475Sdelphij		    mp->body.local_apic_override.apic_addr);
266161475Sdelphij		break;
267161475Sdelphij	case ACPI_MADT_APIC_TYPE_IO_SAPIC:
268161475Sdelphij		acpi_print_io_apic(mp->body.io_sapic.apic_id,
269161475Sdelphij		    mp->body.io_sapic.int_base,
270161475Sdelphij		    mp->body.io_sapic.apic_addr);
271161475Sdelphij		break;
272161475Sdelphij	case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC:
273161475Sdelphij		acpi_print_local_apic(mp->body.local_sapic.cpu_id,
274161475Sdelphij		    mp->body.local_sapic.apic_id, mp->body.local_sapic.flags);
275161475Sdelphij		printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid);
27660786Sps		break;
27760786Sps	case ACPI_MADT_APIC_TYPE_INT_SRC:
278161475Sdelphij		printf("\tType=%s\n",
279161475Sdelphij		    platform_int_types[mp->body.int_src.type]);
280161475Sdelphij		printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id);
28160786Sps		printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id);
282161475Sdelphij		printf("\tSAPIC Vector=%d\n",
283161475Sdelphij		    (u_int)mp->body.int_src.sapic_vector);
284161475Sdelphij		acpi_print_intr(mp->body.int_src.intr,
28560786Sps		    mp->body.int_src.mps_flags);
286161475Sdelphij		break;
287161475Sdelphij	default:
28860786Sps		printf("\tUnknown type %d\n", (u_int)mp->type);
289161475Sdelphij		break;
290161475Sdelphij	}
29160786Sps}
29260786Sps
29360786Spsstatic void
294161475Sdelphijacpi_handle_apic(struct ACPIsdt *sdp)
295161475Sdelphij{
29660786Sps	struct MADTbody *madtp;
297161475Sdelphij	struct MADT_APIC *madt_apicp;
298161475Sdelphij
29960786Sps	printf(BEGIN_COMMENT);
30089019Sps	acpi_print_sdt(sdp);
301161475Sdelphij	madtp = (struct MADTbody *) sdp->body;
302161475Sdelphij	printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr);
303161475Sdelphij	printf("\tFlags={");
304161475Sdelphij	if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT)
305161475Sdelphij		printf("PC-AT");
30660786Sps	printf("}\n");
307161475Sdelphij	madt_apicp = (struct MADT_APIC *)madtp->body;
308161475Sdelphij	while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) {
309161475Sdelphij		printf("\n");
310161475Sdelphij		acpi_print_apic(madt_apicp);
311161475Sdelphij		madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp +
312161475Sdelphij		    madt_apicp->len);
313161475Sdelphij	}
314161475Sdelphij	printf(END_COMMENT);
315161475Sdelphij}
31660786Sps
317161475Sdelphijstatic void
318161475Sdelphijacpi_handle_hpet(struct ACPIsdt *sdp)
319161475Sdelphij{
320161475Sdelphij	struct HPETbody *hpetp;
321161475Sdelphij
32260786Sps	printf(BEGIN_COMMENT);
323161475Sdelphij	acpi_print_sdt(sdp);
324161475Sdelphij	hpetp = (struct HPETbody *) sdp->body;
325170256Sdelphij	printf("\tHPET Number=%d\n", hpetp->hpet_number);
326170256Sdelphij	printf("\tADDR=0x%08x\n", hpetp->base_addr);
32760786Sps	printf("\tHW Rev=0x%x\n", hpetp->block_hwrev);
32860786Sps	printf("\tComparitors=%d\n", hpetp->block_comparitors);
329161475Sdelphij	printf("\tCounter Size=%d\n", hpetp->block_counter_size);
330161475Sdelphij	printf("\tLegacy IRQ routing capable={");
33160786Sps	if (hpetp->block_legacy_capable)
332161475Sdelphij		printf("TRUE}\n");
333161475Sdelphij	else
334161475Sdelphij		printf("FALSE}\n");
335161475Sdelphij	printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor);
33660786Sps	printf("\tMinimal Tick=%d\n", hpetp->clock_tick);
337161475Sdelphij	printf(END_COMMENT);
338161475Sdelphij}
33960786Sps
340161475Sdelphijstatic void
341161475Sdelphijacpi_handle_ecdt(struct ACPIsdt *sdp)
342161475Sdelphij{
34360786Sps	struct ECDTbody *ecdt;
344161475Sdelphij
345161475Sdelphij	printf(BEGIN_COMMENT);
346161475Sdelphij	acpi_print_sdt(sdp);
34760786Sps	ecdt = (struct ECDTbody *) sdp->body;
348161475Sdelphij	printf("\tEC_CONTROL=");
349170256Sdelphij	acpi_print_gas(&ecdt->ec_control);
350161475Sdelphij	printf("\n\tEC_DATA=");
35160786Sps	acpi_print_gas(&ecdt->ec_data);
352170256Sdelphij	printf("\n\tUID=%#x, ", ecdt->uid);
35360786Sps	printf("GPE_BIT=%#x\n", ecdt->gpe_bit);
35460786Sps	printf("\tEC_ID=%s\n", ecdt->ec_id);
355170256Sdelphij	printf(END_COMMENT);
35660786Sps}
357161475Sdelphij
358161475Sdelphijstatic void
35960786Spsacpi_print_sdt(struct ACPIsdt *sdp)
36060786Sps{
361161475Sdelphij	printf("  ");
362161475Sdelphij	acpi_print_string(sdp->signature, 4);
363161475Sdelphij	printf(": Length=%d, Revision=%d, Checksum=%d,\n",
364161475Sdelphij	       sdp->len, sdp->rev, sdp->check);
36560786Sps	printf("\tOEMID=");
36660786Sps	acpi_print_string(sdp->oemid, 6);
36760786Sps	printf(", OEM Table ID=");
368161475Sdelphij	acpi_print_string(sdp->oemtblid, 8);
369161475Sdelphij	printf(", OEM Revision=0x%x,\n", sdp->oemrev);
370161475Sdelphij	printf("\tCreator ID=");
371161475Sdelphij	acpi_print_string(sdp->creator, 4);
372161475Sdelphij	printf(", Creator Revision=0x%x\n", sdp->crerev);
373161475Sdelphij}
374161475Sdelphij
375161475Sdelphijstatic void
37660786Spsacpi_print_rsdt(struct ACPIsdt *rsdp)
37760786Sps{
378161475Sdelphij	int	i, entries;
379161475Sdelphij	u_long	addr;
380161475Sdelphij
381161475Sdelphij	printf(BEGIN_COMMENT);
382161475Sdelphij	acpi_print_sdt(rsdp);
383161475Sdelphij	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
38460786Sps	printf("\tEntries={ ");
38560786Sps	for (i = 0; i < entries; i++) {
386161475Sdelphij		if (i > 0)
387161475Sdelphij			printf(", ");
38860786Sps		switch (addr_size) {
38960786Sps		case 4:
390170256Sdelphij			addr = le32dec((char*)rsdp->body + i * addr_size);
391161475Sdelphij			break;
392170256Sdelphij		case 8:
39389019Sps			addr = le64dec((char*)rsdp->body + i * addr_size);
394161475Sdelphij			break;
395161475Sdelphij		default:
396161475Sdelphij			addr = 0;
397161475Sdelphij		}
398161475Sdelphij		assert(addr != 0);
399161475Sdelphij		printf("0x%08lx", addr);
400170256Sdelphij	}
401170256Sdelphij	printf(" }\n");
402170256Sdelphij	printf(END_COMMENT);
40360786Sps}
404161475Sdelphij
405170256Sdelphijstatic const char *acpi_pm_profiles[] = {
406170256Sdelphij	"Unspecified", "Desktop", "Mobile", "Workstation",
40760786Sps	"Enterprise Server", "SOHO Server", "Appliance PC"
40860786Sps};
40960786Sps
410170256Sdelphijstatic void
41160786Spsacpi_print_fadt(struct FADTbody *fadt)
41260786Sps{
41360786Sps	const char *pm;
414161475Sdelphij	char	    sep;
415161475Sdelphij
41660786Sps	printf(BEGIN_COMMENT);
417161475Sdelphij	printf("  FADT:\tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr,
418161475Sdelphij	       fadt->dsdt_ptr);
419161475Sdelphij	printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC");
420161475Sdelphij	if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *))
42160786Sps		pm = "Reserved";
422161475Sdelphij	else
423161475Sdelphij		pm = acpi_pm_profiles[fadt->pm_profile];
424161475Sdelphij	printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile);
425161475Sdelphij	printf("\tSCI_INT=%d\n", fadt->sci_int);
42660786Sps	printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd);
42760786Sps	printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable);
42860786Sps	printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable);
42960786Sps	printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq);
43060786Sps	printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt);
431170256Sdelphij	printf("\tPM1a_EVT_BLK=0x%x-0x%x\n",
432161475Sdelphij	       fadt->pm1a_evt_blk,
433161475Sdelphij	       fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1);
434161475Sdelphij	if (fadt->pm1b_evt_blk != 0)
43560786Sps		printf("\tPM1b_EVT_BLK=0x%x-0x%x\n",
43660786Sps		       fadt->pm1b_evt_blk,
437161475Sdelphij		       fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1);
438161475Sdelphij	printf("\tPM1a_CNT_BLK=0x%x-0x%x\n",
439161475Sdelphij	       fadt->pm1a_cnt_blk,
440161475Sdelphij	       fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1);
44160786Sps	if (fadt->pm1b_cnt_blk != 0)
442170256Sdelphij		printf("\tPM1b_CNT_BLK=0x%x-0x%x\n",
443170256Sdelphij		       fadt->pm1b_cnt_blk,
444161475Sdelphij		       fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1);
445161475Sdelphij	if (fadt->pm2_cnt_blk != 0)
446170256Sdelphij		printf("\tPM2_CNT_BLK=0x%x-0x%x\n",
447170256Sdelphij		       fadt->pm2_cnt_blk,
448161475Sdelphij		       fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1);
449161475Sdelphij	printf("\tPM_TMR_BLK=0x%x-0x%x\n",
45063128Sps	       fadt->pm_tmr_blk,
45160786Sps	       fadt->pm_tmr_blk + fadt->pm_tmr_len - 1);
452161475Sdelphij	if (fadt->gpe0_blk != 0)
453161475Sdelphij		printf("\tGPE0_BLK=0x%x-0x%x\n",
454161475Sdelphij		       fadt->gpe0_blk,
455161475Sdelphij		       fadt->gpe0_blk + fadt->gpe0_len - 1);
456161475Sdelphij	if (fadt->gpe1_blk != 0)
457161475Sdelphij		printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
458161475Sdelphij		       fadt->gpe1_blk,
459161475Sdelphij		       fadt->gpe1_blk + fadt->gpe1_len - 1,
460128345Stjr		       fadt->gpe1_base);
46160786Sps	if (fadt->cst_cnt != 0)
46260786Sps		printf("\tCST_CNT=0x%x\n", fadt->cst_cnt);
463161475Sdelphij	printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n",
464161475Sdelphij	       fadt->p_lvl2_lat, fadt->p_lvl3_lat);
465161475Sdelphij	printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
46660786Sps	       fadt->flush_size, fadt->flush_stride);
46760786Sps	printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
468170256Sdelphij	       fadt->duty_off, fadt->duty_width);
46960786Sps	printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
47060786Sps	       fadt->day_alrm, fadt->mon_alrm, fadt->century);
471161475Sdelphij
472170256Sdelphij#define PRINTFLAG(var, flag) do {			\
473161475Sdelphij	if ((var) & FADT_FLAG_## flag) {		\
474170256Sdelphij		printf("%c%s", sep, #flag); sep = ',';	\
475128345Stjr	}						\
47660786Sps} while (0)
477170256Sdelphij
478170256Sdelphij	printf("\tIAPC_BOOT_ARCH=");
479170256Sdelphij	sep = '{';
480170256Sdelphij	PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV);
481170256Sdelphij	PRINTFLAG(fadt->iapc_boot_arch, 8042);
482170256Sdelphij	if (fadt->iapc_boot_arch != 0)
483170256Sdelphij		printf("}\n");
484170256Sdelphij
48560786Sps	printf("\tFlags=");
486128345Stjr	sep = '{';
487170256Sdelphij	PRINTFLAG(fadt->flags, WBINVD);
488170256Sdelphij	PRINTFLAG(fadt->flags, WBINVD_FLUSH);
489161475Sdelphij	PRINTFLAG(fadt->flags, PROC_C1);
49063128Sps	PRINTFLAG(fadt->flags, P_LVL2_UP);
49189019Sps	PRINTFLAG(fadt->flags, PWR_BUTTON);
492170256Sdelphij	PRINTFLAG(fadt->flags, SLP_BUTTON);
493161475Sdelphij	PRINTFLAG(fadt->flags, FIX_RTC);
49460786Sps	PRINTFLAG(fadt->flags, RTC_S4);
49563128Sps	PRINTFLAG(fadt->flags, TMR_VAL_EXT);
496161475Sdelphij	PRINTFLAG(fadt->flags, DCK_CAP);
497170256Sdelphij	PRINTFLAG(fadt->flags, RESET_REG);
498170256Sdelphij	PRINTFLAG(fadt->flags, SEALED_CASE);
499170256Sdelphij	PRINTFLAG(fadt->flags, HEADLESS);
500170256Sdelphij	PRINTFLAG(fadt->flags, CPU_SW_SLP);
50160786Sps	if (fadt->flags != 0)
50260786Sps		printf("}\n");
503170256Sdelphij
504161475Sdelphij#undef PRINTFLAG
50560786Sps
50660786Sps	if (fadt->flags & FADT_FLAG_RESET_REG) {
507170256Sdelphij		printf("\tRESET_REG=");
508161475Sdelphij		acpi_print_gas(&fadt->reset_reg);
509161475Sdelphij		printf(", RESET_VALUE=%#x\n", fadt->reset_value);
510170256Sdelphij	}
511161475Sdelphij	if (addr_size == 8) {
51260786Sps		printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr);
51360786Sps		printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr);
514161475Sdelphij		printf("\tX_PM1a_EVT_BLK=");
515161475Sdelphij		acpi_print_gas(&fadt->x_pm1a_evt_blk);
51660786Sps		if (fadt->x_pm1b_evt_blk.address != 0) {
517170256Sdelphij			printf("\n\tX_PM1b_EVT_BLK=");
518161475Sdelphij			acpi_print_gas(&fadt->x_pm1b_evt_blk);
519170256Sdelphij		}
520161475Sdelphij		printf("\n\tX_PM1a_CNT_BLK=");
521161475Sdelphij		acpi_print_gas(&fadt->x_pm1a_cnt_blk);
52260786Sps		if (fadt->x_pm1b_cnt_blk.address != 0) {
52360786Sps			printf("\n\tX_PM1b_CNT_BLK=");
524161475Sdelphij			acpi_print_gas(&fadt->x_pm1b_cnt_blk);
525161475Sdelphij		}
526161475Sdelphij		if (fadt->x_pm1b_cnt_blk.address != 0) {
527161475Sdelphij			printf("\n\tX_PM2_CNT_BLK=");
528161475Sdelphij			acpi_print_gas(&fadt->x_pm2_cnt_blk);
52960786Sps		}
53060786Sps		printf("\n\tX_PM_TMR_BLK=");
531161475Sdelphij		acpi_print_gas(&fadt->x_pm_tmr_blk);
532161475Sdelphij		if (fadt->x_gpe0_blk.address != 0) {
53360786Sps			printf("\n\tX_GPE0_BLK=");
534170256Sdelphij			acpi_print_gas(&fadt->x_gpe0_blk);
535161475Sdelphij		}
536161475Sdelphij		if (fadt->x_gpe1_blk.address != 0) {
537161475Sdelphij			printf("\n\tX_GPE1_BLK=");
538170256Sdelphij			acpi_print_gas(&fadt->x_gpe1_blk);
539170256Sdelphij		}
540161475Sdelphij		printf("\n");
541161475Sdelphij	}
542170256Sdelphij
543170256Sdelphij	printf(END_COMMENT);
544170256Sdelphij}
545170256Sdelphij
546170256Sdelphijstatic void
547170256Sdelphijacpi_print_facs(struct FACSbody *facs)
548170256Sdelphij{
549170256Sdelphij	printf(BEGIN_COMMENT);
550170256Sdelphij	printf("  FACS:\tLength=%u, ", facs->len);
551170256Sdelphij	printf("HwSig=0x%08x, ", facs->hw_sig);
552170256Sdelphij	printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec);
55360786Sps
55463128Sps	printf("\tGlobal_Lock=");
555161475Sdelphij	if (facs->global_lock != 0) {
556161475Sdelphij		if (facs->global_lock & FACS_FLAG_LOCK_PENDING)
557161475Sdelphij			printf("PENDING,");
558161475Sdelphij		if (facs->global_lock & FACS_FLAG_LOCK_OWNED)
55963128Sps			printf("OWNED");
560170256Sdelphij	}
561170256Sdelphij	printf("\n");
562161475Sdelphij
563161475Sdelphij	printf("\tFlags=");
564161475Sdelphij	if (facs->flags & FACS_FLAG_S4BIOS_F)
565170256Sdelphij		printf("S4BIOS");
56660786Sps	printf("\n");
567161475Sdelphij
568170256Sdelphij	if (facs->x_firm_wake_vec != 0) {
569161475Sdelphij		printf("\tX_Firm_Wake_Vec=%08lx\n",
570170256Sdelphij		       (u_long)facs->x_firm_wake_vec);
571161475Sdelphij	}
572161475Sdelphij	printf("\tVersion=%u\n", facs->version);
573128345Stjr
574161475Sdelphij	printf(END_COMMENT);
575170256Sdelphij}
576161475Sdelphij
577161475Sdelphijstatic void
578128345Stjracpi_print_dsdt(struct ACPIsdt *dsdp)
57960786Sps{
580170256Sdelphij	printf(BEGIN_COMMENT);
581170256Sdelphij	acpi_print_sdt(dsdp);
58260786Sps	printf(END_COMMENT);
58360786Sps}
584170256Sdelphij
58560786Spsint
58660786Spsacpi_checksum(void *p, size_t length)
587161475Sdelphij{
588170256Sdelphij	u_int8_t	*bp;
589161475Sdelphij	u_int8_t	sum;
590161475Sdelphij
591161475Sdelphij	bp = p;
592161475Sdelphij	sum = 0;
593161475Sdelphij	while (length--)
594161475Sdelphij		sum += *bp++;
59560786Sps
596128345Stjr	return (sum);
597161475Sdelphij}
598161475Sdelphij
59960786Spsstatic struct ACPIsdt *
600170256Sdelphijacpi_map_sdt(vm_offset_t pa)
601170256Sdelphij{
602161475Sdelphij	struct	ACPIsdt *sp;
603170256Sdelphij
604161475Sdelphij	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
60560786Sps	sp = acpi_map_physical(pa, sp->len);
606170256Sdelphij	return (sp);
607161475Sdelphij}
608161475Sdelphij
60960786Spsstatic void
610161475Sdelphijacpi_print_rsd_ptr(struct ACPIrsdp *rp)
611170256Sdelphij{
612161475Sdelphij	printf(BEGIN_COMMENT);
613170256Sdelphij	printf("  RSD PTR: OEM=");
61463128Sps	acpi_print_string(rp->oem, 6);
615170256Sdelphij	printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x",
616161475Sdelphij	       rp->revision);
617170256Sdelphij	if (rp->revision < 2) {
618170256Sdelphij		printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum);
61963128Sps	} else {
620170256Sdelphij		printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n",
621161475Sdelphij		    (u_long)rp->xsdt_addr, rp->length, rp->xsum);
622161475Sdelphij	}
623170256Sdelphij	printf(END_COMMENT);
624161475Sdelphij}
625161475Sdelphij
626161475Sdelphijstatic void
627161475Sdelphijacpi_handle_rsdt(struct ACPIsdt *rsdp)
628161475Sdelphij{
629161475Sdelphij	struct ACPIsdt *sdp;
630161475Sdelphij	vm_offset_t addr;
631161475Sdelphij	int entries, i;
632161475Sdelphij
63360786Sps	acpi_print_rsdt(rsdp);
63460786Sps	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
635161475Sdelphij	for (i = 0; i < entries; i++) {
636161475Sdelphij		switch (addr_size) {
637161475Sdelphij		case 4:
638161475Sdelphij			addr = le32dec((char*)rsdp->body + i * addr_size);
639161475Sdelphij			break;
640161475Sdelphij		case 8:
64160786Sps			addr = le64dec((char*)rsdp->body + i * addr_size);
642128345Stjr			break;
643161475Sdelphij		default:
644161475Sdelphij			assert((addr = 0));
645128345Stjr		}
646128345Stjr
647161475Sdelphij		sdp = (struct ACPIsdt *)acpi_map_sdt(addr);
648161475Sdelphij		if (acpi_checksum(sdp, sdp->len))
649161475Sdelphij			errx(1, "RSDT entry %d is corrupt", i);
650170256Sdelphij		if (!memcmp(sdp->signature, "FACP", 4))
651161475Sdelphij			acpi_handle_fadt((struct FADTbody *) sdp->body);
652161475Sdelphij		else if (!memcmp(sdp->signature, "APIC", 4))
653161475Sdelphij			acpi_handle_apic(sdp);
654161475Sdelphij		else if (!memcmp(sdp->signature, "HPET", 4))
65560786Sps			acpi_handle_hpet(sdp);
65663128Sps		else if (!memcmp(sdp->signature, "ECDT", 4))
657161475Sdelphij			acpi_handle_ecdt(sdp);
658161475Sdelphij		else {
659161475Sdelphij			printf(BEGIN_COMMENT);
660161475Sdelphij			acpi_print_sdt(sdp);
66163128Sps			printf(END_COMMENT);
66263128Sps		}
66363128Sps	}
664161475Sdelphij}
665161475Sdelphij
666161475Sdelphijstruct ACPIsdt *
667170256Sdelphijsdt_load_devmem()
668161475Sdelphij{
669161475Sdelphij	struct	ACPIrsdp *rp;
670170256Sdelphij	struct	ACPIsdt *rsdp;
671161475Sdelphij
672161475Sdelphij	rp = acpi_find_rsd_ptr();
673161475Sdelphij	if (!rp)
67460786Sps		errx(1, "Can't find ACPI information");
67560786Sps
676161475Sdelphij	if (tflag)
677170256Sdelphij		acpi_print_rsd_ptr(rp);
67860786Sps	if (rp->revision < 2) {
67960786Sps		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr);
680161475Sdelphij		if (memcmp(rsdp->signature, "RSDT", 4) != 0 ||
681161475Sdelphij		    acpi_checksum(rsdp, rsdp->len) != 0)
682161475Sdelphij			errx(1, "RSDT is corrupted");
683161475Sdelphij		addr_size = sizeof(uint32_t);
68460786Sps	} else {
685170256Sdelphij		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr);
686161475Sdelphij		if (memcmp(rsdp->signature, "XSDT", 4) != 0 ||
687161475Sdelphij		    acpi_checksum(rsdp, rsdp->len) != 0)
688161475Sdelphij			errx(1, "XSDT is corrupted");
689170256Sdelphij		addr_size = sizeof(uint64_t);
690161475Sdelphij	}
691161475Sdelphij	return (rsdp);
692170256Sdelphij}
693161475Sdelphij
694170256Sdelphijvoid
695161475Sdelphijdsdt_save_file(char *outfile, struct ACPIsdt *dsdp)
696170256Sdelphij{
69760786Sps	int	fd;
698170256Sdelphij	mode_t	mode;
69989019Sps
70060786Sps	assert(outfile != NULL);
70189019Sps	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
702161475Sdelphij	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode);
703161475Sdelphij	if (fd == -1) {
704161475Sdelphij		perror("dsdt_save_file");
70560786Sps		return;
70689019Sps	}
707161475Sdelphij	write(fd, dsdp, SIZEOF_SDT_HDR);
708161475Sdelphij	write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR);
709161475Sdelphij	close(fd);
71060786Sps}
711161475Sdelphij
712161475Sdelphijvoid
713161475Sdelphijaml_disassemble(struct ACPIsdt *dsdp)
714161475Sdelphij{
715161475Sdelphij	char tmpstr[32], buf[256];
716161475Sdelphij	FILE *fp;
717161475Sdelphij	int fd, len;
718161475Sdelphij
719161475Sdelphij	strcpy(tmpstr, "/tmp/acpidump.XXXXXX");
720161475Sdelphij	fd = mkstemp(tmpstr);
721161475Sdelphij	if (fd < 0) {
72260786Sps		perror("iasl tmp file");
72360786Sps		return;
724170256Sdelphij	}
72560786Sps
72660786Sps	/* Dump DSDT to the temp file */
727161475Sdelphij	write(fd, dsdp, SIZEOF_SDT_HDR);
728161475Sdelphij	write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR);
729161475Sdelphij	close(fd);
730161475Sdelphij
731161475Sdelphij	/* Run iasl -d on the temp file */
732161475Sdelphij	if (fork() == 0) {
733161475Sdelphij		close(STDOUT_FILENO);
73460786Sps		if (vflag == 0)
73560786Sps			close(STDERR_FILENO);
736161475Sdelphij		execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, 0);
737161475Sdelphij		err(1, "exec");
73860786Sps	}
739170256Sdelphij
740170256Sdelphij	wait(NULL);
741170256Sdelphij	unlink(tmpstr);
742170256Sdelphij
743170256Sdelphij	/* Dump iasl's output to stdout */
744170256Sdelphij	fp = fopen("acpidump.dsl", "r");
745170256Sdelphij	unlink("acpidump.dsl");
74660786Sps	if (fp == NULL) {
74789019Sps		perror("iasl tmp file (read)");
748161475Sdelphij		return;
749161475Sdelphij	}
750161475Sdelphij	while ((len = fread(buf, 1, sizeof(buf), fp)) > 0)
751161475Sdelphij		fwrite(buf, 1, len, stdout);
75260786Sps	fclose(fp);
75389019Sps}
754161475Sdelphij
755161475Sdelphijvoid
756161475Sdelphijsdt_print_all(struct ACPIsdt *rsdp)
75760786Sps{
758170256Sdelphij	acpi_handle_rsdt(rsdp);
759161475Sdelphij}
760170256Sdelphij
761161475Sdelphij/* Fetch a table matching the given signature via the RSDT */
762161475Sdelphijstruct ACPIsdt *
76389019Spssdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig)
76460786Sps{
765170256Sdelphij	struct ACPIsdt *sdt;
766170256Sdelphij	vm_offset_t addr;
767161475Sdelphij	int entries, i;
768161475Sdelphij
769170256Sdelphij	entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size;
770170256Sdelphij	for (i = 0; i < entries; i++) {
771170256Sdelphij		switch (addr_size) {
772170256Sdelphij		case 4:
773170256Sdelphij			addr = le32dec((char*)rsdt->body + i * addr_size);
77463128Sps			break;
775170256Sdelphij		case 8:
776161475Sdelphij			addr = le64dec((char*)rsdt->body + i * addr_size);
777161475Sdelphij			break;
778161475Sdelphij		default:
779161475Sdelphij			assert((addr = 0));
780161475Sdelphij		}
781161475Sdelphij		sdt = (struct ACPIsdt *)acpi_map_sdt(addr);
782161475Sdelphij		if (memcmp(sdt->signature, sig, strlen(sig)))
783161475Sdelphij			continue;
784161475Sdelphij		if (acpi_checksum(sdt, sdt->len))
785161475Sdelphij			errx(1, "RSDT entry %d is corrupt", i);
786161475Sdelphij		return (sdt);
787161475Sdelphij	}
78860786Sps
789128345Stjr	return (NULL);
790161475Sdelphij}
791161475Sdelphij
792161475Sdelphijstruct ACPIsdt *
79360786Spsdsdt_from_fadt(struct FADTbody *fadt)
79463128Sps{
795161475Sdelphij	struct	ACPIsdt *sdt;
796161475Sdelphij
797161475Sdelphij	/* Use the DSDT address if it is valid and version 1, else X_DSDT */
798161475Sdelphij	if (addr_size == 4 ||
79963128Sps	    (addr_size == 8 && fadt->dsdt_ptr != 0 &&
800161475Sdelphij	    (fadt->x_dsdt_ptr & 0xffffffff) != fadt->dsdt_ptr))
801161475Sdelphij		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
802161475Sdelphij	else
803161475Sdelphij		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
80460786Sps	if (acpi_checksum(sdt, sdt->len))
805170256Sdelphij		errx(1, "DSDT is corrupt\n");
806170256Sdelphij	return (sdt);
807170256Sdelphij}
808161475Sdelphij