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