xref: /openbsd/sys/dev/acpi/acpidebug.c (revision cda98319)
1*cda98319Smarco /* $OpenBSD: acpidebug.c,v 1.2 2006/03/07 23:13:28 marco Exp $ */
2559cf7adSmarco /*
3559cf7adSmarco  * Copyright (c) 2006 Marco Peereboom <marco@openbsd.org>
4559cf7adSmarco  *
5559cf7adSmarco  * Permission to use, copy, modify, and distribute this software for any
6559cf7adSmarco  * purpose with or without fee is hereby granted, provided that the above
7559cf7adSmarco  * copyright notice and this permission notice appear in all copies.
8559cf7adSmarco  *
9559cf7adSmarco  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10559cf7adSmarco  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11559cf7adSmarco  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12559cf7adSmarco  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13559cf7adSmarco  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14559cf7adSmarco  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15559cf7adSmarco  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16559cf7adSmarco  */
17559cf7adSmarco 
18559cf7adSmarco #include <machine/db_machdep.h>
19559cf7adSmarco #include <ddb/db_command.h>
20559cf7adSmarco #include <ddb/db_output.h>
21*cda98319Smarco #include <ddb/db_extern.h>
22*cda98319Smarco #include <ddb/db_lex.h>
23559cf7adSmarco 
24559cf7adSmarco #include <machine/bus.h>
25559cf7adSmarco 
26559cf7adSmarco #include <dev/acpi/acpireg.h>
27559cf7adSmarco #include <dev/acpi/acpivar.h>
28559cf7adSmarco #include <dev/acpi/amltypes.h>
29559cf7adSmarco #include <dev/acpi/acpidebug.h>
30559cf7adSmarco #include <dev/acpi/dsdt.h>
31559cf7adSmarco 
32559cf7adSmarco void			db_aml_walktree(struct aml_node *);
33559cf7adSmarco void			db_aml_shownode(struct aml_node *);
34*cda98319Smarco void			db_aml_disline(uint8_t *, int, const char *, ...);
35*cda98319Smarco void			db_aml_disint(struct acpi_context *, int, int);
36*cda98319Smarco void			db_aml_disasm(struct acpi_context *, int);
37*cda98319Smarco void			db_spaceit(int);
38*cda98319Smarco const char		*db_aml_objtype(struct aml_value *);
39*cda98319Smarco const char		*db_aml_opname(int);
40*cda98319Smarco struct aml_opcode	*db_findem(int);
41*cda98319Smarco int			db_aml_nodetype(struct aml_node *);
42*cda98319Smarco 
43*cda98319Smarco extern struct aml_node	aml_root;
44*cda98319Smarco 
45*cda98319Smarco /* Perfect hash values for AML opcodes */
46*cda98319Smarco #define HASH_VAL     11
47*cda98319Smarco #define HASH_SIZE    204
48*cda98319Smarco #define HASH_KEY(v)  (((v) * HASH_VAL) % HASH_SIZE)
49*cda98319Smarco 
50*cda98319Smarco struct aml_opcode	*htab[HASH_SIZE];
51*cda98319Smarco 
52*cda98319Smarco /* line buffer */
53*cda98319Smarco char			buf[128];
54*cda98319Smarco 
55*cda98319Smarco /* name of scope for lexer */
56*cda98319Smarco char			scope[80];
57*cda98319Smarco 
58*cda98319Smarco /* Output disassembled line */
59*cda98319Smarco void
60*cda98319Smarco db_spaceit(int len)
61*cda98319Smarco {
62*cda98319Smarco 	while(len--) {
63*cda98319Smarco 		db_printf("..");
64*cda98319Smarco 	}
65*cda98319Smarco }
66*cda98319Smarco 
67*cda98319Smarco struct aml_opcode
68*cda98319Smarco *db_findem(int opcode)
69*cda98319Smarco {
70*cda98319Smarco 	int			key, cnt;
71*cda98319Smarco 
72*cda98319Smarco 	cnt = 0;
73*cda98319Smarco 	key = HASH_KEY(opcode);
74*cda98319Smarco 
75*cda98319Smarco 	while (htab[key] != NULL && htab[key]->opcode != opcode) {
76*cda98319Smarco 		key = (key + 1) % HASH_SIZE;
77*cda98319Smarco 		cnt++;
78*cda98319Smarco 	}
79*cda98319Smarco 
80*cda98319Smarco 	return (htab[key]);
81*cda98319Smarco }
82*cda98319Smarco 
83*cda98319Smarco int
84*cda98319Smarco db_aml_nodetype(struct aml_node *node)
85*cda98319Smarco {
86*cda98319Smarco 	return (node && node->value) ? node->value->type : -1;
87*cda98319Smarco }
88*cda98319Smarco 
89*cda98319Smarco const char *
90*cda98319Smarco db_aml_opname(int opcode)
91*cda98319Smarco {
92*cda98319Smarco 	struct aml_opcode	*opc;
93*cda98319Smarco 
94*cda98319Smarco 	opc = db_findem(opcode);
95*cda98319Smarco 
96*cda98319Smarco 	return (opc ? opc->mnem : "");
97*cda98319Smarco }
98*cda98319Smarco 
99*cda98319Smarco const char *
100*cda98319Smarco db_aml_objtype(struct aml_value *val)
101*cda98319Smarco {
102*cda98319Smarco 	if (val == NULL)
103*cda98319Smarco 		return "nil";
104*cda98319Smarco 
105*cda98319Smarco 	switch (val->type) {
106*cda98319Smarco 	case AML_OBJTYPE_STATICINT:
107*cda98319Smarco 		return "staticint";
108*cda98319Smarco 	case AML_OBJTYPE_INTEGER:
109*cda98319Smarco 		return "integer";
110*cda98319Smarco 	case AML_OBJTYPE_STRING:
111*cda98319Smarco 		return "string";
112*cda98319Smarco 	case AML_OBJTYPE_BUFFER:
113*cda98319Smarco 		return "buffer";
114*cda98319Smarco 	case AML_OBJTYPE_PACKAGE:
115*cda98319Smarco 		return "package";
116*cda98319Smarco 	case AML_OBJTYPE_DEVICE:
117*cda98319Smarco 		return "device";
118*cda98319Smarco 	case AML_OBJTYPE_EVENT:
119*cda98319Smarco 		return "event";
120*cda98319Smarco 	case AML_OBJTYPE_METHOD:
121*cda98319Smarco 		return "method";
122*cda98319Smarco 	case AML_OBJTYPE_MUTEX:
123*cda98319Smarco 		return "mutex";
124*cda98319Smarco 	case AML_OBJTYPE_OPREGION:
125*cda98319Smarco 		return "opregion";
126*cda98319Smarco 	case AML_OBJTYPE_POWERRSRC:
127*cda98319Smarco 		return "powerrsrc";
128*cda98319Smarco 	case AML_OBJTYPE_PROCESSOR:
129*cda98319Smarco 		return "processor";
130*cda98319Smarco 	case AML_OBJTYPE_THERMZONE:
131*cda98319Smarco 		return "thermzone";
132*cda98319Smarco 	case AML_OBJTYPE_DDBHANDLE:
133*cda98319Smarco 		return "ddbhandle";
134*cda98319Smarco 	case AML_OBJTYPE_DEBUGOBJ:
135*cda98319Smarco 		return "debugobj";
136*cda98319Smarco 	case AML_OBJTYPE_NAMEREF:
137*cda98319Smarco 		return "nameref";
138*cda98319Smarco 	case AML_OBJTYPE_OBJREF:
139*cda98319Smarco 		return "refof";
140*cda98319Smarco 	case AML_OBJTYPE_FIELDUNIT:
141*cda98319Smarco 	case AML_OBJTYPE_BUFFERFIELD:
142*cda98319Smarco 		return db_aml_opname(val->v_field.type);
143*cda98319Smarco 	};
144*cda98319Smarco 
145*cda98319Smarco 	return ("");
146*cda98319Smarco }
147*cda98319Smarco 
148*cda98319Smarco void
149*cda98319Smarco db_aml_disline(uint8_t *pos, int level, const char *fmt, ...)
150*cda98319Smarco {
151*cda98319Smarco 	va_list			ap;
152*cda98319Smarco 
153*cda98319Smarco 	db_printf("%.4x %.2x ", pos - aml_root.start, level);
154*cda98319Smarco 	db_spaceit(level);
155*cda98319Smarco 
156*cda98319Smarco 	va_start(ap, fmt);
157*cda98319Smarco 	vsnprintf(buf, sizeof buf, fmt, ap);
158*cda98319Smarco 	db_printf(buf);
159*cda98319Smarco 	va_end(ap);
160*cda98319Smarco 
161*cda98319Smarco 	db_printf("\n");
162*cda98319Smarco }
163*cda98319Smarco 
164*cda98319Smarco /* Output disassembled integer */
165*cda98319Smarco void
166*cda98319Smarco db_aml_disint(struct acpi_context *ctx, int level, int type)
167*cda98319Smarco {
168*cda98319Smarco 	u_int8_t		*pos;
169*cda98319Smarco 	int64_t			i1;
170*cda98319Smarco 
171*cda98319Smarco 	pos = ctx->pos;
172*cda98319Smarco 	i1 = aml_eparseint(ctx, type);
173*cda98319Smarco 	db_aml_disline(pos, level, "%c:0x%.8llx (%lld)", type, i1, i1);
174*cda98319Smarco }
175*cda98319Smarco 
176*cda98319Smarco /* Disassemble AML Opcode */
177*cda98319Smarco void
178*cda98319Smarco db_aml_disasm(struct acpi_context *ctx, int level)
179*cda98319Smarco {
180*cda98319Smarco 	struct aml_opcode	*opc;
181*cda98319Smarco 	uint8_t			*end, *np;
182*cda98319Smarco 	const char		*arg, *fname;
183*cda98319Smarco 	struct aml_node		*node;
184*cda98319Smarco 	int			idx, len;
185*cda98319Smarco 
186*cda98319Smarco #if 0
187*cda98319Smarco 	/* if we want separators */
188*cda98319Smarco 	if (level == 0)
189*cda98319Smarco 		db_printf("<<<<<<<<<<<<<<\n");
190*cda98319Smarco #endif
191*cda98319Smarco 	np = ctx->pos;
192*cda98319Smarco 	opc = aml_getopcode(ctx);
193*cda98319Smarco 	db_aml_disline(np, level, opc->mnem);
194*cda98319Smarco 	for (arg = opc->args; *arg; arg++) {
195*cda98319Smarco 		np = ctx->pos;
196*cda98319Smarco 		switch (*arg) {
197*cda98319Smarco 		case AML_ARG_BYTE:
198*cda98319Smarco 		case AML_ARG_WORD:
199*cda98319Smarco 		case AML_ARG_DWORD:
200*cda98319Smarco 		case AML_ARG_QWORD:
201*cda98319Smarco 			db_aml_disint(ctx, level + 1, *arg);
202*cda98319Smarco 			break;
203*cda98319Smarco 		case AML_ARG_STRING:
204*cda98319Smarco 			db_aml_disline(np, level + 1, ctx->pos);
205*cda98319Smarco 			ctx->pos += strlen(ctx->pos) + 1;
206*cda98319Smarco 			break;
207*cda98319Smarco 		case AML_ARG_NAMESTRING:
208*cda98319Smarco 			fname = aml_parse_name(ctx);
209*cda98319Smarco 			db_aml_disline(np, level + 1, fname);
210*cda98319Smarco 			break;
211*cda98319Smarco 		case AML_ARG_NAMEREF:
212*cda98319Smarco 			fname = aml_parse_name(ctx);
213*cda98319Smarco 			node = aml_searchname(ctx->scope, fname);
214*cda98319Smarco 			db_aml_disline(np, level + 1, "%s:%s", fname,
215*cda98319Smarco 			    node ? db_aml_objtype(node->value) : "none");
216*cda98319Smarco 			if (db_aml_nodetype(node) == AML_OBJTYPE_METHOD)
217*cda98319Smarco 				/* Parse method arguments */
218*cda98319Smarco 				for (idx = 0; idx < AML_METHOD_ARGCOUNT(node->value->v_method.flags); idx++)
219*cda98319Smarco 					db_aml_disasm(ctx, level + 1);
220*cda98319Smarco 			break;
221*cda98319Smarco 		case AML_ARG_INTEGER:
222*cda98319Smarco 		case AML_ARG_TERMOBJ:
223*cda98319Smarco 		case AML_ARG_DATAOBJ:
224*cda98319Smarco 		case AML_ARG_SIMPLENAME:
225*cda98319Smarco 		case AML_ARG_SUPERNAME:
226*cda98319Smarco 			db_aml_disasm(ctx, level + 1);
227*cda98319Smarco 			break;
228*cda98319Smarco 		case AML_ARG_DATAOBJLIST:
229*cda98319Smarco 		case AML_ARG_TERMOBJLIST:
230*cda98319Smarco 		case AML_ARG_METHOD:
231*cda98319Smarco 			while (ctx->pos < end)
232*cda98319Smarco 				db_aml_disasm(ctx, level + 1);
233*cda98319Smarco 			break;
234*cda98319Smarco 		case AML_ARG_BYTELIST:
235*cda98319Smarco 			for (idx = 0; idx < end - ctx->pos - 7; idx += 8) {
236*cda98319Smarco 				db_aml_disline(np, level + 1, "buf %.4x: %.2x "
237*cda98319Smarco 				    "%.2x %.2x %.2x %.2x %.2x %.2x %.2x",
238*cda98319Smarco 				    idx, ctx->pos[idx],
239*cda98319Smarco 				    ctx->pos[idx + 1],
240*cda98319Smarco 				    ctx->pos[idx + 2], ctx->pos[idx + 3],
241*cda98319Smarco 				    ctx->pos[idx + 4], ctx->pos[idx + 5],
242*cda98319Smarco 				    ctx->pos[idx + 6], ctx->pos[idx + 7]);
243*cda98319Smarco 			}
244*cda98319Smarco 			ctx->pos = end;
245*cda98319Smarco 			break;
246*cda98319Smarco 		case AML_ARG_FLAG:
247*cda98319Smarco 			/* Flags */
248*cda98319Smarco 			idx = aml_eparseint(ctx, AML_ARG_BYTE);
249*cda98319Smarco 			if (opc->opcode == AMLOP_METHOD)
250*cda98319Smarco 				db_aml_disline(np, level + 1,
251*cda98319Smarco 				    "args:%d serialized:%d synclevel:%d",
252*cda98319Smarco 				    AML_METHOD_ARGCOUNT(idx),
253*cda98319Smarco 				    AML_METHOD_SERIALIZED(idx),
254*cda98319Smarco 				    AML_METHOD_SYNCLEVEL(idx));
255*cda98319Smarco 			else
256*cda98319Smarco 				db_aml_disline(np, level + 1,
257*cda98319Smarco 				    "acc:%d lock:%d update:%d",
258*cda98319Smarco 				    AML_FIELD_ACCESS(idx),
259*cda98319Smarco 				    AML_FIELD_LOCK(idx),
260*cda98319Smarco 				    AML_FIELD_UPDATE(idx));
261*cda98319Smarco 			break;
262*cda98319Smarco 		case AML_ARG_FIELDLIST:
263*cda98319Smarco 			for (idx = 0; ctx->pos < end; idx += len) {
264*cda98319Smarco 				np = ctx->pos;
265*cda98319Smarco 				switch (*ctx->pos) {
266*cda98319Smarco 				case AML_FIELD_RESERVED:
267*cda98319Smarco 					ctx->pos++;
268*cda98319Smarco 					len = aml_parse_length(ctx);
269*cda98319Smarco 					break;
270*cda98319Smarco 				case AML_FIELD_ATTR__:
271*cda98319Smarco 					db_aml_disline(np, level + 1,
272*cda98319Smarco 					    "-- attr %.2x %.2x",
273*cda98319Smarco 					    ctx->pos[1], ctx->pos[2]);
274*cda98319Smarco 					ctx->pos += 3;
275*cda98319Smarco 					len = 0;
276*cda98319Smarco 					break;
277*cda98319Smarco 				default:
278*cda98319Smarco 					fname = aml_parse_name(ctx);
279*cda98319Smarco 					len = aml_parse_length(ctx);
280*cda98319Smarco 					db_aml_disline(np, level + 1,
281*cda98319Smarco 					    "pos:%.4x len:%.4x name:%s",
282*cda98319Smarco 					    idx, len, fname);
283*cda98319Smarco 					break;
284*cda98319Smarco 				}
285*cda98319Smarco 			}
286*cda98319Smarco 			break;
287*cda98319Smarco 		case AML_ARG_OBJLEN:
288*cda98319Smarco 			end = aml_eparselen(ctx);
289*cda98319Smarco 			break;
290*cda98319Smarco 		}
291*cda98319Smarco 	}
292*cda98319Smarco #if 0
293*cda98319Smarco 	/* if we want separators */
294*cda98319Smarco 	if (level == 0)
295*cda98319Smarco 		db_printf(">>>>>>>>>>>>>>\n");
296*cda98319Smarco #endif
297*cda98319Smarco }
298559cf7adSmarco 
299559cf7adSmarco void
300559cf7adSmarco db_aml_shownode(struct aml_node *node)
301559cf7adSmarco {
302559cf7adSmarco 	db_printf(" opcode:%.4x  mnem:%s %s ",
303559cf7adSmarco 	    node->opcode, node->mnem, node->name ? node->name : "");
304559cf7adSmarco 
305559cf7adSmarco 	switch(node->opcode) {
306559cf7adSmarco 	case AMLOP_METHOD:
307559cf7adSmarco 		break;
308559cf7adSmarco 
309559cf7adSmarco 	case AMLOP_NAMECHAR:
310559cf7adSmarco 		db_printf("%s", node->value->name);
311559cf7adSmarco 		break;
312559cf7adSmarco 
313559cf7adSmarco 	case AMLOP_FIELD:
314559cf7adSmarco 	case AMLOP_BANKFIELD:
315559cf7adSmarco 	case AMLOP_INDEXFIELD:
316559cf7adSmarco 		break;
317559cf7adSmarco 
318559cf7adSmarco 	case AMLOP_BYTEPREFIX:
319559cf7adSmarco 		db_printf("byte: %.2x", node->value->v_integer);
320559cf7adSmarco 		break;
321559cf7adSmarco 	case AMLOP_WORDPREFIX:
322559cf7adSmarco 		db_printf("word: %.4x", node->value->v_integer);
323559cf7adSmarco 		break;
324559cf7adSmarco 	case AMLOP_DWORDPREFIX:
325559cf7adSmarco 		db_printf("dword: %.8x", node->value->v_integer);
326559cf7adSmarco 		break;
327559cf7adSmarco 	case AMLOP_STRINGPREFIX:
328559cf7adSmarco 		db_printf("string: %s", node->value->v_string);
329559cf7adSmarco 		break;
330559cf7adSmarco 	}
331559cf7adSmarco 	db_printf("\n");
332559cf7adSmarco }
333559cf7adSmarco 
334559cf7adSmarco void
335559cf7adSmarco db_aml_walktree(struct aml_node *node)
336559cf7adSmarco {
337559cf7adSmarco 	int			i;
338559cf7adSmarco 
339559cf7adSmarco 	while(node) {
340559cf7adSmarco 		db_printf(" %d ", node->depth);
341559cf7adSmarco 		for(i = 0; i < node->depth; i++)
342559cf7adSmarco 			db_printf("..");
343559cf7adSmarco 
344559cf7adSmarco 		db_aml_shownode(node);
345559cf7adSmarco 		db_aml_walktree(node->child);
346559cf7adSmarco 		node = node->sibling;
347559cf7adSmarco 	}
348559cf7adSmarco }
349559cf7adSmarco 
350559cf7adSmarco /* ddb interface */
351559cf7adSmarco void
352*cda98319Smarco db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
353*cda98319Smarco {
354*cda98319Smarco 	extern struct acpi_softc	*acpi_softc;
355*cda98319Smarco 	struct acpi_softc 		*sc = acpi_softc;
356*cda98319Smarco 	struct acpi_context 		*ctx;
357*cda98319Smarco 	struct aml_node 		*node;
358*cda98319Smarco 	int				t;
359*cda98319Smarco 
360*cda98319Smarco 	memset(scope, 0, sizeof scope);
361*cda98319Smarco 	do {
362*cda98319Smarco 		t = db_read_token();
363*cda98319Smarco 		if (t == tIDENT) {
364*cda98319Smarco 			if (strlcat(scope, db_tok_string, sizeof scope) >=
365*cda98319Smarco 			    sizeof scope) {
366*cda98319Smarco 				printf("Input too long\n");
367*cda98319Smarco 				goto error;
368*cda98319Smarco 			}
369*cda98319Smarco 			t = db_read_token();
370*cda98319Smarco 			if (t == tDOT)
371*cda98319Smarco 				if (strlcat(scope, ".", sizeof scope) >=
372*cda98319Smarco 				    sizeof scope) {
373*cda98319Smarco 					printf("Input too long 2\n");
374*cda98319Smarco 					goto error;
375*cda98319Smarco 				}
376*cda98319Smarco 		}
377*cda98319Smarco 	}
378*cda98319Smarco 	while (t != tEOL);
379*cda98319Smarco 
380*cda98319Smarco 	if (!strlen(scope)) {
381*cda98319Smarco 		db_printf("Invalid input\n");
382*cda98319Smarco 		goto error;
383*cda98319Smarco 	}
384*cda98319Smarco 
385*cda98319Smarco 	/* get rid of the rest of input */
386*cda98319Smarco 	db_flush_lex();
387*cda98319Smarco 
388*cda98319Smarco 	ctx = acpi_alloccontext(sc, &aml_root, 0, NULL);
389*cda98319Smarco 	node = aml_searchname(&aml_root, scope);
390*cda98319Smarco 	if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
391*cda98319Smarco 		ctx->pos = node->value->v_method.start;
392*cda98319Smarco 		while (ctx->pos < node->value->v_method.end)
393*cda98319Smarco 			db_aml_disasm(ctx, 0);
394*cda98319Smarco 	}
395*cda98319Smarco 	acpi_freecontext(ctx);
396*cda98319Smarco 
397*cda98319Smarco error:
398*cda98319Smarco 	db_flush_lex();
399*cda98319Smarco }
400*cda98319Smarco 
401*cda98319Smarco void
402559cf7adSmarco db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
403559cf7adSmarco {
404559cf7adSmarco 	db_aml_walktree(aml_root.child);
405*cda98319Smarco 
406559cf7adSmarco }
407