acpi.c revision 131307
165285Siwasaki/*- 265285Siwasaki * Copyright (c) 1998 Doug Rabson 365285Siwasaki * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 465285Siwasaki * All rights reserved. 565285Siwasaki * 665285Siwasaki * Redistribution and use in source and binary forms, with or without 765285Siwasaki * modification, are permitted provided that the following conditions 865285Siwasaki * are met: 965285Siwasaki * 1. Redistributions of source code must retain the above copyright 1065285Siwasaki * notice, this list of conditions and the following disclaimer. 1165285Siwasaki * 2. Redistributions in binary form must reproduce the above copyright 1265285Siwasaki * notice, this list of conditions and the following disclaimer in the 1365285Siwasaki * documentation and/or other materials provided with the distribution. 1465285Siwasaki * 1565285Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1665285Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1765285Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1865285Siwasaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1965285Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2065285Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2165285Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2265285Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2365285Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2465285Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2565285Siwasaki * SUCH DAMAGE. 2665285Siwasaki * 2765285Siwasaki * $FreeBSD: head/usr.sbin/acpi/acpidump/acpi.c 131307 2004-06-30 03:23:51Z njl $ 2865285Siwasaki */ 2965285Siwasaki 3065285Siwasaki#include <sys/param.h> 31119913Snjl#include <sys/endian.h> 3265285Siwasaki#include <sys/stat.h> 33119515Snjl#include <sys/wait.h> 3465285Siwasaki#include <assert.h> 3565285Siwasaki#include <err.h> 3665285Siwasaki#include <fcntl.h> 3765285Siwasaki#include <stdio.h> 38119515Snjl#include <string.h> 3965285Siwasaki#include <unistd.h> 4065285Siwasaki 4165285Siwasaki#include "acpidump.h" 4265285Siwasaki 4385323Siwasaki#define BEGIN_COMMENT "/*\n" 4485323Siwasaki#define END_COMMENT " */\n" 4585323Siwasaki 46119515Snjlstatic void acpi_print_string(char *s, size_t length); 47119912Snjlstatic void acpi_print_gas(struct ACPIgas *gas); 48128382Snjlstatic int acpi_get_fadt_revision(struct FADTbody *fadt); 49131307Snjlstatic void acpi_handle_fadt(struct ACPIsdt *fadt); 50119515Snjlstatic void acpi_print_cpu(u_char cpu_id); 51119515Snjlstatic void acpi_print_local_apic(u_char cpu_id, u_char apic_id, 52119515Snjl u_int32_t flags); 53119515Snjlstatic void acpi_print_io_apic(u_char apic_id, u_int32_t int_base, 54119515Snjl u_int64_t apic_addr); 55119515Snjlstatic void acpi_print_mps_flags(u_int16_t flags); 56119515Snjlstatic void acpi_print_intr(u_int32_t intr, u_int16_t mps_flags); 57119515Snjlstatic void acpi_print_apic(struct MADT_APIC *mp); 58119515Snjlstatic void acpi_handle_apic(struct ACPIsdt *sdp); 59119515Snjlstatic void acpi_handle_hpet(struct ACPIsdt *sdp); 60119968Snjlstatic void acpi_print_sdt(struct ACPIsdt *sdp); 61131307Snjlstatic void acpi_print_fadt(struct ACPIsdt *sdp); 62119912Snjlstatic void acpi_print_facs(struct FACSbody *facs); 63119515Snjlstatic void acpi_print_dsdt(struct ACPIsdt *dsdp); 64119913Snjlstatic struct ACPIsdt *acpi_map_sdt(vm_offset_t pa); 65119515Snjlstatic void acpi_print_rsd_ptr(struct ACPIrsdp *rp); 66119515Snjlstatic void acpi_handle_rsdt(struct ACPIsdt *rsdp); 6785323Siwasaki 68119968Snjl/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */ 69119913Snjlstatic int addr_size; 70119913Snjl 7165285Siwasakistatic void 7265285Siwasakiacpi_print_string(char *s, size_t length) 7365285Siwasaki{ 7465285Siwasaki int c; 7565285Siwasaki 7665285Siwasaki /* Trim trailing spaces and NULLs */ 7765285Siwasaki while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 7865285Siwasaki length--; 7965285Siwasaki 8065285Siwasaki while (length--) { 8165285Siwasaki c = *s++; 8265285Siwasaki putchar(c); 8365285Siwasaki } 8465285Siwasaki} 8565285Siwasaki 8665285Siwasakistatic void 87119912Snjlacpi_print_gas(struct ACPIgas *gas) 8865285Siwasaki{ 89119912Snjl switch(gas->address_space_id) { 90119912Snjl case ACPI_GAS_MEMORY: 91119968Snjl printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->address, 92119912Snjl gas->bit_offset, gas->bit_width); 93119912Snjl break; 94119912Snjl case ACPI_GAS_IO: 95120030Snjl printf("0x%02lx:%u[%u] (IO)", (u_long)gas->address, 96119912Snjl gas->bit_offset, gas->bit_width); 97119912Snjl break; 98119912Snjl case ACPI_GAS_PCI: 99120030Snjl printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->address >> 32), 100119912Snjl (uint16_t)((gas->address >> 16) & 0xffff), 101119912Snjl (uint16_t)gas->address); 102119912Snjl break; 103119912Snjl /* XXX How to handle these below? */ 104119912Snjl case ACPI_GAS_EMBEDDED: 105120030Snjl printf("0x%x:%u[%u] (EC)", (uint16_t)gas->address, 106119912Snjl gas->bit_offset, gas->bit_width); 107119912Snjl break; 108119912Snjl case ACPI_GAS_SMBUS: 109120030Snjl printf("0x%x:%u[%u] (SMBus)", (uint16_t)gas->address, 110119912Snjl gas->bit_offset, gas->bit_width); 111119912Snjl break; 112119912Snjl case ACPI_GAS_FIXED: 113119912Snjl default: 114119968Snjl printf("0x%08lx (?)", (u_long)gas->address); 115119912Snjl break; 116119912Snjl } 117119912Snjl} 11865285Siwasaki 119128382Snjl/* The FADT revision indicates whether we use the DSDT or X_DSDT addresses. */ 120128382Snjlstatic int 121128382Snjlacpi_get_fadt_revision(struct FADTbody *fadt) 122119912Snjl{ 123128382Snjl int fadt_revision; 124119912Snjl 125124138Snjl /* Set the FADT revision separately from the RSDP version. */ 126124138Snjl if (addr_size == 8) { 127124138Snjl fadt_revision = 2; 128124138Snjl 129124138Snjl /* 130124138Snjl * A few systems (e.g., IBM T23) have an RSDP that claims 131124138Snjl * revision 2 but the 64 bit addresses are invalid. If 132124138Snjl * revision 2 and the 32 bit address is non-zero but the 133124138Snjl * 32 and 64 bit versions don't match, prefer the 32 bit 134124138Snjl * version for all subsequent tables. 135124138Snjl */ 136124138Snjl if (fadt->facs_ptr != 0 && 137124138Snjl (fadt->x_facs_ptr & 0xffffffff) != fadt->facs_ptr) 138124138Snjl fadt_revision = 1; 139128382Snjl } else 140124138Snjl fadt_revision = 1; 141128382Snjl return (fadt_revision); 142128382Snjl} 143128382Snjl 144128382Snjlstatic void 145131307Snjlacpi_handle_fadt(struct ACPIsdt *sdp) 146128382Snjl{ 147128382Snjl struct ACPIsdt *dsdp; 148128382Snjl struct FACSbody *facs; 149131307Snjl struct FADTbody *fadt; 150128382Snjl int fadt_revision; 151128382Snjl 152131307Snjl fadt = (struct FADTbody *)sdp->body; 153131307Snjl acpi_print_fadt(sdp); 154119912Snjl 155128382Snjl fadt_revision = acpi_get_fadt_revision(fadt); 156124138Snjl if (fadt_revision == 1) 157119968Snjl facs = (struct FACSbody *)acpi_map_sdt(fadt->facs_ptr); 158119968Snjl else 159119968Snjl facs = (struct FACSbody *)acpi_map_sdt(fadt->x_facs_ptr); 160119912Snjl if (memcmp(facs->signature, "FACS", 4) != 0 || facs->len < 64) 161119912Snjl errx(1, "FACS is corrupt"); 162119912Snjl acpi_print_facs(facs); 163119912Snjl 164124138Snjl if (fadt_revision == 1) 165119968Snjl dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr); 166119968Snjl else 167119968Snjl dsdp = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr); 16865285Siwasaki if (acpi_checksum(dsdp, dsdp->len)) 169119515Snjl errx(1, "DSDT is corrupt"); 170119515Snjl acpi_print_dsdt(dsdp); 17165285Siwasaki} 17265285Siwasaki 17385323Siwasakistatic void 174108967Sjhbacpi_print_cpu(u_char cpu_id) 175108967Sjhb{ 176108967Sjhb 177108967Sjhb printf("\tACPI CPU="); 178108967Sjhb if (cpu_id == 0xff) 179108967Sjhb printf("ALL\n"); 180108967Sjhb else 181108967Sjhb printf("%d\n", (u_int)cpu_id); 182108967Sjhb} 183108967Sjhb 184108967Sjhbstatic void 185108967Sjhbacpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags) 186108967Sjhb{ 187108967Sjhb acpi_print_cpu(cpu_id); 188108967Sjhb printf("\tFlags={"); 189108967Sjhb if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED) 190108967Sjhb printf("ENABLED"); 191108967Sjhb else 192108967Sjhb printf("DISABLED"); 193108967Sjhb printf("}\n"); 194108967Sjhb printf("\tAPIC ID=%d\n", (u_int)apic_id); 195108967Sjhb} 196108967Sjhb 197108967Sjhbstatic void 198108967Sjhbacpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr) 199108967Sjhb{ 200108967Sjhb printf("\tAPIC ID=%d\n", (u_int)apic_id); 201108967Sjhb printf("\tINT BASE=%d\n", int_base); 202119515Snjl printf("\tADDR=0x%016jx\n", apic_addr); 203108967Sjhb} 204108967Sjhb 205108967Sjhbstatic void 206108967Sjhbacpi_print_mps_flags(u_int16_t flags) 207108967Sjhb{ 208108967Sjhb 209108967Sjhb printf("\tFlags={Polarity="); 210108967Sjhb switch (flags & MPS_INT_FLAG_POLARITY_MASK) { 211108967Sjhb case MPS_INT_FLAG_POLARITY_CONFORM: 212108967Sjhb printf("conforming"); 213108967Sjhb break; 214108967Sjhb case MPS_INT_FLAG_POLARITY_HIGH: 215108967Sjhb printf("active-hi"); 216108967Sjhb break; 217108967Sjhb case MPS_INT_FLAG_POLARITY_LOW: 218108967Sjhb printf("active-lo"); 219108967Sjhb break; 220108967Sjhb default: 221108967Sjhb printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK); 222108967Sjhb break; 223108967Sjhb } 224108967Sjhb printf(", Trigger="); 225108967Sjhb switch (flags & MPS_INT_FLAG_TRIGGER_MASK) { 226108967Sjhb case MPS_INT_FLAG_TRIGGER_CONFORM: 227108967Sjhb printf("conforming"); 228108967Sjhb break; 229108967Sjhb case MPS_INT_FLAG_TRIGGER_EDGE: 230108967Sjhb printf("edge"); 231108967Sjhb break; 232108967Sjhb case MPS_INT_FLAG_TRIGGER_LEVEL: 233108967Sjhb printf("level"); 234108967Sjhb break; 235108967Sjhb default: 236108967Sjhb printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2); 237108967Sjhb } 238108967Sjhb printf("}\n"); 239108967Sjhb} 240108967Sjhb 241108967Sjhbstatic void 242108967Sjhbacpi_print_intr(u_int32_t intr, u_int16_t mps_flags) 243108967Sjhb{ 244108967Sjhb 245108967Sjhb printf("\tINTR=%d\n", (u_int)intr); 246108967Sjhb acpi_print_mps_flags(mps_flags); 247108967Sjhb} 248108967Sjhb 249108967Sjhbconst char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", 250108967Sjhb "Local NMI", "Local APIC Override", "IO SAPIC", 251108967Sjhb "Local SAPIC", "Platform Interrupt" }; 252108967Sjhbconst char *platform_int_types[] = { "PMI", "INIT", 253108967Sjhb "Corrected Platform Error" }; 254108967Sjhb 255108967Sjhbstatic void 256108967Sjhbacpi_print_apic(struct MADT_APIC *mp) 257108967Sjhb{ 258108967Sjhb 259108967Sjhb printf("\tType=%s\n", apic_types[mp->type]); 260108967Sjhb switch (mp->type) { 261108967Sjhb case ACPI_MADT_APIC_TYPE_LOCAL_APIC: 262108967Sjhb acpi_print_local_apic(mp->body.local_apic.cpu_id, 263108967Sjhb mp->body.local_apic.apic_id, mp->body.local_apic.flags); 264108967Sjhb break; 265108967Sjhb case ACPI_MADT_APIC_TYPE_IO_APIC: 266108967Sjhb acpi_print_io_apic(mp->body.io_apic.apic_id, 267108967Sjhb mp->body.io_apic.int_base, 268108967Sjhb mp->body.io_apic.apic_addr); 269108967Sjhb break; 270108967Sjhb case ACPI_MADT_APIC_TYPE_INT_OVERRIDE: 271108967Sjhb printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus); 272108967Sjhb printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source); 273108967Sjhb acpi_print_intr(mp->body.int_override.intr, 274108967Sjhb mp->body.int_override.mps_flags); 275108967Sjhb break; 276108967Sjhb case ACPI_MADT_APIC_TYPE_NMI: 277108967Sjhb acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags); 278108967Sjhb break; 279108967Sjhb case ACPI_MADT_APIC_TYPE_LOCAL_NMI: 280108967Sjhb acpi_print_cpu(mp->body.local_nmi.cpu_id); 281108967Sjhb printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin); 282108967Sjhb acpi_print_mps_flags(mp->body.local_nmi.mps_flags); 283108967Sjhb break; 284108967Sjhb case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE: 285119515Snjl printf("\tLocal APIC ADDR=0x%016jx\n", 286119515Snjl mp->body.local_apic_override.apic_addr); 287108967Sjhb break; 288108967Sjhb case ACPI_MADT_APIC_TYPE_IO_SAPIC: 289108967Sjhb acpi_print_io_apic(mp->body.io_sapic.apic_id, 290108967Sjhb mp->body.io_sapic.int_base, 291108967Sjhb mp->body.io_sapic.apic_addr); 292108967Sjhb break; 293108967Sjhb case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC: 294108967Sjhb acpi_print_local_apic(mp->body.local_sapic.cpu_id, 295108967Sjhb mp->body.local_sapic.apic_id, mp->body.local_sapic.flags); 296108967Sjhb printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid); 297108967Sjhb break; 298108967Sjhb case ACPI_MADT_APIC_TYPE_INT_SRC: 299108967Sjhb printf("\tType=%s\n", 300108967Sjhb platform_int_types[mp->body.int_src.type]); 301108967Sjhb printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id); 302108967Sjhb printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id); 303108967Sjhb printf("\tSAPIC Vector=%d\n", 304108967Sjhb (u_int)mp->body.int_src.sapic_vector); 305108967Sjhb acpi_print_intr(mp->body.int_src.intr, 306108967Sjhb mp->body.int_src.mps_flags); 307108967Sjhb break; 308108967Sjhb default: 309108967Sjhb printf("\tUnknown type %d\n", (u_int)mp->type); 310119515Snjl break; 311108967Sjhb } 312108967Sjhb} 313108967Sjhb 314108967Sjhbstatic void 315108967Sjhbacpi_handle_apic(struct ACPIsdt *sdp) 316108967Sjhb{ 317108967Sjhb struct MADTbody *madtp; 318108967Sjhb struct MADT_APIC *madt_apicp; 319108967Sjhb 320119968Snjl printf(BEGIN_COMMENT); 321119968Snjl acpi_print_sdt(sdp); 322108967Sjhb madtp = (struct MADTbody *) sdp->body; 323108967Sjhb printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr); 324108967Sjhb printf("\tFlags={"); 325108967Sjhb if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT) 326108967Sjhb printf("PC-AT"); 327108967Sjhb printf("}\n"); 328119515Snjl madt_apicp = (struct MADT_APIC *)madtp->body; 329108967Sjhb while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) { 330108967Sjhb printf("\n"); 331108967Sjhb acpi_print_apic(madt_apicp); 332108967Sjhb madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp + 333108967Sjhb madt_apicp->len); 334108967Sjhb } 335108967Sjhb printf(END_COMMENT); 336108967Sjhb} 337108967Sjhb 338108967Sjhbstatic void 339118334Speteracpi_handle_hpet(struct ACPIsdt *sdp) 340118334Speter{ 341118334Speter struct HPETbody *hpetp; 342118334Speter 343119968Snjl printf(BEGIN_COMMENT); 344119968Snjl acpi_print_sdt(sdp); 345118334Speter hpetp = (struct HPETbody *) sdp->body; 346118334Speter printf("\tHPET Number=%d\n", hpetp->hpet_number); 347118334Speter printf("\tADDR=0x%08x\n", hpetp->base_addr); 348118334Speter printf("\tHW Rev=0x%x\n", hpetp->block_hwrev); 349118334Speter printf("\tComparitors=%d\n", hpetp->block_comparitors); 350118334Speter printf("\tCounter Size=%d\n", hpetp->block_counter_size); 351118334Speter printf("\tLegacy IRQ routing capable={"); 352118334Speter if (hpetp->block_legacy_capable) 353118334Speter printf("TRUE}\n"); 354118334Speter else 355118334Speter printf("FALSE}\n"); 356118334Speter printf("\tPCI Vendor ID=0x%04x\n", hpetp->block_pcivendor); 357118335Speter printf("\tMinimal Tick=%d\n", hpetp->clock_tick); 358118334Speter printf(END_COMMENT); 359118334Speter} 360118334Speter 361118334Speterstatic void 362119971Snjlacpi_handle_ecdt(struct ACPIsdt *sdp) 363119971Snjl{ 364119971Snjl struct ECDTbody *ecdt; 365119971Snjl 366119971Snjl printf(BEGIN_COMMENT); 367119971Snjl acpi_print_sdt(sdp); 368119971Snjl ecdt = (struct ECDTbody *) sdp->body; 369119971Snjl printf("\tEC_CONTROL="); 370119971Snjl acpi_print_gas(&ecdt->ec_control); 371119971Snjl printf("\n\tEC_DATA="); 372119971Snjl acpi_print_gas(&ecdt->ec_data); 373119971Snjl printf("\n\tUID=%#x, ", ecdt->uid); 374119971Snjl printf("GPE_BIT=%#x\n", ecdt->gpe_bit); 375119971Snjl printf("\tEC_ID=%s\n", ecdt->ec_id); 376119971Snjl printf(END_COMMENT); 377119971Snjl} 378119971Snjl 379119971Snjlstatic void 380119968Snjlacpi_print_sdt(struct ACPIsdt *sdp) 38185323Siwasaki{ 382119968Snjl printf(" "); 38365285Siwasaki acpi_print_string(sdp->signature, 4); 38485323Siwasaki printf(": Length=%d, Revision=%d, Checksum=%d,\n", 38565285Siwasaki sdp->len, sdp->rev, sdp->check); 38665285Siwasaki printf("\tOEMID="); 38765285Siwasaki acpi_print_string(sdp->oemid, 6); 38865285Siwasaki printf(", OEM Table ID="); 38965285Siwasaki acpi_print_string(sdp->oemtblid, 8); 39065285Siwasaki printf(", OEM Revision=0x%x,\n", sdp->oemrev); 39165285Siwasaki printf("\tCreator ID="); 39265285Siwasaki acpi_print_string(sdp->creator, 4); 39365285Siwasaki printf(", Creator Revision=0x%x\n", sdp->crerev); 39465285Siwasaki} 39565285Siwasaki 396119515Snjlstatic void 39765285Siwasakiacpi_print_rsdt(struct ACPIsdt *rsdp) 39865285Siwasaki{ 39965285Siwasaki int i, entries; 400119913Snjl u_long addr; 40165285Siwasaki 402119968Snjl printf(BEGIN_COMMENT); 403119968Snjl acpi_print_sdt(rsdp); 404119913Snjl entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 40565285Siwasaki printf("\tEntries={ "); 40665285Siwasaki for (i = 0; i < entries; i++) { 40765285Siwasaki if (i > 0) 40865285Siwasaki printf(", "); 409119913Snjl switch (addr_size) { 410119913Snjl case 4: 411119913Snjl addr = le32dec((char*)rsdp->body + i * addr_size); 412119913Snjl break; 413119913Snjl case 8: 414119913Snjl addr = le64dec((char*)rsdp->body + i * addr_size); 415119913Snjl break; 416119913Snjl default: 417119913Snjl addr = 0; 418119913Snjl } 419119913Snjl assert(addr != 0); 420119913Snjl printf("0x%08lx", addr); 42165285Siwasaki } 42265285Siwasaki printf(" }\n"); 42385323Siwasaki printf(END_COMMENT); 42465285Siwasaki} 42565285Siwasaki 426119912Snjlstatic const char *acpi_pm_profiles[] = { 427119912Snjl "Unspecified", "Desktop", "Mobile", "Workstation", 428119912Snjl "Enterprise Server", "SOHO Server", "Appliance PC" 429119912Snjl}; 430119912Snjl 431119515Snjlstatic void 432131307Snjlacpi_print_fadt(struct ACPIsdt *sdp) 43365285Siwasaki{ 434131307Snjl struct FADTbody *fadt; 435119912Snjl const char *pm; 436119912Snjl char sep; 43765285Siwasaki 438131307Snjl fadt = (struct FADTbody *)sdp->body; 43985323Siwasaki printf(BEGIN_COMMENT); 440131307Snjl acpi_print_sdt(sdp); 441131307Snjl printf(" \tFACS=0x%x, DSDT=0x%x\n", fadt->facs_ptr, 442119912Snjl fadt->dsdt_ptr); 443119912Snjl printf("\tINT_MODEL=%s\n", fadt->int_model ? "APIC" : "PIC"); 444119912Snjl if (fadt->pm_profile >= sizeof(acpi_pm_profiles) / sizeof(char *)) 445119912Snjl pm = "Reserved"; 446119912Snjl else 447119912Snjl pm = acpi_pm_profiles[fadt->pm_profile]; 448119912Snjl printf("\tPreferred_PM_Profile=%s (%d)\n", pm, fadt->pm_profile); 449119912Snjl printf("\tSCI_INT=%d\n", fadt->sci_int); 450119912Snjl printf("\tSMI_CMD=0x%x, ", fadt->smi_cmd); 451119912Snjl printf("ACPI_ENABLE=0x%x, ", fadt->acpi_enable); 452119912Snjl printf("ACPI_DISABLE=0x%x, ", fadt->acpi_disable); 453119912Snjl printf("S4BIOS_REQ=0x%x\n", fadt->s4biosreq); 454119912Snjl printf("\tPSTATE_CNT=0x%x\n", fadt->pstate_cnt); 455120032Snjl printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", 456120032Snjl fadt->pm1a_evt_blk, 457120032Snjl fadt->pm1a_evt_blk + fadt->pm1_evt_len - 1); 458119912Snjl if (fadt->pm1b_evt_blk != 0) 45965285Siwasaki printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", 460119912Snjl fadt->pm1b_evt_blk, 461119912Snjl fadt->pm1b_evt_blk + fadt->pm1_evt_len - 1); 462120032Snjl printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", 463120032Snjl fadt->pm1a_cnt_blk, 464120032Snjl fadt->pm1a_cnt_blk + fadt->pm1_cnt_len - 1); 465119912Snjl if (fadt->pm1b_cnt_blk != 0) 46665285Siwasaki printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", 467119912Snjl fadt->pm1b_cnt_blk, 468119912Snjl fadt->pm1b_cnt_blk + fadt->pm1_cnt_len - 1); 469119912Snjl if (fadt->pm2_cnt_blk != 0) 47065285Siwasaki printf("\tPM2_CNT_BLK=0x%x-0x%x\n", 471119912Snjl fadt->pm2_cnt_blk, 472119912Snjl fadt->pm2_cnt_blk + fadt->pm2_cnt_len - 1); 473120032Snjl printf("\tPM_TMR_BLK=0x%x-0x%x\n", 474120032Snjl fadt->pm_tmr_blk, 475120032Snjl fadt->pm_tmr_blk + fadt->pm_tmr_len - 1); 476119912Snjl if (fadt->gpe0_blk != 0) 477119912Snjl printf("\tGPE0_BLK=0x%x-0x%x\n", 478119912Snjl fadt->gpe0_blk, 479119912Snjl fadt->gpe0_blk + fadt->gpe0_len - 1); 480119912Snjl if (fadt->gpe1_blk != 0) 481119912Snjl printf("\tGPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 482119912Snjl fadt->gpe1_blk, 483119912Snjl fadt->gpe1_blk + fadt->gpe1_len - 1, 484119912Snjl fadt->gpe1_base); 485119912Snjl if (fadt->cst_cnt != 0) 486119912Snjl printf("\tCST_CNT=0x%x\n", fadt->cst_cnt); 487120034Snjl printf("\tP_LVL2_LAT=%d us, P_LVL3_LAT=%d us\n", 488119912Snjl fadt->p_lvl2_lat, fadt->p_lvl3_lat); 48965285Siwasaki printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 490119912Snjl fadt->flush_size, fadt->flush_stride); 49165285Siwasaki printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 492119912Snjl fadt->duty_off, fadt->duty_width); 49365285Siwasaki printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 494119912Snjl fadt->day_alrm, fadt->mon_alrm, fadt->century); 49565285Siwasaki 496119912Snjl#define PRINTFLAG(var, flag) do { \ 497119912Snjl if ((var) & FADT_FLAG_## flag) { \ 498119912Snjl printf("%c%s", sep, #flag); sep = ','; \ 499119912Snjl } \ 50065285Siwasaki} while (0) 50165285Siwasaki 502119912Snjl printf("\tIAPC_BOOT_ARCH="); 503119912Snjl sep = '{'; 504119912Snjl PRINTFLAG(fadt->iapc_boot_arch, LEGACY_DEV); 505119912Snjl PRINTFLAG(fadt->iapc_boot_arch, 8042); 506120309Snjl if (fadt->iapc_boot_arch != 0) 507121693Snjl printf("}"); 508121693Snjl printf("\n"); 50965285Siwasaki 510119912Snjl printf("\tFlags="); 511119912Snjl sep = '{'; 512119912Snjl PRINTFLAG(fadt->flags, WBINVD); 513119912Snjl PRINTFLAG(fadt->flags, WBINVD_FLUSH); 514119912Snjl PRINTFLAG(fadt->flags, PROC_C1); 515119912Snjl PRINTFLAG(fadt->flags, P_LVL2_UP); 516119912Snjl PRINTFLAG(fadt->flags, PWR_BUTTON); 517119912Snjl PRINTFLAG(fadt->flags, SLP_BUTTON); 518119912Snjl PRINTFLAG(fadt->flags, FIX_RTC); 519119912Snjl PRINTFLAG(fadt->flags, RTC_S4); 520119912Snjl PRINTFLAG(fadt->flags, TMR_VAL_EXT); 521119912Snjl PRINTFLAG(fadt->flags, DCK_CAP); 522119912Snjl PRINTFLAG(fadt->flags, RESET_REG); 523119912Snjl PRINTFLAG(fadt->flags, SEALED_CASE); 524119912Snjl PRINTFLAG(fadt->flags, HEADLESS); 525119912Snjl PRINTFLAG(fadt->flags, CPU_SW_SLP); 526120309Snjl if (fadt->flags != 0) 527120309Snjl printf("}\n"); 528119912Snjl 52965285Siwasaki#undef PRINTFLAG 53065285Siwasaki 531119912Snjl if (fadt->flags & FADT_FLAG_RESET_REG) { 532119912Snjl printf("\tRESET_REG="); 533119912Snjl acpi_print_gas(&fadt->reset_reg); 534119912Snjl printf(", RESET_VALUE=%#x\n", fadt->reset_value); 535119912Snjl } 536128382Snjl if (acpi_get_fadt_revision(fadt) > 1) { 537119968Snjl printf("\tX_FACS=0x%08lx, ", (u_long)fadt->x_facs_ptr); 538119968Snjl printf("X_DSDT=0x%08lx\n", (u_long)fadt->x_dsdt_ptr); 539120032Snjl printf("\tX_PM1a_EVT_BLK="); 540119968Snjl acpi_print_gas(&fadt->x_pm1a_evt_blk); 541120032Snjl if (fadt->x_pm1b_evt_blk.address != 0) { 542120032Snjl printf("\n\tX_PM1b_EVT_BLK="); 543120032Snjl acpi_print_gas(&fadt->x_pm1b_evt_blk); 544120032Snjl } 545120032Snjl printf("\n\tX_PM1a_CNT_BLK="); 546119968Snjl acpi_print_gas(&fadt->x_pm1a_cnt_blk); 547120032Snjl if (fadt->x_pm1b_cnt_blk.address != 0) { 548120032Snjl printf("\n\tX_PM1b_CNT_BLK="); 549120032Snjl acpi_print_gas(&fadt->x_pm1b_cnt_blk); 550120032Snjl } 551120032Snjl if (fadt->x_pm1b_cnt_blk.address != 0) { 552120032Snjl printf("\n\tX_PM2_CNT_BLK="); 553120032Snjl acpi_print_gas(&fadt->x_pm2_cnt_blk); 554120032Snjl } 555119968Snjl printf("\n\tX_PM_TMR_BLK="); 556119968Snjl acpi_print_gas(&fadt->x_pm_tmr_blk); 557120032Snjl if (fadt->x_gpe0_blk.address != 0) { 558120032Snjl printf("\n\tX_GPE0_BLK="); 559120032Snjl acpi_print_gas(&fadt->x_gpe0_blk); 560120032Snjl } 561120032Snjl if (fadt->x_gpe1_blk.address != 0) { 562120032Snjl printf("\n\tX_GPE1_BLK="); 563120032Snjl acpi_print_gas(&fadt->x_gpe1_blk); 564120032Snjl } 565119968Snjl printf("\n"); 566119968Snjl } 567119912Snjl 568119912Snjl printf(END_COMMENT); 569119912Snjl} 570119912Snjl 571119912Snjlstatic void 572119912Snjlacpi_print_facs(struct FACSbody *facs) 573119912Snjl{ 574119912Snjl printf(BEGIN_COMMENT); 575119912Snjl printf(" FACS:\tLength=%u, ", facs->len); 576119912Snjl printf("HwSig=0x%08x, ", facs->hw_sig); 577119912Snjl printf("Firm_Wake_Vec=0x%08x\n", facs->firm_wake_vec); 578119912Snjl 579119968Snjl printf("\tGlobal_Lock="); 580119912Snjl if (facs->global_lock != 0) { 581119912Snjl if (facs->global_lock & FACS_FLAG_LOCK_PENDING) 582119912Snjl printf("PENDING,"); 583119912Snjl if (facs->global_lock & FACS_FLAG_LOCK_OWNED) 584119912Snjl printf("OWNED"); 585119912Snjl } 586119968Snjl printf("\n"); 587119912Snjl 588119968Snjl printf("\tFlags="); 589119912Snjl if (facs->flags & FACS_FLAG_S4BIOS_F) 590119912Snjl printf("S4BIOS"); 591119968Snjl printf("\n"); 592119912Snjl 593119912Snjl if (facs->x_firm_wake_vec != 0) { 594119912Snjl printf("\tX_Firm_Wake_Vec=%08lx\n", 595119912Snjl (u_long)facs->x_firm_wake_vec); 596119912Snjl } 597119968Snjl printf("\tVersion=%u\n", facs->version); 598119912Snjl 59985323Siwasaki printf(END_COMMENT); 60065285Siwasaki} 60165285Siwasaki 602119515Snjlstatic void 60365285Siwasakiacpi_print_dsdt(struct ACPIsdt *dsdp) 60465285Siwasaki{ 605119968Snjl printf(BEGIN_COMMENT); 606119968Snjl acpi_print_sdt(dsdp); 607119968Snjl printf(END_COMMENT); 60865285Siwasaki} 60965285Siwasaki 61065285Siwasakiint 61165285Siwasakiacpi_checksum(void *p, size_t length) 61265285Siwasaki{ 61365285Siwasaki u_int8_t *bp; 61465285Siwasaki u_int8_t sum; 61565285Siwasaki 61665285Siwasaki bp = p; 61765285Siwasaki sum = 0; 61865285Siwasaki while (length--) 61965285Siwasaki sum += *bp++; 62065285Siwasaki 62165285Siwasaki return (sum); 62265285Siwasaki} 62365285Siwasaki 624119515Snjlstatic struct ACPIsdt * 62565285Siwasakiacpi_map_sdt(vm_offset_t pa) 62665285Siwasaki{ 62765285Siwasaki struct ACPIsdt *sp; 62865285Siwasaki 62965285Siwasaki sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); 63065285Siwasaki sp = acpi_map_physical(pa, sp->len); 63165285Siwasaki return (sp); 63265285Siwasaki} 63365285Siwasaki 634119515Snjlstatic void 63565285Siwasakiacpi_print_rsd_ptr(struct ACPIrsdp *rp) 63665285Siwasaki{ 63785323Siwasaki printf(BEGIN_COMMENT); 638119913Snjl printf(" RSD PTR: OEM="); 63965285Siwasaki acpi_print_string(rp->oem, 6); 640119968Snjl printf(", ACPI_Rev=%s (%d)\n", rp->revision < 2 ? "1.0x" : "2.0x", 641119913Snjl rp->revision); 642119913Snjl if (rp->revision < 2) { 643119913Snjl printf("\tRSDT=0x%08x, cksum=%u\n", rp->rsdt_addr, rp->sum); 644119913Snjl } else { 645119913Snjl printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n", 646119913Snjl (u_long)rp->xsdt_addr, rp->length, rp->xsum); 647119913Snjl } 64885323Siwasaki printf(END_COMMENT); 64965285Siwasaki} 65065285Siwasaki 651119515Snjlstatic void 65265285Siwasakiacpi_handle_rsdt(struct ACPIsdt *rsdp) 65365285Siwasaki{ 654119913Snjl struct ACPIsdt *sdp; 655119913Snjl vm_offset_t addr; 656119913Snjl int entries, i; 65765285Siwasaki 65865285Siwasaki acpi_print_rsdt(rsdp); 659119913Snjl entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size; 66065285Siwasaki for (i = 0; i < entries; i++) { 661119913Snjl switch (addr_size) { 662119913Snjl case 4: 663119913Snjl addr = le32dec((char*)rsdp->body + i * addr_size); 664119913Snjl break; 665119913Snjl case 8: 666119913Snjl addr = le64dec((char*)rsdp->body + i * addr_size); 667119913Snjl break; 668119913Snjl default: 669119913Snjl assert((addr = 0)); 670119913Snjl } 671119913Snjl 672119913Snjl sdp = (struct ACPIsdt *)acpi_map_sdt(addr); 67365285Siwasaki if (acpi_checksum(sdp, sdp->len)) 674119515Snjl errx(1, "RSDT entry %d is corrupt", i); 675119515Snjl if (!memcmp(sdp->signature, "FACP", 4)) 676131307Snjl acpi_handle_fadt(sdp); 677119515Snjl else if (!memcmp(sdp->signature, "APIC", 4)) 678108967Sjhb acpi_handle_apic(sdp); 679119515Snjl else if (!memcmp(sdp->signature, "HPET", 4)) 680118334Speter acpi_handle_hpet(sdp); 681119971Snjl else if (!memcmp(sdp->signature, "ECDT", 4)) 682119971Snjl acpi_handle_ecdt(sdp); 683119968Snjl else { 684119968Snjl printf(BEGIN_COMMENT); 685119968Snjl acpi_print_sdt(sdp); 686119968Snjl printf(END_COMMENT); 687119968Snjl } 68865285Siwasaki } 68965285Siwasaki} 69085323Siwasaki 691119515Snjlstruct ACPIsdt * 692129102Sdessdt_load_devmem(void) 69385323Siwasaki{ 694119515Snjl struct ACPIrsdp *rp; 695119515Snjl struct ACPIsdt *rsdp; 69685323Siwasaki 697119515Snjl rp = acpi_find_rsd_ptr(); 698119515Snjl if (!rp) 699119515Snjl errx(1, "Can't find ACPI information"); 700119515Snjl 701119515Snjl if (tflag) 702119515Snjl acpi_print_rsd_ptr(rp); 703119913Snjl if (rp->revision < 2) { 704119913Snjl rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr); 705119913Snjl if (memcmp(rsdp->signature, "RSDT", 4) != 0 || 706119913Snjl acpi_checksum(rsdp, rsdp->len) != 0) 707119913Snjl errx(1, "RSDT is corrupted"); 708119913Snjl addr_size = sizeof(uint32_t); 709119913Snjl } else { 710119913Snjl rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr); 711119913Snjl if (memcmp(rsdp->signature, "XSDT", 4) != 0 || 712119913Snjl acpi_checksum(rsdp, rsdp->len) != 0) 713119913Snjl errx(1, "XSDT is corrupted"); 714119913Snjl addr_size = sizeof(uint64_t); 715119913Snjl } 716119515Snjl return (rsdp); 71785323Siwasaki} 71885323Siwasaki 719119515Snjlvoid 720119515Snjldsdt_save_file(char *outfile, struct ACPIsdt *dsdp) 72185323Siwasaki{ 722119515Snjl int fd; 723119515Snjl mode_t mode; 72485323Siwasaki 725119515Snjl assert(outfile != NULL); 726119515Snjl mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 727119515Snjl fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, mode); 728119515Snjl if (fd == -1) { 729119515Snjl perror("dsdt_save_file"); 730119515Snjl return; 731119515Snjl } 732119515Snjl write(fd, dsdp, SIZEOF_SDT_HDR); 733119515Snjl write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR); 734119515Snjl close(fd); 73585323Siwasaki} 73685323Siwasaki 737119515Snjlvoid 738119515Snjlaml_disassemble(struct ACPIsdt *dsdp) 73985323Siwasaki{ 740119515Snjl char tmpstr[32], buf[256]; 741119515Snjl FILE *fp; 742119515Snjl int fd, len; 74385323Siwasaki 744119515Snjl strcpy(tmpstr, "/tmp/acpidump.XXXXXX"); 745119515Snjl fd = mkstemp(tmpstr); 746119515Snjl if (fd < 0) { 747119515Snjl perror("iasl tmp file"); 748119515Snjl return; 749119515Snjl } 750119515Snjl 751119515Snjl /* Dump DSDT to the temp file */ 752119515Snjl write(fd, dsdp, SIZEOF_SDT_HDR); 753119515Snjl write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR); 754119515Snjl close(fd); 755119515Snjl 756119515Snjl /* Run iasl -d on the temp file */ 757119515Snjl if (fork() == 0) { 758119515Snjl close(STDOUT_FILENO); 759119515Snjl if (vflag == 0) 760119515Snjl close(STDERR_FILENO); 761119515Snjl execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, 0); 762119515Snjl err(1, "exec"); 763119515Snjl } 764119515Snjl 765119515Snjl wait(NULL); 766119515Snjl unlink(tmpstr); 767119515Snjl 768119515Snjl /* Dump iasl's output to stdout */ 769119515Snjl fp = fopen("acpidump.dsl", "r"); 770119515Snjl unlink("acpidump.dsl"); 771119515Snjl if (fp == NULL) { 772119515Snjl perror("iasl tmp file (read)"); 773119515Snjl return; 774119515Snjl } 775119515Snjl while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) 776119515Snjl fwrite(buf, 1, len, stdout); 777119515Snjl fclose(fp); 77885323Siwasaki} 77985323Siwasaki 780119515Snjlvoid 781119515Snjlsdt_print_all(struct ACPIsdt *rsdp) 78285323Siwasaki{ 783119515Snjl acpi_handle_rsdt(rsdp); 78485323Siwasaki} 78585323Siwasaki 786119515Snjl/* Fetch a table matching the given signature via the RSDT */ 787119515Snjlstruct ACPIsdt * 788119515Snjlsdt_from_rsdt(struct ACPIsdt *rsdt, const char *sig) 78985323Siwasaki{ 790119913Snjl struct ACPIsdt *sdt; 791119913Snjl vm_offset_t addr; 792119913Snjl int entries, i; 79385323Siwasaki 794119913Snjl entries = (rsdt->len - SIZEOF_SDT_HDR) / addr_size; 795119515Snjl for (i = 0; i < entries; i++) { 796119913Snjl switch (addr_size) { 797119913Snjl case 4: 798119913Snjl addr = le32dec((char*)rsdt->body + i * addr_size); 799119913Snjl break; 800119913Snjl case 8: 801119913Snjl addr = le64dec((char*)rsdt->body + i * addr_size); 802119913Snjl break; 803119913Snjl default: 804119913Snjl assert((addr = 0)); 805119913Snjl } 806119913Snjl sdt = (struct ACPIsdt *)acpi_map_sdt(addr); 807119913Snjl if (memcmp(sdt->signature, sig, strlen(sig))) 808119913Snjl continue; 809119515Snjl if (acpi_checksum(sdt, sdt->len)) 810119515Snjl errx(1, "RSDT entry %d is corrupt", i); 811119913Snjl return (sdt); 812119515Snjl } 813119515Snjl 814119515Snjl return (NULL); 81585323Siwasaki} 81685323Siwasaki 817119515Snjlstruct ACPIsdt * 818119912Snjldsdt_from_fadt(struct FADTbody *fadt) 81985323Siwasaki{ 820128382Snjl struct ACPIsdt *sdt; 82185323Siwasaki 822124138Snjl /* Use the DSDT address if it is version 1, otherwise use X_DSDT. */ 823128382Snjl if (acpi_get_fadt_revision(fadt) == 1) 824120044Snjl sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->dsdt_ptr); 825120044Snjl else 826120044Snjl sdt = (struct ACPIsdt *)acpi_map_sdt(fadt->x_dsdt_ptr); 827119515Snjl if (acpi_checksum(sdt, sdt->len)) 828119515Snjl errx(1, "DSDT is corrupt\n"); 829119515Snjl return (sdt); 83085323Siwasaki} 831