acpi.c revision 211221
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: head/usr.sbin/acpi/acpidump/acpi.c 211221 2010-08-12 13:58:46Z takawata $ 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 <paths.h> 38#include <stdio.h> 39#include <stdint.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43#include <inttypes.h> 44 45#include "acpidump.h" 46 47#define BEGIN_COMMENT "/*\n" 48#define END_COMMENT " */\n" 49 50static void acpi_print_string(char *s, size_t length); 51static void acpi_print_gas(ACPI_GENERIC_ADDRESS *gas); 52static int acpi_get_fadt_revision(ACPI_TABLE_FADT *fadt); 53static void acpi_handle_fadt(ACPI_TABLE_HEADER *fadt); 54static void acpi_print_cpu(u_char cpu_id); 55static void acpi_print_cpu_uid(uint32_t uid, char *uid_string); 56static void acpi_print_local_apic(uint32_t apic_id, uint32_t flags); 57static void acpi_print_io_apic(uint32_t apic_id, uint32_t int_base, 58 uint64_t apic_addr); 59static void acpi_print_mps_flags(uint16_t flags); 60static void acpi_print_intr(uint32_t intr, uint16_t mps_flags); 61static void acpi_print_local_nmi(u_int lint, uint16_t mps_flags); 62static void acpi_print_madt(ACPI_SUBTABLE_HEADER *mp); 63static void acpi_handle_madt(ACPI_TABLE_HEADER *sdp); 64static void acpi_handle_ecdt(ACPI_TABLE_HEADER *sdp); 65static void acpi_handle_hpet(ACPI_TABLE_HEADER *sdp); 66static void acpi_handle_mcfg(ACPI_TABLE_HEADER *sdp); 67static void acpi_print_srat_cpu(uint32_t apic_id, uint32_t proximity_domain, 68 uint32_t flags); 69static void acpi_print_srat_memory(ACPI_SRAT_MEM_AFFINITY *mp); 70static void acpi_print_srat(ACPI_SUBTABLE_HEADER *srat); 71static void acpi_handle_srat(ACPI_TABLE_HEADER *sdp); 72static void acpi_handle_tcpa(ACPI_TABLE_HEADER *sdp); 73static void acpi_print_sdt(ACPI_TABLE_HEADER *sdp); 74static void acpi_print_fadt(ACPI_TABLE_HEADER *sdp); 75static void acpi_print_facs(ACPI_TABLE_FACS *facs); 76static void acpi_print_dsdt(ACPI_TABLE_HEADER *dsdp); 77static ACPI_TABLE_HEADER *acpi_map_sdt(vm_offset_t pa); 78static void acpi_print_rsd_ptr(ACPI_TABLE_RSDP *rp); 79static void acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp); 80static void acpi_walk_subtables(ACPI_TABLE_HEADER *table, void *first, 81 void (*action)(ACPI_SUBTABLE_HEADER *)); 82 83/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */ 84static int addr_size; 85 86/* Strings used in the TCPA table */ 87static const char *tcpa_event_type_strings[] = { 88 "PREBOOT Certificate", 89 "POST Code", 90 "Unused", 91 "No Action", 92 "Separator", 93 "Action", 94 "Event Tag", 95 "S-CRTM Contents", 96 "S-CRTM Version", 97 "CPU Microcode", 98 "Platform Config Flags", 99 "Table of Devices", 100 "Compact Hash", 101 "IPL", 102 "IPL Partition Data", 103 "Non-Host Code", 104 "Non-Host Config", 105 "Non-Host Info" 106}; 107 108static const char *TCPA_pcclient_strings[] = { 109 "<undefined>", 110 "SMBIOS", 111 "BIS Certificate", 112 "POST BIOS ROM Strings", 113 "ESCD", 114 "CMOS", 115 "NVRAM", 116 "Option ROM Execute", 117 "Option ROM Configurateion", 118 "<undefined>", 119 "Option ROM Microcode Update ", 120 "S-CRTM Version String", 121 "S-CRTM Contents", 122 "POST Contents", 123 "Table of Devices", 124}; 125 126static void 127acpi_print_string(char *s, size_t length) 128{ 129 int c; 130 131 /* Trim trailing spaces and NULLs */ 132 while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 133 length--; 134 135 while (length--) { 136 c = *s++; 137 putchar(c); 138 } 139} 140 141static void 142acpi_print_gas(ACPI_GENERIC_ADDRESS *gas) 143{ 144 switch(gas->SpaceId) { 145 case ACPI_GAS_MEMORY: 146 printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->Address, 147 gas->BitOffset, gas->BitWidth); 148 break; 149 case ACPI_GAS_IO: 150 printf("0x%02lx:%u[%u] (IO)", (u_long)gas->Address, 151 gas->BitOffset, gas->BitWidth); 152 break; 153 case ACPI_GAS_PCI: 154 printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->Address >> 32), 155 (uint16_t)((gas->Address >> 16) & 0xffff), 156 (uint16_t)gas->Address); 157 break; 158 /* XXX How to handle these below? */ 159 case ACPI_GAS_EMBEDDED: 160 printf("0x%x:%u[%u] (EC)", (uint16_t)gas->Address, 161 gas->BitOffset, gas->BitWidth); 162 break; 163 case ACPI_GAS_SMBUS: 164 printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->Address, 165 gas->BitOffset, gas->BitWidth); 166 break; 167 case ACPI_GAS_CMOS: 168 case ACPI_GAS_PCIBAR: 169 case ACPI_GAS_DATATABLE: 170 case ACPI_GAS_FIXED: 171 default: 172 printf("0x%08lx (?)", (u_long)gas->Address); 173 break; 174 } 175} 176 177/* The FADT revision indicates whether we use the DSDT or X_DSDT addresses. */ 178static int 179acpi_get_fadt_revision(ACPI_TABLE_FADT *fadt) 180{ 181 int fadt_revision; 182 183 /* Set the FADT revision separately from the RSDP version. */ 184 if (addr_size == 8) { 185 fadt_revision = 2; 186 187 /* 188 * A few systems (e.g., IBM T23) have an RSDP that claims 189 * revision 2 but the 64 bit addresses are invalid. If 190 * revision 2 and the 32 bit address is non-zero but the 191 * 32 and 64 bit versions don't match, prefer the 32 bit 192 * version for all subsequent tables. 193 */ 194 if (fadt->Facs != 0 && 195 (fadt->XFacs & 0xffffffff) != fadt->Facs) 196 fadt_revision = 1; 197 } else 198 fadt_revision = 1; 199 return (fadt_revision); 200} 201 202static void 203acpi_handle_fadt(ACPI_TABLE_HEADER *sdp) 204{ 205 ACPI_TABLE_HEADER *dsdp; 206 ACPI_TABLE_FACS *facs; 207 ACPI_TABLE_FADT *fadt; 208 int fadt_revision; 209 210 fadt = (ACPI_TABLE_FADT *)sdp; 211 acpi_print_fadt(sdp); 212 213 fadt_revision = acpi_get_fadt_revision(fadt); 214 if (fadt_revision == 1) 215 facs = (ACPI_TABLE_FACS *)acpi_map_sdt(fadt->Facs); 216 else 217 facs = (ACPI_TABLE_FACS *)acpi_map_sdt(fadt->XFacs); 218 if (memcmp(facs->Signature, ACPI_SIG_FACS, 4) != 0 || facs->Length < 64) 219 errx(1, "FACS is corrupt"); 220 acpi_print_facs(facs); 221 222 if (fadt_revision == 1) 223 dsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->Dsdt); 224 else 225 dsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->XDsdt); 226 if (acpi_checksum(dsdp, dsdp->Length)) 227 errx(1, "DSDT is corrupt"); 228 acpi_print_dsdt(dsdp); 229} 230 231static void 232acpi_walk_subtables(ACPI_TABLE_HEADER *table, void *first, 233 void (*action)(ACPI_SUBTABLE_HEADER *)) 234{ 235 ACPI_SUBTABLE_HEADER *subtable; 236 char *end; 237 238 subtable = first; 239 end = (char *)table + table->Length; 240 while ((char *)subtable < end) { 241 printf("\n"); 242 action(subtable); 243 subtable = (ACPI_SUBTABLE_HEADER *)((char *)subtable + 244 subtable->Length); 245 } 246} 247 248static void 249acpi_print_cpu(u_char cpu_id) 250{ 251 252 printf("\tACPI CPU="); 253 if (cpu_id == 0xff) 254 printf("ALL\n"); 255 else 256 printf("%d\n", (u_int)cpu_id); 257} 258 259static void 260acpi_print_cpu_uid(uint32_t uid, char *uid_string) 261{ 262 263 printf("\tUID=%d", uid); 264 if (uid_string != NULL) 265 printf(" (%s)", uid_string); 266 printf("\n"); 267} 268 269static void 270acpi_print_local_apic(uint32_t apic_id, uint32_t flags) 271{ 272 273 printf("\tFlags={"); 274 if (flags & ACPI_MADT_ENABLED) 275 printf("ENABLED"); 276 else 277 printf("DISABLED"); 278 printf("}\n"); 279 printf("\tAPIC ID=%d\n", apic_id); 280} 281 282static void 283acpi_print_io_apic(uint32_t apic_id, uint32_t int_base, uint64_t apic_addr) 284{ 285 286 printf("\tAPIC ID=%d\n", apic_id); 287 printf("\tINT BASE=%d\n", int_base); 288 printf("\tADDR=0x%016jx\n", (uintmax_t)apic_addr); 289} 290 291static void 292acpi_print_mps_flags(uint16_t flags) 293{ 294 295 printf("\tFlags={Polarity="); 296 switch (flags & ACPI_MADT_POLARITY_MASK) { 297 case ACPI_MADT_POLARITY_CONFORMS: 298 printf("conforming"); 299 break; 300 case ACPI_MADT_POLARITY_ACTIVE_HIGH: 301 printf("active-hi"); 302 break; 303 case ACPI_MADT_POLARITY_ACTIVE_LOW: 304 printf("active-lo"); 305 break; 306 default: 307 printf("0x%x", flags & ACPI_MADT_POLARITY_MASK); 308 break; 309 } 310 printf(", Trigger="); 311 switch (flags & ACPI_MADT_TRIGGER_MASK) { 312 case ACPI_MADT_TRIGGER_CONFORMS: 313 printf("conforming"); 314 break; 315 case ACPI_MADT_TRIGGER_EDGE: 316 printf("edge"); 317 break; 318 case ACPI_MADT_TRIGGER_LEVEL: 319 printf("level"); 320 break; 321 default: 322 printf("0x%x", (flags & ACPI_MADT_TRIGGER_MASK) >> 2); 323 } 324 printf("}\n"); 325} 326 327static void 328acpi_print_intr(uint32_t intr, uint16_t mps_flags) 329{ 330 331 printf("\tINTR=%d\n", intr); 332 acpi_print_mps_flags(mps_flags); 333} 334 335static void 336acpi_print_local_nmi(u_int lint, uint16_t mps_flags) 337{ 338 339 printf("\tLINT Pin=%d\n", lint); 340 acpi_print_mps_flags(mps_flags); 341} 342 343const char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", 344 "Local APIC NMI", "Local APIC Override", 345 "IO SAPIC", "Local SAPIC", "Platform Interrupt", 346 "Local X2APIC", "Local X2APIC NMI" }; 347const char *platform_int_types[] = { "0 (unknown)", "PMI", "INIT", 348 "Corrected Platform Error" }; 349 350static void 351acpi_print_madt(ACPI_SUBTABLE_HEADER *mp) 352{ 353 ACPI_MADT_LOCAL_APIC *lapic; 354 ACPI_MADT_IO_APIC *ioapic; 355 ACPI_MADT_INTERRUPT_OVERRIDE *over; 356 ACPI_MADT_NMI_SOURCE *nmi; 357 ACPI_MADT_LOCAL_APIC_NMI *lapic_nmi; 358 ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_over; 359 ACPI_MADT_IO_SAPIC *iosapic; 360 ACPI_MADT_LOCAL_SAPIC *lsapic; 361 ACPI_MADT_INTERRUPT_SOURCE *isrc; 362 ACPI_MADT_LOCAL_X2APIC *x2apic; 363 ACPI_MADT_LOCAL_X2APIC_NMI *x2apic_nmi; 364 365 if (mp->Type < sizeof(apic_types) / sizeof(apic_types[0])) 366 printf("\tType=%s\n", apic_types[mp->Type]); 367 else 368 printf("\tType=%d (unknown)\n", mp->Type); 369 switch (mp->Type) { 370 case ACPI_MADT_TYPE_LOCAL_APIC: 371 lapic = (ACPI_MADT_LOCAL_APIC *)mp; 372 acpi_print_cpu(lapic->ProcessorId); 373 acpi_print_local_apic(lapic->Id, lapic->LapicFlags); 374 break; 375 case ACPI_MADT_TYPE_IO_APIC: 376 ioapic = (ACPI_MADT_IO_APIC *)mp; 377 acpi_print_io_apic(ioapic->Id, ioapic->GlobalIrqBase, 378 ioapic->Address); 379 break; 380 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 381 over = (ACPI_MADT_INTERRUPT_OVERRIDE *)mp; 382 printf("\tBUS=%d\n", (u_int)over->Bus); 383 printf("\tIRQ=%d\n", (u_int)over->SourceIrq); 384 acpi_print_intr(over->GlobalIrq, over->IntiFlags); 385 break; 386 case ACPI_MADT_TYPE_NMI_SOURCE: 387 nmi = (ACPI_MADT_NMI_SOURCE *)mp; 388 acpi_print_intr(nmi->GlobalIrq, nmi->IntiFlags); 389 break; 390 case ACPI_MADT_TYPE_LOCAL_APIC_NMI: 391 lapic_nmi = (ACPI_MADT_LOCAL_APIC_NMI *)mp; 392 acpi_print_cpu(lapic_nmi->ProcessorId); 393 acpi_print_local_nmi(lapic_nmi->Lint, lapic_nmi->IntiFlags); 394 break; 395 case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: 396 lapic_over = (ACPI_MADT_LOCAL_APIC_OVERRIDE *)mp; 397 printf("\tLocal APIC ADDR=0x%016jx\n", 398 (uintmax_t)lapic_over->Address); 399 break; 400 case ACPI_MADT_TYPE_IO_SAPIC: 401 iosapic = (ACPI_MADT_IO_SAPIC *)mp; 402 acpi_print_io_apic(iosapic->Id, iosapic->GlobalIrqBase, 403 iosapic->Address); 404 break; 405 case ACPI_MADT_TYPE_LOCAL_SAPIC: 406 lsapic = (ACPI_MADT_LOCAL_SAPIC *)mp; 407 acpi_print_cpu(lsapic->ProcessorId); 408 acpi_print_local_apic(lsapic->Id, lsapic->LapicFlags); 409 printf("\tAPIC EID=%d\n", (u_int)lsapic->Eid); 410 if (mp->Length > __offsetof(ACPI_MADT_LOCAL_SAPIC, Uid)) 411 acpi_print_cpu_uid(lsapic->Uid, lsapic->UidString); 412 break; 413 case ACPI_MADT_TYPE_INTERRUPT_SOURCE: 414 isrc = (ACPI_MADT_INTERRUPT_SOURCE *)mp; 415 if (isrc->Type < sizeof(platform_int_types) / 416 sizeof(platform_int_types[0])) 417 printf("\tType=%s\n", platform_int_types[isrc->Type]); 418 else 419 printf("\tType=%d (unknown)\n", isrc->Type); 420 printf("\tAPIC ID=%d\n", (u_int)isrc->Id); 421 printf("\tAPIC EID=%d\n", (u_int)isrc->Eid); 422 printf("\tSAPIC Vector=%d\n", (u_int)isrc->IoSapicVector); 423 acpi_print_intr(isrc->GlobalIrq, isrc->IntiFlags); 424 break; 425 case ACPI_MADT_TYPE_LOCAL_X2APIC: 426 x2apic = (ACPI_MADT_LOCAL_X2APIC *)mp; 427 acpi_print_cpu_uid(x2apic->Uid, NULL); 428 acpi_print_local_apic(x2apic->LocalApicId, x2apic->LapicFlags); 429 break; 430 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: 431 x2apic_nmi = (ACPI_MADT_LOCAL_X2APIC_NMI *)mp; 432 acpi_print_cpu_uid(x2apic_nmi->Uid, NULL); 433 acpi_print_local_nmi(x2apic_nmi->Lint, x2apic_nmi->IntiFlags); 434 break; 435 } 436} 437 438static void 439acpi_handle_madt(ACPI_TABLE_HEADER *sdp) 440{ 441 ACPI_TABLE_MADT *madt; 442 443 printf(BEGIN_COMMENT); 444 acpi_print_sdt(sdp); 445 madt = (ACPI_TABLE_MADT *)sdp; 446 printf("\tLocal APIC ADDR=0x%08x\n", madt->Address); 447 printf("\tFlags={"); 448 if (madt->Flags & ACPI_MADT_PCAT_COMPAT) 449 printf("PC-AT"); 450 printf("}\n"); 451 acpi_walk_subtables(sdp, (madt + 1), acpi_print_madt); 452 printf(END_COMMENT); 453} 454 455static void 456acpi_handle_hpet(ACPI_TABLE_HEADER *sdp) 457{ 458 ACPI_TABLE_HPET *hpet; 459 460 printf(BEGIN_COMMENT); 461 acpi_print_sdt(sdp); 462 hpet = (ACPI_TABLE_HPET *)sdp; 463 printf("\tHPET Number=%d\n", hpet->Sequence); 464 printf("\tADDR="); 465 acpi_print_gas(&hpet->Address); 466 printf("\tHW Rev=0x%x\n", hpet->Id & ACPI_HPET_ID_HARDWARE_REV_ID); 467 printf("\tComparators=%d\n", (hpet->Id & ACPI_HPET_ID_COMPARATORS) >> 468 8); 469 printf("\tCounter Size=%d\n", hpet->Id & ACPI_HPET_ID_COUNT_SIZE_CAP ? 470 1 : 0); 471 printf("\tLegacy IRQ routing capable={"); 472 if (hpet->Id & ACPI_HPET_ID_LEGACY_CAPABLE) 473 printf("TRUE}\n"); 474 else 475 printf("FALSE}\n"); 476 printf("\tPCI Vendor ID=0x%04x\n", hpet->Id >> 16); 477 printf("\tMinimal Tick=%d\n", hpet->MinimumTick); 478 printf(END_COMMENT); 479} 480 481static void 482acpi_handle_ecdt(ACPI_TABLE_HEADER *sdp) 483{ 484 ACPI_TABLE_ECDT *ecdt; 485 486 printf(BEGIN_COMMENT); 487 acpi_print_sdt(sdp); 488 ecdt = (ACPI_TABLE_ECDT *)sdp; 489 printf("\tEC_CONTROL="); 490 acpi_print_gas(&ecdt->Control); 491 printf("\n\tEC_DATA="); 492 acpi_print_gas(&ecdt->Data); 493 printf("\n\tUID=%#x, ", ecdt->Uid); 494 printf("GPE_BIT=%#x\n", ecdt->Gpe); 495 printf("\tEC_ID=%s\n", ecdt->Id); 496 printf(END_COMMENT); 497} 498 499static void 500acpi_handle_mcfg(ACPI_TABLE_HEADER *sdp) 501{ 502 ACPI_TABLE_MCFG *mcfg; 503 ACPI_MCFG_ALLOCATION *alloc; 504 u_int i, entries; 505 506 printf(BEGIN_COMMENT); 507 acpi_print_sdt(sdp); 508 mcfg = (ACPI_TABLE_MCFG *)sdp; 509 entries = (sdp->Length - sizeof(ACPI_TABLE_MCFG)) / 510 sizeof(ACPI_MCFG_ALLOCATION); 511 alloc = (ACPI_MCFG_ALLOCATION *)(mcfg + 1); 512 for (i = 0; i < entries; i++, alloc++) { 513 printf("\n"); 514 printf("\tBase Address=0x%016jx\n", alloc->Address); 515 printf("\tSegment Group=0x%04x\n", alloc->PciSegment); 516 printf("\tStart Bus=%d\n", alloc->StartBusNumber); 517 printf("\tEnd Bus=%d\n", alloc->EndBusNumber); 518 } 519 printf(END_COMMENT); 520} 521 522static void 523acpi_print_srat_cpu(uint32_t apic_id, uint32_t proximity_domain, 524 uint32_t flags) 525{ 526 527 printf("\tFlags={"); 528 if (flags & ACPI_SRAT_CPU_ENABLED) 529 printf("ENABLED"); 530 else 531 printf("DISABLED"); 532 printf("}\n"); 533 printf("\tAPIC ID=%d\n", apic_id); 534 printf("\tProximity Domain=%d\n", proximity_domain); 535} 536 537static char * 538acpi_tcpa_evname(struct TCPAevent *event) 539{ 540 struct TCPApc_event *pc_event; 541 char *eventname = NULL; 542 543 pc_event = (struct TCPApc_event *)(event + 1); 544 545 switch(event->event_type) { 546 case PREBOOT: 547 case POST_CODE: 548 case UNUSED: 549 case NO_ACTION: 550 case SEPARATOR: 551 case SCRTM_CONTENTS: 552 case SCRTM_VERSION: 553 case CPU_MICROCODE: 554 case PLATFORM_CONFIG_FLAGS: 555 case TABLE_OF_DEVICES: 556 case COMPACT_HASH: 557 case IPL: 558 case IPL_PARTITION_DATA: 559 case NONHOST_CODE: 560 case NONHOST_CONFIG: 561 case NONHOST_INFO: 562 asprintf(&eventname, "%s", 563 tcpa_event_type_strings[event->event_type]); 564 break; 565 566 case ACTION: 567 eventname = calloc(event->event_size + 1, sizeof(char)); 568 memcpy(eventname, pc_event, event->event_size); 569 break; 570 571 case EVENT_TAG: 572 switch (pc_event->event_id) { 573 case SMBIOS: 574 case BIS_CERT: 575 case CMOS: 576 case NVRAM: 577 case OPTION_ROM_EXEC: 578 case OPTION_ROM_CONFIG: 579 case S_CRTM_VERSION: 580 case POST_BIOS_ROM: 581 case ESCD: 582 case OPTION_ROM_MICROCODE: 583 case S_CRTM_CONTENTS: 584 case POST_CONTENTS: 585 asprintf(&eventname, "%s", 586 TCPA_pcclient_strings[pc_event->event_id]); 587 break; 588 589 default: 590 asprintf(&eventname, "<unknown tag 0x%02x>", 591 pc_event->event_id); 592 break; 593 } 594 break; 595 596 default: 597 asprintf(&eventname, "<unknown 0x%02x>", event->event_type); 598 break; 599 } 600 601 return eventname; 602} 603 604static void 605acpi_print_tcpa(struct TCPAevent *event) 606{ 607 int i; 608 char *eventname; 609 610 eventname = acpi_tcpa_evname(event); 611 612 printf("\t%d", event->pcr_index); 613 printf(" 0x"); 614 for (i = 0; i < 20; i++) 615 printf("%02x", event->pcr_value[i]); 616 printf(" [%s]\n", eventname ? eventname : "<unknown>"); 617 618 free(eventname); 619} 620 621static void 622acpi_handle_tcpa(ACPI_TABLE_HEADER *sdp) 623{ 624 struct TCPAbody *tcpa; 625 struct TCPAevent *event; 626 u_int64_t len, paddr; 627 unsigned char *vaddr = NULL; 628 unsigned char *vend = NULL; 629 630 printf(BEGIN_COMMENT); 631 acpi_print_sdt(sdp); 632 tcpa = (struct TCPAbody *) sdp; 633 634 switch (tcpa->platform_class) { 635 case ACPI_TCPA_BIOS_CLIENT: 636 len = tcpa->client.log_max_len; 637 paddr = tcpa->client.log_start_addr; 638 break; 639 640 case ACPI_TCPA_BIOS_SERVER: 641 len = tcpa->server.log_max_len; 642 paddr = tcpa->server.log_start_addr; 643 break; 644 645 default: 646 printf("XXX"); 647 printf(END_COMMENT); 648 return; 649 } 650 printf("\tClass %d Base Address 0x%jx Length %" PRIu64 "\n\n", 651 tcpa->platform_class, paddr, len); 652 653 if (len == 0) { 654 printf("\tEmpty TCPA table\n"); 655 printf(END_COMMENT); 656 return; 657 } 658 659 vaddr = (unsigned char *)acpi_map_physical(paddr, len); 660 vend = vaddr + len; 661 662 while (vaddr != NULL) { 663 if (vaddr + sizeof(struct TCPAevent) >= vend) 664 break; 665 event = (struct TCPAevent *)vaddr; 666 if (vaddr + event->event_size >= vend) 667 break; 668 if (event->event_type == 0 && event->event_size == 0) 669 break; 670#if 0 671 { 672 unsigned int i, j, k; 673 674 printf("\n\tsize %d\n\t\t%p ", event->event_size, vaddr); 675 for (j = 0, i = 0; i < 676 sizeof(struct TCPAevent) + event->event_size; i++) { 677 printf("%02x ", vaddr[i]); 678 if ((i+1) % 8 == 0) { 679 for (k = 0; k < 8; k++) 680 printf("%c", isprint(vaddr[j+k]) ? 681 vaddr[j+k] : '.'); 682 printf("\n\t\t%p ", &vaddr[i + 1]); 683 j = i + 1; 684 } 685 } 686 printf("\n"); } 687#endif 688 acpi_print_tcpa(event); 689 690 vaddr += sizeof(struct TCPAevent) + event->event_size; 691 } 692 693 printf(END_COMMENT); 694} 695 696static void 697acpi_print_srat_memory(ACPI_SRAT_MEM_AFFINITY *mp) 698{ 699 700 printf("\tFlags={"); 701 if (mp->Flags & ACPI_SRAT_MEM_ENABLED) 702 printf("ENABLED"); 703 else 704 printf("DISABLED"); 705 if (mp->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) 706 printf(",HOT_PLUGGABLE"); 707 if (mp->Flags & ACPI_SRAT_MEM_NON_VOLATILE) 708 printf(",NON_VOLATILE"); 709 printf("}\n"); 710 printf("\tBase Address=0x%016jx\n", (uintmax_t)mp->BaseAddress); 711 printf("\tLength=0x%016jx\n", (uintmax_t)mp->Length); 712 printf("\tProximity Domain=%d\n", mp->ProximityDomain); 713} 714 715const char *srat_types[] = { "CPU", "Memory", "X2APIC" }; 716 717static void 718acpi_print_srat(ACPI_SUBTABLE_HEADER *srat) 719{ 720 ACPI_SRAT_CPU_AFFINITY *cpu; 721 ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; 722 723 if (srat->Type < sizeof(srat_types) / sizeof(srat_types[0])) 724 printf("\tType=%s\n", srat_types[srat->Type]); 725 else 726 printf("\tType=%d (unknown)\n", srat->Type); 727 switch (srat->Type) { 728 case ACPI_SRAT_TYPE_CPU_AFFINITY: 729 cpu = (ACPI_SRAT_CPU_AFFINITY *)srat; 730 acpi_print_srat_cpu(cpu->ApicId, 731 cpu->ProximityDomainHi[2] << 24 | 732 cpu->ProximityDomainHi[1] << 16 | 733 cpu->ProximityDomainHi[0] << 0 | 734 cpu->ProximityDomainLo, cpu->Flags); 735 break; 736 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: 737 acpi_print_srat_memory((ACPI_SRAT_MEM_AFFINITY *)srat); 738 break; 739 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: 740 x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)srat; 741 acpi_print_srat_cpu(x2apic->ApicId, x2apic->ProximityDomain, 742 x2apic->Flags); 743 break; 744 } 745} 746 747static void 748acpi_handle_srat(ACPI_TABLE_HEADER *sdp) 749{ 750 ACPI_TABLE_SRAT *srat; 751 752 printf(BEGIN_COMMENT); 753 acpi_print_sdt(sdp); 754 srat = (ACPI_TABLE_SRAT *)sdp; 755 printf("\tTable Revision=%d\n", srat->TableRevision); 756 acpi_walk_subtables(sdp, (srat + 1), acpi_print_srat); 757 printf(END_COMMENT); 758} 759 760static void 761acpi_print_sdt(ACPI_TABLE_HEADER *sdp) 762{ 763 printf(" "); 764 acpi_print_string(sdp->Signature, ACPI_NAME_SIZE); 765 printf(": Length=%d, Revision=%d, Checksum=%d,\n", 766 sdp->Length, sdp->Revision, sdp->Checksum); 767 printf("\tOEMID="); 768 acpi_print_string(sdp->OemId, ACPI_OEM_ID_SIZE); 769 printf(", OEM Table ID="); 770 acpi_print_string(sdp->OemTableId, ACPI_OEM_TABLE_ID_SIZE); 771 printf(", OEM Revision=0x%x,\n", sdp->OemRevision); 772 printf("\tCreator ID="); 773 acpi_print_string(sdp->AslCompilerId, ACPI_NAME_SIZE); 774 printf(", Creator Revision=0x%x\n", sdp->AslCompilerRevision); 775} 776 777static void 778acpi_print_rsdt(ACPI_TABLE_HEADER *rsdp) 779{ 780 ACPI_TABLE_RSDT *rsdt; 781 ACPI_TABLE_XSDT *xsdt; 782 int i, entries; 783 u_long addr; 784 785 rsdt = (ACPI_TABLE_RSDT *)rsdp; 786 xsdt = (ACPI_TABLE_XSDT *)rsdp; 787 printf(BEGIN_COMMENT); 788 acpi_print_sdt(rsdp); 789 entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; 790 printf("\tEntries={ "); 791 for (i = 0; i < entries; i++) { 792 if (i > 0) 793 printf(", "); 794 switch (addr_size) { 795 case 4: 796 addr = le32toh(rsdt->TableOffsetEntry[i]); 797 break; 798 case 8: 799 addr = le64toh(xsdt->TableOffsetEntry[i]); 800 break; 801 default: 802 addr = 0; 803 } 804 assert(addr != 0); 805 printf("0x%08lx", addr); 806 } 807 printf(" }\n"); 808 printf(END_COMMENT); 809} 810 811static const char *acpi_pm_profiles[] = { 812 "Unspecified", "Desktop", "Mobile", "Workstation", 813 "Enterprise Server", "SOHO Server", "Appliance PC" 814}; 815 816static void 817acpi_print_fadt(ACPI_TABLE_HEADER *sdp) 818{ 819 ACPI_TABLE_FADT *fadt; 820 const char *pm; 821 char sep; 822 823 fadt = (ACPI_TABLE_FADT *)sdp; 824 printf(BEGIN_COMMENT); 825 acpi_print_sdt(sdp); 826 printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->Facs, 827 fadt->Dsdt); 828 printf("\tINT_MODEL=%s\n", fadt->Model ? "APIC" : "PIC"); 829 if (fadt->PreferredProfile >= sizeof(acpi_pm_profiles) / sizeof(char *)) 830 pm = "Reserved"; 831 else 832 pm = acpi_pm_profiles[fadt->PreferredProfile]; 833 printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->PreferredProfile); 834 printf("\tSCI_INT=%d\n", fadt->SciInterrupt); 835 printf("\tSMI_CMD=0x%x, ", fadt->SmiCommand); 836 printf("ACPI_ENABLE=0x%x, ", fadt->AcpiEnable); 837 printf("ACPI_DISABLE=0x%x, ", fadt->AcpiDisable); 838 printf("S4BIOS_REQ=0x%x\n", fadt->S4BiosRequest); 839 printf("\tPSTATE_CNT=0x%x\n", fadt->PstateControl); 840 printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", 841 fadt->Pm1aEventBlock, 842 fadt->Pm1aEventBlock + fadt->Pm1EventLength - 1); 843 if (fadt->Pm1bEventBlock != 0) 844 printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", 845 fadt->Pm1bEventBlock, 846 fadt->Pm1bEventBlock + fadt->Pm1EventLength - 1); 847 printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", 848 fadt->Pm1aControlBlock, 849 fadt->Pm1aControlBlock + fadt->Pm1ControlLength - 1); 850 if (fadt->Pm1bControlBlock != 0) 851 printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", 852 fadt->Pm1bControlBlock, 853 fadt->Pm1bControlBlock + fadt->Pm1ControlLength - 1); 854 if (fadt->Pm2ControlBlock != 0) 855 printf("\tPM2_CNT_BLK=0x%x-0x%x\n", 856 fadt->Pm2ControlBlock, 857 fadt->Pm2ControlBlock + fadt->Pm2ControlLength - 1); 858 printf("\tPM_TMR_BLK=0x%x-0x%x\n", 859 fadt->PmTimerBlock, 860 fadt->PmTimerBlock + fadt->PmTimerLength - 1); 861 if (fadt->Gpe0Block != 0) 862 printf("\tGPE0_BLK=0x%x-0x%x\n", 863 fadt->Gpe0Block, 864 fadt->Gpe0Block + fadt->Gpe0BlockLength - 1); 865 if (fadt->Gpe1Block != 0) 866 printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 867 fadt->Gpe1Block, 868 fadt->Gpe1Block + fadt->Gpe1BlockLength - 1, 869 fadt->Gpe1Base); 870 if (fadt->CstControl != 0) 871 printf("\tCST_CNT=0x%x\n", fadt->CstControl); 872 printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n", 873 fadt->C2Latency, fadt->C3Latency); 874 printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 875 fadt->FlushSize, fadt->FlushStride); 876 printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 877 fadt->DutyOffset, fadt->DutyWidth); 878 printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 879 fadt->DayAlarm, fadt->MonthAlarm, fadt->Century); 880 881#define PRINTFLAG(var, flag) do { \ 882 if ((var) & ACPI_FADT_## flag) { \ 883 printf("%c%s", sep, #flag); sep = ','; \ 884 } \ 885} while (0) 886 887 printf("\tIAPC_BOOT_ARCH="); 888 sep = '{'; 889 PRINTFLAG(fadt->BootFlags, LEGACY_DEVICES); 890 PRINTFLAG(fadt->BootFlags, 8042); 891 PRINTFLAG(fadt->BootFlags, NO_VGA); 892 PRINTFLAG(fadt->BootFlags, NO_MSI); 893 PRINTFLAG(fadt->BootFlags, NO_ASPM); 894 if (fadt->BootFlags != 0) 895 printf("}"); 896 printf("\n"); 897 898 printf("\tFlags="); 899 sep = '{'; 900 PRINTFLAG(fadt->Flags, WBINVD); 901 PRINTFLAG(fadt->Flags, WBINVD_FLUSH); 902 PRINTFLAG(fadt->Flags, C1_SUPPORTED); 903 PRINTFLAG(fadt->Flags, C2_MP_SUPPORTED); 904 PRINTFLAG(fadt->Flags, POWER_BUTTON); 905 PRINTFLAG(fadt->Flags, SLEEP_BUTTON); 906 PRINTFLAG(fadt->Flags, FIXED_RTC); 907 PRINTFLAG(fadt->Flags, S4_RTC_WAKE); 908 PRINTFLAG(fadt->Flags, 32BIT_TIMER); 909 PRINTFLAG(fadt->Flags, DOCKING_SUPPORTED); 910 PRINTFLAG(fadt->Flags, RESET_REGISTER); 911 PRINTFLAG(fadt->Flags, SEALED_CASE); 912 PRINTFLAG(fadt->Flags, HEADLESS); 913 PRINTFLAG(fadt->Flags, SLEEP_TYPE); 914 PRINTFLAG(fadt->Flags, PCI_EXPRESS_WAKE); 915 PRINTFLAG(fadt->Flags, PLATFORM_CLOCK); 916 PRINTFLAG(fadt->Flags, S4_RTC_VALID); 917 PRINTFLAG(fadt->Flags, REMOTE_POWER_ON); 918 PRINTFLAG(fadt->Flags, APIC_CLUSTER); 919 PRINTFLAG(fadt->Flags, APIC_PHYSICAL); 920 if (fadt->Flags != 0) 921 printf("}\n"); 922 923#undef PRINTFLAG 924 925 if (fadt->Flags & ACPI_FADT_RESET_REGISTER) { 926 printf("\tRESET_REG="); 927 acpi_print_gas(&fadt->ResetRegister); 928 printf(", RESET_VALUE=%#x\n", fadt->ResetValue); 929 } 930 if (acpi_get_fadt_revision(fadt) > 1) { 931 printf("\tX_FACS=0x%08lx, ", (u_long)fadt->XFacs); 932 printf("X_DSDT=0x%08lx\n", (u_long)fadt->XDsdt); 933 printf("\tX_PM1a_EVT_BLK="); 934 acpi_print_gas(&fadt->XPm1aEventBlock); 935 if (fadt->XPm1bEventBlock.Address != 0) { 936 printf("\n\tX_PM1b_EVT_BLK="); 937 acpi_print_gas(&fadt->XPm1bEventBlock); 938 } 939 printf("\n\tX_PM1a_CNT_BLK="); 940 acpi_print_gas(&fadt->XPm1aControlBlock); 941 if (fadt->XPm1bControlBlock.Address != 0) { 942 printf("\n\tX_PM1b_CNT_BLK="); 943 acpi_print_gas(&fadt->XPm1bControlBlock); 944 } 945 if (fadt->XPm2ControlBlock.Address != 0) { 946 printf("\n\tX_PM2_CNT_BLK="); 947 acpi_print_gas(&fadt->XPm2ControlBlock); 948 } 949 printf("\n\tX_PM_TMR_BLK="); 950 acpi_print_gas(&fadt->XPmTimerBlock); 951 if (fadt->XGpe0Block.Address != 0) { 952 printf("\n\tX_GPE0_BLK="); 953 acpi_print_gas(&fadt->XGpe0Block); 954 } 955 if (fadt->XGpe1Block.Address != 0) { 956 printf("\n\tX_GPE1_BLK="); 957 acpi_print_gas(&fadt->XGpe1Block); 958 } 959 printf("\n"); 960 } 961 962 printf(END_COMMENT); 963} 964 965static void 966acpi_print_facs(ACPI_TABLE_FACS *facs) 967{ 968 printf(BEGIN_COMMENT); 969 printf(" FACS:\tLength=%u, ", facs->Length); 970 printf("HwSig=0x%08x, ", facs->HardwareSignature); 971 printf("Firm_Wake_Vec=0x%08x\n", facs->FirmwareWakingVector); 972 973 printf("\tGlobal_Lock="); 974 if (facs->GlobalLock != 0) { 975 if (facs->GlobalLock & ACPI_GLOCK_PENDING) 976 printf("PENDING,"); 977 if (facs->GlobalLock & ACPI_GLOCK_OWNED) 978 printf("OWNED"); 979 } 980 printf("\n"); 981 982 printf("\tFlags="); 983 if (facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) 984 printf("S4BIOS"); 985 printf("\n"); 986 987 if (facs->XFirmwareWakingVector != 0) { 988 printf("\tX_Firm_Wake_Vec=%08lx\n", 989 (u_long)facs->XFirmwareWakingVector); 990 } 991 printf("\tVersion=%u\n", facs->Version); 992 993 printf(END_COMMENT); 994} 995 996static void 997acpi_print_dsdt(ACPI_TABLE_HEADER *dsdp) 998{ 999 printf(BEGIN_COMMENT); 1000 acpi_print_sdt(dsdp); 1001 printf(END_COMMENT); 1002} 1003 1004int 1005acpi_checksum(void *p, size_t length) 1006{ 1007 uint8_t *bp; 1008 uint8_t sum; 1009 1010 bp = p; 1011 sum = 0; 1012 while (length--) 1013 sum += *bp++; 1014 1015 return (sum); 1016} 1017 1018static ACPI_TABLE_HEADER * 1019acpi_map_sdt(vm_offset_t pa) 1020{ 1021 ACPI_TABLE_HEADER *sp; 1022 1023 sp = acpi_map_physical(pa, sizeof(ACPI_TABLE_HEADER)); 1024 sp = acpi_map_physical(pa, sp->Length); 1025 return (sp); 1026} 1027 1028static void 1029acpi_print_rsd_ptr(ACPI_TABLE_RSDP *rp) 1030{ 1031 printf(BEGIN_COMMENT); 1032 printf(" RSD PTR: OEM="); 1033 acpi_print_string(rp->OemId, ACPI_OEM_ID_SIZE); 1034 printf(", ACPI_Rev=%s (%d)\n", rp->Revision < 2 ? "1.0x" : "2.0x", 1035 rp->Revision); 1036 if (rp->Revision < 2) { 1037 printf("\tRSDT=0x%08x, cksum=%u\n", rp->RsdtPhysicalAddress, 1038 rp->Checksum); 1039 } else { 1040 printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n", 1041 (u_long)rp->XsdtPhysicalAddress, rp->Length, 1042 rp->ExtendedChecksum); 1043 } 1044 printf(END_COMMENT); 1045} 1046 1047static void 1048acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp) 1049{ 1050 ACPI_TABLE_HEADER *sdp; 1051 ACPI_TABLE_RSDT *rsdt; 1052 ACPI_TABLE_XSDT *xsdt; 1053 vm_offset_t addr; 1054 int entries, i; 1055 1056 acpi_print_rsdt(rsdp); 1057 rsdt = (ACPI_TABLE_RSDT *)rsdp; 1058 xsdt = (ACPI_TABLE_XSDT *)rsdp; 1059 entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; 1060 for (i = 0; i < entries; i++) { 1061 switch (addr_size) { 1062 case 4: 1063 addr = le32toh(rsdt->TableOffsetEntry[i]); 1064 break; 1065 case 8: 1066 addr = le64toh(xsdt->TableOffsetEntry[i]); 1067 break; 1068 default: 1069 assert((addr = 0)); 1070 } 1071 1072 sdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr); 1073 if (acpi_checksum(sdp, sdp->Length)) { 1074 warnx("RSDT entry %d (sig %.4s) is corrupt", i, 1075 sdp->Signature); 1076 continue; 1077 } 1078 if (!memcmp(sdp->Signature, ACPI_SIG_FADT, 4)) 1079 acpi_handle_fadt(sdp); 1080 else if (!memcmp(sdp->Signature, ACPI_SIG_MADT, 4)) 1081 acpi_handle_madt(sdp); 1082 else if (!memcmp(sdp->Signature, ACPI_SIG_HPET, 4)) 1083 acpi_handle_hpet(sdp); 1084 else if (!memcmp(sdp->Signature, ACPI_SIG_ECDT, 4)) 1085 acpi_handle_ecdt(sdp); 1086 else if (!memcmp(sdp->Signature, ACPI_SIG_MCFG, 4)) 1087 acpi_handle_mcfg(sdp); 1088 else if (!memcmp(sdp->Signature, ACPI_SIG_SRAT, 4)) 1089 acpi_handle_srat(sdp); 1090 else if (!memcmp(sdp->Signature, ACPI_SIG_TCPA, 4)) 1091 acpi_handle_tcpa(sdp); 1092 else { 1093 printf(BEGIN_COMMENT); 1094 acpi_print_sdt(sdp); 1095 printf(END_COMMENT); 1096 } 1097 } 1098} 1099 1100ACPI_TABLE_HEADER * 1101sdt_load_devmem(void) 1102{ 1103 ACPI_TABLE_RSDP *rp; 1104 ACPI_TABLE_HEADER *rsdp; 1105 1106 rp = acpi_find_rsd_ptr(); 1107 if (!rp) 1108 errx(1, "Can't find ACPI information"); 1109 1110 if (tflag) 1111 acpi_print_rsd_ptr(rp); 1112 if (rp->Revision < 2) { 1113 rsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(rp->RsdtPhysicalAddress); 1114 if (memcmp(rsdp->Signature, "RSDT", 4) != 0 || 1115 acpi_checksum(rsdp, rsdp->Length) != 0) 1116 errx(1, "RSDT is corrupted"); 1117 addr_size = sizeof(uint32_t); 1118 } else { 1119 rsdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(rp->XsdtPhysicalAddress); 1120 if (memcmp(rsdp->Signature, "XSDT", 4) != 0 || 1121 acpi_checksum(rsdp, rsdp->Length) != 0) 1122 errx(1, "XSDT is corrupted"); 1123 addr_size = sizeof(uint64_t); 1124 } 1125 return (rsdp); 1126} 1127 1128/* Write the DSDT to a file, concatenating any SSDTs (if present). */ 1129static int 1130write_dsdt(int fd, ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdt) 1131{ 1132 ACPI_TABLE_HEADER sdt; 1133 ACPI_TABLE_HEADER *ssdt; 1134 uint8_t sum; 1135 1136 /* Create a new checksum to account for the DSDT and any SSDTs. */ 1137 sdt = *dsdt; 1138 if (rsdt != NULL) { 1139 sdt.Checksum = 0; 1140 sum = acpi_checksum(dsdt + 1, dsdt->Length - 1141 sizeof(ACPI_TABLE_HEADER)); 1142 ssdt = sdt_from_rsdt(rsdt, ACPI_SIG_SSDT, NULL); 1143 while (ssdt != NULL) { 1144 sdt.Length += ssdt->Length - sizeof(ACPI_TABLE_HEADER); 1145 sum += acpi_checksum(ssdt + 1, 1146 ssdt->Length - sizeof(ACPI_TABLE_HEADER)); 1147 ssdt = sdt_from_rsdt(rsdt, ACPI_SIG_SSDT, ssdt); 1148 } 1149 sum += acpi_checksum(&sdt, sizeof(ACPI_TABLE_HEADER)); 1150 sdt.Checksum -= sum; 1151 } 1152 1153 /* Write out the DSDT header and body. */ 1154 write(fd, &sdt, sizeof(ACPI_TABLE_HEADER)); 1155 write(fd, dsdt + 1, dsdt->Length - sizeof(ACPI_TABLE_HEADER)); 1156 1157 /* Write out any SSDTs (if present.) */ 1158 if (rsdt != NULL) { 1159 ssdt = sdt_from_rsdt(rsdt, "SSDT", NULL); 1160 while (ssdt != NULL) { 1161 write(fd, ssdt + 1, ssdt->Length - 1162 sizeof(ACPI_TABLE_HEADER)); 1163 ssdt = sdt_from_rsdt(rsdt, "SSDT", ssdt); 1164 } 1165 } 1166 return (0); 1167} 1168 1169void 1170dsdt_save_file(char *outfile, ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdp) 1171{ 1172 int fd; 1173 mode_t mode; 1174 1175 assert(outfile != NULL); 1176 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1177 fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode); 1178 if (fd == -1) { 1179 perror("dsdt_save_file"); 1180 return; 1181 } 1182 write_dsdt(fd, rsdt, dsdp); 1183 close(fd); 1184} 1185 1186void 1187aml_disassemble(ACPI_TABLE_HEADER *rsdt, ACPI_TABLE_HEADER *dsdp) 1188{ 1189 char buf[PATH_MAX], tmpstr[PATH_MAX]; 1190 const char *tmpdir; 1191 char *tmpext; 1192 FILE *fp; 1193 size_t len; 1194 int fd; 1195 1196 tmpdir = getenv("TMPDIR"); 1197 if (tmpdir == NULL) 1198 tmpdir = _PATH_TMP; 1199 strncpy(tmpstr, tmpdir, sizeof(tmpstr)); 1200 strncat(tmpstr, "/acpidump.", sizeof(tmpstr) - strlen(tmpdir)); 1201 if (realpath(tmpstr, buf) == NULL) { 1202 perror("realpath tmp file"); 1203 return; 1204 } 1205 strncpy(tmpstr, buf, sizeof(tmpstr)); 1206 len = strlen(buf); 1207 tmpext = tmpstr + len; 1208 strncpy(tmpext, "XXXXXX", sizeof(tmpstr) - len); 1209 fd = mkstemp(tmpstr); 1210 if (fd < 0) { 1211 perror("iasl tmp file"); 1212 return; 1213 } 1214 write_dsdt(fd, rsdt, dsdp); 1215 close(fd); 1216 1217 /* Run iasl -d on the temp file */ 1218 if (fork() == 0) { 1219 close(STDOUT_FILENO); 1220 if (vflag == 0) 1221 close(STDERR_FILENO); 1222 execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, NULL); 1223 err(1, "exec"); 1224 } 1225 1226 wait(NULL); 1227 unlink(tmpstr); 1228 1229 /* Dump iasl's output to stdout */ 1230 strncpy(tmpext, "dsl", sizeof(tmpstr) - len); 1231 fp = fopen(tmpstr, "r"); 1232 unlink(tmpstr); 1233 if (fp == NULL) { 1234 perror("iasl tmp file (read)"); 1235 return; 1236 } 1237 while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) 1238 fwrite(buf, 1, len, stdout); 1239 fclose(fp); 1240} 1241 1242void 1243sdt_print_all(ACPI_TABLE_HEADER *rsdp) 1244{ 1245 acpi_handle_rsdt(rsdp); 1246} 1247 1248/* Fetch a table matching the given signature via the RSDT. */ 1249ACPI_TABLE_HEADER * 1250sdt_from_rsdt(ACPI_TABLE_HEADER *rsdp, const char *sig, ACPI_TABLE_HEADER *last) 1251{ 1252 ACPI_TABLE_HEADER *sdt; 1253 ACPI_TABLE_RSDT *rsdt; 1254 ACPI_TABLE_XSDT *xsdt; 1255 vm_offset_t addr; 1256 int entries, i; 1257 1258 rsdt = (ACPI_TABLE_RSDT *)rsdp; 1259 xsdt = (ACPI_TABLE_XSDT *)rsdp; 1260 entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; 1261 for (i = 0; i < entries; i++) { 1262 switch (addr_size) { 1263 case 4: 1264 addr = le32toh(rsdt->TableOffsetEntry[i]); 1265 break; 1266 case 8: 1267 addr = le64toh(xsdt->TableOffsetEntry[i]); 1268 break; 1269 default: 1270 assert((addr = 0)); 1271 } 1272 sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr); 1273 if (last != NULL) { 1274 if (sdt == last) 1275 last = NULL; 1276 continue; 1277 } 1278 if (memcmp(sdt->Signature, sig, strlen(sig))) 1279 continue; 1280 if (acpi_checksum(sdt, sdt->Length)) 1281 errx(1, "RSDT entry %d is corrupt", i); 1282 return (sdt); 1283 } 1284 1285 return (NULL); 1286} 1287 1288ACPI_TABLE_HEADER * 1289dsdt_from_fadt(ACPI_TABLE_FADT *fadt) 1290{ 1291 ACPI_TABLE_HEADER *sdt; 1292 1293 /* Use the DSDT address if it is version 1, otherwise use XDSDT. */ 1294 if (acpi_get_fadt_revision(fadt) == 1) 1295 sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->Dsdt); 1296 else 1297 sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(fadt->XDsdt); 1298 if (acpi_checksum(sdt, sdt->Length)) 1299 errx(1, "DSDT is corrupt\n"); 1300 return (sdt); 1301} 1302