summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpi/acpidebug.c
diff options
context:
space:
mode:
authormarco <marco@openbsd.org>2006-03-07 23:13:28 +0000
committermarco <marco@openbsd.org>2006-03-07 23:13:28 +0000
commitcda983199459dd28b528141e9397790ea3f13030 (patch)
treeade0db4d9addadb72724c62b153ddf0811f5e6b7 /sys/dev/acpi/acpidebug.c
parentAdd a few more SMSC devices. (diff)
downloadwireguard-openbsd-cda983199459dd28b528141e9397790ea3f13030.tar.xz
wireguard-openbsd-cda983199459dd28b528141e9397790ea3f13030.zip
Add "disasm" code for ddb. With this one can disassemble AML code from DDB.
example : "machine acpi disasm \\_SB_.BIF_" dumps the battery AML on my laptop. Disasm code was written by jordan. Help from miod on ddb lexer magic. ok jordan.
Diffstat (limited to 'sys/dev/acpi/acpidebug.c')
-rw-r--r--sys/dev/acpi/acpidebug.c327
1 files changed, 321 insertions, 6 deletions
diff --git a/sys/dev/acpi/acpidebug.c b/sys/dev/acpi/acpidebug.c
index 863c1a5bb6c..fd09f254822 100644
--- a/sys/dev/acpi/acpidebug.c
+++ b/sys/dev/acpi/acpidebug.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpidebug.c,v 1.1 2006/03/05 14:46:46 marco Exp $ */
+/* $OpenBSD: acpidebug.c,v 1.2 2006/03/07 23:13:28 marco Exp $ */
/*
* Copyright (c) 2006 Marco Peereboom <marco@openbsd.org>
*
@@ -18,6 +18,8 @@
#include <machine/db_machdep.h>
#include <ddb/db_command.h>
#include <ddb/db_output.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_lex.h>
#include <machine/bus.h>
@@ -27,8 +29,272 @@
#include <dev/acpi/acpidebug.h>
#include <dev/acpi/dsdt.h>
-void db_aml_walktree(struct aml_node *);
-void db_aml_shownode(struct aml_node *);
+void db_aml_walktree(struct aml_node *);
+void db_aml_shownode(struct aml_node *);
+void db_aml_disline(uint8_t *, int, const char *, ...);
+void db_aml_disint(struct acpi_context *, int, int);
+void db_aml_disasm(struct acpi_context *, int);
+void db_spaceit(int);
+const char *db_aml_objtype(struct aml_value *);
+const char *db_aml_opname(int);
+struct aml_opcode *db_findem(int);
+int db_aml_nodetype(struct aml_node *);
+
+extern struct aml_node aml_root;
+
+/* Perfect hash values for AML opcodes */
+#define HASH_VAL 11
+#define HASH_SIZE 204
+#define HASH_KEY(v) (((v) * HASH_VAL) % HASH_SIZE)
+
+struct aml_opcode *htab[HASH_SIZE];
+
+/* line buffer */
+char buf[128];
+
+/* name of scope for lexer */
+char scope[80];
+
+/* Output disassembled line */
+void
+db_spaceit(int len)
+{
+ while(len--) {
+ db_printf("..");
+ }
+}
+
+struct aml_opcode
+*db_findem(int opcode)
+{
+ int key, cnt;
+
+ cnt = 0;
+ key = HASH_KEY(opcode);
+
+ while (htab[key] != NULL && htab[key]->opcode != opcode) {
+ key = (key + 1) % HASH_SIZE;
+ cnt++;
+ }
+
+ return (htab[key]);
+}
+
+int
+db_aml_nodetype(struct aml_node *node)
+{
+ return (node && node->value) ? node->value->type : -1;
+}
+
+const char *
+db_aml_opname(int opcode)
+{
+ struct aml_opcode *opc;
+
+ opc = db_findem(opcode);
+
+ return (opc ? opc->mnem : "");
+}
+
+const char *
+db_aml_objtype(struct aml_value *val)
+{
+ if (val == NULL)
+ return "nil";
+
+ switch (val->type) {
+ case AML_OBJTYPE_STATICINT:
+ return "staticint";
+ case AML_OBJTYPE_INTEGER:
+ return "integer";
+ case AML_OBJTYPE_STRING:
+ return "string";
+ case AML_OBJTYPE_BUFFER:
+ return "buffer";
+ case AML_OBJTYPE_PACKAGE:
+ return "package";
+ case AML_OBJTYPE_DEVICE:
+ return "device";
+ case AML_OBJTYPE_EVENT:
+ return "event";
+ case AML_OBJTYPE_METHOD:
+ return "method";
+ case AML_OBJTYPE_MUTEX:
+ return "mutex";
+ case AML_OBJTYPE_OPREGION:
+ return "opregion";
+ case AML_OBJTYPE_POWERRSRC:
+ return "powerrsrc";
+ case AML_OBJTYPE_PROCESSOR:
+ return "processor";
+ case AML_OBJTYPE_THERMZONE:
+ return "thermzone";
+ case AML_OBJTYPE_DDBHANDLE:
+ return "ddbhandle";
+ case AML_OBJTYPE_DEBUGOBJ:
+ return "debugobj";
+ case AML_OBJTYPE_NAMEREF:
+ return "nameref";
+ case AML_OBJTYPE_OBJREF:
+ return "refof";
+ case AML_OBJTYPE_FIELDUNIT:
+ case AML_OBJTYPE_BUFFERFIELD:
+ return db_aml_opname(val->v_field.type);
+ };
+
+ return ("");
+}
+
+void
+db_aml_disline(uint8_t *pos, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ db_printf("%.4x %.2x ", pos - aml_root.start, level);
+ db_spaceit(level);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof buf, fmt, ap);
+ db_printf(buf);
+ va_end(ap);
+
+ db_printf("\n");
+}
+
+/* Output disassembled integer */
+void
+db_aml_disint(struct acpi_context *ctx, int level, int type)
+{
+ u_int8_t *pos;
+ int64_t i1;
+
+ pos = ctx->pos;
+ i1 = aml_eparseint(ctx, type);
+ db_aml_disline(pos, level, "%c:0x%.8llx (%lld)", type, i1, i1);
+}
+
+/* Disassemble AML Opcode */
+void
+db_aml_disasm(struct acpi_context *ctx, int level)
+{
+ struct aml_opcode *opc;
+ uint8_t *end, *np;
+ const char *arg, *fname;
+ struct aml_node *node;
+ int idx, len;
+
+#if 0
+ /* if we want separators */
+ if (level == 0)
+ db_printf("<<<<<<<<<<<<<<\n");
+#endif
+ np = ctx->pos;
+ opc = aml_getopcode(ctx);
+ db_aml_disline(np, level, opc->mnem);
+ for (arg = opc->args; *arg; arg++) {
+ np = ctx->pos;
+ switch (*arg) {
+ case AML_ARG_BYTE:
+ case AML_ARG_WORD:
+ case AML_ARG_DWORD:
+ case AML_ARG_QWORD:
+ db_aml_disint(ctx, level + 1, *arg);
+ break;
+ case AML_ARG_STRING:
+ db_aml_disline(np, level + 1, ctx->pos);
+ ctx->pos += strlen(ctx->pos) + 1;
+ break;
+ case AML_ARG_NAMESTRING:
+ fname = aml_parse_name(ctx);
+ db_aml_disline(np, level + 1, fname);
+ break;
+ case AML_ARG_NAMEREF:
+ fname = aml_parse_name(ctx);
+ node = aml_searchname(ctx->scope, fname);
+ db_aml_disline(np, level + 1, "%s:%s", fname,
+ node ? db_aml_objtype(node->value) : "none");
+ if (db_aml_nodetype(node) == AML_OBJTYPE_METHOD)
+ /* Parse method arguments */
+ for (idx = 0; idx < AML_METHOD_ARGCOUNT(node->value->v_method.flags); idx++)
+ db_aml_disasm(ctx, level + 1);
+ break;
+ case AML_ARG_INTEGER:
+ case AML_ARG_TERMOBJ:
+ case AML_ARG_DATAOBJ:
+ case AML_ARG_SIMPLENAME:
+ case AML_ARG_SUPERNAME:
+ db_aml_disasm(ctx, level + 1);
+ break;
+ case AML_ARG_DATAOBJLIST:
+ case AML_ARG_TERMOBJLIST:
+ case AML_ARG_METHOD:
+ while (ctx->pos < end)
+ db_aml_disasm(ctx, level + 1);
+ break;
+ case AML_ARG_BYTELIST:
+ for (idx = 0; idx < end - ctx->pos - 7; idx += 8) {
+ db_aml_disline(np, level + 1, "buf %.4x: %.2x "
+ "%.2x %.2x %.2x %.2x %.2x %.2x %.2x",
+ idx, ctx->pos[idx],
+ ctx->pos[idx + 1],
+ ctx->pos[idx + 2], ctx->pos[idx + 3],
+ ctx->pos[idx + 4], ctx->pos[idx + 5],
+ ctx->pos[idx + 6], ctx->pos[idx + 7]);
+ }
+ ctx->pos = end;
+ break;
+ case AML_ARG_FLAG:
+ /* Flags */
+ idx = aml_eparseint(ctx, AML_ARG_BYTE);
+ if (opc->opcode == AMLOP_METHOD)
+ db_aml_disline(np, level + 1,
+ "args:%d serialized:%d synclevel:%d",
+ AML_METHOD_ARGCOUNT(idx),
+ AML_METHOD_SERIALIZED(idx),
+ AML_METHOD_SYNCLEVEL(idx));
+ else
+ db_aml_disline(np, level + 1,
+ "acc:%d lock:%d update:%d",
+ AML_FIELD_ACCESS(idx),
+ AML_FIELD_LOCK(idx),
+ AML_FIELD_UPDATE(idx));
+ break;
+ case AML_ARG_FIELDLIST:
+ for (idx = 0; ctx->pos < end; idx += len) {
+ np = ctx->pos;
+ switch (*ctx->pos) {
+ case AML_FIELD_RESERVED:
+ ctx->pos++;
+ len = aml_parse_length(ctx);
+ break;
+ case AML_FIELD_ATTR__:
+ db_aml_disline(np, level + 1,
+ "-- attr %.2x %.2x",
+ ctx->pos[1], ctx->pos[2]);
+ ctx->pos += 3;
+ len = 0;
+ break;
+ default:
+ fname = aml_parse_name(ctx);
+ len = aml_parse_length(ctx);
+ db_aml_disline(np, level + 1,
+ "pos:%.4x len:%.4x name:%s",
+ idx, len, fname);
+ break;
+ }
+ }
+ break;
+ case AML_ARG_OBJLEN:
+ end = aml_eparselen(ctx);
+ break;
+ }
+ }
+#if 0
+ /* if we want separators */
+ if (level == 0)
+ db_printf(">>>>>>>>>>>>>>\n");
+#endif
+}
void
db_aml_shownode(struct aml_node *node)
@@ -68,7 +334,7 @@ db_aml_shownode(struct aml_node *node)
void
db_aml_walktree(struct aml_node *node)
{
- int i;
+ int i;
while(node) {
db_printf(" %d ", node->depth);
@@ -83,9 +349,58 @@ db_aml_walktree(struct aml_node *node)
/* ddb interface */
void
-db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
+db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
- extern struct aml_node aml_root;
+ extern struct acpi_softc *acpi_softc;
+ struct acpi_softc *sc = acpi_softc;
+ struct acpi_context *ctx;
+ struct aml_node *node;
+ int t;
+
+ memset(scope, 0, sizeof scope);
+ do {
+ t = db_read_token();
+ if (t == tIDENT) {
+ if (strlcat(scope, db_tok_string, sizeof scope) >=
+ sizeof scope) {
+ printf("Input too long\n");
+ goto error;
+ }
+ t = db_read_token();
+ if (t == tDOT)
+ if (strlcat(scope, ".", sizeof scope) >=
+ sizeof scope) {
+ printf("Input too long 2\n");
+ goto error;
+ }
+ }
+ }
+ while (t != tEOL);
+ if (!strlen(scope)) {
+ db_printf("Invalid input\n");
+ goto error;
+ }
+
+ /* get rid of the rest of input */
+ db_flush_lex();
+
+ ctx = acpi_alloccontext(sc, &aml_root, 0, NULL);
+ node = aml_searchname(&aml_root, scope);
+ if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) {
+ ctx->pos = node->value->v_method.start;
+ while (ctx->pos < node->value->v_method.end)
+ db_aml_disasm(ctx, 0);
+ }
+ acpi_freecontext(ctx);
+
+error:
+ db_flush_lex();
+}
+
+void
+db_acpi_tree(db_expr_t addr, int haddr, db_expr_t count, char *modif)
+{
db_aml_walktree(aml_root.child);
+
}