1 /* $OpenBSD: acpidebug.c,v 1.14 2006/12/21 19:59:02 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2006 Marco Peereboom <marco@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <machine/db_machdep.h> 19 #include <ddb/db_command.h> 20 #include <ddb/db_output.h> 21 #include <ddb/db_extern.h> 22 #include <ddb/db_lex.h> 23 24 #include <machine/bus.h> 25 #include <sys/malloc.h> 26 27 #include <dev/acpi/acpireg.h> 28 #include <dev/acpi/acpivar.h> 29 #include <dev/acpi/amltypes.h> 30 #include <dev/acpi/acpidebug.h> 31 #include <dev/acpi/dsdt.h> 32 33 void db_aml_disline(uint8_t *, int, const char *, ...); 34 void db_aml_disint(struct aml_scope *, int, int); 35 uint8_t *db_aml_disasm(struct aml_node *, uint8_t *, uint8_t *, int, int); 36 37 extern int aml_pc(uint8_t *); 38 extern struct aml_scope *aml_pushscope(struct aml_scope *, uint8_t *, uint8_t *, struct aml_node *); 39 extern struct aml_scope *aml_popscope(struct aml_scope *); 40 extern uint8_t *aml_parsename(struct aml_scope *); 41 extern uint8_t *aml_parseend(struct aml_scope *); 42 extern int aml_parselength(struct aml_scope *); 43 extern int aml_parseopcode(struct aml_scope *); 44 45 extern const char *aml_mnem(int opcode); 46 extern const char *aml_args(int opcode); 47 extern const char *aml_getname(uint8_t *); 48 extern const char *aml_nodename(struct aml_node *); 49 50 const char *db_aml_objtype(struct aml_value *); 51 const char *db_opregion(int); 52 int db_parse_name(void); 53 void db_aml_dump(int, u_int8_t *); 54 void db_aml_showvalue(struct aml_value *); 55 void db_aml_walktree(struct aml_node *); 56 57 const char *db_aml_fieldacc(int); 58 const char *db_aml_fieldlock(int); 59 const char *db_aml_fieldupdate(int); 60 61 extern struct aml_node aml_root; 62 63 /* name of scope for lexer */ 64 char scope[80]; 65 66 const char * 67 db_opregion(int id) 68 { 69 switch (id) { 70 case 0: 71 return "SystemMemory"; 72 case 1: 73 return "SystemIO"; 74 case 2: 75 return "PCIConfig"; 76 case 3: 77 return "Embedded"; 78 case 4: 79 return "SMBus"; 80 case 5: 81 return "CMOS"; 82 case 6: 83 return "PCIBAR"; 84 } 85 return ""; 86 } 87 void 88 db_aml_dump(int len, u_int8_t *buf) 89 { 90 int idx; 91 92 db_printf("{ "); 93 for (idx = 0; idx < len; idx++) 94 db_printf("%s0x%.2x", idx ? ", " : "", buf[idx]); 95 db_printf(" }\n"); 96 } 97 98 void 99 db_aml_showvalue(struct aml_value *value) 100 { 101 int idx; 102 103 if (value == NULL) 104 return; 105 106 if (value->node) 107 db_printf("[%s] ", aml_nodename(value->node)); 108 109 switch (value->type & ~AML_STATIC) { 110 case AML_OBJTYPE_OBJREF: 111 db_printf("refof: %x {\n", value->v_objref.index); 112 db_aml_showvalue(value->v_objref.ref); 113 db_printf("}\n"); 114 break; 115 case AML_OBJTYPE_NAMEREF: 116 db_printf("nameref: %s\n", value->v_nameref); 117 break; 118 case AML_OBJTYPE_INTEGER: 119 db_printf("integer: %llx %s\n", value->v_integer, 120 (value->type & AML_STATIC) ? "(static)" : ""); 121 break; 122 case AML_OBJTYPE_STRING: 123 db_printf("string: %s\n", value->v_string); 124 break; 125 case AML_OBJTYPE_PACKAGE: 126 db_printf("package: %d {\n", value->length); 127 for (idx = 0; idx < value->length; idx++) 128 db_aml_showvalue(value->v_package[idx]); 129 db_printf("}\n"); 130 break; 131 case AML_OBJTYPE_BUFFER: 132 db_printf("buffer: %d ", value->length); 133 db_aml_dump(value->length, value->v_buffer); 134 break; 135 case AML_OBJTYPE_DEBUGOBJ: 136 db_printf("debug"); 137 break; 138 case AML_OBJTYPE_MUTEX: 139 db_printf("mutex : %llx\n", value->v_integer); 140 break; 141 case AML_OBJTYPE_DEVICE: 142 db_printf("device\n"); 143 break; 144 case AML_OBJTYPE_EVENT: 145 db_printf("event\n"); 146 break; 147 case AML_OBJTYPE_PROCESSOR: 148 db_printf("cpu: %x,%x,%x\n", 149 value->v_processor.proc_id, 150 value->v_processor.proc_addr, 151 value->v_processor.proc_len); 152 break; 153 case AML_OBJTYPE_METHOD: 154 db_printf("method: args=%d, serialized=%d, synclevel=%d\n", 155 AML_METHOD_ARGCOUNT(value->v_method.flags), 156 AML_METHOD_SERIALIZED(value->v_method.flags), 157 AML_METHOD_SYNCLEVEL(value->v_method.flags)); 158 break; 159 case AML_OBJTYPE_FIELDUNIT: 160 db_printf("%s: access=%x,lock=%x,update=%x pos=%.4x " 161 "len=%.4x\n", 162 aml_mnem(value->v_field.type), 163 AML_FIELD_ACCESS(value->v_field.flags), 164 AML_FIELD_LOCK(value->v_field.flags), 165 AML_FIELD_UPDATE(value->v_field.flags), 166 value->v_field.bitpos, 167 value->v_field.bitlen); 168 169 db_aml_showvalue(value->v_field.ref1); 170 db_aml_showvalue(value->v_field.ref2); 171 break; 172 case AML_OBJTYPE_BUFFERFIELD: 173 db_printf("%s: pos=%.4x len=%.4x ", 174 aml_mnem(value->v_field.type), 175 value->v_field.bitpos, 176 value->v_field.bitlen); 177 178 db_aml_dump(aml_bytelen(value->v_field.bitlen), 179 value->v_field.ref1->v_buffer + 180 aml_bytepos(value->v_field.bitpos)); 181 182 db_aml_showvalue(value->v_field.ref1); 183 break; 184 case AML_OBJTYPE_OPREGION: 185 db_printf("opregion: %s,0x%llx,0x%x\n", 186 db_opregion(value->v_opregion.iospace), 187 value->v_opregion.iobase, 188 value->v_opregion.iolen); 189 break; 190 default: 191 db_printf("unknown: %d\n", value->type); 192 break; 193 } 194 } 195 196 const char * 197 db_aml_objtype(struct aml_value *val) 198 { 199 if (val == NULL) 200 return "nil"; 201 202 switch (val->type) { 203 case AML_OBJTYPE_INTEGER+AML_STATIC: 204 return "staticint"; 205 case AML_OBJTYPE_INTEGER: 206 return "integer"; 207 case AML_OBJTYPE_STRING: 208 return "string"; 209 case AML_OBJTYPE_BUFFER: 210 return "buffer"; 211 case AML_OBJTYPE_PACKAGE: 212 return "package"; 213 case AML_OBJTYPE_DEVICE: 214 return "device"; 215 case AML_OBJTYPE_EVENT: 216 return "event"; 217 case AML_OBJTYPE_METHOD: 218 return "method"; 219 case AML_OBJTYPE_MUTEX: 220 return "mutex"; 221 case AML_OBJTYPE_OPREGION: 222 return "opregion"; 223 case AML_OBJTYPE_POWERRSRC: 224 return "powerrsrc"; 225 case AML_OBJTYPE_PROCESSOR: 226 return "processor"; 227 case AML_OBJTYPE_THERMZONE: 228 return "thermzone"; 229 case AML_OBJTYPE_DDBHANDLE: 230 return "ddbhandle"; 231 case AML_OBJTYPE_DEBUGOBJ: 232 return "debugobj"; 233 case AML_OBJTYPE_NAMEREF: 234 return "nameref"; 235 case AML_OBJTYPE_OBJREF: 236 return "refof"; 237 case AML_OBJTYPE_FIELDUNIT: 238 case AML_OBJTYPE_BUFFERFIELD: 239 return aml_mnem(val->v_field.type); 240 } 241 242 return (""); 243 } 244 245 void 246 db_aml_walktree(struct aml_node *node) 247 { 248 while (node) { 249 db_aml_showvalue(node->value); 250 db_aml_walktree(node->child); 251 252 node = node->sibling; 253 } 254 } 255 256 int 257 db_parse_name(void) 258 { 259 int t, rv = 1; 260 261 memset(scope, 0, sizeof scope); 262 do { 263 t = db_read_token(); 264 if (t == tIDENT) { 265 if (strlcat(scope, db_tok_string, sizeof scope) >= 266 sizeof scope) { 267 printf("Input too long\n"); 268 goto error; 269 } 270 t = db_read_token(); 271 if (t == tDOT) 272 if (strlcat(scope, ".", sizeof scope) >= 273 sizeof scope) { 274 printf("Input too long 2\n"); 275 goto error; 276 } 277 } 278 } while (t != tEOL); 279 280 if (!strlen(scope)) { 281 db_printf("Invalid input\n"); 282 goto error; 283 } 284 285 rv = 0; 286 error: 287 /* get rid of the rest of input */ 288 db_flush_lex(); 289 return (rv); 290 } 291 292 /* ddb interface */ 293 void 294 db_acpi_showval(db_expr_t addr, int haddr, db_expr_t count, char *modif) 295 { 296 struct aml_node *node; 297 298 if (db_parse_name()) 299 return; 300 301 node = aml_searchname(&aml_root, scope); 302 if (node) 303 db_aml_showvalue(node->value); 304 else 305 db_printf("Not a valid value\n"); 306 } 307 308 void 309 db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif) 310 { 311 struct aml_node *node; 312 313 if (db_parse_name()) 314 return; 315 316 node = aml_searchname(&aml_root, scope); 317 if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) { 318 db_aml_disasm(node, node->value->v_method.start, 319 node->value->v_method.end, -1, 0); 320 } else 321 db_printf("Not a valid method\n"); 322 } 323 324 void 325 db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif) 326 { 327 db_aml_walktree(aml_root.child); 328 } 329 330 void 331 db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif) 332 { 333 struct aml_scope *root; 334 int idx; 335 extern struct aml_scope *aml_lastscope; 336 337 for (root=aml_lastscope; root && root->pos; root=root->parent) { 338 db_printf("%.4x Called: %s\n", aml_pc(root->pos), 339 aml_nodename(root->node)); 340 for (idx = 0; idx<root->nargs; idx++) { 341 db_printf(" arg%d: ", idx); 342 db_aml_showvalue(&root->args[idx]); 343 } 344 for (idx = 0; root->locals && idx < AML_MAX_LOCAL; idx++) { 345 if (root->locals[idx].type) { 346 db_printf(" local%d: ", idx); 347 db_aml_showvalue(&root->locals[idx]); 348 } 349 } 350 } 351 } 352 353 void 354 db_aml_disline(uint8_t *pos, int depth, const char *fmt, ...) 355 { 356 va_list ap; 357 char line[128]; 358 359 db_printf("%.6x: ", aml_pc(pos)); 360 while (depth--) 361 db_printf(" "); 362 363 va_start(ap, fmt); 364 vsnprintf(line, sizeof(line), fmt, ap); 365 db_printf(line); 366 va_end(ap); 367 } 368 369 void 370 db_aml_disint(struct aml_scope *scope, int opcode, int depth) 371 { 372 switch (opcode) { 373 case AML_ANYINT: 374 db_aml_disasm(scope->node, scope->pos, scope->end, -1, depth); 375 break; 376 case AMLOP_BYTEPREFIX: 377 db_aml_disline(scope->pos, depth, "0x%.2x\n", 378 *(uint8_t *)(scope->pos)); 379 scope->pos += 1; 380 break; 381 case AMLOP_WORDPREFIX: 382 db_aml_disline(scope->pos, depth, "0x%.4x\n", 383 *(uint16_t *)(scope->pos)); 384 scope->pos += 2; 385 break; 386 case AMLOP_DWORDPREFIX: 387 db_aml_disline(scope->pos, depth, "0x%.8x\n", 388 *(uint32_t *)(scope->pos)); 389 scope->pos += 4; 390 break; 391 case AMLOP_QWORDPREFIX: 392 db_aml_disline(scope->pos, depth, "0x%.4llx\n", 393 *(uint64_t *)(scope->pos)); 394 scope->pos += 8; 395 break; 396 } 397 } 398 399 uint8_t * 400 db_aml_disasm(struct aml_node *root, uint8_t *start, uint8_t *end, 401 int count, int depth) 402 { 403 int idx, opcode, len, off=0; 404 struct aml_scope *scope; 405 uint8_t *name, *pos; 406 const char *mnem, *args; 407 struct aml_node *node; 408 char *tmpstr; 409 410 if (start == end) 411 return end; 412 413 scope = aml_pushscope(NULL, start, end, root); 414 while (scope->pos < scope->end && count--) { 415 pos = scope->pos; 416 start = scope->pos; 417 opcode = aml_parseopcode(scope); 418 419 mnem = aml_mnem(opcode); 420 args = aml_args(opcode); 421 422 if (*args == 'p') { 423 end = aml_parseend(scope); 424 args++; 425 } 426 node = scope->node; 427 if (*args == 'N') { 428 name = aml_parsename(scope); 429 node = aml_searchname(scope->node, name); 430 db_aml_disline(pos, depth, "%s %s (%s)\n", 431 mnem, aml_getname(name), aml_nodename(node)); 432 args++; 433 } else if (mnem[0] != '.') { 434 db_aml_disline(pos, depth, "%s\n", mnem); 435 } 436 while (*args) { 437 pos = scope->pos; 438 switch (*args) { 439 case 'k': 440 case 'c': 441 case 'D': 442 case 'L': 443 case 'A': 444 break; 445 case 'i': 446 case 't': 447 case 'S': 448 case 'r': 449 scope->pos = db_aml_disasm(node, scope->pos, 450 scope->end, 1, depth+1); 451 break; 452 case 'T': 453 case 'M': 454 scope->pos = db_aml_disasm(node, scope->pos, 455 end, -1, depth+1); 456 break; 457 case 'I': 458 /* Special case: if */ 459 scope->pos = db_aml_disasm(node, scope->pos, 460 end, -1, depth+1); 461 if (scope->pos >= scope->end) 462 break; 463 if (*scope->pos == AMLOP_ELSE) { 464 ++scope->pos; 465 end = aml_parseend(scope); 466 db_aml_disline(scope->pos, depth, "Else\n"); 467 scope->pos = db_aml_disasm(node, scope->pos, 468 end, -1, depth+1); 469 } 470 break; 471 case 'N': 472 name = aml_parsename(scope); 473 db_aml_disline(pos, depth+1, "%s\n", aml_getname(name)); 474 break; 475 case 'n': 476 off = (opcode != AMLOP_NAMECHAR); 477 name = aml_parsename(scope); 478 node = aml_searchname(scope->node, name); 479 db_aml_disline(pos, depth+off, "%s <%s>\n", 480 aml_getname(name), 481 aml_nodename(node)); 482 483 if (!node || !node->value || 484 node->value->type != AML_OBJTYPE_METHOD) 485 break; 486 487 /* Method calls */ 488 for (idx = 0; 489 idx < AML_METHOD_ARGCOUNT(node->value->v_method.flags); 490 idx++) { 491 scope->pos = db_aml_disasm(node, scope->pos, 492 scope->end, 1, depth+1); 493 } 494 break; 495 case 'b': 496 off = (opcode != AMLOP_BYTEPREFIX); 497 db_aml_disint(scope, AMLOP_BYTEPREFIX, depth+off); 498 break; 499 case 'w': 500 off = (opcode != AMLOP_WORDPREFIX); 501 db_aml_disint(scope, AMLOP_WORDPREFIX, depth+off); 502 break; 503 case 'd': 504 off = (opcode != AMLOP_DWORDPREFIX); 505 db_aml_disint(scope, AMLOP_DWORDPREFIX, depth+off); 506 break; 507 case 's': 508 db_aml_disline(pos, depth, "\"%s\"\n", scope->pos); 509 scope->pos += strlen(scope->pos)+1; 510 break; 511 case 'B': 512 tmpstr = malloc(16 * 6 + 1, M_DEVBUF, M_WAITOK); 513 for (idx = 0; idx < min(end-scope->pos, 8); idx++) 514 snprintf(tmpstr+idx*6, 7, "0x%.2x, ", 515 scope->pos[idx]); 516 db_aml_disline(pos, depth+1, "ByteList <%s>\n", tmpstr); 517 free(tmpstr, M_DEVBUF); 518 scope->pos = end; 519 break; 520 case 'F': 521 off = 0; 522 while (scope->pos < end) { 523 len = 0; 524 pos = scope->pos; 525 switch (*scope->pos) { 526 case 0x00: // reserved 527 scope->pos++; 528 len = aml_parselength(scope); 529 db_aml_disline(pos, depth+1, 530 "Reserved\t%.4x,%.4x\n", 531 off, len); 532 break; 533 case 0x01: // attr 534 db_aml_disline(pos, depth+1, 535 "Attr:%.2x,%.2x\n", 536 scope->pos[1], scope->pos[2]); 537 scope->pos += 3; 538 break; 539 default: 540 name = aml_parsename(scope); 541 len = aml_parselength(scope); 542 db_aml_disline(pos, depth+1, 543 "NamedField\t%.4x,%.4x %s\n", 544 off, len, aml_getname(name)); 545 } 546 off += len; 547 } 548 scope->pos = end; 549 break; 550 default: 551 db_printf("remaining args: '%s'\n", args); 552 } 553 args++; 554 } 555 } 556 pos = scope->pos; 557 aml_popscope(scope); 558 return pos; 559 } 560