acpi.c revision 141905
1116874Ssmkelly/*-
2116874Ssmkelly * Copyright (c) 1998 Doug Rabson
3116874Ssmkelly * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
4116874Ssmkelly * All rights reserved.
5116874Ssmkelly *
6116874Ssmkelly * Redistribution and use in source and binary forms, with or without
7116874Ssmkelly * modification, are permitted provided that the following conditions
8116874Ssmkelly * are met:
9116874Ssmkelly * 1. Redistributions of source code must retain the above copyright
10116874Ssmkelly *    notice, this list of conditions and the following disclaimer.
11116874Ssmkelly * 2. Redistributions in binary form must reproduce the above copyright
12116874Ssmkelly *    notice, this list of conditions and the following disclaimer in the
13116874Ssmkelly *    documentation and/or other materials provided with the distribution.
14116874Ssmkelly *
15116874Ssmkelly * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116874Ssmkelly * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116874Ssmkelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116874Ssmkelly * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116874Ssmkelly * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116874Ssmkelly * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116874Ssmkelly * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116874Ssmkelly * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116874Ssmkelly * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116874Ssmkelly * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116874Ssmkelly * SUCH DAMAGE.
26116874Ssmkelly *
27116874Ssmkelly *	$FreeBSD: head/usr.sbin/acpi/acpidump/acpi.c 141905 2005-02-14 11:21:48Z scottl $
28116874Ssmkelly */
29116874Ssmkelly
30116874Ssmkelly#include <sys/param.h>
31140339Sobrien#include <sys/endian.h>
32180564Sdougb#include <sys/stat.h>
33116874Ssmkelly#include <sys/wait.h>
34116874Ssmkelly#include <assert.h>
35116874Ssmkelly#include <err.h>
36116874Ssmkelly#include <fcntl.h>
37116874Ssmkelly#include <stdio.h>
38116874Ssmkelly#include <string.h>
39116874Ssmkelly#include <unistd.h>
40116874Ssmkelly
41116874Ssmkelly#include "acpidump.h"
42116874Ssmkelly
43#define BEGIN_COMMENT	"/*\n"
44#define END_COMMENT	" */\n"
45
46static void	acpi_print_string(char *s, size_t length);
47static void	acpi_print_gas(struct ACPIgas *gas);
48static int	acpi_get_fadt_revision(struct FADTbody *fadt);
49static void	acpi_handle_fadt(struct ACPIsdt *fadt);
50static void	acpi_print_cpu(u_char cpu_id);
51static void	acpi_print_local_apic(u_char cpu_id, u_char apic_id,
52				      u_int32_t flags);
53static void	acpi_print_io_apic(u_char apic_id, u_int32_t int_base,
54				   u_int64_t apic_addr);
55static void	acpi_print_mps_flags(u_int16_t flags);
56static void	acpi_print_intr(u_int32_t intr, u_int16_t mps_flags);
57static void	acpi_print_apic(struct MADT_APIC *mp);
58static void	acpi_handle_apic(struct ACPIsdt *sdp);
59static void	acpi_handle_hpet(struct ACPIsdt *sdp);
60static void	acpi_print_sdt(struct ACPIsdt *sdp);
61static void	acpi_print_fadt(struct ACPIsdt *sdp);
62static void	acpi_print_facs(struct FACSbody *facs);
63static void	acpi_print_dsdt(struct ACPIsdt *dsdp);
64static struct ACPIsdt *acpi_map_sdt(vm_offset_t pa);
65static void	acpi_print_rsd_ptr(struct ACPIrsdp *rp);
66static void	acpi_handle_rsdt(struct ACPIsdt *rsdp);
67
68/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */
69static int addr_size;
70
71static void
72acpi_print_string(char *s, size_t length)
73{
74	int	c;
75
76	/* Trim trailing spaces and NULLs */
77	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
78		length--;
79
80	while (length--) {
81		c = *s++;
82		putchar(c);
83	}
84}
85
86static void
87acpi_print_gas(struct ACPIgas *gas)
88{
89	switch(gas->address_space_id) {
90	case ACPI_GAS_MEMORY:
91		printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->address,
92		       gas->bit_offset, gas->bit_width);
93		break;
94	case ACPI_GAS_IO:
95		printf("0x%02lx:%u[%u] (IO)", (u_long)gas->address,
96		       gas->bit_offset, gas->bit_width);
97		break;
98	case ACPI_GAS_PCI:
99		printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->address >> 32),
100		       (uint16_t)((gas->address >> 16) & 0xffff),
101		       (uint16_t)gas->address);
102		break;
103	/* XXX How to handle these below? */
104	case ACPI_GAS_EMBEDDED:
105		printf("0x%x:%u[%u] (EC)", (uint16_t)gas->address,
106		       gas->bit_offset, gas->bit_width);
107		break;
108	case ACPI_GAS_SMBUS:
109		printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->address,
110		       gas->bit_offset, gas->bit_width);
111		break;
112	case ACPI_GAS_FIXED:
113	default:
114		printf("0x%08lx (?)", (u_long)gas->address);
115		break;
116	}
117}
118
119/* The FADT revision indicates whether we use the DSDT or X_DSDT addresses. */
120static int
121acpi_get_fadt_revision(struct FADTbody *fadt)
122{
123	int fadt_revision;
124
125	/* Set the FADT revision separately from the RSDP version. */
126	if (addr_size == 8) {
127		fadt_revision = 2;
128
129		/*
130		 * A few systems (e.g., IBM T23) have an RSDP that claims
131		 * revision 2 but the 64 bit addresses are invalid.  If
132		 * revision 2 and the 32 bit address is non-zero but the
133		 * 32 and 64 bit versions don't match, prefer the 32 bit
134		 * version for all subsequent tables.
135		 */
136		if (fadt->facs_ptr != 0 &&
137		    (fadt->x_facs_ptr & 0xffffffff) != fadt->facs_ptr)
138			fadt_revision = 1;
139	} else
140		fadt_revision = 1;
141	return (fadt_revision);
142}
143
144static void
145acpi_handle_fadt(struct ACPIsdt *sdp)
146{
147	struct ACPIsdt	*dsdp;
148	struct FACSbody	*facs;
149	struct FADTbody *fadt;
150	int		fadt_revision;
151
152	fadt = (struct FADTbody *)sdp->body;
153	acpi_print_fadt(sdp);
154
155	fadt_revision = acpi_get_fadt_revision(fadt);
156	if (fadt_revision == 1)
157		facs = (struct FACSbody *)acpi_map_sdt(fadt->facs_ptr);
158	else
159		facs = (struct FACSbody *)acpi_map_sdt(fadt->x_facs_ptr);
160	if (memcmp(facs->signature, "FACS", 4) != 0 || facs->len < 64)
161		errx(1, "FACS is corrupt");
162	acpi_print_facs(facs);
163
164	if (fadt_revision == 1)
165		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
166	else
167		dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
168	if (acpi_checksum(dsdp, dsdp->len))
169		errx(1, "DSDT is corrupt");
170	acpi_print_dsdt(dsdp);
171}
172
173static void
174acpi_print_cpu(u_char cpu_id)
175{
176
177	printf("\tACPI CPU=");
178	if (cpu_id == 0xff)
179		printf("ALL\n");
180	else
181		printf("%d\n", (u_int)cpu_id);
182}
183
184static void
185acpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags)
186{
187	acpi_print_cpu(cpu_id);
188	printf("\tFlags={");
189	if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
190		printf("ENABLED");
191	else
192		printf("DISABLED");
193	printf("}\n");
194	printf("\tAPIC ID=%d\n", (u_int)apic_id);
195}
196
197static void
198acpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr)
199{
200	printf("\tAPIC ID=%d\n", (u_int)apic_id);
201	printf("\tINT BASE=%d\n", int_base);
202	printf("\tADDR=0x%016jx\n", apic_addr);
203}
204
205static void
206acpi_print_mps_flags(u_int16_t flags)
207{
208
209	printf("\tFlags={Polarity=");
210	switch (flags & MPS_INT_FLAG_POLARITY_MASK) {
211	case MPS_INT_FLAG_POLARITY_CONFORM:
212		printf("conforming");
213		break;
214	case MPS_INT_FLAG_POLARITY_HIGH:
215		printf("active-hi");
216		break;
217	case MPS_INT_FLAG_POLARITY_LOW:
218		printf("active-lo");
219		break;
220	default:
221		printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK);
222		break;
223	}
224	printf(", Trigger=");
225	switch (flags & MPS_INT_FLAG_TRIGGER_MASK) {
226	case MPS_INT_FLAG_TRIGGER_CONFORM:
227		printf("conforming");
228		break;
229	case MPS_INT_FLAG_TRIGGER_EDGE:
230		printf("edge");
231		break;
232	case MPS_INT_FLAG_TRIGGER_LEVEL:
233		printf("level");
234		break;
235	default:
236		printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2);
237	}
238	printf("}\n");
239}
240
241static void
242acpi_print_intr(u_int32_t intr, u_int16_t mps_flags)
243{
244
245	printf("\tINTR=%d\n", (u_int)intr);
246	acpi_print_mps_flags(mps_flags);
247}
248
249const char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI",
250			     "Local NMI", "Local APIC Override", "IO SAPIC",
251			     "Local SAPIC", "Platform Interrupt" };
252const char *platform_int_types[] = { "PMI", "INIT",
253				     "Corrected Platform Error" };
254
255static void
256acpi_print_apic(struct MADT_APIC *mp)
257{
258
259	printf("\tType=%s\n", apic_types[mp->type]);
260	switch (mp->type) {
261	case ACPI_MADT_APIC_TYPE_LOCAL_APIC:
262		acpi_print_local_apic(mp->body.local_apic.cpu_id,
263		    mp->body.local_apic.apic_id, mp->body.local_apic.flags);
264		break;
265	case ACPI_MADT_APIC_TYPE_IO_APIC:
266		acpi_print_io_apic(mp->body.io_apic.apic_id,
267		    mp->body.io_apic.int_base,
268		    mp->body.io_apic.apic_addr);
269		break;
270	case ACPI_MADT_APIC_TYPE_INT_OVERRIDE:
271		printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus);
272		printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source);
273		acpi_print_intr(mp->body.int_override.intr,
274		    mp->body.int_override.mps_flags);
275		break;
276	case ACPI_MADT_APIC_TYPE_NMI:
277		acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags);
278		break;
279	case ACPI_MADT_APIC_TYPE_LOCAL_NMI:
280		acpi_print_cpu(mp->body.local_nmi.cpu_id);
281		printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin);
282		acpi_print_mps_flags(mp->body.local_nmi.mps_flags);
283		break;
284	case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE:
285		printf("\tLocal APIC ADDR=0x%016jx\n",
286		    mp->body.local_apic_override.apic_addr);
287		break;
288	case ACPI_MADT_APIC_TYPE_IO_SAPIC:
289		acpi_print_io_apic(mp->body.io_sapic.apic_id,
290		    mp->body.io_sapic.int_base,
291		    mp->body.io_sapic.apic_addr);
292		break;
293	case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC:
294		acpi_print_local_apic(mp->body.local_sapic.cpu_id,
295		    mp->body.local_sapic.apic_id, mp->body.local_sapic.flags);
296		printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid);
297		break;
298	case ACPI_MADT_APIC_TYPE_INT_SRC:
299		printf("\tType=%s\n",
300		    platform_int_types[mp->body.int_src.type]);
301		printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id);
302		printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id);
303		printf("\tSAPIC Vector=%d\n",
304		    (u_int)mp->body.int_src.sapic_vector);
305		acpi_print_intr(mp->body.int_src.intr,
306		    mp->body.int_src.mps_flags);
307		break;
308	default:
309		printf("\tUnknown type %d\n", (u_int)mp->type);
310		break;
311	}
312}
313
314static void
315acpi_handle_apic(struct ACPIsdt *sdp)
316{
317	struct MADTbody *madtp;
318	struct MADT_APIC *madt_apicp;
319
320	printf(BEGIN_COMMENT);
321	acpi_print_sdt(sdp);
322	madtp = (struct MADTbody *) sdp->body;
323	printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr);
324	printf("\tFlags={");
325	if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT)
326		printf("PC-AT");
327	printf("}\n");
328	madt_apicp = (struct MADT_APIC *)madtp->body;
329	while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) {
330		printf("\n");
331		acpi_print_apic(madt_apicp);
332		madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp +
333		    madt_apicp->len);
334	}
335	printf(END_COMMENT);
336}
337
338static void
339acpi_handle_hpet(struct ACPIsdt *sdp)
340{
341	struct HPETbody *hpetp;
342
343	printf(BEGIN_COMMENT);
344	acpi_print_sdt(sdp);
345	hpetp = (struct HPETbody *) sdp->body;
346	printf("\tHPET Number=%d\n", hpetp->hpet_number);
347	printf("\tADDR=0x%08x\n", hpetp->base_addr);
348	printf("\tHW Rev=0x%x\n", hpetp->block_hwrev);
349	printf("\tComparitors=%d\n", hpetp->block_comparitors);
350	printf("\tCounter Size=%d\n", hpetp->block_counter_size);
351	printf("\tLegacy IRQ routing capable={");
352	if (hpetp->block_legacy_capable)
353		printf("TRUE}\n");
354	else
355		printf("FALSE}\n");
356	printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor);
357	printf("\tMinimal Tick=%d\n", hpetp->clock_tick);
358	printf(END_COMMENT);
359}
360
361static void
362acpi_handle_ecdt(struct ACPIsdt *sdp)
363{
364	struct ECDTbody *ecdt;
365
366	printf(BEGIN_COMMENT);
367	acpi_print_sdt(sdp);
368	ecdt = (struct ECDTbody *) sdp->body;
369	printf("\tEC_CONTROL=");
370	acpi_print_gas(&ecdt->ec_control);
371	printf("\n\tEC_DATA=");
372	acpi_print_gas(&ecdt->ec_data);
373	printf("\n\tUID=%#x, ", ecdt->uid);
374	printf("GPE_BIT=%#x\n", ecdt->gpe_bit);
375	printf("\tEC_ID=%s\n", ecdt->ec_id);
376	printf(END_COMMENT);
377}
378
379static void
380acpi_handle_mcfg(struct ACPIsdt *sdp)
381{
382	struct MCFGbody *mcfg;
383	u_int i, e;
384
385	printf(BEGIN_COMMENT);
386	acpi_print_sdt(sdp);
387	mcfg = (struct MCFGbody *) sdp->body;
388
389	e = (sdp->len - ((caddr_t)&mcfg->s[0] - (caddr_t)sdp)) /
390	    sizeof(*mcfg->s);
391	for (i = 0; i < e; i++, mcfg++) {
392		printf("\n");
393		printf("\tBase Address= 0x%016jx\n", mcfg->s[i].baseaddr);
394		printf("\tSegment Group= 0x%04x\n", mcfg->s[i].seg_grp);
395		printf("\tStart Bus= %d\n", mcfg->s[i].start);
396		printf("\tEnd Bus= %d\n", mcfg->s[i].end);
397	}
398	printf(END_COMMENT);
399}
400
401static void
402acpi_print_sdt(struct ACPIsdt *sdp)
403{
404	printf("  ");
405	acpi_print_string(sdp->signature, 4);
406	printf(": Length=%d, Revision=%d, Checksum=%d,\n",
407	       sdp->len, sdp->rev, sdp->check);
408	printf("\tOEMID=");
409	acpi_print_string(sdp->oemid, 6);
410	printf(", OEM Table ID=");
411	acpi_print_string(sdp->oemtblid, 8);
412	printf(", OEM Revision=0x%x,\n", sdp->oemrev);
413	printf("\tCreator ID=");
414	acpi_print_string(sdp->creator, 4);
415	printf(", Creator Revision=0x%x\n", sdp->crerev);
416}
417
418static void
419acpi_print_rsdt(struct ACPIsdt *rsdp)
420{
421	int	i, entries;
422	u_long	addr;
423
424	printf(BEGIN_COMMENT);
425	acpi_print_sdt(rsdp);
426	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
427	printf("\tEntries={ ");
428	for (i = 0; i < entries; i++) {
429		if (i > 0)
430			printf(", ");
431		switch (addr_size) {
432		case 4:
433			addr = le32dec((char*)rsdp->body + i * addr_size);
434			break;
435		case 8:
436			addr = le64dec((char*)rsdp->body + i * addr_size);
437			break;
438		default:
439			addr = 0;
440		}
441		assert(addr != 0);
442		printf("0x%08lx", addr);
443	}
444	printf(" }\n");
445	printf(END_COMMENT);
446}
447
448static const char *acpi_pm_profiles[] = {
449	"Unspecified", "Desktop", "Mobile", "Workstation",
450	"Enterprise Server", "SOHO Server", "Appliance PC"
451};
452
453static void
454acpi_print_fadt(struct ACPIsdt *sdp)
455{
456	struct FADTbody *fadt;
457	const char *pm;
458	char	    sep;
459
460	fadt = (struct FADTbody *)sdp->body;
461	printf(BEGIN_COMMENT);
462	acpi_print_sdt(sdp);
463	printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr,
464	       fadt->dsdt_ptr);
465	printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC");
466	if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *))
467		pm = "Reserved";
468	else
469		pm = acpi_pm_profiles[fadt->pm_profile];
470	printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile);
471	printf("\tSCI_INT=%d\n", fadt->sci_int);
472	printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd);
473	printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable);
474	printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable);
475	printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq);
476	printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt);
477	printf("\tPM1a_EVT_BLK=0x%x-0x%x\n",
478	       fadt->pm1a_evt_blk,
479	       fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1);
480	if (fadt->pm1b_evt_blk != 0)
481		printf("\tPM1b_EVT_BLK=0x%x-0x%x\n",
482		       fadt->pm1b_evt_blk,
483		       fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1);
484	printf("\tPM1a_CNT_BLK=0x%x-0x%x\n",
485	       fadt->pm1a_cnt_blk,
486	       fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1);
487	if (fadt->pm1b_cnt_blk != 0)
488		printf("\tPM1b_CNT_BLK=0x%x-0x%x\n",
489		       fadt->pm1b_cnt_blk,
490		       fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1);
491	if (fadt->pm2_cnt_blk != 0)
492		printf("\tPM2_CNT_BLK=0x%x-0x%x\n",
493		       fadt->pm2_cnt_blk,
494		       fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1);
495	printf("\tPM_TMR_BLK=0x%x-0x%x\n",
496	       fadt->pm_tmr_blk,
497	       fadt->pm_tmr_blk + fadt->pm_tmr_len - 1);
498	if (fadt->gpe0_blk != 0)
499		printf("\tGPE0_BLK=0x%x-0x%x\n",
500		       fadt->gpe0_blk,
501		       fadt->gpe0_blk + fadt->gpe0_len - 1);
502	if (fadt->gpe1_blk != 0)
503		printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
504		       fadt->gpe1_blk,
505		       fadt->gpe1_blk + fadt->gpe1_len - 1,
506		       fadt->gpe1_base);
507	if (fadt->cst_cnt != 0)
508		printf("\tCST_CNT=0x%x\n", fadt->cst_cnt);
509	printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n",
510	       fadt->p_lvl2_lat, fadt->p_lvl3_lat);
511	printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
512	       fadt->flush_size, fadt->flush_stride);
513	printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
514	       fadt->duty_off, fadt->duty_width);
515	printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
516	       fadt->day_alrm, fadt->mon_alrm, fadt->century);
517
518#define PRINTFLAG(var, flag) do {			\
519	if ((var) & FADT_FLAG_## flag) {		\
520		printf("%c%s", sep, #flag); sep = ',';	\
521	}						\
522} while (0)
523
524	printf("\tIAPC_BOOT_ARCH=");
525	sep = '{';
526	PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV);
527	PRINTFLAG(fadt->iapc_boot_arch, 8042);
528	if (fadt->iapc_boot_arch != 0)
529		printf("}");
530	printf("\n");
531
532	printf("\tFlags=");
533	sep = '{';
534	PRINTFLAG(fadt->flags, WBINVD);
535	PRINTFLAG(fadt->flags, WBINVD_FLUSH);
536	PRINTFLAG(fadt->flags, PROC_C1);
537	PRINTFLAG(fadt->flags, P_LVL2_UP);
538	PRINTFLAG(fadt->flags, PWR_BUTTON);
539	PRINTFLAG(fadt->flags, SLP_BUTTON);
540	PRINTFLAG(fadt->flags, FIX_RTC);
541	PRINTFLAG(fadt->flags, RTC_S4);
542	PRINTFLAG(fadt->flags, TMR_VAL_EXT);
543	PRINTFLAG(fadt->flags, DCK_CAP);
544	PRINTFLAG(fadt->flags, RESET_REG);
545	PRINTFLAG(fadt->flags, SEALED_CASE);
546	PRINTFLAG(fadt->flags, HEADLESS);
547	PRINTFLAG(fadt->flags, CPU_SW_SLP);
548	if (fadt->flags != 0)
549		printf("}\n");
550
551#undef PRINTFLAG
552
553	if (fadt->flags & FADT_FLAG_RESET_REG) {
554		printf("\tRESET_REG=");
555		acpi_print_gas(&fadt->reset_reg);
556		printf(", RESET_VALUE=%#x\n", fadt->reset_value);
557	}
558	if (acpi_get_fadt_revision(fadt) > 1) {
559		printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr);
560		printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr);
561		printf("\tX_PM1a_EVT_BLK=");
562		acpi_print_gas(&fadt->x_pm1a_evt_blk);
563		if (fadt->x_pm1b_evt_blk.address != 0) {
564			printf("\n\tX_PM1b_EVT_BLK=");
565			acpi_print_gas(&fadt->x_pm1b_evt_blk);
566		}
567		printf("\n\tX_PM1a_CNT_BLK=");
568		acpi_print_gas(&fadt->x_pm1a_cnt_blk);
569		if (fadt->x_pm1b_cnt_blk.address != 0) {
570			printf("\n\tX_PM1b_CNT_BLK=");
571			acpi_print_gas(&fadt->x_pm1b_cnt_blk);
572		}
573		if (fadt->x_pm1b_cnt_blk.address != 0) {
574			printf("\n\tX_PM2_CNT_BLK=");
575			acpi_print_gas(&fadt->x_pm2_cnt_blk);
576		}
577		printf("\n\tX_PM_TMR_BLK=");
578		acpi_print_gas(&fadt->x_pm_tmr_blk);
579		if (fadt->x_gpe0_blk.address != 0) {
580			printf("\n\tX_GPE0_BLK=");
581			acpi_print_gas(&fadt->x_gpe0_blk);
582		}
583		if (fadt->x_gpe1_blk.address != 0) {
584			printf("\n\tX_GPE1_BLK=");
585			acpi_print_gas(&fadt->x_gpe1_blk);
586		}
587		printf("\n");
588	}
589
590	printf(END_COMMENT);
591}
592
593static void
594acpi_print_facs(struct FACSbody *facs)
595{
596	printf(BEGIN_COMMENT);
597	printf("  FACS:\tLength=%u, ", facs->len);
598	printf("HwSig=0x%08x, ", facs->hw_sig);
599	printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec);
600
601	printf("\tGlobal_Lock=");
602	if (facs->global_lock != 0) {
603		if (facs->global_lock & FACS_FLAG_LOCK_PENDING)
604			printf("PENDING,");
605		if (facs->global_lock & FACS_FLAG_LOCK_OWNED)
606			printf("OWNED");
607	}
608	printf("\n");
609
610	printf("\tFlags=");
611	if (facs->flags & FACS_FLAG_S4BIOS_F)
612		printf("S4BIOS");
613	printf("\n");
614
615	if (facs->x_firm_wake_vec != 0) {
616		printf("\tX_Firm_Wake_Vec=%08lx\n",
617		       (u_long)facs->x_firm_wake_vec);
618	}
619	printf("\tVersion=%u\n", facs->version);
620
621	printf(END_COMMENT);
622}
623
624static void
625acpi_print_dsdt(struct ACPIsdt *dsdp)
626{
627	printf(BEGIN_COMMENT);
628	acpi_print_sdt(dsdp);
629	printf(END_COMMENT);
630}
631
632int
633acpi_checksum(void *p, size_t length)
634{
635	u_int8_t	*bp;
636	u_int8_t	sum;
637
638	bp = p;
639	sum = 0;
640	while (length--)
641		sum += *bp++;
642
643	return (sum);
644}
645
646static struct ACPIsdt *
647acpi_map_sdt(vm_offset_t pa)
648{
649	struct	ACPIsdt *sp;
650
651	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
652	sp = acpi_map_physical(pa, sp->len);
653	return (sp);
654}
655
656static void
657acpi_print_rsd_ptr(struct ACPIrsdp *rp)
658{
659	printf(BEGIN_COMMENT);
660	printf("  RSD PTR: OEM=");
661	acpi_print_string(rp->oem, 6);
662	printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x",
663	       rp->revision);
664	if (rp->revision < 2) {
665		printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum);
666	} else {
667		printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n",
668		    (u_long)rp->xsdt_addr, rp->length, rp->xsum);
669	}
670	printf(END_COMMENT);
671}
672
673static void
674acpi_handle_rsdt(struct ACPIsdt *rsdp)
675{
676	struct ACPIsdt *sdp;
677	vm_offset_t addr;
678	int entries, i;
679
680	acpi_print_rsdt(rsdp);
681	entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
682	for (i = 0; i < entries; i++) {
683		switch (addr_size) {
684		case 4:
685			addr = le32dec((char*)rsdp->body + i * addr_size);
686			break;
687		case 8:
688			addr = le64dec((char*)rsdp->body + i * addr_size);
689			break;
690		default:
691			assert((addr = 0));
692		}
693
694		sdp = (struct ACPIsdt *)acpi_map_sdt(addr);
695		if (acpi_checksum(sdp, sdp->len)) {
696			warnx("RSDT entry %d (sig %.4s) is corrupt", i,
697			    sdp->signature);
698			continue;
699		}
700		if (!memcmp(sdp->signature, "FACP", 4))
701			acpi_handle_fadt(sdp);
702		else if (!memcmp(sdp->signature, "APIC", 4))
703			acpi_handle_apic(sdp);
704		else if (!memcmp(sdp->signature, "HPET", 4))
705			acpi_handle_hpet(sdp);
706		else if (!memcmp(sdp->signature, "ECDT", 4))
707			acpi_handle_ecdt(sdp);
708		else if (!memcmp(sdp->signature, "MCFG", 4))
709			acpi_handle_mcfg(sdp);
710		else {
711			printf(BEGIN_COMMENT);
712			acpi_print_sdt(sdp);
713			printf(END_COMMENT);
714		}
715	}
716}
717
718struct ACPIsdt *
719sdt_load_devmem(void)
720{
721	struct	ACPIrsdp *rp;
722	struct	ACPIsdt *rsdp;
723
724	rp = acpi_find_rsd_ptr();
725	if (!rp)
726		errx(1, "Can't find ACPI information");
727
728	if (tflag)
729		acpi_print_rsd_ptr(rp);
730	if (rp->revision < 2) {
731		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr);
732		if (memcmp(rsdp->signature, "RSDT", 4) != 0 ||
733		    acpi_checksum(rsdp, rsdp->len) != 0)
734			errx(1, "RSDT is corrupted");
735		addr_size = sizeof(uint32_t);
736	} else {
737		rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr);
738		if (memcmp(rsdp->signature, "XSDT", 4) != 0 ||
739		    acpi_checksum(rsdp, rsdp->len) != 0)
740			errx(1, "XSDT is corrupted");
741		addr_size = sizeof(uint64_t);
742	}
743	return (rsdp);
744}
745
746/* Write the DSDT to a file, concatenating any SSDTs (if present). */
747static int
748write_dsdt(int fd, struct ACPIsdt *rsdt, struct ACPIsdt *dsdt)
749{
750	struct ACPIsdt sdt;
751	struct ACPIsdt *ssdt;
752	uint8_t sum;
753
754	/* Create a new checksum to account for the DSDT and any SSDTs. */
755	sdt = *dsdt;
756	if (rsdt != NULL) {
757		sdt.check = 0;
758		sum = acpi_checksum(dsdt->body, dsdt->len - SIZEOF_SDT_HDR);
759		ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL);
760		while (ssdt != NULL) {
761			sdt.len += ssdt->len - SIZEOF_SDT_HDR;
762			sum += acpi_checksum(ssdt->body,
763			    ssdt->len - SIZEOF_SDT_HDR);
764			ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt);
765		}
766		sum += acpi_checksum(&sdt, SIZEOF_SDT_HDR);
767		sdt.check -= sum;
768	}
769
770	/* Write out the DSDT header and body. */
771	write(fd, &sdt, SIZEOF_SDT_HDR);
772	write(fd, dsdt->body, dsdt->len - SIZEOF_SDT_HDR);
773
774	/* Write out any SSDTs (if present.) */
775	if (rsdt != NULL) {
776		ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL);
777		while (ssdt != NULL) {
778			write(fd, ssdt->body, ssdt->len - SIZEOF_SDT_HDR);
779			ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt);
780		}
781	}
782	return (0);
783}
784
785void
786dsdt_save_file(char *outfile, struct ACPIsdt *rsdt, struct ACPIsdt *dsdp)
787{
788	int	fd;
789	mode_t	mode;
790
791	assert(outfile != NULL);
792	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
793	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode);
794	if (fd == -1) {
795		perror("dsdt_save_file");
796		return;
797	}
798	write_dsdt(fd, rsdt, dsdp);
799	close(fd);
800}
801
802void
803aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp)
804{
805	char tmpstr[32], buf[256];
806	FILE *fp;
807	int fd, len;
808
809	strcpy(tmpstr, "/tmp/acpidump.XXXXXX");
810	fd = mkstemp(tmpstr);
811	if (fd < 0) {
812		perror("iasl tmp file");
813		return;
814	}
815	write_dsdt(fd, rsdt, dsdp);
816	close(fd);
817
818	/* Run iasl -d on the temp file */
819	if (fork() == 0) {
820		close(STDOUT_FILENO);
821		if (vflag == 0)
822			close(STDERR_FILENO);
823		execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, 0);
824		err(1, "exec");
825	}
826
827	wait(NULL);
828	unlink(tmpstr);
829
830	/* Dump iasl's output to stdout */
831	fp = fopen("acpidump.dsl", "r");
832	unlink("acpidump.dsl");
833	if (fp == NULL) {
834		perror("iasl tmp file (read)");
835		return;
836	}
837	while ((len = fread(buf, 1, sizeof(buf), fp)) > 0)
838		fwrite(buf, 1, len, stdout);
839	fclose(fp);
840}
841
842void
843sdt_print_all(struct ACPIsdt *rsdp)
844{
845	acpi_handle_rsdt(rsdp);
846}
847
848/* Fetch a table matching the given signature via the RSDT. */
849struct ACPIsdt *
850sdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig, struct ACPIsdt *last)
851{
852	struct ACPIsdt *sdt;
853	vm_offset_t addr;
854	int entries, i;
855
856	entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size;
857	for (i = 0; i < entries; i++) {
858		switch (addr_size) {
859		case 4:
860			addr = le32dec((char*)rsdt->body + i * addr_size);
861			break;
862		case 8:
863			addr = le64dec((char*)rsdt->body + i * addr_size);
864			break;
865		default:
866			assert((addr = 0));
867		}
868		sdt = (struct ACPIsdt *)acpi_map_sdt(addr);
869		if (last != NULL) {
870			if (sdt == last)
871				last = NULL;
872			continue;
873		}
874		if (memcmp(sdt->signature, sig, strlen(sig)))
875			continue;
876		if (acpi_checksum(sdt, sdt->len))
877			errx(1, "RSDT entry %d is corrupt", i);
878		return (sdt);
879	}
880
881	return (NULL);
882}
883
884struct ACPIsdt *
885dsdt_from_fadt(struct FADTbody *fadt)
886{
887	struct	ACPIsdt	*sdt;
888
889	/* Use the DSDT address if it is version 1, otherwise use X_DSDT. */
890	if (acpi_get_fadt_revision(fadt) == 1)
891		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr);
892	else
893		sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr);
894	if (acpi_checksum(sdt, sdt->len))
895		errx(1, "DSDT is corrupt\n");
896	return (sdt);
897}
898