xref: /openbsd-src/sys/dev/acpi/acpidebug.c (revision daf88648c0e349d5c02e1504293082072c981640)
1 /* $OpenBSD: acpidebug.c,v 1.14 2006/12/21 19:59:02 deraadt 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_command.h>
20 #include <ddb/db_output.h>
21 #include <ddb/db_extern.h>
22 #include <ddb/db_lex.h>
23 
24 #include <machine/bus.h>
25 #include <sys/malloc.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 void db_aml_disline(uint8_t *, int, const char *, ...);
34 void db_aml_disint(struct aml_scope *, int, int);
35 uint8_t *db_aml_disasm(struct aml_node *, uint8_t *, uint8_t *, int, int);
36 
37 extern int aml_pc(uint8_t *);
38 extern struct aml_scope *aml_pushscope(struct aml_scope *, uint8_t *, uint8_t *, struct aml_node *);
39 extern struct aml_scope *aml_popscope(struct aml_scope *);
40 extern uint8_t *aml_parsename(struct aml_scope *);
41 extern uint8_t *aml_parseend(struct aml_scope *);
42 extern int aml_parselength(struct aml_scope *);
43 extern int aml_parseopcode(struct aml_scope *);
44 
45 extern const char *aml_mnem(int opcode);
46 extern const char *aml_args(int opcode);
47 extern const char *aml_getname(uint8_t *);
48 extern const char *aml_nodename(struct aml_node *);
49 
50 const char		*db_aml_objtype(struct aml_value *);
51 const char		*db_opregion(int);
52 int			db_parse_name(void);
53 void			db_aml_dump(int, u_int8_t *);
54 void			db_aml_showvalue(struct aml_value *);
55 void			db_aml_walktree(struct aml_node *);
56 
57 const char		*db_aml_fieldacc(int);
58 const char		*db_aml_fieldlock(int);
59 const char		*db_aml_fieldupdate(int);
60 
61 extern struct aml_node	aml_root;
62 
63 /* name of scope for lexer */
64 char			scope[80];
65 
66 const char *
67 db_opregion(int id)
68 {
69 	switch (id) {
70 	case 0:
71 		return "SystemMemory";
72 	case 1:
73 		return "SystemIO";
74 	case 2:
75 		return "PCIConfig";
76 	case 3:
77 		return "Embedded";
78 	case 4:
79 		return "SMBus";
80 	case 5:
81 		return "CMOS";
82 	case 6:
83 		return "PCIBAR";
84 	}
85 	return "";
86 }
87 void
88 db_aml_dump(int len, u_int8_t *buf)
89 {
90 	int		idx;
91 
92 	db_printf("{ ");
93 	for (idx = 0; idx < len; idx++)
94 		db_printf("%s0x%.2x", idx ? ", " : "", buf[idx]);
95 	db_printf(" }\n");
96 }
97 
98 void
99 db_aml_showvalue(struct aml_value *value)
100 {
101 	int		idx;
102 
103 	if (value == NULL)
104 		return;
105 
106 	if (value->node)
107 		db_printf("[%s] ", aml_nodename(value->node));
108 
109 	switch (value->type & ~AML_STATIC) {
110 	case AML_OBJTYPE_OBJREF:
111 		db_printf("refof: %x {\n", value->v_objref.index);
112 		db_aml_showvalue(value->v_objref.ref);
113 		db_printf("}\n");
114 		break;
115 	case AML_OBJTYPE_NAMEREF:
116 		db_printf("nameref: %s\n", value->v_nameref);
117 		break;
118 	case AML_OBJTYPE_INTEGER:
119 		db_printf("integer: %llx %s\n", value->v_integer,
120 		    (value->type & AML_STATIC) ? "(static)" : "");
121 		break;
122 	case AML_OBJTYPE_STRING:
123 		db_printf("string: %s\n", value->v_string);
124 		break;
125 	case AML_OBJTYPE_PACKAGE:
126 		db_printf("package: %d {\n", value->length);
127 		for (idx = 0; idx < value->length; idx++)
128 			db_aml_showvalue(value->v_package[idx]);
129 		db_printf("}\n");
130 		break;
131 	case AML_OBJTYPE_BUFFER:
132 		db_printf("buffer: %d ", value->length);
133 		db_aml_dump(value->length, value->v_buffer);
134 		break;
135 	case AML_OBJTYPE_DEBUGOBJ:
136 		db_printf("debug");
137 		break;
138 	case AML_OBJTYPE_MUTEX:
139 		db_printf("mutex : %llx\n", value->v_integer);
140 		break;
141 	case AML_OBJTYPE_DEVICE:
142 		db_printf("device\n");
143 		break;
144 	case AML_OBJTYPE_EVENT:
145 		db_printf("event\n");
146 		break;
147 	case AML_OBJTYPE_PROCESSOR:
148 		db_printf("cpu: %x,%x,%x\n",
149 		    value->v_processor.proc_id,
150 		    value->v_processor.proc_addr,
151 		    value->v_processor.proc_len);
152 		break;
153 	case AML_OBJTYPE_METHOD:
154 		db_printf("method: args=%d, serialized=%d, synclevel=%d\n",
155 		    AML_METHOD_ARGCOUNT(value->v_method.flags),
156 		    AML_METHOD_SERIALIZED(value->v_method.flags),
157 		    AML_METHOD_SYNCLEVEL(value->v_method.flags));
158 		break;
159 	case AML_OBJTYPE_FIELDUNIT:
160 		db_printf("%s: access=%x,lock=%x,update=%x pos=%.4x "
161 		    "len=%.4x\n",
162 		    aml_mnem(value->v_field.type),
163 		    AML_FIELD_ACCESS(value->v_field.flags),
164 		    AML_FIELD_LOCK(value->v_field.flags),
165 		    AML_FIELD_UPDATE(value->v_field.flags),
166 		    value->v_field.bitpos,
167 		    value->v_field.bitlen);
168 
169 		db_aml_showvalue(value->v_field.ref1);
170 		db_aml_showvalue(value->v_field.ref2);
171 		break;
172 	case AML_OBJTYPE_BUFFERFIELD:
173 		db_printf("%s: pos=%.4x len=%.4x ",
174 		    aml_mnem(value->v_field.type),
175 		    value->v_field.bitpos,
176 		    value->v_field.bitlen);
177 
178 		db_aml_dump(aml_bytelen(value->v_field.bitlen),
179 		    value->v_field.ref1->v_buffer +
180 		    aml_bytepos(value->v_field.bitpos));
181 
182 		db_aml_showvalue(value->v_field.ref1);
183 		break;
184 	case AML_OBJTYPE_OPREGION:
185 		db_printf("opregion: %s,0x%llx,0x%x\n",
186 		    db_opregion(value->v_opregion.iospace),
187 		    value->v_opregion.iobase,
188 		    value->v_opregion.iolen);
189 		break;
190 	default:
191 		db_printf("unknown: %d\n", value->type);
192 		break;
193 	}
194 }
195 
196 const char *
197 db_aml_objtype(struct aml_value *val)
198 {
199 	if (val == NULL)
200 		return "nil";
201 
202 	switch (val->type) {
203 	case AML_OBJTYPE_INTEGER+AML_STATIC:
204 		return "staticint";
205 	case AML_OBJTYPE_INTEGER:
206 		return "integer";
207 	case AML_OBJTYPE_STRING:
208 		return "string";
209 	case AML_OBJTYPE_BUFFER:
210 		return "buffer";
211 	case AML_OBJTYPE_PACKAGE:
212 		return "package";
213 	case AML_OBJTYPE_DEVICE:
214 		return "device";
215 	case AML_OBJTYPE_EVENT:
216 		return "event";
217 	case AML_OBJTYPE_METHOD:
218 		return "method";
219 	case AML_OBJTYPE_MUTEX:
220 		return "mutex";
221 	case AML_OBJTYPE_OPREGION:
222 		return "opregion";
223 	case AML_OBJTYPE_POWERRSRC:
224 		return "powerrsrc";
225 	case AML_OBJTYPE_PROCESSOR:
226 		return "processor";
227 	case AML_OBJTYPE_THERMZONE:
228 		return "thermzone";
229 	case AML_OBJTYPE_DDBHANDLE:
230 		return "ddbhandle";
231 	case AML_OBJTYPE_DEBUGOBJ:
232 		return "debugobj";
233 	case AML_OBJTYPE_NAMEREF:
234 		return "nameref";
235 	case AML_OBJTYPE_OBJREF:
236 		return "refof";
237 	case AML_OBJTYPE_FIELDUNIT:
238 	case AML_OBJTYPE_BUFFERFIELD:
239 		return aml_mnem(val->v_field.type);
240 	}
241 
242 	return ("");
243 }
244 
245 void
246 db_aml_walktree(struct aml_node *node)
247 {
248 	while (node) {
249 		db_aml_showvalue(node->value);
250 		db_aml_walktree(node->child);
251 
252 		node = node->sibling;
253 	}
254 }
255 
256 int
257 db_parse_name(void)
258 {
259 	int		t, rv = 1;
260 
261 	memset(scope, 0, sizeof scope);
262 	do {
263 		t = db_read_token();
264 		if (t == tIDENT) {
265 			if (strlcat(scope, db_tok_string, sizeof scope) >=
266 			    sizeof scope) {
267 				printf("Input too long\n");
268 				goto error;
269 			}
270 			t = db_read_token();
271 			if (t == tDOT)
272 				if (strlcat(scope, ".", sizeof scope) >=
273 				    sizeof scope) {
274 					printf("Input too long 2\n");
275 					goto error;
276 				}
277 		}
278 	} while (t != tEOL);
279 
280 	if (!strlen(scope)) {
281 		db_printf("Invalid input\n");
282 		goto error;
283 	}
284 
285 	rv = 0;
286 error:
287 	/* get rid of the rest of input */
288 	db_flush_lex();
289 	return (rv);
290 }
291 
292 /* ddb interface */
293 void
294 db_acpi_showval(db_expr_t addr, int haddr, db_expr_t count, char *modif)
295 {
296 	struct aml_node *node;
297 
298 	if (db_parse_name())
299 		return;
300 
301 	node = aml_searchname(&aml_root, scope);
302 	if (node)
303 		db_aml_showvalue(node->value);
304 	else
305 		db_printf("Not a valid value\n");
306 }
307 
308 void
309 db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
310 {
311 	struct aml_node *node;
312 
313 	if (db_parse_name())
314 		return;
315 
316 	node = aml_searchname(&aml_root, scope);
317 	if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
318 		db_aml_disasm(node, node->value->v_method.start,
319 		    node->value->v_method.end, -1, 0);
320 	} else
321 		db_printf("Not a valid method\n");
322 }
323 
324 void
325 db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
326 {
327 	db_aml_walktree(aml_root.child);
328 }
329 
330 void
331 db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif)
332 {
333 	struct aml_scope *root;
334 	int idx;
335 	extern struct aml_scope *aml_lastscope;
336 
337 	for (root=aml_lastscope; root && root->pos; root=root->parent) {
338 		db_printf("%.4x Called: %s\n", aml_pc(root->pos),
339 		    aml_nodename(root->node));
340 		for (idx = 0; idx<root->nargs; idx++) {
341 			db_printf("  arg%d: ", idx);
342 			db_aml_showvalue(&root->args[idx]);
343 		}
344 		for (idx = 0; root->locals && idx < AML_MAX_LOCAL; idx++) {
345 			if (root->locals[idx].type) {
346 				db_printf("  local%d: ", idx);
347 				db_aml_showvalue(&root->locals[idx]);
348 			}
349 		}
350 	}
351 }
352 
353 void
354 db_aml_disline(uint8_t *pos, int depth, const char *fmt, ...)
355 {
356 	va_list ap;
357 	char line[128];
358 
359 	db_printf("%.6x: ", aml_pc(pos));
360 	while (depth--)
361 		db_printf("  ");
362 
363 	va_start(ap, fmt);
364 	vsnprintf(line, sizeof(line), fmt, ap);
365 	db_printf(line);
366 	va_end(ap);
367 }
368 
369 void
370 db_aml_disint(struct aml_scope *scope, int opcode, int depth)
371 {
372 	switch (opcode) {
373 	case AML_ANYINT:
374 		db_aml_disasm(scope->node, scope->pos, scope->end, -1, depth);
375 		break;
376 	case AMLOP_BYTEPREFIX:
377 		db_aml_disline(scope->pos, depth, "0x%.2x\n",
378 		    *(uint8_t *)(scope->pos));
379 		scope->pos += 1;
380 		break;
381 	case AMLOP_WORDPREFIX:
382 		db_aml_disline(scope->pos, depth, "0x%.4x\n",
383 		    *(uint16_t *)(scope->pos));
384 		scope->pos += 2;
385 		break;
386 	case AMLOP_DWORDPREFIX:
387 		db_aml_disline(scope->pos, depth, "0x%.8x\n",
388 		    *(uint32_t *)(scope->pos));
389 		scope->pos += 4;
390 		break;
391 	case AMLOP_QWORDPREFIX:
392 		db_aml_disline(scope->pos, depth, "0x%.4llx\n",
393 		    *(uint64_t *)(scope->pos));
394 		scope->pos += 8;
395 		break;
396 	}
397 }
398 
399 uint8_t *
400 db_aml_disasm(struct aml_node *root, uint8_t *start, uint8_t *end,
401     int count, int depth)
402 {
403 	int idx, opcode, len, off=0;
404 	struct aml_scope *scope;
405 	uint8_t *name, *pos;
406 	const char *mnem, *args;
407 	struct aml_node *node;
408 	char *tmpstr;
409 
410 	if (start == end)
411 		return end;
412 
413 	scope = aml_pushscope(NULL, start, end, root);
414 	while (scope->pos < scope->end && count--) {
415 		pos = scope->pos;
416 		start = scope->pos;
417 		opcode = aml_parseopcode(scope);
418 
419 		mnem = aml_mnem(opcode);
420 		args = aml_args(opcode);
421 
422 		if (*args == 'p') {
423 			end = aml_parseend(scope);
424 			args++;
425 		}
426 		node = scope->node;
427 		if (*args == 'N') {
428 			name = aml_parsename(scope);
429 			node = aml_searchname(scope->node, name);
430 			db_aml_disline(pos, depth, "%s %s (%s)\n",
431 			    mnem, aml_getname(name), aml_nodename(node));
432 			args++;
433 		} else if (mnem[0] != '.') {
434 			db_aml_disline(pos, depth, "%s\n", mnem);
435 		}
436 		while (*args) {
437 			pos = scope->pos;
438 			switch (*args) {
439 			case 'k':
440 			case 'c':
441 			case 'D':
442 			case 'L':
443 			case 'A':
444 				break;
445 			case 'i':
446 			case 't':
447 			case 'S':
448 			case 'r':
449 				scope->pos = db_aml_disasm(node, scope->pos,
450 				    scope->end, 1, depth+1);
451 				break;
452 			case 'T':
453 			case 'M':
454 				scope->pos = db_aml_disasm(node, scope->pos,
455 				    end, -1, depth+1);
456 				break;
457 			case 'I':
458 				/* Special case: if */
459 				scope->pos = db_aml_disasm(node, scope->pos,
460 				    end, -1, depth+1);
461 				if (scope->pos >= scope->end)
462 					break;
463 				if (*scope->pos == AMLOP_ELSE) {
464 					++scope->pos;
465 					end = aml_parseend(scope);
466 					db_aml_disline(scope->pos, depth, "Else\n");
467 					scope->pos = db_aml_disasm(node, scope->pos,
468 					    end, -1, depth+1);
469 				}
470 				break;
471 			case 'N':
472 				name = aml_parsename(scope);
473 				db_aml_disline(pos, depth+1, "%s\n", aml_getname(name));
474 				break;
475 			case 'n':
476 				off = (opcode != AMLOP_NAMECHAR);
477 				name = aml_parsename(scope);
478 				node = aml_searchname(scope->node, name);
479 				db_aml_disline(pos, depth+off, "%s <%s>\n",
480 					       aml_getname(name),
481 					       aml_nodename(node));
482 
483 				if (!node || !node->value ||
484 				    node->value->type != AML_OBJTYPE_METHOD)
485 					break;
486 
487 				/* Method calls */
488 				for (idx = 0;
489 				     idx < AML_METHOD_ARGCOUNT(node->value->v_method.flags);
490 				     idx++) {
491 					scope->pos = db_aml_disasm(node, scope->pos,
492 					    scope->end, 1, depth+1);
493 				}
494 				break;
495 			case 'b':
496 				off = (opcode != AMLOP_BYTEPREFIX);
497 				db_aml_disint(scope, AMLOP_BYTEPREFIX, depth+off);
498 				break;
499 			case 'w':
500 				off = (opcode != AMLOP_WORDPREFIX);
501 				db_aml_disint(scope, AMLOP_WORDPREFIX, depth+off);
502 				break;
503 			case 'd':
504 				off = (opcode != AMLOP_DWORDPREFIX);
505 				db_aml_disint(scope, AMLOP_DWORDPREFIX, depth+off);
506 				break;
507 			case 's':
508 				db_aml_disline(pos, depth, "\"%s\"\n", scope->pos);
509 				scope->pos += strlen(scope->pos)+1;
510 				break;
511 			case 'B':
512 				tmpstr = malloc(16 * 6 + 1, M_DEVBUF, M_WAITOK);
513 				for (idx = 0; idx < min(end-scope->pos, 8); idx++)
514 					snprintf(tmpstr+idx*6, 7, "0x%.2x, ",
515 					    scope->pos[idx]);
516 				db_aml_disline(pos, depth+1, "ByteList <%s>\n", tmpstr);
517 			        free(tmpstr, M_DEVBUF);
518 				scope->pos = end;
519 				break;
520 			case 'F':
521 				off = 0;
522 				while (scope->pos < end) {
523 					len = 0;
524 					pos = scope->pos;
525 					switch (*scope->pos) {
526 					case 0x00: // reserved
527 						scope->pos++;
528 						len = aml_parselength(scope);
529 						db_aml_disline(pos, depth+1,
530 						    "Reserved\t%.4x,%.4x\n",
531 						     off, len);
532 						break;
533 					case 0x01: // attr
534 						db_aml_disline(pos, depth+1,
535 						    "Attr:%.2x,%.2x\n",
536 						     scope->pos[1], scope->pos[2]);
537 						scope->pos += 3;
538 						break;
539 					default:
540 						name = aml_parsename(scope);
541 						len = aml_parselength(scope);
542 						db_aml_disline(pos, depth+1,
543 						    "NamedField\t%.4x,%.4x %s\n",
544 						    off, len, aml_getname(name));
545 					}
546 					off += len;
547 				}
548 				scope->pos = end;
549 				break;
550 			default:
551 				db_printf("remaining args: '%s'\n", args);
552 			}
553 			args++;
554 		}
555 	}
556 	pos = scope->pos;
557 	aml_popscope(scope);
558 	return pos;
559 }
560