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