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