1/* $OpenBSD: acpidebug.c,v 1.34 2024/05/13 01:15:50 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
35extern int aml_pc(uint8_t *);
36
37extern const char *aml_mnem(int opcode, uint8_t *);
38extern const char *aml_nodename(struct aml_node *);
39extern void aml_disasm(struct aml_scope *scope, int lvl,
40    void (*dbprintf)(void *, const char *, ...),
41    void *arg);
42
43const char		*db_aml_objtype(struct aml_value *);
44const char		*db_opregion(int);
45int			db_parse_name(void);
46void			db_aml_dump(int, uint8_t *);
47void			db_aml_showvalue(struct aml_value *);
48void			db_aml_walktree(struct aml_node *);
49void			db_disprint(void *, const char *, ...);
50
51/* name of scope for lexer */
52char			scope[80];
53
54const char *
55db_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}
75void
76db_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
86void
87db_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
183const char *
184db_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
230void
231db_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
240int
241db_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;
270error:
271	/* get rid of the rest of input */
272	db_flush_lex();
273	return (rv);
274}
275
276/* ddb interface */
277void
278db_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
292void db_disprint(void *arg, const char *fmt, ...)
293{
294	va_list ap;
295
296	va_start(ap,fmt);
297	db_vprintf(fmt, ap);
298	va_end(ap);
299}
300
301void
302db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
303{
304	struct aml_node *node;
305
306	if (db_parse_name())
307		return;
308
309	node = aml_searchname(acpi_softc->sc_root, scope);
310	if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
311		struct aml_scope ns;
312
313		memset(&ns, 0, sizeof(ns));
314		ns.pos   = node->value->v_method.start;
315		ns.end   = node->value->v_method.end;
316		ns.node  = node;
317		while (ns.pos < ns.end)
318			aml_disasm(&ns, 0, db_disprint, 0);
319	}
320	else
321		db_printf("Not a valid method\n");
322}
323
324void
325db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
326{
327	db_aml_walktree(acpi_softc->sc_root);
328}
329
330void
331db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif)
332{
333	struct aml_scope *root;
334	struct aml_value *sp;
335	int idx;
336	extern struct aml_scope *aml_lastscope;
337
338	for (root=aml_lastscope; root && root->pos; root=root->parent) {
339		db_printf("%.4x Called: %s\n", aml_pc(root->pos),
340		    aml_nodename(root->node));
341		for (idx = 0; idx< AML_MAX_ARG; idx++) {
342			sp = aml_getstack(root, AMLOP_ARG0 + idx);
343			if (sp && sp->type) {
344				db_printf("  arg%d: ", idx);
345				db_aml_showvalue(sp);
346		}
347			}
348		for (idx = 0; idx < AML_MAX_LOCAL; idx++) {
349			sp = aml_getstack(root, AMLOP_LOCAL0 + idx);
350			if (sp && sp->type) {
351				db_printf("  local%d: ", idx);
352				db_aml_showvalue(sp);
353		}
354	}
355	}
356}
357
358#endif /* DDB */
359