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$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/endian.h> 32 #include <sys/stat.h> 33 #include <sys/wait.h> 34 #include <assert.h> 35 #include <err.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "acpidump.h" 42 43 #define BEGIN_COMMENT "/*\n" 44 #define END_COMMENT " */\n" 45 46 static void acpi_print_string(char *s, size_t length); 47 static void acpi_print_gas(struct ACPIgas *gas); 48 static int acpi_get_fadt_revision(struct FADTbody *fadt); 49 static void acpi_handle_fadt(struct ACPIsdt *fadt); 50 static void acpi_print_cpu(u_char cpu_id); 51 static void acpi_print_local_apic(u_char cpu_id, u_char apic_id, 52 u_int32_t flags); 53 static void acpi_print_io_apic(u_char apic_id, u_int32_t int_base, 54 u_int64_t apic_addr); 55 static void acpi_print_mps_flags(u_int16_t flags); 56 static void acpi_print_intr(u_int32_t intr, u_int16_t mps_flags); 57 static void acpi_print_apic(struct MADT_APIC *mp); 58 static void acpi_handle_apic(struct ACPIsdt *sdp); 59 static void acpi_handle_hpet(struct ACPIsdt *sdp); 60 static void acpi_print_sdt(struct ACPIsdt *sdp); 61 static void acpi_print_fadt(struct ACPIsdt *sdp); 62 static void acpi_print_facs(struct FACSbody *facs); 63 static void acpi_print_dsdt(struct ACPIsdt *dsdp); 64 static struct ACPIsdt *acpi_map_sdt(vm_offset_t pa); 65 static void acpi_print_rsd_ptr(struct ACPIrsdp *rp); 66 static 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. */ 69 static int addr_size; 70 71 static void 72 acpi_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 86 static void 87 acpi_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. */ 120 static int 121 acpi_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 144 static void 145 acpi_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 173 static void 174 acpi_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 184 static void 185 acpi_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 197 static void 198 acpi_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 205 static void 206 acpi_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 241 static void 242 acpi_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 249 const char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", 250 "Local NMI", "Local APIC Override", "IO SAPIC", 251 "Local SAPIC", "Platform Interrupt" }; 252 const char *platform_int_types[] = { "PMI", "INIT", 253 "Corrected Platform Error" }; 254 255 static void 256 acpi_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 314 static void 315 acpi_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 338 static void 339 acpi_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="); 348 acpi_print_gas(&hpetp->genaddr); 349 printf("\tHW Rev=0x%x\n", hpetp->block_hwrev); 350 printf("\tComparitors=%d\n", hpetp->block_comparitors); 351 printf("\tCounter Size=%d\n", hpetp->block_counter_size); 352 printf("\tLegacy IRQ routing capable={"); 353 if (hpetp->block_legacy_capable) 354 printf("TRUE}\n"); 355 else 356 printf("FALSE}\n"); 357 printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor); 358 printf("\tMinimal Tick=%d\n", hpetp->clock_tick); 359 printf(END_COMMENT); 360 } 361 362 static void 363 acpi_handle_ecdt(struct ACPIsdt *sdp) 364 { 365 struct ECDTbody *ecdt; 366 367 printf(BEGIN_COMMENT); 368 acpi_print_sdt(sdp); 369 ecdt = (struct ECDTbody *) sdp->body; 370 printf("\tEC_CONTROL="); 371 acpi_print_gas(&ecdt->ec_control); 372 printf("\n\tEC_DATA="); 373 acpi_print_gas(&ecdt->ec_data); 374 printf("\n\tUID=%#x, ", ecdt->uid); 375 printf("GPE_BIT=%#x\n", ecdt->gpe_bit); 376 printf("\tEC_ID=%s\n", ecdt->ec_id); 377 printf(END_COMMENT); 378 } 379 380 static void 381 acpi_handle_mcfg(struct ACPIsdt *sdp) 382 { 383 struct MCFGbody *mcfg; 384 u_int i, e; 385 386 printf(BEGIN_COMMENT); 387 acpi_print_sdt(sdp); 388 mcfg = (struct MCFGbody *) sdp->body; 389 390 e = (sdp->len - ((caddr_t)&mcfg->s[0] - (caddr_t)sdp)) / 391 sizeof(*mcfg->s); 392 for (i = 0; i < e; i++, mcfg++) { 393 printf("\n"); 394 printf("\tBase Address= 0x%016jx\n", mcfg->s[i].baseaddr); 395 printf("\tSegment Group= 0x%04x\n", mcfg->s[i].seg_grp); 396 printf("\tStart Bus= %d\n", mcfg->s[i].start); 397 printf("\tEnd Bus= %d\n", mcfg->s[i].end); 398 } 399 printf(END_COMMENT); 400 } 401 402 static void 403 acpi_print_sdt(struct ACPIsdt *sdp) 404 { 405 printf(" "); 406 acpi_print_string(sdp->signature, 4); 407 printf(": Length=%d, Revision=%d, Checksum=%d,\n", 408 sdp->len, sdp->rev, sdp->check); 409 printf("\tOEMID="); 410 acpi_print_string(sdp->oemid, 6); 411 printf(", OEM Table ID="); 412 acpi_print_string(sdp->oemtblid, 8); 413 printf(", OEM Revision=0x%x,\n", sdp->oemrev); 414 printf("\tCreator ID="); 415 acpi_print_string(sdp->creator, 4); 416 printf(", Creator Revision=0x%x\n", sdp->crerev); 417 } 418 419 static void 420 acpi_print_rsdt(struct ACPIsdt *rsdp) 421 { 422 int i, entries; 423 u_long addr; 424 425 printf(BEGIN_COMMENT); 426 acpi_print_sdt(rsdp); 427 entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 428 printf("\tEntries={ "); 429 for (i = 0; i < entries; i++) { 430 if (i > 0) 431 printf(", "); 432 switch (addr_size) { 433 case 4: 434 addr = le32dec((char*)rsdp->body + i * addr_size); 435 break; 436 case 8: 437 addr = le64dec((char*)rsdp->body + i * addr_size); 438 break; 439 default: 440 addr = 0; 441 } 442 assert(addr != 0); 443 printf("0x%08lx", addr); 444 } 445 printf(" }\n"); 446 printf(END_COMMENT); 447 } 448 449 static const char *acpi_pm_profiles[] = { 450 "Unspecified", "Desktop", "Mobile", "Workstation", 451 "Enterprise Server", "SOHO Server", "Appliance PC" 452 }; 453 454 static void 455 acpi_print_fadt(struct ACPIsdt *sdp) 456 { 457 struct FADTbody *fadt; 458 const char *pm; 459 char sep; 460 461 fadt = (struct FADTbody *)sdp->body; 462 printf(BEGIN_COMMENT); 463 acpi_print_sdt(sdp); 464 printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr, 465 fadt->dsdt_ptr); 466 printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC"); 467 if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *)) 468 pm = "Reserved"; 469 else 470 pm = acpi_pm_profiles[fadt->pm_profile]; 471 printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile); 472 printf("\tSCI_INT=%d\n", fadt->sci_int); 473 printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd); 474 printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable); 475 printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable); 476 printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq); 477 printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt); 478 printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", 479 fadt->pm1a_evt_blk, 480 fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1); 481 if (fadt->pm1b_evt_blk != 0) 482 printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", 483 fadt->pm1b_evt_blk, 484 fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1); 485 printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", 486 fadt->pm1a_cnt_blk, 487 fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1); 488 if (fadt->pm1b_cnt_blk != 0) 489 printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", 490 fadt->pm1b_cnt_blk, 491 fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1); 492 if (fadt->pm2_cnt_blk != 0) 493 printf("\tPM2_CNT_BLK=0x%x-0x%x\n", 494 fadt->pm2_cnt_blk, 495 fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1); 496 printf("\tPM_TMR_BLK=0x%x-0x%x\n", 497 fadt->pm_tmr_blk, 498 fadt->pm_tmr_blk + fadt->pm_tmr_len - 1); 499 if (fadt->gpe0_blk != 0) 500 printf("\tGPE0_BLK=0x%x-0x%x\n", 501 fadt->gpe0_blk, 502 fadt->gpe0_blk + fadt->gpe0_len - 1); 503 if (fadt->gpe1_blk != 0) 504 printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 505 fadt->gpe1_blk, 506 fadt->gpe1_blk + fadt->gpe1_len - 1, 507 fadt->gpe1_base); 508 if (fadt->cst_cnt != 0) 509 printf("\tCST_CNT=0x%x\n", fadt->cst_cnt); 510 printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n", 511 fadt->p_lvl2_lat, fadt->p_lvl3_lat); 512 printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 513 fadt->flush_size, fadt->flush_stride); 514 printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 515 fadt->duty_off, fadt->duty_width); 516 printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 517 fadt->day_alrm, fadt->mon_alrm, fadt->century); 518 519 #define PRINTFLAG(var, flag) do { \ 520 if ((var) & FADT_FLAG_## flag) { \ 521 printf("%c%s", sep, #flag); sep = ','; \ 522 } \ 523 } while (0) 524 525 printf("\tIAPC_BOOT_ARCH="); 526 sep = '{'; 527 PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV); 528 PRINTFLAG(fadt->iapc_boot_arch, 8042); 529 if (fadt->iapc_boot_arch != 0) 530 printf("}"); 531 printf("\n"); 532 533 printf("\tFlags="); 534 sep = '{'; 535 PRINTFLAG(fadt->flags, WBINVD); 536 PRINTFLAG(fadt->flags, WBINVD_FLUSH); 537 PRINTFLAG(fadt->flags, PROC_C1); 538 PRINTFLAG(fadt->flags, P_LVL2_UP); 539 PRINTFLAG(fadt->flags, PWR_BUTTON); 540 PRINTFLAG(fadt->flags, SLP_BUTTON); 541 PRINTFLAG(fadt->flags, FIX_RTC); 542 PRINTFLAG(fadt->flags, RTC_S4); 543 PRINTFLAG(fadt->flags, TMR_VAL_EXT); 544 PRINTFLAG(fadt->flags, DCK_CAP); 545 PRINTFLAG(fadt->flags, RESET_REG); 546 PRINTFLAG(fadt->flags, SEALED_CASE); 547 PRINTFLAG(fadt->flags, HEADLESS); 548 PRINTFLAG(fadt->flags, CPU_SW_SLP); 549 if (fadt->flags != 0) 550 printf("}\n"); 551 552 #undef PRINTFLAG 553 554 if (fadt->flags & FADT_FLAG_RESET_REG) { 555 printf("\tRESET_REG="); 556 acpi_print_gas(&fadt->reset_reg); 557 printf(", RESET_VALUE=%#x\n", fadt->reset_value); 558 } 559 if (acpi_get_fadt_revision(fadt) > 1) { 560 printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr); 561 printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr); 562 printf("\tX_PM1a_EVT_BLK="); 563 acpi_print_gas(&fadt->x_pm1a_evt_blk); 564 if (fadt->x_pm1b_evt_blk.address != 0) { 565 printf("\n\tX_PM1b_EVT_BLK="); 566 acpi_print_gas(&fadt->x_pm1b_evt_blk); 567 } 568 printf("\n\tX_PM1a_CNT_BLK="); 569 acpi_print_gas(&fadt->x_pm1a_cnt_blk); 570 if (fadt->x_pm1b_cnt_blk.address != 0) { 571 printf("\n\tX_PM1b_CNT_BLK="); 572 acpi_print_gas(&fadt->x_pm1b_cnt_blk); 573 } 574 if (fadt->x_pm1b_cnt_blk.address != 0) { 575 printf("\n\tX_PM2_CNT_BLK="); 576 acpi_print_gas(&fadt->x_pm2_cnt_blk); 577 } 578 printf("\n\tX_PM_TMR_BLK="); 579 acpi_print_gas(&fadt->x_pm_tmr_blk); 580 if (fadt->x_gpe0_blk.address != 0) { 581 printf("\n\tX_GPE0_BLK="); 582 acpi_print_gas(&fadt->x_gpe0_blk); 583 } 584 if (fadt->x_gpe1_blk.address != 0) { 585 printf("\n\tX_GPE1_BLK="); 586 acpi_print_gas(&fadt->x_gpe1_blk); 587 } 588 printf("\n"); 589 } 590 591 printf(END_COMMENT); 592 } 593 594 static void 595 acpi_print_facs(struct FACSbody *facs) 596 { 597 printf(BEGIN_COMMENT); 598 printf(" FACS:\tLength=%u, ", facs->len); 599 printf("HwSig=0x%08x, ", facs->hw_sig); 600 printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec); 601 602 printf("\tGlobal_Lock="); 603 if (facs->global_lock != 0) { 604 if (facs->global_lock & FACS_FLAG_LOCK_PENDING) 605 printf("PENDING,"); 606 if (facs->global_lock & FACS_FLAG_LOCK_OWNED) 607 printf("OWNED"); 608 } 609 printf("\n"); 610 611 printf("\tFlags="); 612 if (facs->flags & FACS_FLAG_S4BIOS_F) 613 printf("S4BIOS"); 614 printf("\n"); 615 616 if (facs->x_firm_wake_vec != 0) { 617 printf("\tX_Firm_Wake_Vec=%08lx\n", 618 (u_long)facs->x_firm_wake_vec); 619 } 620 printf("\tVersion=%u\n", facs->version); 621 622 printf(END_COMMENT); 623 } 624 625 static void 626 acpi_print_dsdt(struct ACPIsdt *dsdp) 627 { 628 printf(BEGIN_COMMENT); 629 acpi_print_sdt(dsdp); 630 printf(END_COMMENT); 631 } 632 633 int 634 acpi_checksum(void *p, size_t length) 635 { 636 u_int8_t *bp; 637 u_int8_t sum; 638 639 bp = p; 640 sum = 0; 641 while (length--) 642 sum += *bp++; 643 644 return (sum); 645 } 646 647 static struct ACPIsdt * 648 acpi_map_sdt(vm_offset_t pa) 649 { 650 struct ACPIsdt *sp; 651 652 sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); 653 sp = acpi_map_physical(pa, sp->len); 654 return (sp); 655 } 656 657 static void 658 acpi_print_rsd_ptr(struct ACPIrsdp *rp) 659 { 660 printf(BEGIN_COMMENT); 661 printf(" RSD PTR: OEM="); 662 acpi_print_string(rp->oem, 6); 663 printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x", 664 rp->revision); 665 if (rp->revision < 2) { 666 printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum); 667 } else { 668 printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n", 669 (u_long)rp->xsdt_addr, rp->length, rp->xsum); 670 } 671 printf(END_COMMENT); 672 } 673 674 static void 675 acpi_handle_rsdt(struct ACPIsdt *rsdp) 676 { 677 struct ACPIsdt *sdp; 678 vm_offset_t addr; 679 int entries, i; 680 681 acpi_print_rsdt(rsdp); 682 entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 683 for (i = 0; i < entries; i++) { 684 switch (addr_size) { 685 case 4: 686 addr = le32dec((char*)rsdp->body + i * addr_size); 687 break; 688 case 8: 689 addr = le64dec((char*)rsdp->body + i * addr_size); 690 break; 691 default: 692 assert((addr = 0)); 693 } 694 695 sdp = (struct ACPIsdt *)acpi_map_sdt(addr); 696 if (acpi_checksum(sdp, sdp->len)) { 697 warnx("RSDT entry %d (sig %.4s) is corrupt", i, 698 sdp->signature); 699 continue; 700 } 701 if (!memcmp(sdp->signature, "FACP", 4)) 702 acpi_handle_fadt(sdp); 703 else if (!memcmp(sdp->signature, "APIC", 4)) 704 acpi_handle_apic(sdp); 705 else if (!memcmp(sdp->signature, "HPET", 4)) 706 acpi_handle_hpet(sdp); 707 else if (!memcmp(sdp->signature, "ECDT", 4)) 708 acpi_handle_ecdt(sdp); 709 else if (!memcmp(sdp->signature, "MCFG", 4)) 710 acpi_handle_mcfg(sdp); 711 else { 712 printf(BEGIN_COMMENT); 713 acpi_print_sdt(sdp); 714 printf(END_COMMENT); 715 } 716 } 717 } 718 719 struct ACPIsdt * 720 sdt_load_devmem(void) 721 { 722 struct ACPIrsdp *rp; 723 struct ACPIsdt *rsdp; 724 725 rp = acpi_find_rsd_ptr(); 726 if (!rp) 727 errx(1, "Can't find ACPI information"); 728 729 if (tflag) 730 acpi_print_rsd_ptr(rp); 731 if (rp->revision < 2) { 732 rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr); 733 if (memcmp(rsdp->signature, "RSDT", 4) != 0 || 734 acpi_checksum(rsdp, rsdp->len) != 0) 735 errx(1, "RSDT is corrupted"); 736 addr_size = sizeof(uint32_t); 737 } else { 738 rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr); 739 if (memcmp(rsdp->signature, "XSDT", 4) != 0 || 740 acpi_checksum(rsdp, rsdp->len) != 0) 741 errx(1, "XSDT is corrupted"); 742 addr_size = sizeof(uint64_t); 743 } 744 return (rsdp); 745 } 746 747 /* Write the DSDT to a file, concatenating any SSDTs (if present). */ 748 static int 749 write_dsdt(int fd, struct ACPIsdt *rsdt, struct ACPIsdt *dsdt) 750 { 751 struct ACPIsdt sdt; 752 struct ACPIsdt *ssdt; 753 uint8_t sum; 754 755 /* Create a new checksum to account for the DSDT and any SSDTs. */ 756 sdt = *dsdt; 757 if (rsdt != NULL) { 758 sdt.check = 0; 759 sum = acpi_checksum(dsdt->body, dsdt->len - SIZEOF_SDT_HDR); 760 ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL); 761 while (ssdt != NULL) { 762 sdt.len += ssdt->len - SIZEOF_SDT_HDR; 763 sum += acpi_checksum(ssdt->body, 764 ssdt->len - SIZEOF_SDT_HDR); 765 ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt); 766 } 767 sum += acpi_checksum(&sdt, SIZEOF_SDT_HDR); 768 sdt.check -= sum; 769 } 770 771 /* Write out the DSDT header and body. */ 772 write(fd, &sdt, SIZEOF_SDT_HDR); 773 write(fd, dsdt->body, dsdt->len - SIZEOF_SDT_HDR); 774 775 /* Write out any SSDTs (if present.) */ 776 if (rsdt != NULL) { 777 ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL); 778 while (ssdt != NULL) { 779 write(fd, ssdt->body, ssdt->len - SIZEOF_SDT_HDR); 780 ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt); 781 } 782 } 783 return (0); 784 } 785 786 void 787 dsdt_save_file(char *outfile, struct ACPIsdt *rsdt, struct ACPIsdt *dsdp) 788 { 789 int fd; 790 mode_t mode; 791 792 assert(outfile != NULL); 793 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 794 fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode); 795 if (fd == -1) { 796 perror("dsdt_save_file"); 797 return; 798 } 799 write_dsdt(fd, rsdt, dsdp); 800 close(fd); 801 } 802 803 void 804 aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp) 805 { 806 char tmpstr[32], buf[256]; 807 FILE *fp; 808 int fd, len; 809 810 strcpy(tmpstr, "/tmp/acpidump.XXXXXX"); 811 fd = mkstemp(tmpstr); 812 if (fd < 0) { 813 perror("iasl tmp file"); 814 return; 815 } 816 write_dsdt(fd, rsdt, dsdp); 817 close(fd); 818 819 /* Run iasl -d on the temp file */ 820 if (fork() == 0) { 821 close(STDOUT_FILENO); 822 if (vflag == 0) 823 close(STDERR_FILENO); 824 execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, (char *) 0); 825 err(1, "exec"); 826 } 827 828 wait(NULL); 829 unlink(tmpstr); 830 831 /* Dump iasl's output to stdout */ 832 fp = fopen("acpidump.dsl", "r"); 833 unlink("acpidump.dsl"); 834 if (fp == NULL) { 835 perror("iasl tmp file (read)"); 836 return; 837 } 838 while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) 839 fwrite(buf, 1, len, stdout); 840 fclose(fp); 841 } 842 843 void 844 sdt_print_all(struct ACPIsdt *rsdp) 845 { 846 acpi_handle_rsdt(rsdp); 847 } 848 849 /* Fetch a table matching the given signature via the RSDT. */ 850 struct ACPIsdt * 851 sdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig, struct ACPIsdt *last) 852 { 853 struct ACPIsdt *sdt; 854 vm_offset_t addr; 855 int entries, i; 856 857 entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size; 858 for (i = 0; i < entries; i++) { 859 switch (addr_size) { 860 case 4: 861 addr = le32dec((char*)rsdt->body + i * addr_size); 862 break; 863 case 8: 864 addr = le64dec((char*)rsdt->body + i * addr_size); 865 break; 866 default: 867 assert((addr = 0)); 868 } 869 sdt = (struct ACPIsdt *)acpi_map_sdt(addr); 870 if (last != NULL) { 871 if (sdt == last) 872 last = NULL; 873 continue; 874 } 875 if (memcmp(sdt->signature, sig, strlen(sig))) 876 continue; 877 if (acpi_checksum(sdt, sdt->len)) 878 errx(1, "RSDT entry %d is corrupt", i); 879 return (sdt); 880 } 881 882 return (NULL); 883 } 884 885 struct ACPIsdt * 886 dsdt_from_fadt(struct FADTbody *fadt) 887 { 888 struct ACPIsdt *sdt; 889 890 /* Use the DSDT address if it is version 1, otherwise use X_DSDT. */ 891 if (acpi_get_fadt_revision(fadt) == 1) 892 sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr); 893 else 894 sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr); 895 if (acpi_checksum(sdt, sdt->len)) 896 errx(1, "DSDT is corrupt\n"); 897 return (sdt); 898 } 899