1 /* $OpenBSD: acpidebug.c,v 1.27 2010/07/21 19:35:15 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 #ifdef DDB 34 35 extern int aml_pc(uint8_t *); 36 37 extern const char *aml_mnem(int opcode, uint8_t *); 38 extern const char *aml_nodename(struct aml_node *); 39 extern void aml_disasm(struct aml_scope *scope, int lvl, 40 void (*dbprintf)(void *, const char *, ...), 41 void *arg); 42 43 const char *db_aml_objtype(struct aml_value *); 44 const char *db_opregion(int); 45 int db_parse_name(void); 46 void db_aml_dump(int, u_int8_t *); 47 void db_aml_showvalue(struct aml_value *); 48 void db_aml_walktree(struct aml_node *); 49 void db_disprint(void *, const char *, ...); 50 51 const char *db_aml_fieldacc(int); 52 const char *db_aml_fieldlock(int); 53 const char *db_aml_fieldupdate(int); 54 55 extern struct aml_node aml_root; 56 57 /* name of scope for lexer */ 58 char scope[80]; 59 60 const char * 61 db_opregion(int id) 62 { 63 switch (id) { 64 case 0: 65 return "SystemMemory"; 66 case 1: 67 return "SystemIO"; 68 case 2: 69 return "PCIConfig"; 70 case 3: 71 return "Embedded"; 72 case 4: 73 return "SMBus"; 74 case 5: 75 return "CMOS"; 76 case 6: 77 return "PCIBAR"; 78 } 79 return ""; 80 } 81 void 82 db_aml_dump(int len, u_int8_t *buf) 83 { 84 int idx; 85 86 db_printf("{ "); 87 for (idx = 0; idx < len; idx++) 88 db_printf("%s0x%.2x", idx ? ", " : "", buf[idx]); 89 db_printf(" }\n"); 90 } 91 92 void 93 db_aml_showvalue(struct aml_value *value) 94 { 95 int idx; 96 97 if (value == NULL) 98 return; 99 100 if (value->node) 101 db_printf("[%s] ", aml_nodename(value->node)); 102 103 switch (value->type) { 104 case AML_OBJTYPE_OBJREF: 105 db_printf("refof: %x {\n", value->v_objref.index); 106 db_aml_showvalue(value->v_objref.ref); 107 db_printf("}\n"); 108 break; 109 case AML_OBJTYPE_NAMEREF: 110 db_printf("nameref: %s\n", value->v_nameref); 111 break; 112 case AML_OBJTYPE_INTEGER: 113 db_printf("integer: %llx\n", value->v_integer); 114 break; 115 case AML_OBJTYPE_STRING: 116 db_printf("string: %s\n", value->v_string); 117 break; 118 case AML_OBJTYPE_PACKAGE: 119 db_printf("package: %d {\n", value->length); 120 for (idx = 0; idx < value->length; idx++) 121 db_aml_showvalue(value->v_package[idx]); 122 db_printf("}\n"); 123 break; 124 case AML_OBJTYPE_BUFFER: 125 db_printf("buffer: %d ", value->length); 126 db_aml_dump(value->length, value->v_buffer); 127 break; 128 case AML_OBJTYPE_DEBUGOBJ: 129 db_printf("debug"); 130 break; 131 case AML_OBJTYPE_MUTEX: 132 db_printf("mutex : %llx\n", value->v_integer); 133 break; 134 case AML_OBJTYPE_DEVICE: 135 db_printf("device\n"); 136 break; 137 case AML_OBJTYPE_EVENT: 138 db_printf("event\n"); 139 break; 140 case AML_OBJTYPE_PROCESSOR: 141 db_printf("cpu: %x,%x,%x\n", 142 value->v_processor.proc_id, 143 value->v_processor.proc_addr, 144 value->v_processor.proc_len); 145 break; 146 case AML_OBJTYPE_METHOD: 147 db_printf("method: args=%d, serialized=%d, synclevel=%d\n", 148 AML_METHOD_ARGCOUNT(value->v_method.flags), 149 AML_METHOD_SERIALIZED(value->v_method.flags), 150 AML_METHOD_SYNCLEVEL(value->v_method.flags)); 151 break; 152 case AML_OBJTYPE_FIELDUNIT: 153 db_printf("%s: access=%x,lock=%x,update=%x pos=%.4x " 154 "len=%.4x\n", 155 aml_mnem(value->v_field.type, NULL), 156 AML_FIELD_ACCESS(value->v_field.flags), 157 AML_FIELD_LOCK(value->v_field.flags), 158 AML_FIELD_UPDATE(value->v_field.flags), 159 value->v_field.bitpos, 160 value->v_field.bitlen); 161 if (value->v_field.ref2) 162 db_printf(" index: %.3x %s\n", 163 value->v_field.ref3, 164 aml_nodename(value->v_field.ref2->node)); 165 if (value->v_field.ref1) 166 db_printf(" data: %s\n", 167 aml_nodename(value->v_field.ref1->node)); 168 break; 169 case AML_OBJTYPE_BUFFERFIELD: 170 db_printf("%s: pos=%.4x len=%.4x\n", 171 aml_mnem(value->v_field.type, NULL), 172 value->v_field.bitpos, 173 value->v_field.bitlen); 174 db_printf(" buffer: %s\n", 175 aml_nodename(value->v_field.ref1->node)); 176 break; 177 case AML_OBJTYPE_OPREGION: 178 db_printf("opregion: %s,0x%llx,0x%x\n", 179 db_opregion(value->v_opregion.iospace), 180 value->v_opregion.iobase, 181 value->v_opregion.iolen); 182 break; 183 default: 184 db_printf("unknown: %d\n", value->type); 185 break; 186 } 187 } 188 189 const char * 190 db_aml_objtype(struct aml_value *val) 191 { 192 if (val == NULL) 193 return "nil"; 194 195 switch (val->type) { 196 case AML_OBJTYPE_INTEGER: 197 return "integer"; 198 case AML_OBJTYPE_STRING: 199 return "string"; 200 case AML_OBJTYPE_BUFFER: 201 return "buffer"; 202 case AML_OBJTYPE_PACKAGE: 203 return "package"; 204 case AML_OBJTYPE_DEVICE: 205 return "device"; 206 case AML_OBJTYPE_EVENT: 207 return "event"; 208 case AML_OBJTYPE_METHOD: 209 return "method"; 210 case AML_OBJTYPE_MUTEX: 211 return "mutex"; 212 case AML_OBJTYPE_OPREGION: 213 return "opregion"; 214 case AML_OBJTYPE_POWERRSRC: 215 return "powerrsrc"; 216 case AML_OBJTYPE_PROCESSOR: 217 return "processor"; 218 case AML_OBJTYPE_THERMZONE: 219 return "thermzone"; 220 case AML_OBJTYPE_DDBHANDLE: 221 return "ddbhandle"; 222 case AML_OBJTYPE_DEBUGOBJ: 223 return "debugobj"; 224 case AML_OBJTYPE_NAMEREF: 225 return "nameref"; 226 case AML_OBJTYPE_OBJREF: 227 return "refof"; 228 case AML_OBJTYPE_FIELDUNIT: 229 case AML_OBJTYPE_BUFFERFIELD: 230 return aml_mnem(val->v_field.type, NULL); 231 } 232 233 return (""); 234 } 235 236 void 237 db_aml_walktree(struct aml_node *node) 238 { 239 while (node) { 240 db_aml_showvalue(node->value); 241 db_aml_walktree(SIMPLEQ_FIRST(&node->son)); 242 node = SIMPLEQ_NEXT(node, sib); 243 } 244 } 245 246 int 247 db_parse_name(void) 248 { 249 int t, rv = 1; 250 251 memset(scope, 0, sizeof scope); 252 do { 253 t = db_read_token(); 254 if (t == tIDENT) { 255 if (strlcat(scope, db_tok_string, sizeof scope) >= 256 sizeof scope) { 257 printf("Input too long\n"); 258 goto error; 259 } 260 t = db_read_token(); 261 if (t == tDOT) 262 if (strlcat(scope, ".", sizeof scope) >= 263 sizeof scope) { 264 printf("Input too long 2\n"); 265 goto error; 266 } 267 } 268 } while (t != tEOL); 269 270 if (!strlen(scope)) { 271 db_printf("Invalid input\n"); 272 goto error; 273 } 274 275 rv = 0; 276 error: 277 /* get rid of the rest of input */ 278 db_flush_lex(); 279 return (rv); 280 } 281 282 /* ddb interface */ 283 void 284 db_acpi_showval(db_expr_t addr, int haddr, db_expr_t count, char *modif) 285 { 286 struct aml_node *node; 287 288 if (db_parse_name()) 289 return; 290 291 node = aml_searchname(&aml_root, scope); 292 if (node) 293 db_aml_showvalue(node->value); 294 else 295 db_printf("Not a valid value\n"); 296 } 297 298 void db_disprint(void *arg, const char *fmt, ...) 299 { 300 va_list ap; 301 char stre[64]; 302 303 va_start(ap,fmt); 304 vsnprintf(stre, sizeof(stre), fmt, ap); 305 va_end(ap); 306 307 db_printf(stre); 308 } 309 310 void 311 db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif) 312 { 313 struct aml_node *node; 314 315 if (db_parse_name()) 316 return; 317 318 node = aml_searchname(&aml_root, scope); 319 if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) { 320 struct aml_scope ns; 321 322 memset(&ns, 0, sizeof(ns)); 323 ns.pos = node->value->v_method.start; 324 ns.end = node->value->v_method.end; 325 ns.node = node; 326 while (ns.pos < ns.end) 327 aml_disasm(&ns, 0, db_disprint, 0); 328 } 329 else 330 db_printf("Not a valid method\n"); 331 } 332 333 void 334 db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif) 335 { 336 db_aml_walktree(&aml_root); 337 } 338 339 void 340 db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif) 341 { 342 struct aml_scope *root; 343 struct aml_value *sp; 344 int idx; 345 extern struct aml_scope *aml_lastscope; 346 347 for (root=aml_lastscope; root && root->pos; root=root->parent) { 348 db_printf("%.4x Called: %s\n", aml_pc(root->pos), 349 aml_nodename(root->node)); 350 for (idx = 0; idx< AML_MAX_ARG; idx++) { 351 sp = aml_getstack(root, AMLOP_ARG0 + idx); 352 if (sp && sp->type) { 353 db_printf(" arg%d: ", idx); 354 db_aml_showvalue(sp); 355 } 356 } 357 for (idx = 0; idx < AML_MAX_LOCAL; idx++) { 358 sp = aml_getstack(root, AMLOP_LOCAL0 + idx); 359 if (sp && sp->type) { 360 db_printf(" local%d: ", idx); 361 db_aml_showvalue(sp); 362 } 363 } 364 } 365 } 366 367 #endif /* DDB */ 368