acpi.c revision 119971
1187770Sluigi/*- 2187770Sluigi * Copyright (c) 1998 Doug Rabson 3187770Sluigi * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 4187770Sluigi * All rights reserved. 5187770Sluigi * 6187770Sluigi * Redistribution and use in source and binary forms, with or without 7187770Sluigi * modification, are permitted provided that the following conditions 8187770Sluigi * are met: 9187770Sluigi * 1. Redistributions of source code must retain the above copyright 10187770Sluigi * notice, this list of conditions and the following disclaimer. 11187770Sluigi * 2. Redistributions in binary form must reproduce the above copyright 12187770Sluigi * notice, this list of conditions and the following disclaimer in the 13187770Sluigi * documentation and/or other materials provided with the distribution. 14187770Sluigi * 15187770Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16187770Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17187770Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18187770Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19187770Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20187770Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21187770Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22187770Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23187770Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24187770Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25187770Sluigi * SUCH DAMAGE. 26187770Sluigi * 27187770Sluigi * $FreeBSD: head/usr.sbin/acpi/acpidump/acpi.c 119971 2003-09-10 23:52:12Z njl $ 28187770Sluigi */ 29187770Sluigi 30187770Sluigi#include <sys/param.h> 31187770Sluigi#include <sys/endian.h> 32187770Sluigi#include <sys/stat.h> 33187770Sluigi#include <sys/wait.h> 34187770Sluigi#include <assert.h> 35187770Sluigi#include <err.h> 36187770Sluigi#include <fcntl.h> 37187770Sluigi#include <stdio.h> 38187770Sluigi#include <string.h> 39187770Sluigi#include <unistd.h> 40187770Sluigi 41187770Sluigi#include "acpidump.h" 42187770Sluigi 43187770Sluigi#define BEGIN_COMMENT "/*\n" 44187770Sluigi#define END_COMMENT " */\n" 45187770Sluigi 46187770Sluigistatic void acpi_print_string(char *s, size_t length); 47187770Sluigistatic void acpi_print_gas(struct ACPIgas *gas); 48187770Sluigistatic void acpi_handle_fadt(struct FADTbody *fadt); 49187770Sluigistatic void acpi_print_cpu(u_char cpu_id); 50220802Sglebiusstatic void acpi_print_local_apic(u_char cpu_id, u_char apic_id, 51220802Sglebius u_int32_t flags); 52220802Sglebiusstatic void acpi_print_io_apic(u_char apic_id, u_int32_t int_base, 53220802Sglebius u_int64_t apic_addr); 54220802Sglebiusstatic void acpi_print_mps_flags(u_int16_t flags); 55220802Sglebiusstatic void acpi_print_intr(u_int32_t intr, u_int16_t mps_flags); 56223080Saestatic void acpi_print_apic(struct MADT_APIC *mp); 57220802Sglebiusstatic void acpi_handle_apic(struct ACPIsdt *sdp); 58220804Sglebiusstatic void acpi_handle_hpet(struct ACPIsdt *sdp); 59220802Sglebiusstatic void acpi_print_sdt(struct ACPIsdt *sdp); 60187770Sluigistatic void acpi_print_fadt(struct FADTbody *fadt); 61187770Sluigistatic void acpi_print_facs(struct FACSbody *facs); 62187770Sluigistatic void acpi_print_dsdt(struct ACPIsdt *dsdp); 63187770Sluigistatic struct ACPIsdt *acpi_map_sdt(vm_offset_t pa); 64187770Sluigistatic void acpi_print_rsd_ptr(struct ACPIrsdp *rp); 65187770Sluigistatic void acpi_handle_rsdt(struct ACPIsdt *rsdp); 66187770Sluigi 67220802Sglebius/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */ 68187770Sluigistatic int addr_size; 69187770Sluigi 70220802Sglebiusstatic void 71187770Sluigiacpi_print_string(char *s, size_t length) 72187770Sluigi{ 73187770Sluigi int c; 74187770Sluigi 75187770Sluigi /* Trim trailing spaces and NULLs */ 76187770Sluigi while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 77187770Sluigi length--; 78187770Sluigi 79187770Sluigi while (length--) { 80187770Sluigi c = *s++; 81187770Sluigi putchar(c); 82187770Sluigi } 83187770Sluigi} 84187770Sluigi 85187770Sluigistatic void 86187770Sluigiacpi_print_gas(struct ACPIgas *gas) 87187770Sluigi{ 88220804Sglebius switch(gas->address_space_id) { 89187770Sluigi case ACPI_GAS_MEMORY: 90220804Sglebius printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->address, 91187770Sluigi gas->bit_offset, gas->bit_width); 92187770Sluigi break; 93187770Sluigi case ACPI_GAS_IO: 94187770Sluigi printf("0x%08lx:%u[%u] (IO)", (u_long)gas->address, 95187770Sluigi gas->bit_offset, gas->bit_width); 96187770Sluigi break; 97187770Sluigi case ACPI_GAS_PCI: 98187770Sluigi printf("%x:%x+%#x (PCI)", (uint16_t)(gas->address >> 32), 99187770Sluigi (uint16_t)((gas->address >> 16) & 0xffff), 100187770Sluigi (uint16_t)gas->address); 101187770Sluigi break; 102187770Sluigi /* XXX How to handle these below? */ 103187770Sluigi case ACPI_GAS_EMBEDDED: 104187770Sluigi printf("0x%#x:%u[%u] (EC)", (uint16_t)gas->address, 105187770Sluigi gas->bit_offset, gas->bit_width); 106187770Sluigi break; 107187770Sluigi case ACPI_GAS_SMBUS: 108187770Sluigi printf("0x%#x:%u[%u] (SMBus)", (uint16_t)gas->address, 109187770Sluigi gas->bit_offset, gas->bit_width); 110187770Sluigi break; 111187770Sluigi case ACPI_GAS_FIXED: 112187770Sluigi default: 113187770Sluigi printf("0x%08lx (?)", (u_long)gas->address); 114187770Sluigi break; 115187770Sluigi } 116187770Sluigi} 117187770Sluigi 118187770Sluigistatic void 119187770Sluigiacpi_handle_fadt(struct FADTbody *fadt) 120187770Sluigi{ 121187770Sluigi struct ACPIsdt *dsdp; 122187770Sluigi struct FACSbody *facs; 123187770Sluigi 124187770Sluigi acpi_print_fadt(fadt); 125187770Sluigi 126187770Sluigi /* 127187770Sluigi * My T23 is revision 2 but the 64 bit addresses are invalid. 128187770Sluigi * If revision 2 and the 32 bit address is non-zero but the 32 129187770Sluigi * and 64 bit versions don't match, prefer the 32 bit version. 130187770Sluigi */ 131187770Sluigi if (addr_size == 4 || 132187770Sluigi (addr_size == 8 && fadt->facs_ptr != 0 && 133187770Sluigi (fadt->x_facs_ptr & 0xffffffff) != fadt->facs_ptr)) 134187770Sluigi facs = (struct FACSbody *)acpi_map_sdt(fadt->facs_ptr); 135187770Sluigi else 136187770Sluigi facs = (struct FACSbody *)acpi_map_sdt(fadt->x_facs_ptr); 137187770Sluigi if (memcmp(facs->signature, "FACS", 4) != 0 || facs->len < 64) 138187770Sluigi errx(1, "FACS is corrupt"); 139187770Sluigi acpi_print_facs(facs); 140187770Sluigi 141187770Sluigi if (addr_size == 4 || 142187770Sluigi (addr_size == 8 && fadt->dsdt_ptr != 0 && 143187770Sluigi (fadt->x_dsdt_ptr & 0xffffffff) != fadt->dsdt_ptr)) 144187770Sluigi dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr); 145187770Sluigi else 146187770Sluigi dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr); 147187770Sluigi if (acpi_checksum(dsdp, dsdp->len)) 148187770Sluigi errx(1, "DSDT is corrupt"); 149187770Sluigi acpi_print_dsdt(dsdp); 150187770Sluigi} 151187770Sluigi 152187770Sluigistatic void 153187770Sluigiacpi_print_cpu(u_char cpu_id) 154187770Sluigi{ 155187770Sluigi 156187770Sluigi printf("\tACPI CPU="); 157187770Sluigi if (cpu_id == 0xff) 158187770Sluigi printf("ALL\n"); 159187770Sluigi else 160187770Sluigi printf("%d\n", (u_int)cpu_id); 161187770Sluigi} 162187770Sluigi 163187770Sluigistatic void 164187770Sluigiacpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags) 165187770Sluigi{ 166187770Sluigi acpi_print_cpu(cpu_id); 167220802Sglebius printf("\tFlags={"); 168187770Sluigi if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED) 169220802Sglebius printf("ENABLED"); 170220802Sglebius else 171187770Sluigi printf("DISABLED"); 172187770Sluigi printf("}\n"); 173187770Sluigi printf("\tAPIC ID=%d\n", (u_int)apic_id); 174187770Sluigi} 175187770Sluigi 176187770Sluigistatic void 177220802Sglebiusacpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr) 178187770Sluigi{ 179187770Sluigi printf("\tAPIC ID=%d\n", (u_int)apic_id); 180187770Sluigi printf("\tINT BASE=%d\n", int_base); 181187770Sluigi printf("\tADDR=0x%016jx\n", apic_addr); 182187770Sluigi} 183220802Sglebius 184220802Sglebiusstatic void 185220802Sglebiusacpi_print_mps_flags(u_int16_t flags) 186187770Sluigi{ 187187770Sluigi 188187770Sluigi printf("\tFlags={Polarity="); 189187770Sluigi switch (flags & MPS_INT_FLAG_POLARITY_MASK) { 190187770Sluigi case MPS_INT_FLAG_POLARITY_CONFORM: 191187770Sluigi printf("conforming"); 192187770Sluigi break; 193220802Sglebius case MPS_INT_FLAG_POLARITY_HIGH: 194187770Sluigi printf("active-hi"); 195187770Sluigi break; 196187770Sluigi case MPS_INT_FLAG_POLARITY_LOW: 197187770Sluigi printf("active-lo"); 198187770Sluigi break; 199187770Sluigi default: 200187770Sluigi printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK); 201187770Sluigi break; 202187770Sluigi } 203187770Sluigi printf(", Trigger="); 204187770Sluigi switch (flags & MPS_INT_FLAG_TRIGGER_MASK) { 205187770Sluigi case MPS_INT_FLAG_TRIGGER_CONFORM: 206187770Sluigi printf("conforming"); 207187770Sluigi break; 208220802Sglebius case MPS_INT_FLAG_TRIGGER_EDGE: 209187770Sluigi printf("edge"); 210187770Sluigi break; 211220802Sglebius case MPS_INT_FLAG_TRIGGER_LEVEL: 212187770Sluigi printf("level"); 213187770Sluigi break; 214220802Sglebius default: 215220802Sglebius printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2); 216220804Sglebius } 217187770Sluigi printf("}\n"); 218187770Sluigi} 219187770Sluigi 220220802Sglebiusstatic void 221187770Sluigiacpi_print_intr(u_int32_t intr, u_int16_t mps_flags) 222187770Sluigi{ 223187770Sluigi 224220802Sglebius printf("\tINTR=%d\n", (u_int)intr); 225187770Sluigi acpi_print_mps_flags(mps_flags); 226187770Sluigi} 227187770Sluigi 228220802Sglebiusconst char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", 229187770Sluigi "Local NMI", "Local APIC Override", "IO SAPIC", 230220802Sglebius "Local SAPIC", "Platform Interrupt" }; 231220802Sglebiusconst char *platform_int_types[] = { "PMI", "INIT", 232187770Sluigi "Corrected Platform Error" }; 233187770Sluigi 234187770Sluigistatic void 235187770Sluigiacpi_print_apic(struct MADT_APIC *mp) 236187770Sluigi{ 237187770Sluigi 238187770Sluigi printf("\tType=%s\n", apic_types[mp->type]); 239187770Sluigi switch (mp->type) { 240187770Sluigi case ACPI_MADT_APIC_TYPE_LOCAL_APIC: 241187770Sluigi acpi_print_local_apic(mp->body.local_apic.cpu_id, 242187770Sluigi mp->body.local_apic.apic_id, mp->body.local_apic.flags); 243187770Sluigi break; 244220802Sglebius case ACPI_MADT_APIC_TYPE_IO_APIC: 245187770Sluigi acpi_print_io_apic(mp->body.io_apic.apic_id, 246187770Sluigi mp->body.io_apic.int_base, 247220802Sglebius mp->body.io_apic.apic_addr); 248187770Sluigi break; 249187770Sluigi case ACPI_MADT_APIC_TYPE_INT_OVERRIDE: 250187770Sluigi printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus); 251187770Sluigi printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source); 252220802Sglebius acpi_print_intr(mp->body.int_override.intr, 253187770Sluigi mp->body.int_override.mps_flags); 254187770Sluigi break; 255187770Sluigi case ACPI_MADT_APIC_TYPE_NMI: 256187770Sluigi acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags); 257187770Sluigi break; 258187770Sluigi case ACPI_MADT_APIC_TYPE_LOCAL_NMI: 259187770Sluigi acpi_print_cpu(mp->body.local_nmi.cpu_id); 260187770Sluigi printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin); 261188294Spiso acpi_print_mps_flags(mp->body.local_nmi.mps_flags); 262188294Spiso break; 263188294Spiso case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE: 264187770Sluigi printf("\tLocal APIC ADDR=0x%016jx\n", 265187770Sluigi mp->body.local_apic_override.apic_addr); 266220802Sglebius break; 267220802Sglebius case ACPI_MADT_APIC_TYPE_IO_SAPIC: 268220802Sglebius acpi_print_io_apic(mp->body.io_sapic.apic_id, 269187770Sluigi mp->body.io_sapic.int_base, 270187770Sluigi mp->body.io_sapic.apic_addr); 271187770Sluigi break; 272187770Sluigi case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC: 273187770Sluigi acpi_print_local_apic(mp->body.local_sapic.cpu_id, 274187770Sluigi mp->body.local_sapic.apic_id, mp->body.local_sapic.flags); 275187770Sluigi printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid); 276187770Sluigi break; 277187770Sluigi case ACPI_MADT_APIC_TYPE_INT_SRC: 278187770Sluigi printf("\tType=%s\n", 279187770Sluigi platform_int_types[mp->body.int_src.type]); 280187770Sluigi printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id); 281187770Sluigi printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id); 282187770Sluigi printf("\tSAPIC Vector=%d\n", 283187770Sluigi (u_int)mp->body.int_src.sapic_vector); 284187770Sluigi acpi_print_intr(mp->body.int_src.intr, 285220802Sglebius mp->body.int_src.mps_flags); 286220802Sglebius break; 287220802Sglebius default: 288187770Sluigi printf("\tUnknown type %d\n", (u_int)mp->type); 289187770Sluigi break; 290220802Sglebius } 291220802Sglebius} 292187770Sluigi 293220802Sglebiusstatic void 294187770Sluigiacpi_handle_apic(struct ACPIsdt *sdp) 295187770Sluigi{ 296220802Sglebius struct MADTbody *madtp; 297187770Sluigi struct MADT_APIC *madt_apicp; 298187770Sluigi 299187770Sluigi printf(BEGIN_COMMENT); 300187770Sluigi acpi_print_sdt(sdp); 301220802Sglebius madtp = (struct MADTbody *) sdp->body; 302187770Sluigi printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr); 303187770Sluigi printf("\tFlags={"); 304187770Sluigi if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT) 305187770Sluigi printf("PC-AT"); 306187770Sluigi printf("}\n"); 307220802Sglebius madt_apicp = (struct MADT_APIC *)madtp->body; 308187770Sluigi while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) { 309220802Sglebius printf("\n"); 310220802Sglebius acpi_print_apic(madt_apicp); 311187770Sluigi madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp + 312187770Sluigi madt_apicp->len); 313187770Sluigi } 314187770Sluigi printf(END_COMMENT); 315220835Sglebius} 316187770Sluigi 317220835Sglebiusstatic void 318223185Sglebiusacpi_handle_hpet(struct ACPIsdt *sdp) 319223185Sglebius{ 320220835Sglebius struct HPETbody *hpetp; 321223185Sglebius 322223185Sglebius printf(BEGIN_COMMENT); 323223185Sglebius acpi_print_sdt(sdp); 324220835Sglebius hpetp = (struct HPETbody *) sdp->body; 325220835Sglebius printf("\tHPET Number=%d\n", hpetp->hpet_number); 326223185Sglebius printf("\tADDR=0x%08x\n", hpetp->base_addr); 327223185Sglebius printf("\tHW Rev=0x%x\n", hpetp->block_hwrev); 328223185Sglebius printf("\tComparitors=%d\n", hpetp->block_comparitors); 329223185Sglebius printf("\tCounter Size=%d\n", hpetp->block_counter_size); 330223185Sglebius printf("\tLegacy IRQ routing capable={"); 331220835Sglebius if (hpetp->block_legacy_capable) 332220835Sglebius printf("TRUE}\n"); 333220835Sglebius else 334220835Sglebius printf("FALSE}\n"); 335220835Sglebius printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor); 336220835Sglebius printf("\tMinimal Tick=%d\n", hpetp->clock_tick); 337220804Sglebius printf(END_COMMENT); 338220835Sglebius} 339220835Sglebius 340187770Sluigistatic void 341220835Sglebiusacpi_handle_ecdt(struct ACPIsdt *sdp) 342187770Sluigi{ 343220835Sglebius struct ECDTbody *ecdt; 344220835Sglebius 345220835Sglebius printf(BEGIN_COMMENT); 346220835Sglebius acpi_print_sdt(sdp); 347187770Sluigi ecdt = (struct ECDTbody *) sdp->body; 348220835Sglebius printf("\tEC_CONTROL="); 349220835Sglebius acpi_print_gas(&ecdt->ec_control); 350220835Sglebius printf("\n\tEC_DATA="); 351220835Sglebius acpi_print_gas(&ecdt->ec_data); 352187770Sluigi printf("\n\tUID=%#x, ", ecdt->uid); 353187770Sluigi printf("GPE_BIT=%#x\n", ecdt->gpe_bit); 354220835Sglebius printf("\tEC_ID=%s\n", ecdt->ec_id); 355220835Sglebius printf(END_COMMENT); 356220835Sglebius} 357220835Sglebius 358187770Sluigistatic void 359187770Sluigiacpi_print_sdt(struct ACPIsdt *sdp) 360220835Sglebius{ 361187770Sluigi printf(" "); 362187770Sluigi acpi_print_string(sdp->signature, 4); 363220835Sglebius printf(": Length=%d, Revision=%d, Checksum=%d,\n", 364220835Sglebius sdp->len, sdp->rev, sdp->check); 365220835Sglebius printf("\tOEMID="); 366220835Sglebius acpi_print_string(sdp->oemid, 6); 367220835Sglebius printf(", OEM Table ID="); 368220835Sglebius acpi_print_string(sdp->oemtblid, 8); 369220835Sglebius printf(", OEM Revision=0x%x,\n", sdp->oemrev); 370220835Sglebius printf("\tCreator ID="); 371220835Sglebius acpi_print_string(sdp->creator, 4); 372220835Sglebius printf(", Creator Revision=0x%x\n", sdp->crerev); 373220835Sglebius} 374220835Sglebius 375220835Sglebiusstatic void 376220835Sglebiusacpi_print_rsdt(struct ACPIsdt *rsdp) 377220835Sglebius{ 378223185Sglebius int i, entries; 379223185Sglebius u_long addr; 380220835Sglebius 381223185Sglebius printf(BEGIN_COMMENT); 382223185Sglebius acpi_print_sdt(rsdp); 383223185Sglebius entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 384187770Sluigi printf("\tEntries={ "); 385220835Sglebius for (i = 0; i < entries; i++) { 386223185Sglebius if (i > 0) 387223185Sglebius printf(", "); 388223185Sglebius switch (addr_size) { 389223185Sglebius case 4: 390223185Sglebius addr = le32dec((char*)rsdp->body + i * addr_size); 391220835Sglebius break; 392187770Sluigi case 8: 393187770Sluigi addr = le64dec((char*)rsdp->body + i * addr_size); 394187770Sluigi break; 395220835Sglebius default: 396187770Sluigi addr = 0; 397187770Sluigi } 398220835Sglebius assert(addr != 0); 399220835Sglebius printf("0x%08lx", addr); 400187770Sluigi } 401220804Sglebius printf(" }\n"); 402187770Sluigi printf(END_COMMENT); 403220804Sglebius} 404187770Sluigi 405220835Sglebiusstatic const char *acpi_pm_profiles[] = { 406187770Sluigi "Unspecified", "Desktop", "Mobile", "Workstation", 407220835Sglebius "Enterprise Server", "SOHO Server", "Appliance PC" 408220835Sglebius}; 409220835Sglebius 410220835Sglebiusstatic void 411187770Sluigiacpi_print_fadt(struct FADTbody *fadt) 412187770Sluigi{ 413187770Sluigi const char *pm; 414220835Sglebius char sep; 415220835Sglebius 416220835Sglebius printf(BEGIN_COMMENT); 417187770Sluigi printf(" FADT:\tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr, 418187770Sluigi fadt->dsdt_ptr); 419187770Sluigi printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC"); 420187770Sluigi if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *)) 421220835Sglebius pm = "Reserved"; 422187770Sluigi else 423187770Sluigi pm = acpi_pm_profiles[fadt->pm_profile]; 424187770Sluigi printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile); 425220835Sglebius printf("\tSCI_INT=%d\n", fadt->sci_int); 426187770Sluigi printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd); 427188294Spiso printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable); 428220802Sglebius printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable); 429220802Sglebius printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq); 430188294Spiso printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt); 431188294Spiso if (fadt->pm1a_evt_blk != 0) 432188294Spiso printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", 433220835Sglebius fadt->pm1a_evt_blk, 434188294Spiso fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1); 435220835Sglebius if (fadt->pm1b_evt_blk != 0) 436220835Sglebius printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", 437188294Spiso fadt->pm1b_evt_blk, 438220835Sglebius fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1); 439188294Spiso if (fadt->pm1a_cnt_blk != 0) 440220835Sglebius printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", 441220835Sglebius fadt->pm1a_cnt_blk, 442220835Sglebius fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1); 443188294Spiso if (fadt->pm1b_cnt_blk != 0) 444187770Sluigi printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", 445188294Spiso fadt->pm1b_cnt_blk, 446188294Spiso fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1); 447188294Spiso if (fadt->pm2_cnt_blk != 0) 448187770Sluigi printf("\tPM2_CNT_BLK=0x%x-0x%x\n", 449220835Sglebius fadt->pm2_cnt_blk, 450187770Sluigi fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1); 451187770Sluigi if (fadt->pm_tmr_blk != 0) 452187770Sluigi printf("\tPM2_TMR_BLK=0x%x-0x%x\n", 453187770Sluigi fadt->pm_tmr_blk, 454220835Sglebius fadt->pm_tmr_blk + fadt->pm_tmr_len - 1); 455220835Sglebius if (fadt->gpe0_blk != 0) 456187770Sluigi printf("\tGPE0_BLK=0x%x-0x%x\n", 457220835Sglebius fadt->gpe0_blk, 458187770Sluigi fadt->gpe0_blk + fadt->gpe0_len - 1); 459187770Sluigi if (fadt->gpe1_blk != 0) 460187770Sluigi printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 461220835Sglebius fadt->gpe1_blk, 462220835Sglebius fadt->gpe1_blk + fadt->gpe1_len - 1, 463187770Sluigi fadt->gpe1_base); 464187770Sluigi if (fadt->cst_cnt != 0) 465187770Sluigi printf("\tCST_CNT=0x%x\n", fadt->cst_cnt); 466187770Sluigi printf("\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n", 467188294Spiso fadt->p_lvl2_lat, fadt->p_lvl3_lat); 468188294Spiso printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 469188294Spiso fadt->flush_size, fadt->flush_stride); 470188294Spiso printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 471187770Sluigi fadt->duty_off, fadt->duty_width); 472220835Sglebius printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 473187770Sluigi fadt->day_alrm, fadt->mon_alrm, fadt->century); 474187770Sluigi 475187770Sluigi#define PRINTFLAG(var, flag) do { \ 476220804Sglebius if ((var) & FADT_FLAG_## flag) { \ 477220802Sglebius printf("%c%s", sep, #flag); sep = ','; \ 478223185Sglebius } \ 479187770Sluigi} while (0) 480187770Sluigi 481223185Sglebius printf("\tIAPC_BOOT_ARCH="); 482220835Sglebius sep = '{'; 483220835Sglebius PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV); 484187770Sluigi PRINTFLAG(fadt->iapc_boot_arch, 8042); 485220835Sglebius printf("}\n"); 486187770Sluigi 487187770Sluigi printf("\tFlags="); 488220802Sglebius sep = '{'; 489187770Sluigi PRINTFLAG(fadt->flags, WBINVD); 490220835Sglebius PRINTFLAG(fadt->flags, WBINVD_FLUSH); 491187770Sluigi PRINTFLAG(fadt->flags, PROC_C1); 492220835Sglebius PRINTFLAG(fadt->flags, P_LVL2_UP); 493187770Sluigi PRINTFLAG(fadt->flags, PWR_BUTTON); 494187770Sluigi PRINTFLAG(fadt->flags, SLP_BUTTON); 495187770Sluigi PRINTFLAG(fadt->flags, FIX_RTC); 496187770Sluigi PRINTFLAG(fadt->flags, RTC_S4); 497187770Sluigi PRINTFLAG(fadt->flags, TMR_VAL_EXT); 498187770Sluigi PRINTFLAG(fadt->flags, DCK_CAP); 499187770Sluigi PRINTFLAG(fadt->flags, RESET_REG); 500187770Sluigi PRINTFLAG(fadt->flags, SEALED_CASE); 501220802Sglebius PRINTFLAG(fadt->flags, HEADLESS); 502187770Sluigi PRINTFLAG(fadt->flags, CPU_SW_SLP); 503187770Sluigi printf("}\n"); 504187770Sluigi 505220835Sglebius#undef PRINTFLAG 506187770Sluigi 507187770Sluigi if (fadt->flags & FADT_FLAG_RESET_REG) { 508187770Sluigi printf("\tRESET_REG="); 509220802Sglebius acpi_print_gas(&fadt->reset_reg); 510187770Sluigi printf(", RESET_VALUE=%#x\n", fadt->reset_value); 511220802Sglebius } 512187770Sluigi if (addr_size == 8) { 513187770Sluigi printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr); 514220835Sglebius printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr); 515220835Sglebius printf("\tX_PM1A_EVT_BLK="); 516220835Sglebius acpi_print_gas(&fadt->x_pm1a_evt_blk); 517220835Sglebius printf("\n\tX_PM1B_EVT_BLK="); 518220835Sglebius acpi_print_gas(&fadt->x_pm1b_evt_blk); 519187770Sluigi printf("\n\tX_PM1A_CNT_BLK="); 520220835Sglebius acpi_print_gas(&fadt->x_pm1a_cnt_blk); 521220835Sglebius printf("\n\tX_PM1B_CNT_BLK="); 522188294Spiso acpi_print_gas(&fadt->x_pm1b_cnt_blk); 523220835Sglebius printf("\n\tX_PM2_CNT_BLK="); 524220835Sglebius acpi_print_gas(&fadt->x_pm2_cnt_blk); 525220835Sglebius printf("\n\tX_PM_TMR_BLK="); 526188294Spiso acpi_print_gas(&fadt->x_pm_tmr_blk); 527188294Spiso printf("\n\tX_GPE0_BLK="); 528188294Spiso acpi_print_gas(&fadt->x_gpe0_blk); 529188294Spiso printf("\n\tX_GPE1_BLK="); 530188294Spiso acpi_print_gas(&fadt->x_gpe1_blk); 531188294Spiso printf("\n"); 532188294Spiso } 533188294Spiso 534220835Sglebius printf(END_COMMENT); 535220835Sglebius} 536188294Spiso 537188294Spisostatic void 538220835Sglebiusacpi_print_facs(struct FACSbody *facs) 539188294Spiso{ 540188294Spiso printf(BEGIN_COMMENT); 541188294Spiso printf(" FACS:\tLength=%u, ", facs->len); 542188294Spiso printf("HwSig=0x%08x, ", facs->hw_sig); 543188294Spiso printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec); 544188294Spiso 545188294Spiso printf("\tGlobal_Lock="); 546220835Sglebius if (facs->global_lock != 0) { 547188294Spiso if (facs->global_lock & FACS_FLAG_LOCK_PENDING) 548220804Sglebius printf("PENDING,"); 549187770Sluigi if (facs->global_lock & FACS_FLAG_LOCK_OWNED) 550220835Sglebius printf("OWNED"); 551187770Sluigi } 552187770Sluigi printf("\n"); 553187770Sluigi 554220835Sglebius printf("\tFlags="); 555187770Sluigi if (facs->flags & FACS_FLAG_S4BIOS_F) 556187770Sluigi printf("S4BIOS"); 557187770Sluigi printf("\n"); 558187770Sluigi 559220835Sglebius if (facs->x_firm_wake_vec != 0) { 560187770Sluigi printf("\tX_Firm_Wake_Vec=%08lx\n", 561220835Sglebius (u_long)facs->x_firm_wake_vec); 562187770Sluigi } 563220835Sglebius printf("\tVersion=%u\n", facs->version); 564220804Sglebius 565220835Sglebius printf(END_COMMENT); 566187770Sluigi} 567220835Sglebius 568220835Sglebiusstatic void 569220835Sglebiusacpi_print_dsdt(struct ACPIsdt *dsdp) 570220835Sglebius{ 571187770Sluigi printf(BEGIN_COMMENT); 572187770Sluigi acpi_print_sdt(dsdp); 573220804Sglebius printf(END_COMMENT); 574220835Sglebius} 575187770Sluigi 576220835Sglebiusint 577187770Sluigiacpi_checksum(void *p, size_t length) 578187770Sluigi{ 579187770Sluigi u_int8_t *bp; 580220835Sglebius u_int8_t sum; 581220804Sglebius 582187770Sluigi bp = p; 583187770Sluigi sum = 0; 584187770Sluigi while (length--) 585220835Sglebius sum += *bp++; 586187770Sluigi 587220835Sglebius return (sum); 588220804Sglebius} 589187770Sluigi 590187770Sluigistatic struct ACPIsdt * 591187770Sluigiacpi_map_sdt(vm_offset_t pa) 592220835Sglebius{ 593220804Sglebius struct ACPIsdt *sp; 594220804Sglebius 595187770Sluigi sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); 596187770Sluigi sp = acpi_map_physical(pa, sp->len); 597223185Sglebius return (sp); 598220835Sglebius} 599220835Sglebius 600220804Sglebiusstatic void 601187770Sluigiacpi_print_rsd_ptr(struct ACPIrsdp *rp) 602187770Sluigi{ 603220804Sglebius printf(BEGIN_COMMENT); 604187770Sluigi printf(" RSD PTR: OEM="); 605223185Sglebius acpi_print_string(rp->oem, 6); 606220835Sglebius printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x", 607220835Sglebius rp->revision); 608187770Sluigi if (rp->revision < 2) { 609220804Sglebius printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum); 610187770Sluigi } else { 611220835Sglebius printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n", 612187770Sluigi (u_long)rp->xsdt_addr, rp->length, rp->xsum); 613187770Sluigi } 614187770Sluigi printf(END_COMMENT); 615187770Sluigi} 616187770Sluigi 617187770Sluigistatic void 618187770Sluigiacpi_handle_rsdt(struct ACPIsdt *rsdp) 619187770Sluigi{ 620187770Sluigi struct ACPIsdt *sdp; 621187770Sluigi vm_offset_t addr; 622187770Sluigi int entries, i; 623187770Sluigi 624187770Sluigi acpi_print_rsdt(rsdp); 625187770Sluigi entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 626187770Sluigi for (i = 0; i < entries; i++) { 627187770Sluigi switch (addr_size) { 628187770Sluigi case 4: 629187770Sluigi addr = le32dec((char*)rsdp->body + i * addr_size); 630187770Sluigi break; 631187770Sluigi case 8: 632187770Sluigi addr = le64dec((char*)rsdp->body + i * addr_size); 633187770Sluigi break; 634187770Sluigi default: 635187770Sluigi assert((addr = 0)); 636187770Sluigi } 637187770Sluigi 638187770Sluigi sdp = (struct ACPIsdt *)acpi_map_sdt(addr); 639187770Sluigi if (acpi_checksum(sdp, sdp->len)) 640187770Sluigi errx(1, "RSDT entry %d is corrupt", i); 641187770Sluigi if (!memcmp(sdp->signature, "FACP", 4)) 642223080Sae acpi_handle_fadt((struct FADTbody *) sdp->body); 643223080Sae else if (!memcmp(sdp->signature, "APIC", 4)) 644223080Sae acpi_handle_apic(sdp); 645187770Sluigi else if (!memcmp(sdp->signature, "HPET", 4)) 646187770Sluigi acpi_handle_hpet(sdp); 647187770Sluigi else if (!memcmp(sdp->signature, "ECDT", 4)) 648187770Sluigi acpi_handle_ecdt(sdp); 649187770Sluigi else { 650187770Sluigi printf(BEGIN_COMMENT); 651187770Sluigi acpi_print_sdt(sdp); 652187770Sluigi printf(END_COMMENT); 653187770Sluigi } 654187770Sluigi } 655187770Sluigi} 656187770Sluigi 657187770Sluigistruct ACPIsdt * 658187770Sluigisdt_load_devmem() 659187770Sluigi{ 660187770Sluigi struct ACPIrsdp *rp; 661187770Sluigi struct ACPIsdt *rsdp; 662187770Sluigi 663187770Sluigi rp = acpi_find_rsd_ptr(); 664187770Sluigi if (!rp) 665187770Sluigi errx(1, "Can't find ACPI information"); 666187770Sluigi 667187770Sluigi if (tflag) 668187770Sluigi acpi_print_rsd_ptr(rp); 669187770Sluigi if (rp->revision < 2) { 670187770Sluigi rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr); 671187770Sluigi if (memcmp(rsdp->signature, "RSDT", 4) != 0 || 672187770Sluigi acpi_checksum(rsdp, rsdp->len) != 0) 673220802Sglebius errx(1, "RSDT is corrupted"); 674187770Sluigi addr_size = sizeof(uint32_t); 675187770Sluigi } else { 676187770Sluigi rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr); 677187770Sluigi if (memcmp(rsdp->signature, "XSDT", 4) != 0 || 678187770Sluigi acpi_checksum(rsdp, rsdp->len) != 0) 679187770Sluigi errx(1, "XSDT is corrupted"); 680187770Sluigi addr_size = sizeof(uint64_t); 681187770Sluigi } 682187770Sluigi return (rsdp); 683187770Sluigi} 684187770Sluigi 685187770Sluigivoid 686220802Sglebiusdsdt_save_file(char *outfile, struct ACPIsdt *dsdp) 687187770Sluigi{ 688187770Sluigi int fd; 689187770Sluigi mode_t mode; 690187770Sluigi 691187770Sluigi assert(outfile != NULL); 692187770Sluigi mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 693220802Sglebius fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode); 694187770Sluigi if (fd == -1) { 695187770Sluigi perror("dsdt_save_file"); 696187770Sluigi return; 697187770Sluigi } 698187770Sluigi write(fd, dsdp, SIZEOF_SDT_HDR); 699187770Sluigi write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR); 700220802Sglebius close(fd); 701187770Sluigi} 702187770Sluigi 703187770Sluigivoid 704187770Sluigiaml_disassemble(struct ACPIsdt *dsdp) 705187770Sluigi{ 706187770Sluigi char tmpstr[32], buf[256]; 707187770Sluigi FILE *fp; 708187770Sluigi int fd, len; 709187770Sluigi 710220802Sglebius strcpy(tmpstr, "/tmp/acpidump.XXXXXX"); 711187770Sluigi fd = mkstemp(tmpstr); 712187770Sluigi if (fd < 0) { 713187770Sluigi perror("iasl tmp file"); 714187770Sluigi return; 715187770Sluigi } 716187770Sluigi 717220802Sglebius /* Dump DSDT to the temp file */ 718187770Sluigi write(fd, dsdp, SIZEOF_SDT_HDR); 719187770Sluigi write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR); 720187770Sluigi close(fd); 721187770Sluigi 722187770Sluigi /* Run iasl -d on the temp file */ 723187770Sluigi if (fork() == 0) { 724187770Sluigi close(STDOUT_FILENO); 725187770Sluigi if (vflag == 0) 726187770Sluigi close(STDERR_FILENO); 727187770Sluigi execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, 0); 728187770Sluigi err(1, "exec"); 729187770Sluigi } 730187770Sluigi 731187770Sluigi wait(NULL); 732187770Sluigi unlink(tmpstr); 733187770Sluigi 734187770Sluigi /* Dump iasl's output to stdout */ 735187770Sluigi fp = fopen("acpidump.dsl", "r"); 736220802Sglebius unlink("acpidump.dsl"); 737220835Sglebius if (fp == NULL) { 738223079Sae perror("iasl tmp file (read)"); 739220835Sglebius return; 740220804Sglebius } 741187770Sluigi while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) 742187770Sluigi fwrite(buf, 1, len, stdout); 743223079Sae fclose(fp); 744187770Sluigi} 745223079Sae 746223079Saevoid 747223079Saesdt_print_all(struct ACPIsdt *rsdp) 748223079Sae{ 749223079Sae acpi_handle_rsdt(rsdp); 750220802Sglebius} 751187770Sluigi 752187770Sluigi/* Fetch a table matching the given signature via the RSDT */ 753220835Sglebiusstruct ACPIsdt * 754220835Sglebiussdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig) 755220835Sglebius{ 756220835Sglebius struct ACPIsdt *sdt; 757220835Sglebius vm_offset_t addr; 758220835Sglebius int entries, i; 759220835Sglebius 760220835Sglebius entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size; 761220835Sglebius for (i = 0; i < entries; i++) { 762220835Sglebius switch (addr_size) { 763223080Sae case 4: 764220835Sglebius addr = le32dec((char*)rsdt->body + i * addr_size); 765220835Sglebius break; 766220835Sglebius case 8: 767223080Sae addr = le64dec((char*)rsdt->body + i * addr_size); 768220835Sglebius break; 769220835Sglebius default: 770220835Sglebius assert((addr = 0)); 771220835Sglebius } 772220835Sglebius sdt = (struct ACPIsdt *)acpi_map_sdt(addr); 773220835Sglebius if (memcmp(sdt->signature, sig, strlen(sig))) 774220835Sglebius continue; 775220835Sglebius if (acpi_checksum(sdt, sdt->len)) 776220835Sglebius errx(1, "RSDT entry %d is corrupt", i); 777220835Sglebius return (sdt); 778220835Sglebius } 779220835Sglebius 780220835Sglebius return (NULL); 781220835Sglebius} 782220835Sglebius 783220835Sglebiusstruct ACPIsdt * 784220835Sglebiusdsdt_from_fadt(struct FADTbody *fadt) 785220835Sglebius{ 786220835Sglebius struct ACPIsdt *sdt; 787223185Sglebius 788223185Sglebius sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr); 789223185Sglebius if (acpi_checksum(sdt, sdt->len)) 790220835Sglebius errx(1, "DSDT is corrupt\n"); 791220835Sglebius return (sdt); 792220835Sglebius} 793220835Sglebius