1*cda98319Smarco /* $OpenBSD: acpidebug.c,v 1.2 2006/03/07 23:13:28 marco Exp $ */ 2559cf7adSmarco /* 3559cf7adSmarco * Copyright (c) 2006 Marco Peereboom <marco@openbsd.org> 4559cf7adSmarco * 5559cf7adSmarco * Permission to use, copy, modify, and distribute this software for any 6559cf7adSmarco * purpose with or without fee is hereby granted, provided that the above 7559cf7adSmarco * copyright notice and this permission notice appear in all copies. 8559cf7adSmarco * 9559cf7adSmarco * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10559cf7adSmarco * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11559cf7adSmarco * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12559cf7adSmarco * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13559cf7adSmarco * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14559cf7adSmarco * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15559cf7adSmarco * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16559cf7adSmarco */ 17559cf7adSmarco 18559cf7adSmarco #include <machine/db_machdep.h> 19559cf7adSmarco #include <ddb/db_command.h> 20559cf7adSmarco #include <ddb/db_output.h> 21*cda98319Smarco #include <ddb/db_extern.h> 22*cda98319Smarco #include <ddb/db_lex.h> 23559cf7adSmarco 24559cf7adSmarco #include <machine/bus.h> 25559cf7adSmarco 26559cf7adSmarco #include <dev/acpi/acpireg.h> 27559cf7adSmarco #include <dev/acpi/acpivar.h> 28559cf7adSmarco #include <dev/acpi/amltypes.h> 29559cf7adSmarco #include <dev/acpi/acpidebug.h> 30559cf7adSmarco #include <dev/acpi/dsdt.h> 31559cf7adSmarco 32559cf7adSmarco void db_aml_walktree(struct aml_node *); 33559cf7adSmarco void db_aml_shownode(struct aml_node *); 34*cda98319Smarco void db_aml_disline(uint8_t *, int, const char *, ...); 35*cda98319Smarco void db_aml_disint(struct acpi_context *, int, int); 36*cda98319Smarco void db_aml_disasm(struct acpi_context *, int); 37*cda98319Smarco void db_spaceit(int); 38*cda98319Smarco const char *db_aml_objtype(struct aml_value *); 39*cda98319Smarco const char *db_aml_opname(int); 40*cda98319Smarco struct aml_opcode *db_findem(int); 41*cda98319Smarco int db_aml_nodetype(struct aml_node *); 42*cda98319Smarco 43*cda98319Smarco extern struct aml_node aml_root; 44*cda98319Smarco 45*cda98319Smarco /* Perfect hash values for AML opcodes */ 46*cda98319Smarco #define HASH_VAL 11 47*cda98319Smarco #define HASH_SIZE 204 48*cda98319Smarco #define HASH_KEY(v) (((v) * HASH_VAL) % HASH_SIZE) 49*cda98319Smarco 50*cda98319Smarco struct aml_opcode *htab[HASH_SIZE]; 51*cda98319Smarco 52*cda98319Smarco /* line buffer */ 53*cda98319Smarco char buf[128]; 54*cda98319Smarco 55*cda98319Smarco /* name of scope for lexer */ 56*cda98319Smarco char scope[80]; 57*cda98319Smarco 58*cda98319Smarco /* Output disassembled line */ 59*cda98319Smarco void 60*cda98319Smarco db_spaceit(int len) 61*cda98319Smarco { 62*cda98319Smarco while(len--) { 63*cda98319Smarco db_printf(".."); 64*cda98319Smarco } 65*cda98319Smarco } 66*cda98319Smarco 67*cda98319Smarco struct aml_opcode 68*cda98319Smarco *db_findem(int opcode) 69*cda98319Smarco { 70*cda98319Smarco int key, cnt; 71*cda98319Smarco 72*cda98319Smarco cnt = 0; 73*cda98319Smarco key = HASH_KEY(opcode); 74*cda98319Smarco 75*cda98319Smarco while (htab[key] != NULL && htab[key]->opcode != opcode) { 76*cda98319Smarco key = (key + 1) % HASH_SIZE; 77*cda98319Smarco cnt++; 78*cda98319Smarco } 79*cda98319Smarco 80*cda98319Smarco return (htab[key]); 81*cda98319Smarco } 82*cda98319Smarco 83*cda98319Smarco int 84*cda98319Smarco db_aml_nodetype(struct aml_node *node) 85*cda98319Smarco { 86*cda98319Smarco return (node && node->value) ? node->value->type : -1; 87*cda98319Smarco } 88*cda98319Smarco 89*cda98319Smarco const char * 90*cda98319Smarco db_aml_opname(int opcode) 91*cda98319Smarco { 92*cda98319Smarco struct aml_opcode *opc; 93*cda98319Smarco 94*cda98319Smarco opc = db_findem(opcode); 95*cda98319Smarco 96*cda98319Smarco return (opc ? opc->mnem : ""); 97*cda98319Smarco } 98*cda98319Smarco 99*cda98319Smarco const char * 100*cda98319Smarco db_aml_objtype(struct aml_value *val) 101*cda98319Smarco { 102*cda98319Smarco if (val == NULL) 103*cda98319Smarco return "nil"; 104*cda98319Smarco 105*cda98319Smarco switch (val->type) { 106*cda98319Smarco case AML_OBJTYPE_STATICINT: 107*cda98319Smarco return "staticint"; 108*cda98319Smarco case AML_OBJTYPE_INTEGER: 109*cda98319Smarco return "integer"; 110*cda98319Smarco case AML_OBJTYPE_STRING: 111*cda98319Smarco return "string"; 112*cda98319Smarco case AML_OBJTYPE_BUFFER: 113*cda98319Smarco return "buffer"; 114*cda98319Smarco case AML_OBJTYPE_PACKAGE: 115*cda98319Smarco return "package"; 116*cda98319Smarco case AML_OBJTYPE_DEVICE: 117*cda98319Smarco return "device"; 118*cda98319Smarco case AML_OBJTYPE_EVENT: 119*cda98319Smarco return "event"; 120*cda98319Smarco case AML_OBJTYPE_METHOD: 121*cda98319Smarco return "method"; 122*cda98319Smarco case AML_OBJTYPE_MUTEX: 123*cda98319Smarco return "mutex"; 124*cda98319Smarco case AML_OBJTYPE_OPREGION: 125*cda98319Smarco return "opregion"; 126*cda98319Smarco case AML_OBJTYPE_POWERRSRC: 127*cda98319Smarco return "powerrsrc"; 128*cda98319Smarco case AML_OBJTYPE_PROCESSOR: 129*cda98319Smarco return "processor"; 130*cda98319Smarco case AML_OBJTYPE_THERMZONE: 131*cda98319Smarco return "thermzone"; 132*cda98319Smarco case AML_OBJTYPE_DDBHANDLE: 133*cda98319Smarco return "ddbhandle"; 134*cda98319Smarco case AML_OBJTYPE_DEBUGOBJ: 135*cda98319Smarco return "debugobj"; 136*cda98319Smarco case AML_OBJTYPE_NAMEREF: 137*cda98319Smarco return "nameref"; 138*cda98319Smarco case AML_OBJTYPE_OBJREF: 139*cda98319Smarco return "refof"; 140*cda98319Smarco case AML_OBJTYPE_FIELDUNIT: 141*cda98319Smarco case AML_OBJTYPE_BUFFERFIELD: 142*cda98319Smarco return db_aml_opname(val->v_field.type); 143*cda98319Smarco }; 144*cda98319Smarco 145*cda98319Smarco return (""); 146*cda98319Smarco } 147*cda98319Smarco 148*cda98319Smarco void 149*cda98319Smarco db_aml_disline(uint8_t *pos, int level, const char *fmt, ...) 150*cda98319Smarco { 151*cda98319Smarco va_list ap; 152*cda98319Smarco 153*cda98319Smarco db_printf("%.4x %.2x ", pos - aml_root.start, level); 154*cda98319Smarco db_spaceit(level); 155*cda98319Smarco 156*cda98319Smarco va_start(ap, fmt); 157*cda98319Smarco vsnprintf(buf, sizeof buf, fmt, ap); 158*cda98319Smarco db_printf(buf); 159*cda98319Smarco va_end(ap); 160*cda98319Smarco 161*cda98319Smarco db_printf("\n"); 162*cda98319Smarco } 163*cda98319Smarco 164*cda98319Smarco /* Output disassembled integer */ 165*cda98319Smarco void 166*cda98319Smarco db_aml_disint(struct acpi_context *ctx, int level, int type) 167*cda98319Smarco { 168*cda98319Smarco u_int8_t *pos; 169*cda98319Smarco int64_t i1; 170*cda98319Smarco 171*cda98319Smarco pos = ctx->pos; 172*cda98319Smarco i1 = aml_eparseint(ctx, type); 173*cda98319Smarco db_aml_disline(pos, level, "%c:0x%.8llx (%lld)", type, i1, i1); 174*cda98319Smarco } 175*cda98319Smarco 176*cda98319Smarco /* Disassemble AML Opcode */ 177*cda98319Smarco void 178*cda98319Smarco db_aml_disasm(struct acpi_context *ctx, int level) 179*cda98319Smarco { 180*cda98319Smarco struct aml_opcode *opc; 181*cda98319Smarco uint8_t *end, *np; 182*cda98319Smarco const char *arg, *fname; 183*cda98319Smarco struct aml_node *node; 184*cda98319Smarco int idx, len; 185*cda98319Smarco 186*cda98319Smarco #if 0 187*cda98319Smarco /* if we want separators */ 188*cda98319Smarco if (level == 0) 189*cda98319Smarco db_printf("<<<<<<<<<<<<<<\n"); 190*cda98319Smarco #endif 191*cda98319Smarco np = ctx->pos; 192*cda98319Smarco opc = aml_getopcode(ctx); 193*cda98319Smarco db_aml_disline(np, level, opc->mnem); 194*cda98319Smarco for (arg = opc->args; *arg; arg++) { 195*cda98319Smarco np = ctx->pos; 196*cda98319Smarco switch (*arg) { 197*cda98319Smarco case AML_ARG_BYTE: 198*cda98319Smarco case AML_ARG_WORD: 199*cda98319Smarco case AML_ARG_DWORD: 200*cda98319Smarco case AML_ARG_QWORD: 201*cda98319Smarco db_aml_disint(ctx, level + 1, *arg); 202*cda98319Smarco break; 203*cda98319Smarco case AML_ARG_STRING: 204*cda98319Smarco db_aml_disline(np, level + 1, ctx->pos); 205*cda98319Smarco ctx->pos += strlen(ctx->pos) + 1; 206*cda98319Smarco break; 207*cda98319Smarco case AML_ARG_NAMESTRING: 208*cda98319Smarco fname = aml_parse_name(ctx); 209*cda98319Smarco db_aml_disline(np, level + 1, fname); 210*cda98319Smarco break; 211*cda98319Smarco case AML_ARG_NAMEREF: 212*cda98319Smarco fname = aml_parse_name(ctx); 213*cda98319Smarco node = aml_searchname(ctx->scope, fname); 214*cda98319Smarco db_aml_disline(np, level + 1, "%s:%s", fname, 215*cda98319Smarco node ? db_aml_objtype(node->value) : "none"); 216*cda98319Smarco if (db_aml_nodetype(node) == AML_OBJTYPE_METHOD) 217*cda98319Smarco /* Parse method arguments */ 218*cda98319Smarco for (idx = 0; idx < AML_METHOD_ARGCOUNT(node->value->v_method.flags); idx++) 219*cda98319Smarco db_aml_disasm(ctx, level + 1); 220*cda98319Smarco break; 221*cda98319Smarco case AML_ARG_INTEGER: 222*cda98319Smarco case AML_ARG_TERMOBJ: 223*cda98319Smarco case AML_ARG_DATAOBJ: 224*cda98319Smarco case AML_ARG_SIMPLENAME: 225*cda98319Smarco case AML_ARG_SUPERNAME: 226*cda98319Smarco db_aml_disasm(ctx, level + 1); 227*cda98319Smarco break; 228*cda98319Smarco case AML_ARG_DATAOBJLIST: 229*cda98319Smarco case AML_ARG_TERMOBJLIST: 230*cda98319Smarco case AML_ARG_METHOD: 231*cda98319Smarco while (ctx->pos < end) 232*cda98319Smarco db_aml_disasm(ctx, level + 1); 233*cda98319Smarco break; 234*cda98319Smarco case AML_ARG_BYTELIST: 235*cda98319Smarco for (idx = 0; idx < end - ctx->pos - 7; idx += 8) { 236*cda98319Smarco db_aml_disline(np, level + 1, "buf %.4x: %.2x " 237*cda98319Smarco "%.2x %.2x %.2x %.2x %.2x %.2x %.2x", 238*cda98319Smarco idx, ctx->pos[idx], 239*cda98319Smarco ctx->pos[idx + 1], 240*cda98319Smarco ctx->pos[idx + 2], ctx->pos[idx + 3], 241*cda98319Smarco ctx->pos[idx + 4], ctx->pos[idx + 5], 242*cda98319Smarco ctx->pos[idx + 6], ctx->pos[idx + 7]); 243*cda98319Smarco } 244*cda98319Smarco ctx->pos = end; 245*cda98319Smarco break; 246*cda98319Smarco case AML_ARG_FLAG: 247*cda98319Smarco /* Flags */ 248*cda98319Smarco idx = aml_eparseint(ctx, AML_ARG_BYTE); 249*cda98319Smarco if (opc->opcode == AMLOP_METHOD) 250*cda98319Smarco db_aml_disline(np, level + 1, 251*cda98319Smarco "args:%d serialized:%d synclevel:%d", 252*cda98319Smarco AML_METHOD_ARGCOUNT(idx), 253*cda98319Smarco AML_METHOD_SERIALIZED(idx), 254*cda98319Smarco AML_METHOD_SYNCLEVEL(idx)); 255*cda98319Smarco else 256*cda98319Smarco db_aml_disline(np, level + 1, 257*cda98319Smarco "acc:%d lock:%d update:%d", 258*cda98319Smarco AML_FIELD_ACCESS(idx), 259*cda98319Smarco AML_FIELD_LOCK(idx), 260*cda98319Smarco AML_FIELD_UPDATE(idx)); 261*cda98319Smarco break; 262*cda98319Smarco case AML_ARG_FIELDLIST: 263*cda98319Smarco for (idx = 0; ctx->pos < end; idx += len) { 264*cda98319Smarco np = ctx->pos; 265*cda98319Smarco switch (*ctx->pos) { 266*cda98319Smarco case AML_FIELD_RESERVED: 267*cda98319Smarco ctx->pos++; 268*cda98319Smarco len = aml_parse_length(ctx); 269*cda98319Smarco break; 270*cda98319Smarco case AML_FIELD_ATTR__: 271*cda98319Smarco db_aml_disline(np, level + 1, 272*cda98319Smarco "-- attr %.2x %.2x", 273*cda98319Smarco ctx->pos[1], ctx->pos[2]); 274*cda98319Smarco ctx->pos += 3; 275*cda98319Smarco len = 0; 276*cda98319Smarco break; 277*cda98319Smarco default: 278*cda98319Smarco fname = aml_parse_name(ctx); 279*cda98319Smarco len = aml_parse_length(ctx); 280*cda98319Smarco db_aml_disline(np, level + 1, 281*cda98319Smarco "pos:%.4x len:%.4x name:%s", 282*cda98319Smarco idx, len, fname); 283*cda98319Smarco break; 284*cda98319Smarco } 285*cda98319Smarco } 286*cda98319Smarco break; 287*cda98319Smarco case AML_ARG_OBJLEN: 288*cda98319Smarco end = aml_eparselen(ctx); 289*cda98319Smarco break; 290*cda98319Smarco } 291*cda98319Smarco } 292*cda98319Smarco #if 0 293*cda98319Smarco /* if we want separators */ 294*cda98319Smarco if (level == 0) 295*cda98319Smarco db_printf(">>>>>>>>>>>>>>\n"); 296*cda98319Smarco #endif 297*cda98319Smarco } 298559cf7adSmarco 299559cf7adSmarco void 300559cf7adSmarco db_aml_shownode(struct aml_node *node) 301559cf7adSmarco { 302559cf7adSmarco db_printf(" opcode:%.4x mnem:%s %s ", 303559cf7adSmarco node->opcode, node->mnem, node->name ? node->name : ""); 304559cf7adSmarco 305559cf7adSmarco switch(node->opcode) { 306559cf7adSmarco case AMLOP_METHOD: 307559cf7adSmarco break; 308559cf7adSmarco 309559cf7adSmarco case AMLOP_NAMECHAR: 310559cf7adSmarco db_printf("%s", node->value->name); 311559cf7adSmarco break; 312559cf7adSmarco 313559cf7adSmarco case AMLOP_FIELD: 314559cf7adSmarco case AMLOP_BANKFIELD: 315559cf7adSmarco case AMLOP_INDEXFIELD: 316559cf7adSmarco break; 317559cf7adSmarco 318559cf7adSmarco case AMLOP_BYTEPREFIX: 319559cf7adSmarco db_printf("byte: %.2x", node->value->v_integer); 320559cf7adSmarco break; 321559cf7adSmarco case AMLOP_WORDPREFIX: 322559cf7adSmarco db_printf("word: %.4x", node->value->v_integer); 323559cf7adSmarco break; 324559cf7adSmarco case AMLOP_DWORDPREFIX: 325559cf7adSmarco db_printf("dword: %.8x", node->value->v_integer); 326559cf7adSmarco break; 327559cf7adSmarco case AMLOP_STRINGPREFIX: 328559cf7adSmarco db_printf("string: %s", node->value->v_string); 329559cf7adSmarco break; 330559cf7adSmarco } 331559cf7adSmarco db_printf("\n"); 332559cf7adSmarco } 333559cf7adSmarco 334559cf7adSmarco void 335559cf7adSmarco db_aml_walktree(struct aml_node *node) 336559cf7adSmarco { 337559cf7adSmarco int i; 338559cf7adSmarco 339559cf7adSmarco while(node) { 340559cf7adSmarco db_printf(" %d ", node->depth); 341559cf7adSmarco for(i = 0; i < node->depth; i++) 342559cf7adSmarco db_printf(".."); 343559cf7adSmarco 344559cf7adSmarco db_aml_shownode(node); 345559cf7adSmarco db_aml_walktree(node->child); 346559cf7adSmarco node = node->sibling; 347559cf7adSmarco } 348559cf7adSmarco } 349559cf7adSmarco 350559cf7adSmarco /* ddb interface */ 351559cf7adSmarco void 352*cda98319Smarco db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif) 353*cda98319Smarco { 354*cda98319Smarco extern struct acpi_softc *acpi_softc; 355*cda98319Smarco struct acpi_softc *sc = acpi_softc; 356*cda98319Smarco struct acpi_context *ctx; 357*cda98319Smarco struct aml_node *node; 358*cda98319Smarco int t; 359*cda98319Smarco 360*cda98319Smarco memset(scope, 0, sizeof scope); 361*cda98319Smarco do { 362*cda98319Smarco t = db_read_token(); 363*cda98319Smarco if (t == tIDENT) { 364*cda98319Smarco if (strlcat(scope, db_tok_string, sizeof scope) >= 365*cda98319Smarco sizeof scope) { 366*cda98319Smarco printf("Input too long\n"); 367*cda98319Smarco goto error; 368*cda98319Smarco } 369*cda98319Smarco t = db_read_token(); 370*cda98319Smarco if (t == tDOT) 371*cda98319Smarco if (strlcat(scope, ".", sizeof scope) >= 372*cda98319Smarco sizeof scope) { 373*cda98319Smarco printf("Input too long 2\n"); 374*cda98319Smarco goto error; 375*cda98319Smarco } 376*cda98319Smarco } 377*cda98319Smarco } 378*cda98319Smarco while (t != tEOL); 379*cda98319Smarco 380*cda98319Smarco if (!strlen(scope)) { 381*cda98319Smarco db_printf("Invalid input\n"); 382*cda98319Smarco goto error; 383*cda98319Smarco } 384*cda98319Smarco 385*cda98319Smarco /* get rid of the rest of input */ 386*cda98319Smarco db_flush_lex(); 387*cda98319Smarco 388*cda98319Smarco ctx = acpi_alloccontext(sc, &aml_root, 0, NULL); 389*cda98319Smarco node = aml_searchname(&aml_root, scope); 390*cda98319Smarco if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) { 391*cda98319Smarco ctx->pos = node->value->v_method.start; 392*cda98319Smarco while (ctx->pos < node->value->v_method.end) 393*cda98319Smarco db_aml_disasm(ctx, 0); 394*cda98319Smarco } 395*cda98319Smarco acpi_freecontext(ctx); 396*cda98319Smarco 397*cda98319Smarco error: 398*cda98319Smarco db_flush_lex(); 399*cda98319Smarco } 400*cda98319Smarco 401*cda98319Smarco void 402559cf7adSmarco db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif) 403559cf7adSmarco { 404559cf7adSmarco db_aml_walktree(aml_root.child); 405*cda98319Smarco 406559cf7adSmarco } 407