xref: /openbsd-src/sys/dev/acpi/acpidebug.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
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