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