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$ 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/acapps.h> 48 #include <contrib/dev/acpica/include/acdebug.h> 49 #include <contrib/dev/acpica/include/amlresrc.h> 50 51 /* 52 * Dummy DSDT Table Header 53 */ 54 55 static ACPI_TABLE_HEADER dummy_dsdt_table = { 56 "DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1 57 }; 58 59 /* 60 * Region space I/O routines on virtual machine 61 */ 62 63 static int aml_debug_prompt = 1; 64 65 struct ACPIRegionContent { 66 TAILQ_ENTRY(ACPIRegionContent) links; 67 int regtype; 68 ACPI_PHYSICAL_ADDRESS addr; 69 UINT8 value; 70 }; 71 72 TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); 73 static struct ACPIRegionContentList RegionContentList; 74 75 static int aml_simulation_initialized = 0; 76 77 ACPI_PHYSICAL_ADDRESS AeLocalGetRootPointer(void); 78 void AeDoObjectOverrides(void); 79 void AeTableOverride(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER **); 80 81 static void aml_simulation_init(void); 82 static int aml_simulate_regcontent_add(int regtype, 83 ACPI_PHYSICAL_ADDRESS addr, 84 UINT8 value); 85 static int aml_simulate_regcontent_read(int regtype, 86 ACPI_PHYSICAL_ADDRESS addr, 87 UINT8 *valuep); 88 static int aml_simulate_regcontent_write(int regtype, 89 ACPI_PHYSICAL_ADDRESS addr, 90 UINT8 *valuep); 91 static UINT64 aml_simulate_prompt(char *msg, UINT64 def_val); 92 static void aml_simulation_regload(const char *dumpfile); 93 static void aml_simulation_regdump(const char *dumpfile); 94 95 /* Stubs to simplify linkage to the ACPICA core subsystem. */ 96 ACPI_PHYSICAL_ADDRESS 97 AcpiOsGetRootPointer(void) 98 { 99 100 return (0); 101 } 102 103 void 104 AeDoObjectOverrides(void) 105 { 106 } 107 108 void 109 AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable) 110 { 111 } 112 113 void 114 MpSaveGpioInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, 115 UINT32 PinCount, UINT16 *PinList, char *DeviceName) 116 { 117 } 118 119 void 120 MpSaveSerialInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource, 121 char *DeviceName) 122 { 123 } 124 125 static void 126 aml_simulation_init(void) 127 { 128 129 aml_simulation_initialized = 1; 130 TAILQ_INIT(&RegionContentList); 131 aml_simulation_regload("region.ini"); 132 } 133 134 static int 135 aml_simulate_regcontent_add(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 value) 136 { 137 struct ACPIRegionContent *rc; 138 139 rc = malloc(sizeof(struct ACPIRegionContent)); 140 if (rc == NULL) { 141 return (-1); /* malloc fail */ 142 } 143 rc->regtype = regtype; 144 rc->addr = addr; 145 rc->value = value; 146 147 TAILQ_INSERT_TAIL(&RegionContentList, rc, links); 148 return (0); 149 } 150 151 static int 152 aml_simulate_regcontent_read(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) 153 { 154 struct ACPIRegionContent *rc; 155 156 if (!aml_simulation_initialized) { 157 aml_simulation_init(); 158 } 159 TAILQ_FOREACH(rc, &RegionContentList, links) { 160 if (rc->regtype == regtype && rc->addr == addr) { 161 *valuep = rc->value; 162 return (1); /* found */ 163 } 164 } 165 166 *valuep = 0; 167 return (aml_simulate_regcontent_add(regtype, addr, *valuep)); 168 } 169 170 static int 171 aml_simulate_regcontent_write(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep) 172 { 173 struct ACPIRegionContent *rc; 174 175 if (!aml_simulation_initialized) { 176 aml_simulation_init(); 177 } 178 TAILQ_FOREACH(rc, &RegionContentList, links) { 179 if (rc->regtype == regtype && rc->addr == addr) { 180 rc->value = *valuep; 181 return (1); /* exists */ 182 } 183 } 184 185 return (aml_simulate_regcontent_add(regtype, addr, *valuep)); 186 } 187 188 static UINT64 189 aml_simulate_prompt(char *msg, UINT64 def_val) 190 { 191 char buf[16], *ep; 192 UINT64 val; 193 194 val = def_val; 195 printf("DEBUG"); 196 if (msg != NULL) { 197 printf("%s", msg); 198 } 199 printf("(default: 0x%jx ", (uintmax_t)val); 200 printf(" / %ju) >>", (uintmax_t)val); 201 fflush(stdout); 202 203 bzero(buf, sizeof buf); 204 while (1) { 205 if (read(0, buf, sizeof buf) == 0) { 206 continue; 207 } 208 if (buf[0] == '\n') { 209 break; /* use default value */ 210 } 211 if (buf[0] == '0' && buf[1] == 'x') { 212 val = strtoq(buf, &ep, 16); 213 } else { 214 val = strtoq(buf, &ep, 10); 215 } 216 break; 217 } 218 return (val); 219 } 220 221 static void 222 aml_simulation_regload(const char *dumpfile) 223 { 224 char buf[256], *np, *ep; 225 struct ACPIRegionContent rc; 226 FILE *fp; 227 228 if (!aml_simulation_initialized) { 229 return; 230 } 231 232 if ((fp = fopen(dumpfile, "r")) == NULL) { 233 return; 234 } 235 236 while (fgets(buf, sizeof buf, fp) != NULL) { 237 np = buf; 238 /* reading region type */ 239 rc.regtype = strtoq(np, &ep, 10); 240 if (np == ep) { 241 continue; 242 } 243 np = ep; 244 245 /* reading address */ 246 rc.addr = strtoq(np, &ep, 16); 247 if (np == ep) { 248 continue; 249 } 250 np = ep; 251 252 /* reading value */ 253 rc.value = strtoq(np, &ep, 16); 254 if (np == ep) { 255 continue; 256 } 257 aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value); 258 } 259 260 fclose(fp); 261 } 262 263 static void 264 aml_simulation_regdump(const char *dumpfile) 265 { 266 struct ACPIRegionContent *rc; 267 FILE *fp; 268 269 if (!aml_simulation_initialized) { 270 return; 271 } 272 if ((fp = fopen(dumpfile, "w")) == NULL) { 273 warn("%s", dumpfile); 274 return; 275 } 276 while (!TAILQ_EMPTY(&RegionContentList)) { 277 rc = TAILQ_FIRST(&RegionContentList); 278 fprintf(fp, "%d 0x%jx 0x%x\n", 279 rc->regtype, (uintmax_t)rc->addr, rc->value); 280 TAILQ_REMOVE(&RegionContentList, rc, links); 281 free(rc); 282 } 283 284 fclose(fp); 285 TAILQ_INIT(&RegionContentList); 286 } 287 288 /* 289 * Space handlers on virtual machine 290 */ 291 292 static ACPI_STATUS 293 aml_vm_space_handler( 294 UINT32 SpaceID, 295 UINT32 Function, 296 ACPI_PHYSICAL_ADDRESS Address, 297 UINT32 BitWidth, 298 UINT64 *Value, 299 int Prompt) 300 { 301 int state; 302 UINT8 val; 303 UINT64 value, i; 304 char msg[256]; 305 static const char *space_names[] = { 306 "SYSTEM_MEMORY", "SYSTEM_IO", "PCI_CONFIG", 307 "EC", "SMBUS", "CMOS", "PCI_BAR_TARGET"}; 308 309 switch (Function) { 310 case ACPI_READ: 311 value = 0; 312 for (i = 0; (i * 8) < BitWidth; i++) { 313 state = aml_simulate_regcontent_read(SpaceID, 314 Address + i, &val); 315 if (state == -1) { 316 return (AE_NO_MEMORY); 317 } 318 value |= val << (i * 8); 319 } 320 *Value = value; 321 if (Prompt) { 322 sprintf(msg, "[read (%s, %2d, 0x%jx)]", 323 space_names[SpaceID], BitWidth, 324 (uintmax_t)Address); 325 *Value = aml_simulate_prompt(msg, value); 326 if (*Value != value) { 327 return(aml_vm_space_handler(SpaceID, 328 ACPI_WRITE, 329 Address, BitWidth, Value, 0)); 330 } 331 } 332 break; 333 334 case ACPI_WRITE: 335 value = *Value; 336 if (Prompt) { 337 sprintf(msg, "[write(%s, %2d, 0x%jx)]", 338 space_names[SpaceID], BitWidth, 339 (uintmax_t)Address); 340 value = aml_simulate_prompt(msg, *Value); 341 } 342 *Value = value; 343 for (i = 0; (i * 8) < BitWidth; i++) { 344 val = value & 0xff; 345 state = aml_simulate_regcontent_write(SpaceID, 346 Address + i, &val); 347 if (state == -1) { 348 return (AE_NO_MEMORY); 349 } 350 value = value >> 8; 351 } 352 } 353 354 return (AE_OK); 355 } 356 357 #define DECLARE_VM_SPACE_HANDLER(name, id); \ 358 static ACPI_STATUS \ 359 aml_vm_space_handler_##name ( \ 360 UINT32 Function, \ 361 ACPI_PHYSICAL_ADDRESS Address, \ 362 UINT32 BitWidth, \ 363 UINT64 *Value) \ 364 { \ 365 return (aml_vm_space_handler(id, Function, Address, \ 366 BitWidth, Value, aml_debug_prompt)); \ 367 } 368 369 DECLARE_VM_SPACE_HANDLER(system_memory, ACPI_ADR_SPACE_SYSTEM_MEMORY); 370 DECLARE_VM_SPACE_HANDLER(system_io, ACPI_ADR_SPACE_SYSTEM_IO); 371 DECLARE_VM_SPACE_HANDLER(pci_config, ACPI_ADR_SPACE_PCI_CONFIG); 372 DECLARE_VM_SPACE_HANDLER(ec, ACPI_ADR_SPACE_EC); 373 DECLARE_VM_SPACE_HANDLER(smbus, ACPI_ADR_SPACE_SMBUS); 374 DECLARE_VM_SPACE_HANDLER(cmos, ACPI_ADR_SPACE_CMOS); 375 DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET); 376 377 /* 378 * Load DSDT data file and invoke debugger 379 */ 380 381 static int 382 load_dsdt(const char *dsdtfile) 383 { 384 char filetmp[PATH_MAX]; 385 ACPI_NEW_TABLE_DESC *list; 386 u_int8_t *code; 387 struct stat sb; 388 int fd, fd2; 389 int error; 390 391 fd = open(dsdtfile, O_RDONLY, 0); 392 if (fd == -1) { 393 perror("open"); 394 return (-1); 395 } 396 if (fstat(fd, &sb) == -1) { 397 perror("fstat"); 398 close(fd); 399 return (-1); 400 } 401 code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); 402 if (code == NULL) { 403 perror("mmap"); 404 return (-1); 405 } 406 if ((error = AcpiInitializeSubsystem()) != AE_OK) { 407 return (-1); 408 } 409 410 /* 411 * make sure DSDT data contains table header or not. 412 */ 413 if (strncmp((char *)code, "DSDT", 4) == 0) { 414 strncpy(filetmp, dsdtfile, sizeof(filetmp)); 415 } else { 416 mode_t mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 417 dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size; 418 snprintf(filetmp, sizeof(filetmp), "%s.tmp", dsdtfile); 419 fd2 = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode); 420 if (fd2 == -1) { 421 perror("open"); 422 return (-1); 423 } 424 write(fd2, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER)); 425 426 write(fd2, code, sb.st_size); 427 close(fd2); 428 } 429 430 /* 431 * Install the virtual machine version of address space handlers. 432 */ 433 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 434 ACPI_ADR_SPACE_SYSTEM_MEMORY, 435 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_memory, 436 NULL, NULL)) != AE_OK) { 437 fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error); 438 return (-1); 439 } 440 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 441 ACPI_ADR_SPACE_SYSTEM_IO, 442 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_io, 443 NULL, NULL)) != AE_OK) { 444 fprintf(stderr, "could not initialise SystemIO handler: %d\n", error); 445 return (-1); 446 } 447 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 448 ACPI_ADR_SPACE_PCI_CONFIG, 449 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_config, 450 NULL, NULL)) != AE_OK) { 451 fprintf(stderr, "could not initialise PciConfig handler: %d\n", error); 452 return (-1); 453 } 454 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 455 ACPI_ADR_SPACE_EC, 456 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_ec, 457 NULL, NULL)) != AE_OK) { 458 fprintf(stderr, "could not initialise EC handler: %d\n", error); 459 return (-1); 460 } 461 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 462 ACPI_ADR_SPACE_SMBUS, 463 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_smbus, 464 NULL, NULL)) != AE_OK) { 465 fprintf(stderr, "could not initialise SMBUS handler: %d\n", error); 466 return (-1); 467 } 468 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 469 ACPI_ADR_SPACE_CMOS, 470 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_cmos, 471 NULL, NULL)) != AE_OK) { 472 fprintf(stderr, "could not initialise CMOS handler: %d\n", error); 473 return (-1); 474 } 475 if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 476 ACPI_ADR_SPACE_PCI_BAR_TARGET, 477 (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_bar_target, 478 NULL, NULL)) != AE_OK) { 479 fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error); 480 return (-1); 481 } 482 483 list = NULL; 484 AcGetAllTablesFromFile(filetmp, TRUE, &list); 485 486 AcpiInitializeDebugger(); 487 AcpiGbl_DebuggerConfiguration = 0; 488 AcpiDbUserCommands(':', NULL); 489 490 if (strcmp(dsdtfile, filetmp) != 0) { 491 unlink(filetmp); 492 } 493 494 return (0); 495 } 496 497 static void 498 usage(const char *progname) 499 { 500 501 printf("usage: %s dsdt_file\n", progname); 502 exit(1); 503 } 504 505 int 506 main(int argc, char *argv[]) 507 { 508 char *progname; 509 510 progname = argv[0]; 511 512 if (argc == 1) { 513 usage(progname); 514 } 515 516 AcpiDbgLevel = ACPI_DEBUG_DEFAULT; 517 518 /* 519 * Match kernel options for the interpreter. Global variable names 520 * can be found in acglobal.h. 521 */ 522 AcpiGbl_EnableInterpreterSlack = TRUE; 523 524 aml_simulation_regload("region.ini"); 525 if (load_dsdt(argv[1]) == 0) { 526 aml_simulation_regdump("region.dmp"); 527 } 528 529 return (0); 530 } 531