acpidb.c revision 301142
1/*- 2 * Copyright (c) 2000-2002 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: stable/10/usr.sbin/acpi/acpidb/acpidb.c 301142 2016-06-01 17:16:35Z truckman $ 27 */ 28 29#include <sys/param.h> 30#include <sys/queue.h> 31#include <sys/mman.h> 32#include <sys/stat.h> 33#include <sys/stdint.h> 34#include <sys/types.h> 35 36#include <assert.h> 37#include <ctype.h> 38#include <err.h> 39#include <fcntl.h> 40#include <limits.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <unistd.h> 44 45#include <contrib/dev/acpica/include/acpi.h> 46#include <contrib/dev/acpica/include/accommon.h> 47#include <contrib/dev/acpica/include/acdebug.h> 48#include <contrib/dev/acpica/include/amlresrc.h> 49 50/* 51 * Dummy DSDT Table Header 52 */ 53 54static ACPI_TABLE_HEADER dummy_dsdt_table = { 55 "DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1 56}; 57 58/* 59 * Region space I/O routines on virtual machine 60 */ 61 62static int aml_debug_prompt = 1; 63 64struct ACPIRegionContent { 65 TAILQ_ENTRY(ACPIRegionContent) links; 66 int regtype; 67 ACPI_PHYSICAL_ADDRESS addr; 68 UINT8 value; 69}; 70 71TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); 72static struct ACPIRegionContentList RegionContentList; 73 74static int aml_simulation_initialized = 0; 75 76ACPI_PHYSICAL_ADDRESS AeLocalGetRootPointer(void); 77void AeDoObjectOverrides(void); 78void AeTableOverride(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER **); 79 80static void aml_simulation_init(void); 81static int aml_simulate_regcontent_add(int regtype, 82 ACPI_PHYSICAL_ADDRESS addr, 83 UINT8 value); 84static int aml_simulate_regcontent_read(int regtype, 85 ACPI_PHYSICAL_ADDRESS addr, 86 UINT8 *valuep); 87static int aml_simulate_regcontent_write(int regtype, 88 ACPI_PHYSICAL_ADDRESS addr, 89 UINT8 *valuep); 90static UINT64 aml_simulate_prompt(char *msg, UINT64 def_val); 91static void aml_simulation_regload(const char *dumpfile); 92static void aml_simulation_regdump(const char *dumpfile); 93 94/* Stubs to simplify linkage to the ACPICA core subsystem. */ 95ACPI_PHYSICAL_ADDRESS 96AcpiOsGetRootPointer(void) 97{ 98 99 return (0); 100} 101 102void 103AeDoObjectOverrides(void) 104{ 105} 106 107void 108AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable) 109{ 110} 111 112void 113MpSaveGpioInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, 114 UINT32 PinCount, UINT16 *PinList, char *DeviceName) 115{ 116} 117 118void 119MpSaveSerialInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, 120 char *DeviceName) 121{ 122} 123 124static void 125aml_simulation_init(void) 126{ 127 128 aml_simulation_initialized = 1; 129 TAILQ_INIT(&RegionContentList); 130 aml_simulation_regload("region.ini"); 131} 132 133static int 134aml_simulate_regcontent_add(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 value) 135{ 136 struct ACPIRegionContent *rc; 137 138 rc = malloc(sizeof(struct ACPIRegionContent)); 139 if (rc == NULL) { 140 return (-1); /* malloc fail */ 141 } 142 rc->regtype = regtype; 143 rc->addr = addr; 144 rc->value = value; 145 146 TAILQ_INSERT_TAIL(&RegionContentList, rc, links); 147 return (0); 148} 149 150static int 151aml_simulate_regcontent_read(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) 152{ 153 struct ACPIRegionContent *rc; 154 155 if (!aml_simulation_initialized) { 156 aml_simulation_init(); 157 } 158 TAILQ_FOREACH(rc, &RegionContentList, links) { 159 if (rc->regtype == regtype && rc->addr == addr) { 160 *valuep = rc->value; 161 return (1); /* found */ 162 } 163 } 164 165 *valuep = 0; 166 return (aml_simulate_regcontent_add(regtype, addr, *valuep)); 167} 168 169static int 170aml_simulate_regcontent_write(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) 171{ 172 struct ACPIRegionContent *rc; 173 174 if (!aml_simulation_initialized) { 175 aml_simulation_init(); 176 } 177 TAILQ_FOREACH(rc, &RegionContentList, links) { 178 if (rc->regtype == regtype && rc->addr == addr) { 179 rc->value = *valuep; 180 return (1); /* exists */ 181 } 182 } 183 184 return (aml_simulate_regcontent_add(regtype, addr, *valuep)); 185} 186 187static UINT64 188aml_simulate_prompt(char *msg, UINT64 def_val) 189{ 190 char buf[16], *ep; 191 UINT64 val; 192 193 val = def_val; 194 printf("DEBUG"); 195 if (msg != NULL) { 196 printf("%s", msg); 197 } 198 printf("(default: 0x%jx ", (uintmax_t)val); 199 printf(" / %ju) >>", (uintmax_t)val); 200 fflush(stdout); 201 202 bzero(buf, sizeof buf); 203 while (1) { 204 if (read(0, buf, sizeof buf) == 0) { 205 continue; 206 } 207 if (buf[0] == '\n') { 208 break; /* use default value */ 209 } 210 if (buf[0] == '0' && buf[1] == 'x') { 211 val = strtoq(buf, &ep, 16); 212 } else { 213 val = strtoq(buf, &ep, 10); 214 } 215 break; 216 } 217 return (val); 218} 219 220static void 221aml_simulation_regload(const char *dumpfile) 222{ 223 char buf[256], *np, *ep; 224 struct ACPIRegionContent rc; 225 FILE *fp; 226 227 if (!aml_simulation_initialized) { 228 return; 229 } 230 231 if ((fp = fopen(dumpfile, "r")) == NULL) { 232 return; 233 } 234 235 while (fgets(buf, sizeof buf, fp) != NULL) { 236 np = buf; 237 /* reading region type */ 238 rc.regtype = strtoq(np, &ep, 10); 239 if (np == ep) { 240 continue; 241 } 242 np = ep; 243 244 /* reading address */ 245 rc.addr = strtoq(np, &ep, 16); 246 if (np == ep) { 247 continue; 248 } 249 np = ep; 250 251 /* reading value */ 252 rc.value = strtoq(np, &ep, 16); 253 if (np == ep) { 254 continue; 255 } 256 aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value); 257 } 258 259 fclose(fp); 260} 261 262static void 263aml_simulation_regdump(const char *dumpfile) 264{ 265 struct ACPIRegionContent *rc; 266 FILE *fp; 267 268 if (!aml_simulation_initialized) { 269 return; 270 } 271 if ((fp = fopen(dumpfile, "w")) == NULL) { 272 warn("%s", dumpfile); 273 return; 274 } 275 while (!TAILQ_EMPTY(&RegionContentList)) { 276 rc = TAILQ_FIRST(&RegionContentList); 277 fprintf(fp, "%d 0x%jx 0x%x\n", 278 rc->regtype, (uintmax_t)rc->addr, rc->value); 279 TAILQ_REMOVE(&RegionContentList, rc, links); 280 free(rc); 281 } 282 283 fclose(fp); 284 TAILQ_INIT(&RegionContentList); 285} 286 287/* 288 * Space handlers on virtual machine 289 */ 290 291static ACPI_STATUS 292aml_vm_space_handler( 293 UINT32 SpaceID, 294 UINT32 Function, 295 ACPI_PHYSICAL_ADDRESS Address, 296 UINT32 BitWidth, 297 UINT64 *Value, 298 int Prompt) 299{ 300 int state; 301 UINT8 val; 302 UINT64 value, i; 303 char msg[256]; 304 static const char *space_names[] = { 305 "SYSTEM_MEMORY", "SYSTEM_IO", "PCI_CONFIG", 306 "EC", "SMBUS", "CMOS", "PCI_BAR_TARGET"}; 307 308 switch (Function) { 309 case ACPI_READ: 310 value = 0; 311 for (i = 0; (i * 8) < BitWidth; i++) { 312 state = aml_simulate_regcontent_read(SpaceID, 313 Address + i, &val); 314 if (state == -1) { 315 return (AE_NO_MEMORY); 316 } 317 value |= val << (i * 8); 318 } 319 *Value = value; 320 if (Prompt) { 321 sprintf(msg, "[read (%s, %2d, 0x%jx)]", 322 space_names[SpaceID], BitWidth, 323 (uintmax_t)Address); 324 *Value = aml_simulate_prompt(msg, value); 325 if (*Value != value) { 326 return(aml_vm_space_handler(SpaceID, 327 ACPI_WRITE, 328 Address, BitWidth, Value, 0)); 329 } 330 } 331 break; 332 333 case ACPI_WRITE: 334 value = *Value; 335 if (Prompt) { 336 sprintf(msg, "[write(%s, %2d, 0x%jx)]", 337 space_names[SpaceID], BitWidth, 338 (uintmax_t)Address); 339 value = aml_simulate_prompt(msg, *Value); 340 } 341 *Value = value; 342 for (i = 0; (i * 8) < BitWidth; i++) { 343 val = value & 0xff; 344 state = aml_simulate_regcontent_write(SpaceID, 345 Address + i, &val); 346 if (state == -1) { 347 return (AE_NO_MEMORY); 348 } 349 value = value >> 8; 350 } 351 } 352 353 return (AE_OK); 354} 355 356#define DECLARE_VM_SPACE_HANDLER(name, id); \ 357static ACPI_STATUS \ 358aml_vm_space_handler_##name ( \ 359 UINT32 Function, \ 360 ACPI_PHYSICAL_ADDRESS Address, \ 361 UINT32 BitWidth, \ 362 UINT64 *Value) \ 363{ \ 364 return (aml_vm_space_handler(id, Function, Address, \ 365 BitWidth, Value, aml_debug_prompt)); \ 366} 367 368DECLARE_VM_SPACE_HANDLER(system_memory, ACPI_ADR_SPACE_SYSTEM_MEMORY); 369DECLARE_VM_SPACE_HANDLER(system_io, ACPI_ADR_SPACE_SYSTEM_IO); 370DECLARE_VM_SPACE_HANDLER(pci_config, ACPI_ADR_SPACE_PCI_CONFIG); 371DECLARE_VM_SPACE_HANDLER(ec, ACPI_ADR_SPACE_EC); 372DECLARE_VM_SPACE_HANDLER(smbus, ACPI_ADR_SPACE_SMBUS); 373DECLARE_VM_SPACE_HANDLER(cmos, ACPI_ADR_SPACE_CMOS); 374DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET); 375 376/* 377 * Load DSDT data file and invoke debugger 378 */ 379 380static int 381load_dsdt(const char *dsdtfile) 382{ 383 char filetmp[PATH_MAX]; 384 u_int8_t *code; 385 struct stat sb; 386 int dounlink, error, fd; 387 388 fd = open(dsdtfile, O_RDONLY, 0); 389 if (fd == -1) { 390 perror("open"); 391 return (-1); 392 } 393 if (fstat(fd, &sb) == -1) { 394 perror("fstat"); 395 close(fd); 396 return (-1); 397 } 398 code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); 399 close(fd); 400 if (code == NULL) { 401 perror("mmap"); 402 return (-1); 403 } 404 if ((error = AcpiInitializeSubsystem()) != AE_OK) { 405 munmap(code, (size_t)sb.st_size); 406 return (-1); 407 } 408 409 /* 410 * make sure DSDT data contains table header or not. 411 */ 412 if (strncmp((char *)code, "DSDT", 4) == 0) { 413 dounlink = 0; 414 strlcpy(filetmp, dsdtfile, sizeof(filetmp)); 415 } else { 416 dounlink = 1; 417 mode_t mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 418 dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size; 419 if ((size_t)snprintf(filetmp, sizeof(filetmp), "%s.tmp", 420 dsdtfile) > sizeof(filetmp) - 1) { 421 fprintf(stderr, "file name too long\n"); 422 munmap(code, (size_t)sb.st_size); 423 return (-1); 424 } 425 fd = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode); 426 if (fd == -1) { 427 perror("open"); 428 munmap(code, (size_t)sb.st_size); 429 return (-1); 430 } 431 write(fd, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER)); 432 433 write(fd, code, sb.st_size); 434 close(fd); 435 } 436 munmap(code, (size_t)sb.st_size); 437 438 /* 439 * Install the virtual machine version of address space handlers. 440 */ 441 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 442 ACPI_ADR_SPACE_SYSTEM_MEMORY, 443 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_memory, 444 NULL, NULL)) != AE_OK) { 445 fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error); 446 return (-1); 447 } 448 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 449 ACPI_ADR_SPACE_SYSTEM_IO, 450 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_io, 451 NULL, NULL)) != AE_OK) { 452 fprintf(stderr, "could not initialise SystemIO handler: %d\n", error); 453 return (-1); 454 } 455 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 456 ACPI_ADR_SPACE_PCI_CONFIG, 457 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_config, 458 NULL, NULL)) != AE_OK) { 459 fprintf(stderr, "could not initialise PciConfig handler: %d\n", error); 460 return (-1); 461 } 462 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 463 ACPI_ADR_SPACE_EC, 464 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_ec, 465 NULL, NULL)) != AE_OK) { 466 fprintf(stderr, "could not initialise EC handler: %d\n", error); 467 return (-1); 468 } 469 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 470 ACPI_ADR_SPACE_SMBUS, 471 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_smbus, 472 NULL, NULL)) != AE_OK) { 473 fprintf(stderr, "could not initialise SMBUS handler: %d\n", error); 474 return (-1); 475 } 476 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 477 ACPI_ADR_SPACE_CMOS, 478 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_cmos, 479 NULL, NULL)) != AE_OK) { 480 fprintf(stderr, "could not initialise CMOS handler: %d\n", error); 481 return (-1); 482 } 483 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 484 ACPI_ADR_SPACE_PCI_BAR_TARGET, 485 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_bar_target, 486 NULL, NULL)) != AE_OK) { 487 fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error); 488 return (-1); 489 } 490 491 AcpiDbGetTableFromFile(filetmp, NULL, TRUE); 492 493 AcpiDbInitialize(); 494 AcpiGbl_DebuggerConfiguration = 0; 495 AcpiDbUserCommands(':', NULL); 496 497 if (dounlink) { 498 unlink(filetmp); 499 } 500 501 return (0); 502} 503 504static void 505usage(const char *progname) 506{ 507 508 printf("usage: %s dsdt_file\n", progname); 509 exit(1); 510} 511 512int 513main(int argc, char *argv[]) 514{ 515 char *progname; 516 517 progname = argv[0]; 518 519 if (argc == 1) { 520 usage(progname); 521 } 522 523 AcpiDbgLevel = ACPI_DEBUG_DEFAULT; 524 525 /* 526 * Match kernel options for the interpreter. Global variable names 527 * can be found in acglobal.h. 528 */ 529 AcpiGbl_EnableInterpreterSlack = TRUE; 530 531 aml_simulation_regload("region.ini"); 532 if (load_dsdt(argv[1]) == 0) { 533 aml_simulation_regdump("region.dmp"); 534 } 535 536 return (0); 537} 538