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