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