acpi.c revision 131307
165285Siwasaki/*-
265285Siwasaki * Copyright (c) 1998 Doug Rabson
365285Siwasaki * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
465285Siwasaki * All rights reserved.
565285Siwasaki *
665285Siwasaki * Redistribution and use in source and binary forms, with or without
765285Siwasaki * modification, are permitted provided that the following conditions
865285Siwasaki * are met:
965285Siwasaki * 1. Redistributions of source code must retain the above copyright
1065285Siwasaki *    notice, this list of conditions and the following disclaimer.
1165285Siwasaki * 2. Redistributions in binary form must reproduce the above copyright
1265285Siwasaki *    notice, this list of conditions and the following disclaimer in the
1365285Siwasaki *    documentation and/or other materials provided with the distribution.
1465285Siwasaki *
1565285Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1665285Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1765285Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1865285Siwasaki * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1965285Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2065285Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2165285Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2265285Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2365285Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2465285Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2565285Siwasaki * SUCH DAMAGE.
2665285Siwasaki *
2765285Siwasaki *	$FreeBSD: head/usr.sbin/acpi/acpidump/acpi.c 131307 2004-06-30 03:23:51Z njl $
2865285Siwasaki */
2965285Siwasaki
3065285Siwasaki#include <sys/param.h>
31119913Snjl#include <sys/endian.h>
3265285Siwasaki#include <sys/stat.h>
33119515Snjl#include <sys/wait.h>
3465285Siwasaki#include <assert.h>
3565285Siwasaki#include <err.h>
3665285Siwasaki#include <fcntl.h>
3765285Siwasaki#include <stdio.h>
38119515Snjl#include <string.h>
3965285Siwasaki#include <unistd.h>
4065285Siwasaki
4165285Siwasaki#include "acpidump.h"
4265285Siwasaki
4385323Siwasaki#define BEGIN_COMMENT	"/*\n"
4485323Siwasaki#define END_COMMENT	" */\n"
4585323Siwasaki
46119515Snjlstatic void	acpi_print_string(char *s, size_t length);
47119912Snjlstatic void	acpi_print_gas(struct ACPIgas *gas);
48128382Snjlstatic int	acpi_get_fadt_revision(struct FADTbody *fadt);
49131307Snjlstatic void	acpi_handle_fadt(struct ACPIsdt *fadt);
50119515Snjlstatic void	acpi_print_cpu(u_char cpu_id);
51119515Snjlstatic void	acpi_print_local_apic(u_char cpu_id, u_char apic_id,
52119515Snjl				      u_int32_t flags);
53119515Snjlstatic void	acpi_print_io_apic(u_char apic_id, u_int32_t int_base,
54119515Snjl				   u_int64_t apic_addr);
55119515Snjlstatic void	acpi_print_mps_flags(u_int16_t flags);
56119515Snjlstatic void	acpi_print_intr(u_int32_t intr, u_int16_t mps_flags);
57119515Snjlstatic void	acpi_print_apic(struct MADT_APIC *mp);
58119515Snjlstatic void	acpi_handle_apic(struct ACPIsdt *sdp);
59119515Snjlstatic void	acpi_handle_hpet(struct ACPIsdt *sdp);
60119968Snjlstatic void	acpi_print_sdt(struct ACPIsdt *sdp);
61131307Snjlstatic void	acpi_print_fadt(struct ACPIsdt *sdp);
62119912Snjlstatic void	acpi_print_facs(struct FACSbody *facs);
63119515Snjlstatic void	acpi_print_dsdt(struct ACPIsdt *dsdp);
64119913Snjlstatic struct ACPIsdt *acpi_map_sdt(vm_offset_t pa);
65119515Snjlstatic void	acpi_print_rsd_ptr(struct ACPIrsdp *rp);
66119515Snjlstatic void	acpi_handle_rsdt(struct ACPIsdt *rsdp);
6785323Siwasaki
68119968Snjl/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */
69119913Snjlstatic int addr_size;
70119913Snjl
7165285Siwasakistatic void
7265285Siwasakiacpi_print_string(char *s, size_t length)
7365285Siwasaki{
7465285Siwasaki	int	c;
7565285Siwasaki
7665285Siwasaki	/* Trim trailing spaces and NULLs */
7765285Siwasaki	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
7865285Siwasaki		length--;
7965285Siwasaki
8065285Siwasaki	while (length--) {
8165285Siwasaki		c = *s++;
8265285Siwasaki		putchar(c);
8365285Siwasaki	}
8465285Siwasaki}
8565285Siwasaki
8665285Siwasakistatic void
87119912Snjlacpi_print_gas(struct ACPIgas *gas)
8865285Siwasaki{
89119912Snjl	switch(gas->address_space_id) {
90119912Snjl	case ACPI_GAS_MEMORY:
91119968Snjl		printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->address,
92119912Snjl		       gas->bit_offset, gas->bit_width);
93119912Snjl		break;
94119912Snjl	case ACPI_GAS_IO:
95120030Snjl		printf("0x%02lx:%u[%u] (IO)", (u_long)gas->address,
96119912Snjl		       gas->bit_offset, gas->bit_width);
97119912Snjl		break;
98119912Snjl	case ACPI_GAS_PCI:
99120030Snjl		printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->address >> 32),
100119912Snjl		       (uint16_t)((gas->address >> 16) & 0xffff),
101119912Snjl		       (uint16_t)gas->address);
102119912Snjl		break;
103119912Snjl	/* XXX How to handle these below? */
104119912Snjl	case ACPI_GAS_EMBEDDED:
105120030Snjl		printf("0x%x:%u[%u] (EC)", (uint16_t)gas->address,
106119912Snjl		       gas->bit_offset, gas->bit_width);
107119912Snjl		break;
108119912Snjl	case ACPI_GAS_SMBUS:
109120030Snjl		printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->address,
110119912Snjl		       gas->bit_offset, gas->bit_width);
111119912Snjl		break;
112119912Snjl	case ACPI_GAS_FIXED:
113119912Snjl	default:
114119968Snjl		printf("0x%08lx (?)", (u_long)gas->address);
115119912Snjl		break;
116119912Snjl	}
117119912Snjl}
11865285Siwasaki
119128382Snjl/* The FADT revision indicates whether we use the DSDT or X_DSDT addresses. */
120128382Snjlstatic int
121128382Snjlacpi_get_fadt_revision(struct FADTbody *fadt)
122119912Snjl{
123128382Snjl	int fadt_revision;
124119912Snjl
125124138Snjl	/* Set the FADT revision separately from the RSDP version. */
126124138Snjl	if (addr_size == 8) {
127124138Snjl		fadt_revision = 2;
128124138Snjl
129124138Snjl		/*
130124138Snjl		 * A few systems (e.g., IBM T23) have an RSDP that claims
131124138Snjl		 * revision 2 but the 64 bit addresses are invalid.  If
132124138Snjl		 * revision 2 and the 32 bit address is non-zero but the
133124138Snjl		 * 32 and 64 bit versions don't match, prefer the 32 bit
134124138Snjl		 * version for all subsequent tables.
135124138Snjl		 */
136124138Snjl		if (fadt->facs_ptr != 0 &&
137124138Snjl		    (fadt->x_facs_ptr & 0xffffffff) != fadt->facs_ptr)
138124138Snjl			fadt_revision = 1;
139128382Snjl	} else
140124138Snjl		fadt_revision = 1;
141128382Snjl	return (fadt_revision);
142128382Snjl}
143128382Snjl
144128382Snjlstatic void
145131307Snjlacpi_handle_fadt(struct ACPIsdt *sdp)
146128382Snjl{
147128382Snjl	struct ACPIsdt	*dsdp;
148128382Snjl	struct FACSbody	*facs;
149131307Snjl	struct FADTbody *fadt;
150128382Snjl	int		fadt_revision;
151128382Snjl
152131307Snjl	fadt = (struct FADTbody *)sdp->body;
153131307Snjl	acpi_print_fadt(sdp);
154119912Snjl
155128382Snjl	fadt_revision = acpi_get_fadt_revision(fadt);
156124138Snjl	if (fadt_revision == 1)
157119968Snjl		facs = (struct FACSbody *)acpi_map_sdt(fadt->facs_ptr);
158119968Snjl	else
159119968Snjl		facs = (struct FACSbody *)acpi_map_sdt(fadt->x_facs_ptr);
160119912Snjl	if (memcmp(facs->signature, "FACS", 4) != 0 || facs->len < 64)
161119912Snjl		errx(1, "FACS is corrupt");
162119912Snjl	acpi_print_facs(facs);
163119912Snjl
164124138Snjl	if (fadt_revision == 1)
165119968Snjl		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
166119968Snjl	else
167119968Snjl		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
16865285Siwasaki	if (acpi_checksum(dsdp, dsdp->len))
169119515Snjl		errx(1, "DSDT is corrupt");
170119515Snjl	acpi_print_dsdt(dsdp);
17165285Siwasaki}
17265285Siwasaki
17385323Siwasakistatic void
174108967Sjhbacpi_print_cpu(u_char cpu_id)
175108967Sjhb{
176108967Sjhb
177108967Sjhb	printf("\tACPI CPU=");
178108967Sjhb	if (cpu_id == 0xff)
179108967Sjhb		printf("ALL\n");
180108967Sjhb	else
181108967Sjhb		printf("%d\n", (u_int)cpu_id);
182108967Sjhb}
183108967Sjhb
184108967Sjhbstatic void
185108967Sjhbacpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags)
186108967Sjhb{
187108967Sjhb	acpi_print_cpu(cpu_id);
188108967Sjhb	printf("\tFlags={");
189108967Sjhb	if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
190108967Sjhb		printf("ENABLED");
191108967Sjhb	else
192108967Sjhb		printf("DISABLED");
193108967Sjhb	printf("}\n");
194108967Sjhb	printf("\tAPIC ID=%d\n", (u_int)apic_id);
195108967Sjhb}
196108967Sjhb
197108967Sjhbstatic void
198108967Sjhbacpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr)
199108967Sjhb{
200108967Sjhb	printf("\tAPIC ID=%d\n", (u_int)apic_id);
201108967Sjhb	printf("\tINT BASE=%d\n", int_base);
202119515Snjl	printf("\tADDR=0x%016jx\n", apic_addr);
203108967Sjhb}
204108967Sjhb
205108967Sjhbstatic void
206108967Sjhbacpi_print_mps_flags(u_int16_t flags)
207108967Sjhb{
208108967Sjhb
209108967Sjhb	printf("\tFlags={Polarity=");
210108967Sjhb	switch (flags & MPS_INT_FLAG_POLARITY_MASK) {
211108967Sjhb	case MPS_INT_FLAG_POLARITY_CONFORM:
212108967Sjhb		printf("conforming");
213108967Sjhb		break;
214108967Sjhb	case MPS_INT_FLAG_POLARITY_HIGH:
215108967Sjhb		printf("active-hi");
216108967Sjhb		break;
217108967Sjhb	case MPS_INT_FLAG_POLARITY_LOW:
218108967Sjhb		printf("active-lo");
219108967Sjhb		break;
220108967Sjhb	default:
221108967Sjhb		printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK);
222108967Sjhb		break;
223108967Sjhb	}
224108967Sjhb	printf(", Trigger=");
225108967Sjhb	switch (flags & MPS_INT_FLAG_TRIGGER_MASK) {
226108967Sjhb	case MPS_INT_FLAG_TRIGGER_CONFORM:
227108967Sjhb		printf("conforming");
228108967Sjhb		break;
229108967Sjhb	case MPS_INT_FLAG_TRIGGER_EDGE:
230108967Sjhb		printf("edge");
231108967Sjhb		break;
232108967Sjhb	case MPS_INT_FLAG_TRIGGER_LEVEL:
233108967Sjhb		printf("level");
234108967Sjhb		break;
235108967Sjhb	default:
236108967Sjhb		printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2);
237108967Sjhb	}
238108967Sjhb	printf("}\n");
239108967Sjhb}
240108967Sjhb
241108967Sjhbstatic void
242108967Sjhbacpi_print_intr(u_int32_t intr, u_int16_t mps_flags)
243108967Sjhb{
244108967Sjhb
245108967Sjhb	printf("\tINTR=%d\n", (u_int)intr);
246108967Sjhb	acpi_print_mps_flags(mps_flags);
247108967Sjhb}
248108967Sjhb
249108967Sjhbconst char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI",
250108967Sjhb			     "Local NMI", "Local APIC Override", "IO SAPIC",
251108967Sjhb			     "Local SAPIC", "Platform Interrupt" };
252108967Sjhbconst char *platform_int_types[] = { "PMI", "INIT",
253108967Sjhb				     "Corrected Platform Error" };
254108967Sjhb
255108967Sjhbstatic void
256108967Sjhbacpi_print_apic(struct MADT_APIC *mp)
257108967Sjhb{
258108967Sjhb
259108967Sjhb	printf("\tType=%s\n", apic_types[mp->type]);
260108967Sjhb	switch (mp->type) {
261108967Sjhb	case ACPI_MADT_APIC_TYPE_LOCAL_APIC:
262108967Sjhb		acpi_print_local_apic(mp->body.local_apic.cpu_id,
263108967Sjhb		    mp->body.local_apic.apic_id, mp->body.local_apic.flags);
264108967Sjhb		break;
265108967Sjhb	case ACPI_MADT_APIC_TYPE_IO_APIC:
266108967Sjhb		acpi_print_io_apic(mp->body.io_apic.apic_id,
267108967Sjhb		    mp->body.io_apic.int_base,
268108967Sjhb		    mp->body.io_apic.apic_addr);
269108967Sjhb		break;
270108967Sjhb	case ACPI_MADT_APIC_TYPE_INT_OVERRIDE:
271108967Sjhb		printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus);
272108967Sjhb		printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source);
273108967Sjhb		acpi_print_intr(mp->body.int_override.intr,
274108967Sjhb		    mp->body.int_override.mps_flags);
275108967Sjhb		break;
276108967Sjhb	case ACPI_MADT_APIC_TYPE_NMI:
277108967Sjhb		acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags);
278108967Sjhb		break;
279108967Sjhb	case ACPI_MADT_APIC_TYPE_LOCAL_NMI:
280108967Sjhb		acpi_print_cpu(mp->body.local_nmi.cpu_id);
281108967Sjhb		printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin);
282108967Sjhb		acpi_print_mps_flags(mp->body.local_nmi.mps_flags);
283108967Sjhb		break;
284108967Sjhb	case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE:
285119515Snjl		printf("\tLocal APIC ADDR=0x%016jx\n",
286119515Snjl		    mp->body.local_apic_override.apic_addr);
287108967Sjhb		break;
288108967Sjhb	case ACPI_MADT_APIC_TYPE_IO_SAPIC:
289108967Sjhb		acpi_print_io_apic(mp->body.io_sapic.apic_id,
290108967Sjhb		    mp->body.io_sapic.int_base,
291108967Sjhb		    mp->body.io_sapic.apic_addr);
292108967Sjhb		break;
293108967Sjhb	case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC:
294108967Sjhb		acpi_print_local_apic(mp->body.local_sapic.cpu_id,
295108967Sjhb		    mp->body.local_sapic.apic_id, mp->body.local_sapic.flags);
296108967Sjhb		printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid);
297108967Sjhb		break;
298108967Sjhb	case ACPI_MADT_APIC_TYPE_INT_SRC:
299108967Sjhb		printf("\tType=%s\n",
300108967Sjhb		    platform_int_types[mp->body.int_src.type]);
301108967Sjhb		printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id);
302108967Sjhb		printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id);
303108967Sjhb		printf("\tSAPIC Vector=%d\n",
304108967Sjhb		    (u_int)mp->body.int_src.sapic_vector);
305108967Sjhb		acpi_print_intr(mp->body.int_src.intr,
306108967Sjhb		    mp->body.int_src.mps_flags);
307108967Sjhb		break;
308108967Sjhb	default:
309108967Sjhb		printf("\tUnknown type %d\n", (u_int)mp->type);
310119515Snjl		break;
311108967Sjhb	}
312108967Sjhb}
313108967Sjhb
314108967Sjhbstatic void
315108967Sjhbacpi_handle_apic(struct ACPIsdt *sdp)
316108967Sjhb{
317108967Sjhb	struct MADTbody *madtp;
318108967Sjhb	struct MADT_APIC *madt_apicp;
319108967Sjhb
320119968Snjl	printf(BEGIN_COMMENT);
321119968Snjl	acpi_print_sdt(sdp);
322108967Sjhb	madtp = (struct MADTbody *) sdp->body;
323108967Sjhb	printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr);
324108967Sjhb	printf("\tFlags={");
325108967Sjhb	if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT)
326108967Sjhb		printf("PC-AT");
327108967Sjhb	printf("}\n");
328119515Snjl	madt_apicp = (struct MADT_APIC *)madtp->body;
329108967Sjhb	while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) {
330108967Sjhb		printf("\n");
331108967Sjhb		acpi_print_apic(madt_apicp);
332108967Sjhb		madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp +
333108967Sjhb		    madt_apicp->len);
334108967Sjhb	}
335108967Sjhb	printf(END_COMMENT);
336108967Sjhb}
337108967Sjhb
338108967Sjhbstatic void
339118334Speteracpi_handle_hpet(struct ACPIsdt *sdp)
340118334Speter{
341118334Speter	struct HPETbody *hpetp;
342118334Speter
343119968Snjl	printf(BEGIN_COMMENT);
344119968Snjl	acpi_print_sdt(sdp);
345118334Speter	hpetp = (struct HPETbody *) sdp->body;
346118334Speter	printf("\tHPET Number=%d\n", hpetp->hpet_number);
347118334Speter	printf("\tADDR=0x%08x\n", hpetp->base_addr);
348118334Speter	printf("\tHW Rev=0x%x\n", hpetp->block_hwrev);
349118334Speter	printf("\tComparitors=%d\n", hpetp->block_comparitors);
350118334Speter	printf("\tCounter Size=%d\n", hpetp->block_counter_size);
351118334Speter	printf("\tLegacy IRQ routing capable={");
352118334Speter	if (hpetp->block_legacy_capable)
353118334Speter		printf("TRUE}\n");
354118334Speter	else
355118334Speter		printf("FALSE}\n");
356118334Speter	printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor);
357118335Speter	printf("\tMinimal Tick=%d\n", hpetp->clock_tick);
358118334Speter	printf(END_COMMENT);
359118334Speter}
360118334Speter
361118334Speterstatic void
362119971Snjlacpi_handle_ecdt(struct ACPIsdt *sdp)
363119971Snjl{
364119971Snjl	struct ECDTbody *ecdt;
365119971Snjl
366119971Snjl	printf(BEGIN_COMMENT);
367119971Snjl	acpi_print_sdt(sdp);
368119971Snjl	ecdt = (struct ECDTbody *) sdp->body;
369119971Snjl	printf("\tEC_CONTROL=");
370119971Snjl	acpi_print_gas(&ecdt->ec_control);
371119971Snjl	printf("\n\tEC_DATA=");
372119971Snjl	acpi_print_gas(&ecdt->ec_data);
373119971Snjl	printf("\n\tUID=%#x, ", ecdt->uid);
374119971Snjl	printf("GPE_BIT=%#x\n", ecdt->gpe_bit);
375119971Snjl	printf("\tEC_ID=%s\n", ecdt->ec_id);
376119971Snjl	printf(END_COMMENT);
377119971Snjl}
378119971Snjl
379119971Snjlstatic void
380119968Snjlacpi_print_sdt(struct ACPIsdt *sdp)
38185323Siwasaki{
382119968Snjl	printf("  ");
38365285Siwasaki	acpi_print_string(sdp->signature, 4);
38485323Siwasaki	printf(": Length=%d, Revision=%d, Checksum=%d,\n",
38565285Siwasaki	       sdp->len, sdp->rev, sdp->check);
38665285Siwasaki	printf("\tOEMID=");
38765285Siwasaki	acpi_print_string(sdp->oemid, 6);
38865285Siwasaki	printf(", OEM Table ID=");
38965285Siwasaki	acpi_print_string(sdp->oemtblid, 8);
39065285Siwasaki	printf(", OEM Revision=0x%x,\n", sdp->oemrev);
39165285Siwasaki	printf("\tCreator ID=");
39265285Siwasaki	acpi_print_string(sdp->creator, 4);
39365285Siwasaki	printf(", Creator Revision=0x%x\n", sdp->crerev);
39465285Siwasaki}
39565285Siwasaki
396119515Snjlstatic void
39765285Siwasakiacpi_print_rsdt(struct ACPIsdt *rsdp)
39865285Siwasaki{
39965285Siwasaki	int	i, entries;
400119913Snjl	u_long	addr;
40165285Siwasaki
402119968Snjl	printf(BEGIN_COMMENT);
403119968Snjl	acpi_print_sdt(rsdp);
404119913Snjl	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
40565285Siwasaki	printf("\tEntries={ ");
40665285Siwasaki	for (i = 0; i < entries; i++) {
40765285Siwasaki		if (i > 0)
40865285Siwasaki			printf(", ");
409119913Snjl		switch (addr_size) {
410119913Snjl		case 4:
411119913Snjl			addr = le32dec((char*)rsdp->body + i * addr_size);
412119913Snjl			break;
413119913Snjl		case 8:
414119913Snjl			addr = le64dec((char*)rsdp->body + i * addr_size);
415119913Snjl			break;
416119913Snjl		default:
417119913Snjl			addr = 0;
418119913Snjl		}
419119913Snjl		assert(addr != 0);
420119913Snjl		printf("0x%08lx", addr);
42165285Siwasaki	}
42265285Siwasaki	printf(" }\n");
42385323Siwasaki	printf(END_COMMENT);
42465285Siwasaki}
42565285Siwasaki
426119912Snjlstatic const char *acpi_pm_profiles[] = {
427119912Snjl	"Unspecified", "Desktop", "Mobile", "Workstation",
428119912Snjl	"Enterprise Server", "SOHO Server", "Appliance PC"
429119912Snjl};
430119912Snjl
431119515Snjlstatic void
432131307Snjlacpi_print_fadt(struct ACPIsdt *sdp)
43365285Siwasaki{
434131307Snjl	struct FADTbody *fadt;
435119912Snjl	const char *pm;
436119912Snjl	char	    sep;
43765285Siwasaki
438131307Snjl	fadt = (struct FADTbody *)sdp->body;
43985323Siwasaki	printf(BEGIN_COMMENT);
440131307Snjl	acpi_print_sdt(sdp);
441131307Snjl	printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr,
442119912Snjl	       fadt->dsdt_ptr);
443119912Snjl	printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC");
444119912Snjl	if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *))
445119912Snjl		pm = "Reserved";
446119912Snjl	else
447119912Snjl		pm = acpi_pm_profiles[fadt->pm_profile];
448119912Snjl	printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile);
449119912Snjl	printf("\tSCI_INT=%d\n", fadt->sci_int);
450119912Snjl	printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd);
451119912Snjl	printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable);
452119912Snjl	printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable);
453119912Snjl	printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq);
454119912Snjl	printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt);
455120032Snjl	printf("\tPM1a_EVT_BLK=0x%x-0x%x\n",
456120032Snjl	       fadt->pm1a_evt_blk,
457120032Snjl	       fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1);
458119912Snjl	if (fadt->pm1b_evt_blk != 0)
45965285Siwasaki		printf("\tPM1b_EVT_BLK=0x%x-0x%x\n",
460119912Snjl		       fadt->pm1b_evt_blk,
461119912Snjl		       fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1);
462120032Snjl	printf("\tPM1a_CNT_BLK=0x%x-0x%x\n",
463120032Snjl	       fadt->pm1a_cnt_blk,
464120032Snjl	       fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1);
465119912Snjl	if (fadt->pm1b_cnt_blk != 0)
46665285Siwasaki		printf("\tPM1b_CNT_BLK=0x%x-0x%x\n",
467119912Snjl		       fadt->pm1b_cnt_blk,
468119912Snjl		       fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1);
469119912Snjl	if (fadt->pm2_cnt_blk != 0)
47065285Siwasaki		printf("\tPM2_CNT_BLK=0x%x-0x%x\n",
471119912Snjl		       fadt->pm2_cnt_blk,
472119912Snjl		       fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1);
473120032Snjl	printf("\tPM_TMR_BLK=0x%x-0x%x\n",
474120032Snjl	       fadt->pm_tmr_blk,
475120032Snjl	       fadt->pm_tmr_blk + fadt->pm_tmr_len - 1);
476119912Snjl	if (fadt->gpe0_blk != 0)
477119912Snjl		printf("\tGPE0_BLK=0x%x-0x%x\n",
478119912Snjl		       fadt->gpe0_blk,
479119912Snjl		       fadt->gpe0_blk + fadt->gpe0_len - 1);
480119912Snjl	if (fadt->gpe1_blk != 0)
481119912Snjl		printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
482119912Snjl		       fadt->gpe1_blk,
483119912Snjl		       fadt->gpe1_blk + fadt->gpe1_len - 1,
484119912Snjl		       fadt->gpe1_base);
485119912Snjl	if (fadt->cst_cnt != 0)
486119912Snjl		printf("\tCST_CNT=0x%x\n", fadt->cst_cnt);
487120034Snjl	printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n",
488119912Snjl	       fadt->p_lvl2_lat, fadt->p_lvl3_lat);
48965285Siwasaki	printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
490119912Snjl	       fadt->flush_size, fadt->flush_stride);
49165285Siwasaki	printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
492119912Snjl	       fadt->duty_off, fadt->duty_width);
49365285Siwasaki	printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
494119912Snjl	       fadt->day_alrm, fadt->mon_alrm, fadt->century);
49565285Siwasaki
496119912Snjl#define PRINTFLAG(var, flag) do {			\
497119912Snjl	if ((var) & FADT_FLAG_## flag) {		\
498119912Snjl		printf("%c%s", sep, #flag); sep = ',';	\
499119912Snjl	}						\
50065285Siwasaki} while (0)
50165285Siwasaki
502119912Snjl	printf("\tIAPC_BOOT_ARCH=");
503119912Snjl	sep = '{';
504119912Snjl	PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV);
505119912Snjl	PRINTFLAG(fadt->iapc_boot_arch, 8042);
506120309Snjl	if (fadt->iapc_boot_arch != 0)
507121693Snjl		printf("}");
508121693Snjl	printf("\n");
50965285Siwasaki
510119912Snjl	printf("\tFlags=");
511119912Snjl	sep = '{';
512119912Snjl	PRINTFLAG(fadt->flags, WBINVD);
513119912Snjl	PRINTFLAG(fadt->flags, WBINVD_FLUSH);
514119912Snjl	PRINTFLAG(fadt->flags, PROC_C1);
515119912Snjl	PRINTFLAG(fadt->flags, P_LVL2_UP);
516119912Snjl	PRINTFLAG(fadt->flags, PWR_BUTTON);
517119912Snjl	PRINTFLAG(fadt->flags, SLP_BUTTON);
518119912Snjl	PRINTFLAG(fadt->flags, FIX_RTC);
519119912Snjl	PRINTFLAG(fadt->flags, RTC_S4);
520119912Snjl	PRINTFLAG(fadt->flags, TMR_VAL_EXT);
521119912Snjl	PRINTFLAG(fadt->flags, DCK_CAP);
522119912Snjl	PRINTFLAG(fadt->flags, RESET_REG);
523119912Snjl	PRINTFLAG(fadt->flags, SEALED_CASE);
524119912Snjl	PRINTFLAG(fadt->flags, HEADLESS);
525119912Snjl	PRINTFLAG(fadt->flags, CPU_SW_SLP);
526120309Snjl	if (fadt->flags != 0)
527120309Snjl		printf("}\n");
528119912Snjl
52965285Siwasaki#undef PRINTFLAG
53065285Siwasaki
531119912Snjl	if (fadt->flags & FADT_FLAG_RESET_REG) {
532119912Snjl		printf("\tRESET_REG=");
533119912Snjl		acpi_print_gas(&fadt->reset_reg);
534119912Snjl		printf(", RESET_VALUE=%#x\n", fadt->reset_value);
535119912Snjl	}
536128382Snjl	if (acpi_get_fadt_revision(fadt) > 1) {
537119968Snjl		printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr);
538119968Snjl		printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr);
539120032Snjl		printf("\tX_PM1a_EVT_BLK=");
540119968Snjl		acpi_print_gas(&fadt->x_pm1a_evt_blk);
541120032Snjl		if (fadt->x_pm1b_evt_blk.address != 0) {
542120032Snjl			printf("\n\tX_PM1b_EVT_BLK=");
543120032Snjl			acpi_print_gas(&fadt->x_pm1b_evt_blk);
544120032Snjl		}
545120032Snjl		printf("\n\tX_PM1a_CNT_BLK=");
546119968Snjl		acpi_print_gas(&fadt->x_pm1a_cnt_blk);
547120032Snjl		if (fadt->x_pm1b_cnt_blk.address != 0) {
548120032Snjl			printf("\n\tX_PM1b_CNT_BLK=");
549120032Snjl			acpi_print_gas(&fadt->x_pm1b_cnt_blk);
550120032Snjl		}
551120032Snjl		if (fadt->x_pm1b_cnt_blk.address != 0) {
552120032Snjl			printf("\n\tX_PM2_CNT_BLK=");
553120032Snjl			acpi_print_gas(&fadt->x_pm2_cnt_blk);
554120032Snjl		}
555119968Snjl		printf("\n\tX_PM_TMR_BLK=");
556119968Snjl		acpi_print_gas(&fadt->x_pm_tmr_blk);
557120032Snjl		if (fadt->x_gpe0_blk.address != 0) {
558120032Snjl			printf("\n\tX_GPE0_BLK=");
559120032Snjl			acpi_print_gas(&fadt->x_gpe0_blk);
560120032Snjl		}
561120032Snjl		if (fadt->x_gpe1_blk.address != 0) {
562120032Snjl			printf("\n\tX_GPE1_BLK=");
563120032Snjl			acpi_print_gas(&fadt->x_gpe1_blk);
564120032Snjl		}
565119968Snjl		printf("\n");
566119968Snjl	}
567119912Snjl
568119912Snjl	printf(END_COMMENT);
569119912Snjl}
570119912Snjl
571119912Snjlstatic void
572119912Snjlacpi_print_facs(struct FACSbody *facs)
573119912Snjl{
574119912Snjl	printf(BEGIN_COMMENT);
575119912Snjl	printf("  FACS:\tLength=%u, ", facs->len);
576119912Snjl	printf("HwSig=0x%08x, ", facs->hw_sig);
577119912Snjl	printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec);
578119912Snjl
579119968Snjl	printf("\tGlobal_Lock=");
580119912Snjl	if (facs->global_lock != 0) {
581119912Snjl		if (facs->global_lock & FACS_FLAG_LOCK_PENDING)
582119912Snjl			printf("PENDING,");
583119912Snjl		if (facs->global_lock & FACS_FLAG_LOCK_OWNED)
584119912Snjl			printf("OWNED");
585119912Snjl	}
586119968Snjl	printf("\n");
587119912Snjl
588119968Snjl	printf("\tFlags=");
589119912Snjl	if (facs->flags & FACS_FLAG_S4BIOS_F)
590119912Snjl		printf("S4BIOS");
591119968Snjl	printf("\n");
592119912Snjl
593119912Snjl	if (facs->x_firm_wake_vec != 0) {
594119912Snjl		printf("\tX_Firm_Wake_Vec=%08lx\n",
595119912Snjl		       (u_long)facs->x_firm_wake_vec);
596119912Snjl	}
597119968Snjl	printf("\tVersion=%u\n", facs->version);
598119912Snjl
59985323Siwasaki	printf(END_COMMENT);
60065285Siwasaki}
60165285Siwasaki
602119515Snjlstatic void
60365285Siwasakiacpi_print_dsdt(struct ACPIsdt *dsdp)
60465285Siwasaki{
605119968Snjl	printf(BEGIN_COMMENT);
606119968Snjl	acpi_print_sdt(dsdp);
607119968Snjl	printf(END_COMMENT);
60865285Siwasaki}
60965285Siwasaki
61065285Siwasakiint
61165285Siwasakiacpi_checksum(void *p, size_t length)
61265285Siwasaki{
61365285Siwasaki	u_int8_t	*bp;
61465285Siwasaki	u_int8_t	sum;
61565285Siwasaki
61665285Siwasaki	bp = p;
61765285Siwasaki	sum = 0;
61865285Siwasaki	while (length--)
61965285Siwasaki		sum += *bp++;
62065285Siwasaki
62165285Siwasaki	return (sum);
62265285Siwasaki}
62365285Siwasaki
624119515Snjlstatic struct ACPIsdt *
62565285Siwasakiacpi_map_sdt(vm_offset_t pa)
62665285Siwasaki{
62765285Siwasaki	struct	ACPIsdt *sp;
62865285Siwasaki
62965285Siwasaki	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
63065285Siwasaki	sp = acpi_map_physical(pa, sp->len);
63165285Siwasaki	return (sp);
63265285Siwasaki}
63365285Siwasaki
634119515Snjlstatic void
63565285Siwasakiacpi_print_rsd_ptr(struct ACPIrsdp *rp)
63665285Siwasaki{
63785323Siwasaki	printf(BEGIN_COMMENT);
638119913Snjl	printf("  RSD PTR: OEM=");
63965285Siwasaki	acpi_print_string(rp->oem, 6);
640119968Snjl	printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x",
641119913Snjl	       rp->revision);
642119913Snjl	if (rp->revision < 2) {
643119913Snjl		printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum);
644119913Snjl	} else {
645119913Snjl		printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n",
646119913Snjl		    (u_long)rp->xsdt_addr, rp->length, rp->xsum);
647119913Snjl	}
64885323Siwasaki	printf(END_COMMENT);
64965285Siwasaki}
65065285Siwasaki
651119515Snjlstatic void
65265285Siwasakiacpi_handle_rsdt(struct ACPIsdt *rsdp)
65365285Siwasaki{
654119913Snjl	struct ACPIsdt *sdp;
655119913Snjl	vm_offset_t addr;
656119913Snjl	int entries, i;
65765285Siwasaki
65865285Siwasaki	acpi_print_rsdt(rsdp);
659119913Snjl	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
66065285Siwasaki	for (i = 0; i < entries; i++) {
661119913Snjl		switch (addr_size) {
662119913Snjl		case 4:
663119913Snjl			addr = le32dec((char*)rsdp->body + i * addr_size);
664119913Snjl			break;
665119913Snjl		case 8:
666119913Snjl			addr = le64dec((char*)rsdp->body + i * addr_size);
667119913Snjl			break;
668119913Snjl		default:
669119913Snjl			assert((addr = 0));
670119913Snjl		}
671119913Snjl
672119913Snjl		sdp = (struct ACPIsdt *)acpi_map_sdt(addr);
67365285Siwasaki		if (acpi_checksum(sdp, sdp->len))
674119515Snjl			errx(1, "RSDT entry %d is corrupt", i);
675119515Snjl		if (!memcmp(sdp->signature, "FACP", 4))
676131307Snjl			acpi_handle_fadt(sdp);
677119515Snjl		else if (!memcmp(sdp->signature, "APIC", 4))
678108967Sjhb			acpi_handle_apic(sdp);
679119515Snjl		else if (!memcmp(sdp->signature, "HPET", 4))
680118334Speter			acpi_handle_hpet(sdp);
681119971Snjl		else if (!memcmp(sdp->signature, "ECDT", 4))
682119971Snjl			acpi_handle_ecdt(sdp);
683119968Snjl		else {
684119968Snjl			printf(BEGIN_COMMENT);
685119968Snjl			acpi_print_sdt(sdp);
686119968Snjl			printf(END_COMMENT);
687119968Snjl		}
68865285Siwasaki	}
68965285Siwasaki}
69085323Siwasaki
691119515Snjlstruct ACPIsdt *
692129102Sdessdt_load_devmem(void)
69385323Siwasaki{
694119515Snjl	struct	ACPIrsdp *rp;
695119515Snjl	struct	ACPIsdt *rsdp;
69685323Siwasaki
697119515Snjl	rp = acpi_find_rsd_ptr();
698119515Snjl	if (!rp)
699119515Snjl		errx(1, "Can't find ACPI information");
700119515Snjl
701119515Snjl	if (tflag)
702119515Snjl		acpi_print_rsd_ptr(rp);
703119913Snjl	if (rp->revision < 2) {
704119913Snjl		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr);
705119913Snjl		if (memcmp(rsdp->signature, "RSDT", 4) != 0 ||
706119913Snjl		    acpi_checksum(rsdp, rsdp->len) != 0)
707119913Snjl			errx(1, "RSDT is corrupted");
708119913Snjl		addr_size = sizeof(uint32_t);
709119913Snjl	} else {
710119913Snjl		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr);
711119913Snjl		if (memcmp(rsdp->signature, "XSDT", 4) != 0 ||
712119913Snjl		    acpi_checksum(rsdp, rsdp->len) != 0)
713119913Snjl			errx(1, "XSDT is corrupted");
714119913Snjl		addr_size = sizeof(uint64_t);
715119913Snjl	}
716119515Snjl	return (rsdp);
71785323Siwasaki}
71885323Siwasaki
719119515Snjlvoid
720119515Snjldsdt_save_file(char *outfile, struct ACPIsdt *dsdp)
72185323Siwasaki{
722119515Snjl	int	fd;
723119515Snjl	mode_t	mode;
72485323Siwasaki
725119515Snjl	assert(outfile != NULL);
726119515Snjl	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
727119515Snjl	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode);
728119515Snjl	if (fd == -1) {
729119515Snjl		perror("dsdt_save_file");
730119515Snjl		return;
731119515Snjl	}
732119515Snjl	write(fd, dsdp, SIZEOF_SDT_HDR);
733119515Snjl	write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR);
734119515Snjl	close(fd);
73585323Siwasaki}
73685323Siwasaki
737119515Snjlvoid
738119515Snjlaml_disassemble(struct ACPIsdt *dsdp)
73985323Siwasaki{
740119515Snjl	char tmpstr[32], buf[256];
741119515Snjl	FILE *fp;
742119515Snjl	int fd, len;
74385323Siwasaki
744119515Snjl	strcpy(tmpstr, "/tmp/acpidump.XXXXXX");
745119515Snjl	fd = mkstemp(tmpstr);
746119515Snjl	if (fd < 0) {
747119515Snjl		perror("iasl tmp file");
748119515Snjl		return;
749119515Snjl	}
750119515Snjl
751119515Snjl	/* Dump DSDT to the temp file */
752119515Snjl	write(fd, dsdp, SIZEOF_SDT_HDR);
753119515Snjl	write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR);
754119515Snjl	close(fd);
755119515Snjl
756119515Snjl	/* Run iasl -d on the temp file */
757119515Snjl	if (fork() == 0) {
758119515Snjl		close(STDOUT_FILENO);
759119515Snjl		if (vflag == 0)
760119515Snjl			close(STDERR_FILENO);
761119515Snjl		execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, 0);
762119515Snjl		err(1, "exec");
763119515Snjl	}
764119515Snjl
765119515Snjl	wait(NULL);
766119515Snjl	unlink(tmpstr);
767119515Snjl
768119515Snjl	/* Dump iasl's output to stdout */
769119515Snjl	fp = fopen("acpidump.dsl", "r");
770119515Snjl	unlink("acpidump.dsl");
771119515Snjl	if (fp == NULL) {
772119515Snjl		perror("iasl tmp file (read)");
773119515Snjl		return;
774119515Snjl	}
775119515Snjl	while ((len = fread(buf, 1, sizeof(buf), fp)) > 0)
776119515Snjl		fwrite(buf, 1, len, stdout);
777119515Snjl	fclose(fp);
77885323Siwasaki}
77985323Siwasaki
780119515Snjlvoid
781119515Snjlsdt_print_all(struct ACPIsdt *rsdp)
78285323Siwasaki{
783119515Snjl	acpi_handle_rsdt(rsdp);
78485323Siwasaki}
78585323Siwasaki
786119515Snjl/* Fetch a table matching the given signature via the RSDT */
787119515Snjlstruct ACPIsdt *
788119515Snjlsdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig)
78985323Siwasaki{
790119913Snjl	struct ACPIsdt *sdt;
791119913Snjl	vm_offset_t addr;
792119913Snjl	int entries, i;
79385323Siwasaki
794119913Snjl	entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size;
795119515Snjl	for (i = 0; i < entries; i++) {
796119913Snjl		switch (addr_size) {
797119913Snjl		case 4:
798119913Snjl			addr = le32dec((char*)rsdt->body + i * addr_size);
799119913Snjl			break;
800119913Snjl		case 8:
801119913Snjl			addr = le64dec((char*)rsdt->body + i * addr_size);
802119913Snjl			break;
803119913Snjl		default:
804119913Snjl			assert((addr = 0));
805119913Snjl		}
806119913Snjl		sdt = (struct ACPIsdt *)acpi_map_sdt(addr);
807119913Snjl		if (memcmp(sdt->signature, sig, strlen(sig)))
808119913Snjl			continue;
809119515Snjl		if (acpi_checksum(sdt, sdt->len))
810119515Snjl			errx(1, "RSDT entry %d is corrupt", i);
811119913Snjl		return (sdt);
812119515Snjl	}
813119515Snjl
814119515Snjl	return (NULL);
81585323Siwasaki}
81685323Siwasaki
817119515Snjlstruct ACPIsdt *
818119912Snjldsdt_from_fadt(struct FADTbody *fadt)
81985323Siwasaki{
820128382Snjl	struct	ACPIsdt	*sdt;
82185323Siwasaki
822124138Snjl	/* Use the DSDT address if it is version 1, otherwise use X_DSDT. */
823128382Snjl	if (acpi_get_fadt_revision(fadt) == 1)
824120044Snjl		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
825120044Snjl	else
826120044Snjl		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
827119515Snjl	if (acpi_checksum(sdt, sdt->len))
828119515Snjl		errx(1, "DSDT is corrupt\n");
829119515Snjl	return (sdt);
83085323Siwasaki}
831