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