xref: /openbsd/sys/dev/acpi/acpidebug.c (revision 0f9e9ec2)
1*0f9e9ec2Sjsg /* $OpenBSD: acpidebug.c,v 1.34 2024/05/13 01:15:50 jsg 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 
18311b6aa8Smpi #include <sys/param.h>
19311b6aa8Smpi #include <sys/systm.h>
20311b6aa8Smpi #include <sys/malloc.h>
21311b6aa8Smpi #include <machine/bus.h>
22559cf7adSmarco #include <machine/db_machdep.h>
23559cf7adSmarco #include <ddb/db_output.h>
24cda98319Smarco #include <ddb/db_extern.h>
25cda98319Smarco #include <ddb/db_lex.h>
26559cf7adSmarco 
27559cf7adSmarco #include <dev/acpi/acpireg.h>
28559cf7adSmarco #include <dev/acpi/acpivar.h>
29559cf7adSmarco #include <dev/acpi/amltypes.h>
30559cf7adSmarco #include <dev/acpi/acpidebug.h>
31559cf7adSmarco #include <dev/acpi/dsdt.h>
32559cf7adSmarco 
33df33944cSmarco #ifdef DDB
3430a01ff4Sjordan 
3530a01ff4Sjordan extern int aml_pc(uint8_t *);
3630a01ff4Sjordan 
37048d6e7cSjordan extern const char *aml_mnem(int opcode, uint8_t *);
3830a01ff4Sjordan extern const char *aml_nodename(struct aml_node *);
39ce151df9Sjordan extern void aml_disasm(struct aml_scope *scope, int lvl,
40ce151df9Sjordan     void (*dbprintf)(void *, const char *, ...),
41ce151df9Sjordan     void *arg);
4230a01ff4Sjordan 
43127317ceSmarco const char		*db_aml_objtype(struct aml_value *);
44127317ceSmarco const char		*db_opregion(int);
45127317ceSmarco int			db_parse_name(void);
46d2eaebe9Skettenis void			db_aml_dump(int, uint8_t *);
474e3126f2Smarco void			db_aml_showvalue(struct aml_value *);
48127317ceSmarco void			db_aml_walktree(struct aml_node *);
49ce151df9Sjordan void			db_disprint(void *, const char *, ...);
50d478d440Sjordan 
51cda98319Smarco /* name of scope for lexer */
52cda98319Smarco char			scope[80];
53cda98319Smarco 
544e3126f2Smarco const char *
db_opregion(int id)554e3126f2Smarco db_opregion(int id)
564e3126f2Smarco {
574e3126f2Smarco 	switch (id) {
584e3126f2Smarco 	case 0:
594e3126f2Smarco 		return "SystemMemory";
604e3126f2Smarco 	case 1:
614e3126f2Smarco 		return "SystemIO";
624e3126f2Smarco 	case 2:
634e3126f2Smarco 		return "PCIConfig";
644e3126f2Smarco 	case 3:
654e3126f2Smarco 		return "Embedded";
664e3126f2Smarco 	case 4:
674e3126f2Smarco 		return "SMBus";
684e3126f2Smarco 	case 5:
694e3126f2Smarco 		return "CMOS";
704e3126f2Smarco 	case 6:
714e3126f2Smarco 		return "PCIBAR";
724e3126f2Smarco 	}
734e3126f2Smarco 	return "";
744e3126f2Smarco }
754e3126f2Smarco void
db_aml_dump(int len,uint8_t * buf)76d2eaebe9Skettenis db_aml_dump(int len, uint8_t *buf)
774e3126f2Smarco {
784e3126f2Smarco 	int		idx;
794e3126f2Smarco 
804e3126f2Smarco 	db_printf("{ ");
817d03a03dSmarco 	for (idx = 0; idx < len; idx++)
824e3126f2Smarco 		db_printf("%s0x%.2x", idx ? ", " : "", buf[idx]);
834e3126f2Smarco 	db_printf(" }\n");
844e3126f2Smarco }
854e3126f2Smarco 
864e3126f2Smarco void
db_aml_showvalue(struct aml_value * value)874e3126f2Smarco db_aml_showvalue(struct aml_value *value)
884e3126f2Smarco {
894e3126f2Smarco 	int		idx;
904e3126f2Smarco 
914e3126f2Smarco 	if (value == NULL)
924e3126f2Smarco 		return;
934e3126f2Smarco 
944e3126f2Smarco 	if (value->node)
9530a01ff4Sjordan 		db_printf("[%s] ", aml_nodename(value->node));
964e3126f2Smarco 
970cfeeb27Sjordan 	switch (value->type) {
984e3126f2Smarco 	case AML_OBJTYPE_OBJREF:
994e3126f2Smarco 		db_printf("refof: %x {\n", value->v_objref.index);
1004e3126f2Smarco 		db_aml_showvalue(value->v_objref.ref);
1014e3126f2Smarco 		db_printf("}\n");
1024e3126f2Smarco 		break;
1034e3126f2Smarco 	case AML_OBJTYPE_NAMEREF:
1046ab98c39Sjordan 		db_printf("nameref: %s\n", value->v_nameref);
1054e3126f2Smarco 		break;
1064e3126f2Smarco 	case AML_OBJTYPE_INTEGER:
1070cfeeb27Sjordan 		db_printf("integer: %llx\n", value->v_integer);
1084e3126f2Smarco 		break;
1094e3126f2Smarco 	case AML_OBJTYPE_STRING:
1104e3126f2Smarco 		db_printf("string: %s\n", value->v_string);
1114e3126f2Smarco 		break;
1124e3126f2Smarco 	case AML_OBJTYPE_PACKAGE:
1134e3126f2Smarco 		db_printf("package: %d {\n", value->length);
1144e3126f2Smarco 		for (idx = 0; idx < value->length; idx++)
1154e3126f2Smarco 			db_aml_showvalue(value->v_package[idx]);
1164e3126f2Smarco 		db_printf("}\n");
1174e3126f2Smarco 		break;
1184e3126f2Smarco 	case AML_OBJTYPE_BUFFER:
1194e3126f2Smarco 		db_printf("buffer: %d ", value->length);
1204e3126f2Smarco 		db_aml_dump(value->length, value->v_buffer);
1214e3126f2Smarco 		break;
1224e3126f2Smarco 	case AML_OBJTYPE_DEBUGOBJ:
1234e3126f2Smarco 		db_printf("debug");
1244e3126f2Smarco 		break;
1254e3126f2Smarco 	case AML_OBJTYPE_MUTEX:
1264e3126f2Smarco 		db_printf("mutex : %llx\n", value->v_integer);
1274e3126f2Smarco 		break;
1284e3126f2Smarco 	case AML_OBJTYPE_DEVICE:
1294e3126f2Smarco 		db_printf("device\n");
1304e3126f2Smarco 		break;
1314e3126f2Smarco 	case AML_OBJTYPE_EVENT:
1324e3126f2Smarco 		db_printf("event\n");
1334e3126f2Smarco 		break;
1344e3126f2Smarco 	case AML_OBJTYPE_PROCESSOR:
1354e3126f2Smarco 		db_printf("cpu: %x,%x,%x\n",
1364e3126f2Smarco 		    value->v_processor.proc_id,
1374e3126f2Smarco 		    value->v_processor.proc_addr,
1384e3126f2Smarco 		    value->v_processor.proc_len);
1394e3126f2Smarco 		break;
1404e3126f2Smarco 	case AML_OBJTYPE_METHOD:
1414e3126f2Smarco 		db_printf("method: args=%d, serialized=%d, synclevel=%d\n",
1424e3126f2Smarco 		    AML_METHOD_ARGCOUNT(value->v_method.flags),
1434e3126f2Smarco 		    AML_METHOD_SERIALIZED(value->v_method.flags),
1444e3126f2Smarco 		    AML_METHOD_SYNCLEVEL(value->v_method.flags));
1454e3126f2Smarco 		break;
1464e3126f2Smarco 	case AML_OBJTYPE_FIELDUNIT:
1474e3126f2Smarco 		db_printf("%s: access=%x,lock=%x,update=%x pos=%.4x "
1484e3126f2Smarco 		    "len=%.4x\n",
149048d6e7cSjordan 		    aml_mnem(value->v_field.type, NULL),
1504e3126f2Smarco 		    AML_FIELD_ACCESS(value->v_field.flags),
1514e3126f2Smarco 		    AML_FIELD_LOCK(value->v_field.flags),
1524e3126f2Smarco 		    AML_FIELD_UPDATE(value->v_field.flags),
1534e3126f2Smarco 		    value->v_field.bitpos,
1544e3126f2Smarco 		    value->v_field.bitlen);
1553b455a03Smarco 		if (value->v_field.ref2)
1563b455a03Smarco 			db_printf("  index: %.3x %s\n",
1573b455a03Smarco 			    value->v_field.ref3,
1583b455a03Smarco 			    aml_nodename(value->v_field.ref2->node));
1593b455a03Smarco 		if (value->v_field.ref1)
1603b455a03Smarco 			db_printf("  data: %s\n",
1613b455a03Smarco 			    aml_nodename(value->v_field.ref1->node));
1624e3126f2Smarco 		break;
1634e3126f2Smarco 	case AML_OBJTYPE_BUFFERFIELD:
1643b455a03Smarco 		db_printf("%s: pos=%.4x len=%.4x\n",
165048d6e7cSjordan 		    aml_mnem(value->v_field.type, NULL),
1664e3126f2Smarco 		    value->v_field.bitpos,
1674e3126f2Smarco 		    value->v_field.bitlen);
1683b455a03Smarco 		db_printf("  buffer: %s\n",
1693b455a03Smarco 		    aml_nodename(value->v_field.ref1->node));
1704e3126f2Smarco 		break;
1714e3126f2Smarco 	case AML_OBJTYPE_OPREGION:
1724e3126f2Smarco 		db_printf("opregion: %s,0x%llx,0x%x\n",
1734e3126f2Smarco 		    db_opregion(value->v_opregion.iospace),
1744e3126f2Smarco 		    value->v_opregion.iobase,
1754e3126f2Smarco 		    value->v_opregion.iolen);
1764e3126f2Smarco 		break;
1774e3126f2Smarco 	default:
1784e3126f2Smarco 		db_printf("unknown: %d\n", value->type);
1794e3126f2Smarco 		break;
1804e3126f2Smarco 	}
1814e3126f2Smarco }
1824e3126f2Smarco 
183cda98319Smarco const char *
db_aml_objtype(struct aml_value * val)184cda98319Smarco db_aml_objtype(struct aml_value *val)
185cda98319Smarco {
186cda98319Smarco 	if (val == NULL)
187cda98319Smarco 		return "nil";
188cda98319Smarco 
189cda98319Smarco 	switch (val->type) {
190cda98319Smarco 	case AML_OBJTYPE_INTEGER:
191cda98319Smarco 		return "integer";
192cda98319Smarco 	case AML_OBJTYPE_STRING:
193cda98319Smarco 		return "string";
194cda98319Smarco 	case AML_OBJTYPE_BUFFER:
195cda98319Smarco 		return "buffer";
196cda98319Smarco 	case AML_OBJTYPE_PACKAGE:
197cda98319Smarco 		return "package";
198cda98319Smarco 	case AML_OBJTYPE_DEVICE:
199cda98319Smarco 		return "device";
200cda98319Smarco 	case AML_OBJTYPE_EVENT:
201cda98319Smarco 		return "event";
202cda98319Smarco 	case AML_OBJTYPE_METHOD:
203cda98319Smarco 		return "method";
204cda98319Smarco 	case AML_OBJTYPE_MUTEX:
205cda98319Smarco 		return "mutex";
206cda98319Smarco 	case AML_OBJTYPE_OPREGION:
207cda98319Smarco 		return "opregion";
208cda98319Smarco 	case AML_OBJTYPE_POWERRSRC:
209cda98319Smarco 		return "powerrsrc";
210cda98319Smarco 	case AML_OBJTYPE_PROCESSOR:
211cda98319Smarco 		return "processor";
212cda98319Smarco 	case AML_OBJTYPE_THERMZONE:
213cda98319Smarco 		return "thermzone";
214cda98319Smarco 	case AML_OBJTYPE_DDBHANDLE:
215cda98319Smarco 		return "ddbhandle";
216cda98319Smarco 	case AML_OBJTYPE_DEBUGOBJ:
217cda98319Smarco 		return "debugobj";
218cda98319Smarco 	case AML_OBJTYPE_NAMEREF:
219cda98319Smarco 		return "nameref";
220cda98319Smarco 	case AML_OBJTYPE_OBJREF:
221cda98319Smarco 		return "refof";
222cda98319Smarco 	case AML_OBJTYPE_FIELDUNIT:
223cda98319Smarco 	case AML_OBJTYPE_BUFFERFIELD:
224048d6e7cSjordan 		return aml_mnem(val->v_field.type, NULL);
225e6117b4fSderaadt 	}
226cda98319Smarco 
227cda98319Smarco 	return ("");
228cda98319Smarco }
229cda98319Smarco 
230cda98319Smarco void
db_aml_walktree(struct aml_node * node)231559cf7adSmarco db_aml_walktree(struct aml_node *node)
232559cf7adSmarco {
233559cf7adSmarco 	while (node) {
23430a01ff4Sjordan 		db_aml_showvalue(node->value);
235311c37bcSjordan 		db_aml_walktree(SIMPLEQ_FIRST(&node->son));
236311c37bcSjordan 		node = SIMPLEQ_NEXT(node, sib);
237559cf7adSmarco 	}
238559cf7adSmarco }
239559cf7adSmarco 
240fc0379faSmarco int
db_parse_name(void)241fc0379faSmarco db_parse_name(void)
2424e3126f2Smarco {
243fc0379faSmarco 	int		t, rv = 1;
2444e3126f2Smarco 
2454e3126f2Smarco 	memset(scope, 0, sizeof scope);
2464e3126f2Smarco 	do {
2474e3126f2Smarco 		t = db_read_token();
2484e3126f2Smarco 		if (t == tIDENT) {
2494e3126f2Smarco 			if (strlcat(scope, db_tok_string, sizeof scope) >=
2504e3126f2Smarco 			    sizeof scope) {
2514e3126f2Smarco 				printf("Input too long\n");
2524e3126f2Smarco 				goto error;
2534e3126f2Smarco 			}
2544e3126f2Smarco 			t = db_read_token();
2554e3126f2Smarco 			if (t == tDOT)
2564e3126f2Smarco 				if (strlcat(scope, ".", sizeof scope) >=
2574e3126f2Smarco 				    sizeof scope) {
2584e3126f2Smarco 					printf("Input too long 2\n");
2594e3126f2Smarco 					goto error;
2604e3126f2Smarco 				}
2614e3126f2Smarco 		}
262e6117b4fSderaadt 	} while (t != tEOL);
2634e3126f2Smarco 
2644e3126f2Smarco 	if (!strlen(scope)) {
2654e3126f2Smarco 		db_printf("Invalid input\n");
2664e3126f2Smarco 		goto error;
2674e3126f2Smarco 	}
2684e3126f2Smarco 
269fc0379faSmarco 	rv = 0;
270fc0379faSmarco error:
2714e3126f2Smarco 	/* get rid of the rest of input */
2724e3126f2Smarco 	db_flush_lex();
273fc0379faSmarco 	return (rv);
274fc0379faSmarco }
275fc0379faSmarco 
276fc0379faSmarco /* ddb interface */
277fc0379faSmarco void
db_acpi_showval(db_expr_t addr,int haddr,db_expr_t count,char * modif)278fc0379faSmarco db_acpi_showval(db_expr_t addr, int haddr, db_expr_t count, char *modif)
279fc0379faSmarco {
280fc0379faSmarco 	struct aml_node *node;
281fc0379faSmarco 
282fc0379faSmarco 	if (db_parse_name())
283fc0379faSmarco 		return;
2844e3126f2Smarco 
2859108e412Spatrick 	node = aml_searchname(acpi_softc->sc_root, scope);
2864e3126f2Smarco 	if (node)
2874e3126f2Smarco 		db_aml_showvalue(node->value);
2884e3126f2Smarco 	else
2894e3126f2Smarco 		db_printf("Not a valid value\n");
2904e3126f2Smarco }
2914e3126f2Smarco 
db_disprint(void * arg,const char * fmt,...)2923b455a03Smarco void db_disprint(void *arg, const char *fmt, ...)
2933b455a03Smarco {
2943b455a03Smarco 	va_list ap;
2953b455a03Smarco 
2963b455a03Smarco 	va_start(ap,fmt);
2970a331823Sguenther 	db_vprintf(fmt, ap);
2983b455a03Smarco 	va_end(ap);
2993b455a03Smarco }
3003b455a03Smarco 
3013b455a03Smarco void
db_acpi_disasm(db_expr_t addr,int haddr,db_expr_t count,char * modif)302cda98319Smarco db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
303cda98319Smarco {
304cda98319Smarco 	struct aml_node *node;
305cda98319Smarco 
306fc0379faSmarco 	if (db_parse_name())
307fc0379faSmarco 		return;
308cda98319Smarco 
3099108e412Spatrick 	node = aml_searchname(acpi_softc->sc_root, scope);
310cda98319Smarco 	if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
3113b455a03Smarco 		struct aml_scope ns;
3123b455a03Smarco 
3133b455a03Smarco 		memset(&ns, 0, sizeof(ns));
3143b455a03Smarco 		ns.pos   = node->value->v_method.start;
3153b455a03Smarco 		ns.end   = node->value->v_method.end;
3163b455a03Smarco 		ns.node  = node;
3173b455a03Smarco 		while (ns.pos < ns.end)
3183b455a03Smarco 			aml_disasm(&ns, 0, db_disprint, 0);
3193b455a03Smarco 	}
3203b455a03Smarco 	else
3213b455a03Smarco 		db_printf("Not a valid method\n");
322cda98319Smarco }
323cda98319Smarco 
324cda98319Smarco void
db_acpi_tree(db_expr_t addr,int haddr,db_expr_t count,char * modif)325559cf7adSmarco db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
326559cf7adSmarco {
3279108e412Spatrick 	db_aml_walktree(acpi_softc->sc_root);
328559cf7adSmarco }
32930a01ff4Sjordan 
3306c53ca5eSjordan void
db_acpi_trace(db_expr_t addr,int haddr,db_expr_t count,char * modif)3316c53ca5eSjordan db_acpi_trace(db_expr_t addr, int haddr, db_expr_t count, char *modif)
3326c53ca5eSjordan {
3336c53ca5eSjordan 	struct aml_scope *root;
334ce151df9Sjordan 	struct aml_value *sp;
3356c53ca5eSjordan 	int idx;
3366c53ca5eSjordan 	extern struct aml_scope *aml_lastscope;
3376c53ca5eSjordan 
3386c53ca5eSjordan 	for (root=aml_lastscope; root && root->pos; root=root->parent) {
3396c53ca5eSjordan 		db_printf("%.4x Called: %s\n", aml_pc(root->pos),
3406c53ca5eSjordan 		    aml_nodename(root->node));
341ce151df9Sjordan 		for (idx = 0; idx< AML_MAX_ARG; idx++) {
342ce151df9Sjordan 			sp = aml_getstack(root, AMLOP_ARG0 + idx);
343ce151df9Sjordan 			if (sp && sp->type) {
3446c53ca5eSjordan 				db_printf("  arg%d: ", idx);
345ce151df9Sjordan 				db_aml_showvalue(sp);
3466c53ca5eSjordan 		}
347ce151df9Sjordan 			}
348ce151df9Sjordan 		for (idx = 0; idx < AML_MAX_LOCAL; idx++) {
349ce151df9Sjordan 			sp = aml_getstack(root, AMLOP_LOCAL0 + idx);
350ce151df9Sjordan 			if (sp && sp->type) {
3516c53ca5eSjordan 				db_printf("  local%d: ", idx);
352ce151df9Sjordan 				db_aml_showvalue(sp);
3536c53ca5eSjordan 		}
3546c53ca5eSjordan 	}
3556c53ca5eSjordan 	}
3566c53ca5eSjordan }
3576c53ca5eSjordan 
358080446a7Smarco #endif /* DDB */
359