1 /* $OpenBSD: acpidebug.c,v 1.35 2024/06/26 01:40:49 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
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 /* name of scope for lexer */
52 char scope[80];
53
54 const char *
db_opregion(int id)55 db_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 }
75 void
db_aml_dump(int len,uint8_t * buf)76 db_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
86 void
db_aml_showvalue(struct aml_value * value)87 db_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
183 const char *
db_aml_objtype(struct aml_value * val)184 db_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
230 void
db_aml_walktree(struct aml_node * node)231 db_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
240 int
db_parse_name(void)241 db_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;
270 error:
271 /* get rid of the rest of input */
272 db_flush_lex();
273 return (rv);
274 }
275
276 /* ddb interface */
277 void
db_acpi_showval(db_expr_t addr,int haddr,db_expr_t count,char * modif)278 db_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
292 void
db_disprint(void * arg,const char * fmt,...)293 db_disprint(void *arg, const char *fmt, ...)
294 {
295 va_list ap;
296
297 va_start(ap,fmt);
298 db_vprintf(fmt, ap);
299 va_end(ap);
300 }
301
302 void
db_acpi_disasm(db_expr_t addr,int haddr,db_expr_t count,char * modif)303 db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
304 {
305 struct aml_node *node;
306
307 if (db_parse_name())
308 return;
309
310 node = aml_searchname(acpi_softc->sc_root, scope);
311 if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
312 struct aml_scope ns;
313
314 memset(&ns, 0, sizeof(ns));
315 ns.pos = node->value->v_method.start;
316 ns.end = node->value->v_method.end;
317 ns.node = node;
318 while (ns.pos < ns.end)
319 aml_disasm(&ns, 0, db_disprint, 0);
320 }
321 else
322 db_printf("Not a valid method\n");
323 }
324
325 void
db_acpi_tree(db_expr_t addr,int haddr,db_expr_t count,char * modif)326 db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
327 {
328 db_aml_walktree(acpi_softc->sc_root);
329 }
330
331 void
db_acpi_trace(db_expr_t addr,int haddr,db_expr_t count,char * modif)332 db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif)
333 {
334 struct aml_scope *root;
335 struct aml_value *sp;
336 int idx;
337 extern struct aml_scope *aml_lastscope;
338
339 for (root=aml_lastscope; root && root->pos; root=root->parent) {
340 db_printf("%.4x Called: %s\n", aml_pc(root->pos),
341 aml_nodename(root->node));
342 for (idx = 0; idx< AML_MAX_ARG; idx++) {
343 sp = aml_getstack(root, AMLOP_ARG0 + idx);
344 if (sp && sp->type) {
345 db_printf(" arg%d: ", idx);
346 db_aml_showvalue(sp);
347 }
348 }
349 for (idx = 0; idx < AML_MAX_LOCAL; idx++) {
350 sp = aml_getstack(root, AMLOP_LOCAL0 + idx);
351 if (sp && sp->type) {
352 db_printf(" local%d: ", idx);
353 db_aml_showvalue(sp);
354 }
355 }
356 }
357 }
358
359 #endif /* DDB */
360