1 /* $OpenBSD: acpidump.c,v 1.17 2016/09/26 19:58:26 kettenis Exp $ */ 2 /* 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 */ 28 29 #include <sys/types.h> 30 #include <sys/mman.h> 31 #include <sys/queue.h> 32 #include <sys/stat.h> 33 #include <machine/biosvar.h> 34 35 #include <assert.h> 36 #include <err.h> 37 #include <fcntl.h> 38 #include <kvm.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <limits.h> 44 45 46 #define vm_page_size sysconf(_SC_PAGESIZE) 47 #define PRINTFLAG(xx) \ 48 do { \ 49 if (facp->flags & ACPI_FACP_FLAG_## xx) { \ 50 fprintf(fhdr, "%c%s", sep, #xx); sep = ','; \ 51 } \ 52 } while (0) 53 54 55 typedef unsigned long vm_offset_t; 56 57 struct ACPIrsdp { 58 u_char signature[8]; 59 u_char sum; 60 u_char oem[6]; 61 u_char res; 62 u_int32_t addr; 63 } __packed; 64 65 struct ACPIsdt { 66 u_char signature[4]; 67 u_int32_t len; 68 u_char rev; 69 u_char check; 70 u_char oemid[6]; 71 u_char oemtblid[8]; 72 u_int32_t oemrev; 73 u_char creator[4]; 74 u_int32_t crerev; 75 #define SIZEOF_SDT_HDR 36 /* struct size except body */ 76 u_int32_t body[1];/* This member should be casted */ 77 } __packed; 78 79 struct ACPIgas { 80 u_int8_t address_space_id; 81 #define ACPI_GAS_MEMORY 0 82 #define ACPI_GAS_IO 1 83 #define ACPI_GAS_PCI 2 84 #define ACPI_GAS_EMBEDDED 3 85 #define ACPI_GAS_SMBUS 4 86 #define ACPI_GAS_FIXED 0x7f 87 u_int8_t register_bit_width; 88 u_int8_t register_bit_offset; 89 u_int8_t res; 90 u_int64_t address; 91 } __packed; 92 93 struct FACPbody { 94 u_int32_t facs_ptr; 95 u_int32_t dsdt_ptr; 96 u_int8_t int_model; 97 #define ACPI_FACP_INTMODEL_PIC 0 /* Standard PC-AT PIC */ 98 #define ACPI_FACP_INTMODEL_APIC 1 /* Multiple APIC */ 99 u_char reserved1; 100 u_int16_t sci_int; 101 u_int32_t smi_cmd; 102 u_int8_t acpi_enable; 103 u_int8_t acpi_disable; 104 u_int8_t s4biosreq; 105 u_int8_t reserved2; 106 u_int32_t pm1a_evt_blk; 107 u_int32_t pm1b_evt_blk; 108 u_int32_t pm1a_cnt_blk; 109 u_int32_t pm1b_cnt_blk; 110 u_int32_t pm2_cnt_blk; 111 u_int32_t pm_tmr_blk; 112 u_int32_t gpe0_blk; 113 u_int32_t gpe1_blk; 114 u_int8_t pm1_evt_len; 115 u_int8_t pm1_cnt_len; 116 u_int8_t pm2_cnt_len; 117 u_int8_t pm_tmr_len; 118 u_int8_t gpe0_len; 119 u_int8_t gpe1_len; 120 u_int8_t gpe1_base; 121 u_int8_t reserved3; 122 u_int16_t p_lvl2_lat; 123 u_int16_t p_lvl3_lat; 124 u_int16_t flush_size; 125 u_int16_t flush_stride; 126 u_int8_t duty_off; 127 u_int8_t duty_width; 128 u_int8_t day_alrm; 129 u_int8_t mon_alrm; 130 u_int8_t century; 131 u_int16_t iapc_boot_arch; 132 u_char reserved4[1]; 133 u_int32_t flags; 134 #define ACPI_FACP_FLAG_WBINVD 1 /* WBINVD is correctly supported */ 135 #define ACPI_FACP_FLAG_WBINVD_FLUSH 2 /* WBINVD flushes caches */ 136 #define ACPI_FACP_FLAG_PROC_C1 4 /* C1 power state supported */ 137 #define ACPI_FACP_FLAG_P_LVL2_UP 8 /* C2 power state works on SMP */ 138 #define ACPI_FACP_FLAG_PWR_BUTTON 16 /* Power button uses control method */ 139 #define ACPI_FACP_FLAG_SLP_BUTTON 32 /* Sleep button uses control method */ 140 #define ACPI_FACP_FLAG_FIX_RTC 64 /* RTC wakeup not supported */ 141 #define ACPI_FACP_FLAG_RTC_S4 128 /* RTC can wakeup from S4 state */ 142 #define ACPI_FACP_FLAG_TMR_VAL_EXT 256 /* TMR_VAL is 32bit */ 143 #define ACPI_FACP_FLAG_DCK_CAP 512 /* Can support docking */ 144 struct ACPIgas reset_reg; 145 u_int8_t reset_value; 146 u_int8_t reserved5[3]; 147 u_int64_t x_firmware_ctrl; 148 u_int64_t x_dsdt; 149 struct ACPIgas x_pm1a_evt_blk; 150 struct ACPIgas x_pm1b_evt_blk; 151 struct ACPIgas x_pm1a_cnt_blk; 152 struct ACPIgas x_pm1b_cnt_blk; 153 struct ACPIgas x_pm2_cnt_blk; 154 struct ACPIgas x_pm_tmr_blk; 155 struct ACPIgas x_gpe0_blk; 156 struct ACPIgas x_gpe1_blk; 157 } __packed; 158 159 struct acpi_user_mapping { 160 LIST_ENTRY(acpi_user_mapping) link; 161 vm_offset_t pa; 162 caddr_t va; 163 size_t size; 164 }; 165 166 LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist; 167 168 int acpi_mem_fd = -1; 169 char *aml_dumpfile; 170 int aml_dumpdir; 171 FILE *fhdr; 172 173 int acpi_checksum(void *_p, size_t _length); 174 struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t _pa, size_t _size); 175 void *acpi_map_physical(vm_offset_t _pa, size_t _size); 176 void acpi_user_init(void); 177 struct ACPIrsdp *acpi_find_rsd_ptr(void); 178 void acpi_print_string(char *_s, size_t _length); 179 void acpi_print_rsd_ptr(struct ACPIrsdp *_rp); 180 struct ACPIsdt *acpi_map_sdt(vm_offset_t _pa); 181 void aml_dump(struct ACPIsdt *_hdr); 182 void acpi_print_sdt(struct ACPIsdt *_sdp); 183 void acpi_print_rsdt(struct ACPIsdt *_rsdp); 184 void acpi_print_facp(struct FACPbody *_facp); 185 void acpi_print_dsdt(struct ACPIsdt *_dsdp); 186 void acpi_handle_dsdt(struct ACPIsdt *_dsdp); 187 void acpi_handle_facp(struct FACPbody *_facp); 188 void acpi_handle_rsdt(struct ACPIsdt *_rsdp); 189 void asl_dump_from_devmem(void); 190 void usage(void); 191 u_long bios_acpi_addr(void); 192 193 194 struct ACPIsdt dsdt_header = { 195 "DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678 196 }; 197 198 int 199 acpi_checksum(void *p, size_t length) 200 { 201 u_int8_t *bp; 202 u_int8_t sum; 203 204 bp = p; 205 sum = 0; 206 while (length--) 207 sum += *bp++; 208 209 return (sum); 210 } 211 212 struct acpi_user_mapping * 213 acpi_user_find_mapping(vm_offset_t pa, size_t size) 214 { 215 struct acpi_user_mapping *map; 216 int page_mask = getpagesize() - 1; 217 218 /* First search for an existing mapping */ 219 for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) { 220 if (map->pa <= pa && map->size >= pa + size - map->pa) 221 return (map); 222 } 223 224 /* Then create a new one */ 225 #undef round_page 226 #undef trunc_page 227 #define round_page(x) (((x) + page_mask) & ~page_mask) 228 #define trunc_page(x) ((x) & ~page_mask) 229 size = round_page(pa + size) - trunc_page(pa); 230 pa = trunc_page(pa); 231 #undef round_page 232 #undef trunc_page 233 map = malloc(sizeof(struct acpi_user_mapping)); 234 if (!map) 235 errx(1, "out of memory"); 236 map->pa = pa; 237 map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); 238 map->size = size; 239 if (map->va == MAP_FAILED) 240 err(1, "can't map address"); 241 LIST_INSERT_HEAD(&maplist, map, link); 242 243 return (map); 244 } 245 246 void * 247 acpi_map_physical(vm_offset_t pa, size_t size) 248 { 249 struct acpi_user_mapping *map; 250 251 map = acpi_user_find_mapping(pa, size); 252 return (map->va + (pa - map->pa)); 253 } 254 255 void 256 acpi_user_init(void) 257 { 258 if (acpi_mem_fd == -1) { 259 acpi_mem_fd = open("/dev/mem", O_RDONLY); 260 if (acpi_mem_fd == -1) 261 err(1, "opening /dev/mem"); 262 LIST_INIT(&maplist); 263 } 264 } 265 266 struct ACPIrsdp * 267 acpi_find_rsd_ptr(void) 268 { 269 int i; 270 u_int8_t buf[sizeof(struct ACPIrsdp)]; 271 u_long addr; 272 273 if ((addr = bios_acpi_addr()) != 0) { 274 lseek(acpi_mem_fd, addr, SEEK_SET); 275 read(acpi_mem_fd, buf, 16); 276 if (!memcmp(buf, "RSD PTR ", 8)) { 277 read(acpi_mem_fd, buf + 16, 278 sizeof(struct ACPIrsdp) - 16); 279 if (!acpi_checksum(buf, sizeof(struct ACPIrsdp))) 280 return (acpi_map_physical(addr, 281 sizeof(struct ACPIrsdp))); 282 } 283 lseek(acpi_mem_fd, 0, SEEK_SET); 284 } 285 for (i = 0; i < 1024 * 1024; i += 16) { 286 lseek(acpi_mem_fd, i, SEEK_SET); 287 read(acpi_mem_fd, buf, 16); 288 if (!memcmp(buf, "RSD PTR ", 8)) { 289 /* Read the rest of the structure */ 290 read(acpi_mem_fd, buf + 16, 291 sizeof(struct ACPIrsdp) - 16); 292 293 /* Verify checksum before accepting it. */ 294 if (acpi_checksum(buf, sizeof(struct ACPIrsdp))) 295 continue; 296 297 return (acpi_map_physical(i, sizeof(struct ACPIrsdp))); 298 } 299 } 300 301 return (0); 302 } 303 304 void 305 acpi_print_string(char *s, size_t length) 306 { 307 int c; 308 309 /* Trim trailing spaces and NULLs */ 310 while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) 311 length--; 312 313 while (length--) { 314 c = *s++; 315 fputc(c, fhdr); 316 } 317 } 318 319 void 320 acpi_print_rsd_ptr(struct ACPIrsdp *rp) 321 { 322 fprintf(fhdr, "\n"); 323 fprintf(fhdr, "RSD PTR: Checksum=%d, OEMID=", rp->sum); 324 acpi_print_string(rp->oem, 6); 325 fprintf(fhdr, ", RsdtAddress=0x%08x\n", rp->addr); 326 fprintf(fhdr, "\n"); 327 } 328 329 struct ACPIsdt * 330 acpi_map_sdt(vm_offset_t pa) 331 { 332 struct ACPIsdt *sp; 333 334 sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); 335 sp = acpi_map_physical(pa, sp->len); 336 return (sp); 337 } 338 339 void 340 aml_dump(struct ACPIsdt *hdr) 341 { 342 static int hdr_index; 343 char name[PATH_MAX]; 344 int fd; 345 mode_t mode; 346 347 snprintf(name, sizeof(name), "%s%c%c%c%c%c.%d", 348 aml_dumpfile, aml_dumpdir ? '/' : '.', 349 hdr->signature[0], hdr->signature[1], 350 hdr->signature[2], hdr->signature[3], 351 hdr_index++); 352 353 mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 354 fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode); 355 if (fd == -1) 356 err(1, "aml_dump"); 357 358 write(fd, hdr, SIZEOF_SDT_HDR); 359 write(fd, hdr->body, hdr->len - SIZEOF_SDT_HDR); 360 close(fd); 361 } 362 363 void 364 acpi_print_sdt(struct ACPIsdt *sdp) 365 { 366 fprintf(fhdr, "\n"); 367 acpi_print_string(sdp->signature, 4); 368 fprintf(fhdr, ": Length=%d, Revision=%d, Checksum=%d,\n", 369 sdp->len, sdp->rev, sdp->check); 370 fprintf(fhdr, "\tOEMID="); 371 acpi_print_string(sdp->oemid, 6); 372 fprintf(fhdr, ", OEM Table ID="); 373 acpi_print_string(sdp->oemtblid, 8); 374 fprintf(fhdr, ", OEM Revision=0x%x,\n", sdp->oemrev); 375 fprintf(fhdr, "\tCreator ID="); 376 acpi_print_string(sdp->creator, 4); 377 fprintf(fhdr, ", Creator Revision=0x%x\n", sdp->crerev); 378 fprintf(fhdr, "\n"); 379 if (!memcmp(sdp->signature, "DSDT", 4)) 380 memcpy(&dsdt_header, sdp, sizeof(dsdt_header)); 381 } 382 383 void 384 acpi_print_rsdt(struct ACPIsdt *rsdp) 385 { 386 int i, entries; 387 388 acpi_print_sdt(rsdp); 389 entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); 390 fprintf(fhdr, "\n"); 391 fprintf(fhdr, "\tEntries={ "); 392 for (i = 0; i < entries; i++) { 393 if (i > 0) 394 fprintf(fhdr, ", "); 395 fprintf(fhdr, "0x%08x", rsdp->body[i]); 396 } 397 fprintf(fhdr, " }\n"); 398 fprintf(fhdr, "\n"); 399 } 400 401 void 402 acpi_print_facp(struct FACPbody *facp) 403 { 404 char sep; 405 406 fprintf(fhdr, "\n"); 407 fprintf(fhdr, "\tDSDT=0x%x\n", facp->dsdt_ptr); 408 fprintf(fhdr, "\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC"); 409 fprintf(fhdr, "\tSCI_INT=%d\n", facp->sci_int); 410 fprintf(fhdr, "\tSMI_CMD=0x%x, ", facp->smi_cmd); 411 fprintf(fhdr, "ACPI_ENABLE=0x%x, ", facp->acpi_enable); 412 fprintf(fhdr, "ACPI_DISABLE=0x%x, ", facp->acpi_disable); 413 fprintf(fhdr, "S4BIOS_REQ=0x%x\n", facp->s4biosreq); 414 if (facp->pm1a_evt_blk) 415 fprintf(fhdr, "\tPM1a_EVT_BLK=0x%x-0x%x\n", 416 facp->pm1a_evt_blk, 417 facp->pm1a_evt_blk + facp->pm1_evt_len - 1); 418 if (facp->pm1b_evt_blk) 419 fprintf(fhdr, "\tPM1b_EVT_BLK=0x%x-0x%x\n", 420 facp->pm1b_evt_blk, 421 facp->pm1b_evt_blk + facp->pm1_evt_len - 1); 422 if (facp->pm1a_cnt_blk) 423 fprintf(fhdr, "\tPM1a_CNT_BLK=0x%x-0x%x\n", 424 facp->pm1a_cnt_blk, 425 facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1); 426 if (facp->pm1b_cnt_blk) 427 fprintf(fhdr, "\tPM1b_CNT_BLK=0x%x-0x%x\n", 428 facp->pm1b_cnt_blk, 429 facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1); 430 if (facp->pm2_cnt_blk) 431 fprintf(fhdr, "\tPM2_CNT_BLK=0x%x-0x%x\n", 432 facp->pm2_cnt_blk, 433 facp->pm2_cnt_blk + facp->pm2_cnt_len - 1); 434 if (facp->pm_tmr_blk) 435 fprintf(fhdr, "\tPM2_TMR_BLK=0x%x-0x%x\n", 436 facp->pm_tmr_blk, 437 facp->pm_tmr_blk + facp->pm_tmr_len - 1); 438 if (facp->gpe0_blk) 439 fprintf(fhdr, "\tPM2_GPE0_BLK=0x%x-0x%x\n", 440 facp->gpe0_blk, 441 facp->gpe0_blk + facp->gpe0_len - 1); 442 if (facp->gpe1_blk) 443 fprintf(fhdr, "\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", 444 facp->gpe1_blk, 445 facp->gpe1_blk + facp->gpe1_len - 1, 446 facp->gpe1_base); 447 fprintf(fhdr, "\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n", 448 facp->p_lvl2_lat, facp->p_lvl3_lat); 449 fprintf(fhdr, "\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", 450 facp->flush_size, facp->flush_stride); 451 fprintf(fhdr, "\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", 452 facp->duty_off, facp->duty_width); 453 fprintf(fhdr, "\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", 454 facp->day_alrm, facp->mon_alrm, facp->century); 455 fprintf(fhdr, "\tFlags="); 456 sep = '{'; 457 458 PRINTFLAG(WBINVD); 459 PRINTFLAG(WBINVD_FLUSH); 460 PRINTFLAG(PROC_C1); 461 PRINTFLAG(P_LVL2_UP); 462 PRINTFLAG(PWR_BUTTON); 463 PRINTFLAG(SLP_BUTTON); 464 PRINTFLAG(FIX_RTC); 465 PRINTFLAG(RTC_S4); 466 PRINTFLAG(TMR_VAL_EXT); 467 PRINTFLAG(DCK_CAP); 468 469 fprintf(fhdr, "}\n"); 470 fprintf(fhdr, "\n"); 471 } 472 473 void 474 acpi_print_dsdt(struct ACPIsdt *dsdp) 475 { 476 acpi_print_sdt(dsdp); 477 } 478 479 void 480 acpi_handle_dsdt(struct ACPIsdt *dsdp) 481 { 482 u_int8_t *dp; 483 u_int8_t *end; 484 485 acpi_print_dsdt(dsdp); 486 487 dp = (u_int8_t *)dsdp->body; 488 end = (u_int8_t *)dsdp + dsdp->len; 489 } 490 491 void 492 acpi_handle_facp(struct FACPbody *facp) 493 { 494 struct ACPIsdt *dsdp; 495 496 acpi_print_facp(facp); 497 dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr); 498 if (acpi_checksum(dsdp, dsdp->len)) 499 errx(1, "DSDT is corrupt"); 500 acpi_handle_dsdt(dsdp); 501 aml_dump(dsdp); 502 } 503 504 void 505 acpi_handle_rsdt(struct ACPIsdt *rsdp) 506 { 507 int i; 508 int entries; 509 struct ACPIsdt *sdp; 510 511 aml_dump(rsdp); 512 entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); 513 acpi_print_rsdt(rsdp); 514 for (i = 0; i < entries; i++) { 515 sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]); 516 if (acpi_checksum(sdp, sdp->len)) 517 errx(1, "RSDT entry %d is corrupt", i); 518 aml_dump(sdp); 519 if (!memcmp(sdp->signature, "FACP", 4)) { 520 acpi_handle_facp((struct FACPbody *) sdp->body); 521 } else { 522 acpi_print_sdt(sdp); 523 } 524 } 525 } 526 527 void 528 asl_dump_from_devmem(void) 529 { 530 struct ACPIrsdp *rp; 531 struct ACPIsdt *rsdp; 532 char name[PATH_MAX]; 533 534 snprintf(name, sizeof(name), "%s%cheaders", aml_dumpfile, 535 aml_dumpdir ? '/' : '.'); 536 537 acpi_user_init(); 538 539 if (pledge("stdio rpath wpath cpath", NULL) == -1) 540 err(1, "pledge"); 541 542 rp = acpi_find_rsd_ptr(); 543 if (!rp) 544 errx(1, "Can't find ACPI information"); 545 546 fhdr = fopen(name, "w"); 547 if (fhdr == NULL) 548 err(1, "asl_dump_from_devmem"); 549 550 acpi_print_rsd_ptr(rp); 551 rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr); 552 if (memcmp(rsdp->signature, "RSDT", 4) || 553 acpi_checksum(rsdp, rsdp->len)) 554 errx(1, "RSDT is corrupted"); 555 556 acpi_handle_rsdt(rsdp); 557 558 fclose(fhdr); 559 } 560 561 void 562 usage(void) 563 { 564 extern char *__progname; 565 566 fprintf(stderr, "usage: %s -o prefix\n", __progname); 567 exit(1); 568 } 569 570 int 571 main(int argc, char *argv[]) 572 { 573 struct stat st; 574 char c; 575 576 while ((c = getopt(argc, argv, "o:")) != -1) { 577 switch (c) { 578 case 'o': 579 aml_dumpfile = optarg; 580 break; 581 default: 582 usage(); 583 break; 584 } 585 } 586 587 if (aml_dumpfile == NULL) 588 usage(); 589 590 if (stat(aml_dumpfile, &st) == 0 && S_ISDIR(st.st_mode)) 591 aml_dumpdir = 1; 592 593 asl_dump_from_devmem(); 594 595 return (0); 596 } 597 598 u_long 599 bios_acpi_addr(void) 600 { 601 kvm_t *kd; 602 struct nlist nl[2]; 603 bios_efiinfo_t efiinfo; 604 u_long ptr; 605 606 memset(&nl, 0, sizeof(nl)); 607 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL); 608 if (kd == NULL) 609 goto on_error; 610 nl[0].n_name = "_bios_efiinfo"; 611 if (kvm_nlist(kd, nl) == -1) 612 goto on_error; 613 if (kvm_read(kd, nl[0].n_value, &ptr, sizeof(ptr)) == -1) 614 goto on_error; 615 if (kvm_read(kd, ptr, &efiinfo, sizeof(efiinfo)) == -1) 616 goto on_error; 617 618 kvm_close(kd); 619 return (efiinfo.config_acpi); 620 621 on_error: 622 if (kd != NULL) 623 kvm_close(kd); 624 return (0); 625 } 626