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 * $Id: acpi.c,v 1.4 2000/08/09 14:47:52 iwasaki Exp $ 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/stat.h> 33 34 #include <assert.h> 35 #include <err.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <unistd.h> 39 40 #include "acpidump.h" 41 42 #include "aml/aml_env.h" 43 #include "aml/aml_common.h" 44 45 #define BEGIN_COMMENT "/*\n" 46 #define END_COMMENT " */\n" 47 48 struct ACPIsdt dsdt_header = { 49 "DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678 50 }; 51 52 static void 53 acpi_trim_string(char *s, size_t length) 54 { 55 56 /* Trim trailing spaces and NULLs */ 57 while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 58 s[length-- - 1] = '\0'; 59 } 60 61 static void 62 acpi_print_dsdt_definition(void) 63 { 64 char oemid[6 + 1]; 65 char oemtblid[8 + 1]; 66 67 acpi_trim_string(dsdt_header.oemid, 6); 68 acpi_trim_string(dsdt_header.oemtblid, 8); 69 strncpy(oemid, dsdt_header.oemid, 6); 70 oemid[6] = '\0'; 71 strncpy(oemtblid, dsdt_header.oemtblid, 8); 72 oemtblid[8] = '\0'; 73 74 printf("DefinitionBlock ( 75 \"acpi_dsdt.aml\", //Output filename 76 \"DSDT\", //Signature 77 0x%x, //DSDT Revision 78 \"%s\", //OEMID 79 \"%s\", //TABLE ID 80 0x%x //OEM Revision\n)\n", 81 dsdt_header.rev, oemid, oemtblid, dsdt_header.oemrev); 82 } 83 84 static void 85 acpi_print_string(char *s, size_t length) 86 { 87 int c; 88 89 /* Trim trailing spaces and NULLs */ 90 while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 91 length--; 92 93 while (length--) { 94 c = *s++; 95 putchar(c); 96 } 97 } 98 99 static void 100 acpi_handle_dsdt(struct ACPIsdt *dsdp) 101 { 102 u_int8_t *dp; 103 u_int8_t *end; 104 105 acpi_print_dsdt(dsdp); 106 dp = (u_int8_t *)dsdp->body; 107 end = (u_int8_t *)dsdp + dsdp->len; 108 109 acpi_dump_dsdt(dp, end); 110 } 111 112 static void 113 acpi_handle_facp(struct FACPbody *facp) 114 { 115 struct ACPIsdt *dsdp; 116 117 acpi_print_facp(facp); 118 dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr); 119 if (acpi_checksum(dsdp, dsdp->len)) 120 errx(1, "DSDT is corrupt\n"); 121 acpi_handle_dsdt(dsdp); 122 aml_dump(dsdp); 123 } 124 125 static void 126 acpi_print_cpu(u_char cpu_id) 127 { 128 129 printf("\tACPI CPU="); 130 if (cpu_id == 0xff) 131 printf("ALL\n"); 132 else 133 printf("%d\n", (u_int)cpu_id); 134 } 135 136 static void 137 acpi_print_local_apic(u_char cpu_id, u_char apic_id, u_int32_t flags) 138 { 139 acpi_print_cpu(cpu_id); 140 printf("\tFlags={"); 141 if (flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED) 142 printf("ENABLED"); 143 else 144 printf("DISABLED"); 145 printf("}\n"); 146 printf("\tAPIC ID=%d\n", (u_int)apic_id); 147 } 148 149 static void 150 acpi_print_io_apic(u_char apic_id, u_int32_t int_base, u_int64_t apic_addr) 151 { 152 u_int addr_hi; 153 154 printf("\tAPIC ID=%d\n", (u_int)apic_id); 155 printf("\tINT BASE=%d\n", int_base); 156 printf("\tADDR=0x"); 157 addr_hi = apic_addr >> 32; 158 if (addr_hi != 0) { 159 printf("%08x", addr_hi); 160 apic_addr &= 0xffffffff; 161 } 162 printf("%08x\n", (u_int)apic_addr); 163 } 164 165 static void 166 acpi_print_mps_flags(u_int16_t flags) 167 { 168 169 printf("\tFlags={Polarity="); 170 switch (flags & MPS_INT_FLAG_POLARITY_MASK) { 171 case MPS_INT_FLAG_POLARITY_CONFORM: 172 printf("conforming"); 173 break; 174 case MPS_INT_FLAG_POLARITY_HIGH: 175 printf("active-hi"); 176 break; 177 case MPS_INT_FLAG_POLARITY_LOW: 178 printf("active-lo"); 179 break; 180 default: 181 printf("0x%x", flags & MPS_INT_FLAG_POLARITY_MASK); 182 break; 183 } 184 printf(", Trigger="); 185 switch (flags & MPS_INT_FLAG_TRIGGER_MASK) { 186 case MPS_INT_FLAG_TRIGGER_CONFORM: 187 printf("conforming"); 188 break; 189 case MPS_INT_FLAG_TRIGGER_EDGE: 190 printf("edge"); 191 break; 192 case MPS_INT_FLAG_TRIGGER_LEVEL: 193 printf("level"); 194 break; 195 default: 196 printf("0x%x", (flags & MPS_INT_FLAG_TRIGGER_MASK) >> 2); 197 } 198 printf("}\n"); 199 } 200 201 static void 202 acpi_print_intr(u_int32_t intr, u_int16_t mps_flags) 203 { 204 205 printf("\tINTR=%d\n", (u_int)intr); 206 acpi_print_mps_flags(mps_flags); 207 } 208 209 const char *apic_types[] = { "Local APIC", "IO APIC", "INT Override", "NMI", 210 "Local NMI", "Local APIC Override", "IO SAPIC", 211 "Local SAPIC", "Platform Interrupt" }; 212 const char *platform_int_types[] = { "PMI", "INIT", 213 "Corrected Platform Error" }; 214 215 static void 216 acpi_print_apic(struct MADT_APIC *mp) 217 { 218 219 printf("\tType=%s\n", apic_types[mp->type]); 220 switch (mp->type) { 221 case ACPI_MADT_APIC_TYPE_LOCAL_APIC: 222 acpi_print_local_apic(mp->body.local_apic.cpu_id, 223 mp->body.local_apic.apic_id, mp->body.local_apic.flags); 224 break; 225 case ACPI_MADT_APIC_TYPE_IO_APIC: 226 acpi_print_io_apic(mp->body.io_apic.apic_id, 227 mp->body.io_apic.int_base, 228 mp->body.io_apic.apic_addr); 229 break; 230 case ACPI_MADT_APIC_TYPE_INT_OVERRIDE: 231 printf("\tBUS=%d\n", (u_int)mp->body.int_override.bus); 232 printf("\tIRQ=%d\n", (u_int)mp->body.int_override.source); 233 acpi_print_intr(mp->body.int_override.intr, 234 mp->body.int_override.mps_flags); 235 break; 236 case ACPI_MADT_APIC_TYPE_NMI: 237 acpi_print_intr(mp->body.nmi.intr, mp->body.nmi.mps_flags); 238 break; 239 case ACPI_MADT_APIC_TYPE_LOCAL_NMI: 240 acpi_print_cpu(mp->body.local_nmi.cpu_id); 241 printf("\tLINT Pin=%d\n", mp->body.local_nmi.lintpin); 242 acpi_print_mps_flags(mp->body.local_nmi.mps_flags); 243 break; 244 case ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE: 245 printf("\tLocal APIC ADDR=0x%08x%08x\n", 246 (u_int)(mp->body.local_apic_override.apic_addr >> 32), 247 (u_int)(mp->body.local_apic_override.apic_addr & 0xffffffff)); 248 break; 249 case ACPI_MADT_APIC_TYPE_IO_SAPIC: 250 acpi_print_io_apic(mp->body.io_sapic.apic_id, 251 mp->body.io_sapic.int_base, 252 mp->body.io_sapic.apic_addr); 253 break; 254 case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC: 255 acpi_print_local_apic(mp->body.local_sapic.cpu_id, 256 mp->body.local_sapic.apic_id, mp->body.local_sapic.flags); 257 printf("\tAPIC EID=%d\n", (u_int)mp->body.local_sapic.apic_eid); 258 break; 259 case ACPI_MADT_APIC_TYPE_INT_SRC: 260 printf("\tType=%s\n", 261 platform_int_types[mp->body.int_src.type]); 262 printf("\tCPU ID=%d\n", (u_int)mp->body.int_src.cpu_id); 263 printf("\tCPU EID=%d\n", (u_int)mp->body.int_src.cpu_id); 264 printf("\tSAPIC Vector=%d\n", 265 (u_int)mp->body.int_src.sapic_vector); 266 acpi_print_intr(mp->body.int_src.intr, 267 mp->body.int_src.mps_flags); 268 break; 269 default: 270 printf("\tUnknown type %d\n", (u_int)mp->type); 271 } 272 } 273 274 static void 275 acpi_handle_apic(struct ACPIsdt *sdp) 276 { 277 struct MADTbody *madtp; 278 struct MADT_APIC *madt_apicp; 279 280 acpi_print_sdt(sdp); 281 madtp = (struct MADTbody *) sdp->body; 282 printf(BEGIN_COMMENT); 283 printf("\tLocal APIC ADDR=0x%08x\n", madtp->lapic_addr); 284 printf("\tFlags={"); 285 if (madtp->flags & ACPI_APIC_FLAG_PCAT_COMPAT) 286 printf("PC-AT"); 287 printf("}\n"); 288 madt_apicp = (struct MADT_APIC *) madtp->body; 289 while (((uintptr_t)madt_apicp) - ((uintptr_t)sdp) < sdp->len) { 290 printf("\n"); 291 acpi_print_apic(madt_apicp); 292 madt_apicp = (struct MADT_APIC *) ((char *)madt_apicp + 293 madt_apicp->len); 294 } 295 printf(END_COMMENT); 296 } 297 298 static void 299 init_namespace() 300 { 301 struct aml_environ env; 302 struct aml_name *newname; 303 304 aml_new_name_group(AML_NAME_GROUP_OS_DEFINED); 305 env.curname = aml_get_rootname(); 306 newname = aml_create_name(&env, "\\_OS_"); 307 newname->property = aml_alloc_object(aml_t_string, NULL); 308 newname->property->str.needfree = 0; 309 newname->property->str.string = "Microsoft Windows NT"; 310 } 311 312 /* 313 * Public interfaces 314 */ 315 316 void 317 acpi_dump_dsdt(u_int8_t *dp, u_int8_t *end) 318 { 319 extern struct aml_environ asl_env; 320 321 acpi_print_dsdt_definition(); 322 323 /* 1st stage: parse only w/o printing */ 324 init_namespace(); 325 aml_new_name_group((int)dp); 326 bzero(&asl_env, sizeof(asl_env)); 327 328 asl_env.dp = dp; 329 asl_env.end = end; 330 asl_env.curname = aml_get_rootname(); 331 332 aml_local_stack_push(aml_local_stack_create()); 333 aml_parse_objectlist(&asl_env, 0); 334 aml_local_stack_delete(aml_local_stack_pop()); 335 336 assert(asl_env.dp == asl_env.end); 337 asl_env.dp = dp; 338 339 /* 2nd stage: dump whole object list */ 340 printf("\n{\n"); 341 asl_dump_objectlist(&dp, end, 0); 342 printf("\n}\n"); 343 assert(dp == end); 344 } 345 346 void 347 acpi_print_sdt(struct ACPIsdt *sdp) 348 { 349 350 printf(BEGIN_COMMENT); 351 acpi_print_string(sdp->signature, 4); 352 printf(": Length=%d, Revision=%d, Checksum=%d,\n", 353 sdp->len, sdp->rev, sdp->check); 354 printf("\tOEMID="); 355 acpi_print_string(sdp->oemid, 6); 356 printf(", OEM Table ID="); 357 acpi_print_string(sdp->oemtblid, 8); 358 printf(", OEM Revision=0x%x,\n", sdp->oemrev); 359 printf("\tCreator ID="); 360 acpi_print_string(sdp->creator, 4); 361 printf(", Creator Revision=0x%x\n", sdp->crerev); 362 printf(END_COMMENT); 363 if (!memcmp(sdp->signature, "DSDT", 4)) { 364 memcpy(&dsdt_header, sdp, sizeof(dsdt_header)); 365 } 366 } 367 368 void 369 acpi_print_rsdt(struct ACPIsdt *rsdp) 370 { 371 int i, entries; 372 373 acpi_print_sdt(rsdp); 374 entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); 375 printf(BEGIN_COMMENT); 376 printf("\tEntries={ "); 377 for (i = 0; i < entries; i++) { 378 if (i > 0) 379 printf(", "); 380 printf("0x%08x", rsdp->body[i]); 381 } 382 printf(" }\n"); 383 printf(END_COMMENT); 384 } 385 386 void 387 acpi_print_facp(struct FACPbody *facp) 388 { 389 char sep; 390 391 printf(BEGIN_COMMENT); 392 printf("\tDSDT=0x%x\n", facp->dsdt_ptr); 393 printf("\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC"); 394 printf("\tSCI_INT=%d\n", facp->sci_int); 395 printf("\tSMI_CMD=0x%x, ", facp->smi_cmd); 396 printf("ACPI_ENABLE=0x%x, ", facp->acpi_enable); 397 printf("ACPI_DISABLE=0x%x, ", facp->acpi_disable); 398 printf("S4BIOS_REQ=0x%x\n", facp->s4biosreq); 399 if (facp->pm1a_evt_blk) 400 printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", 401 facp->pm1a_evt_blk, 402 facp->pm1a_evt_blk + facp->pm1_evt_len - 1); 403 if (facp->pm1b_evt_blk) 404 printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", 405 facp->pm1b_evt_blk, 406 facp->pm1b_evt_blk + facp->pm1_evt_len - 1); 407 if (facp->pm1a_cnt_blk) 408 printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", 409 facp->pm1a_cnt_blk, 410 facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1); 411 if (facp->pm1b_cnt_blk) 412 printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", 413 facp->pm1b_cnt_blk, 414 facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1); 415 if (facp->pm2_cnt_blk) 416 printf("\tPM2_CNT_BLK=0x%x-0x%x\n", 417 facp->pm2_cnt_blk, 418 facp->pm2_cnt_blk + facp->pm2_cnt_len - 1); 419 if (facp->pm_tmr_blk) 420 printf("\tPM2_TMR_BLK=0x%x-0x%x\n", 421 facp->pm_tmr_blk, 422 facp->pm_tmr_blk + facp->pm_tmr_len - 1); 423 if (facp->gpe0_blk) 424 printf("\tPM2_GPE0_BLK=0x%x-0x%x\n", 425 facp->gpe0_blk, 426 facp->gpe0_blk + facp->gpe0_len - 1); 427 if (facp->gpe1_blk) 428 printf("\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 429 facp->gpe1_blk, 430 facp->gpe1_blk + facp->gpe1_len - 1, 431 facp->gpe1_base); 432 printf("\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n", 433 facp->p_lvl2_lat, facp->p_lvl3_lat); 434 printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 435 facp->flush_size, facp->flush_stride); 436 printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 437 facp->duty_off, facp->duty_width); 438 printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 439 facp->day_alrm, facp->mon_alrm, facp->century); 440 printf("\tFlags="); 441 sep = '{'; 442 443 #define PRINTFLAG(xx) do { \ 444 if (facp->flags & ACPI_FACP_FLAG_## xx) { \ 445 printf("%c%s", sep, #xx); sep = ','; \ 446 } \ 447 } while (0) 448 449 PRINTFLAG(WBINVD); 450 PRINTFLAG(WBINVD_FLUSH); 451 PRINTFLAG(PROC_C1); 452 PRINTFLAG(P_LVL2_UP); 453 PRINTFLAG(PWR_BUTTON); 454 PRINTFLAG(SLP_BUTTON); 455 PRINTFLAG(FIX_RTC); 456 PRINTFLAG(RTC_S4); 457 PRINTFLAG(TMR_VAL_EXT); 458 PRINTFLAG(DCK_CAP); 459 460 #undef PRINTFLAG 461 462 printf("}\n"); 463 printf(END_COMMENT); 464 } 465 466 void 467 acpi_print_dsdt(struct ACPIsdt *dsdp) 468 { 469 470 acpi_print_sdt(dsdp); 471 } 472 473 int 474 acpi_checksum(void *p, size_t length) 475 { 476 u_int8_t *bp; 477 u_int8_t sum; 478 479 bp = p; 480 sum = 0; 481 while (length--) 482 sum += *bp++; 483 484 return (sum); 485 } 486 487 struct ACPIsdt * 488 acpi_map_sdt(vm_offset_t pa) 489 { 490 struct ACPIsdt *sp; 491 492 sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); 493 sp = acpi_map_physical(pa, sp->len); 494 return (sp); 495 } 496 497 void 498 acpi_print_rsd_ptr(struct ACPIrsdp *rp) 499 { 500 501 printf(BEGIN_COMMENT); 502 printf("RSD PTR: Checksum=%d, OEMID=", rp->sum); 503 acpi_print_string(rp->oem, 6); 504 printf(", RsdtAddress=0x%08x\n", rp->rsdt_addr); 505 printf(END_COMMENT); 506 } 507 508 void 509 acpi_handle_rsdt(struct ACPIsdt *rsdp) 510 { 511 int i; 512 int entries; 513 struct ACPIsdt *sdp; 514 515 entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); 516 acpi_print_rsdt(rsdp); 517 for (i = 0; i < entries; i++) { 518 sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]); 519 if (acpi_checksum(sdp, sdp->len)) 520 errx(1, "RSDT entry %d is corrupt\n", i); 521 if (!memcmp(sdp->signature, "FACP", 4)) { 522 acpi_handle_facp((struct FACPbody *) sdp->body); 523 } else if (!memcmp(sdp->signature, "APIC", 4)) { 524 acpi_handle_apic(sdp); 525 } else { 526 acpi_print_sdt(sdp); 527 } 528 } 529 } 530 531 /* 532 * Dummy functions 533 */ 534 535 void 536 aml_dbgr(struct aml_environ *env1, struct aml_environ *env2) 537 { 538 /* do nothing */ 539 } 540 541 int 542 aml_region_read_simple(struct aml_region_handle *h, vm_offset_t offset, 543 u_int32_t *valuep) 544 { 545 return (0); 546 } 547 548 int 549 aml_region_write_simple(struct aml_region_handle *h, vm_offset_t offset, 550 u_int32_t value) 551 { 552 return (0); 553 } 554 555 u_int32_t 556 aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value) 557 { 558 return (0); 559 } 560 561 u_int32_t 562 aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value) 563 { 564 return (0); 565 } 566 567 int 568 aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value, 569 struct aml_region_handle *h) 570 { 571 return (0); 572 } 573 574 u_int32_t 575 aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags, 576 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 577 { 578 return (0); 579 } 580 581 int 582 aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags, 583 u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 584 { 585 return (0); 586 } 587 588 int 589 aml_region_write_from_buffer(struct aml_environ *env, int regtype, 590 u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, 591 u_int32_t bitlen) 592 { 593 return (0); 594 } 595 596 int 597 aml_region_bcopy(struct aml_environ *env, int regtype, u_int32_t flags, 598 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, 599 u_int32_t dflags, u_int32_t daddr, 600 u_int32_t dbitoffset, u_int32_t dbitlen) 601 { 602 return (0); 603 } 604 605 int 606 aml_region_read_into_buffer(struct aml_environ *env, int regtype, 607 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, 608 u_int32_t bitlen, u_int8_t *buffer) 609 { 610 return (0); 611 } 612 613