diff options
Diffstat (limited to 'sys/dev/acpi/dsdt.c')
-rw-r--r-- | sys/dev/acpi/dsdt.c | 4668 |
1 files changed, 2778 insertions, 1890 deletions
diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index b86b5913a3a..7c24ff679c3 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,5 +1,5 @@ -/* $OpenBSD: dsdt.c,v 1.115 2008/05/16 06:50:55 dlg Exp $ */ +/* $OpenBSD: dsdt.c,v 1.116 2008/06/01 17:59:55 marco Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -34,6 +34,10 @@ #include <dev/acpi/amltypes.h> #include <dev/acpi/dsdt.h> +#ifdef SMALL_KERNEL +#undef ACPI_DEBUG +#endif + #define opsize(opcode) (((opcode) & 0xFF00) ? 2 : 1) #define AML_CHECKSTACK() @@ -52,8 +56,9 @@ extern int hz; struct aml_scope; - +#if 0 int aml_cmpvalue(struct aml_value *, struct aml_value *, int); +#endif void aml_copyvalue(struct aml_value *, struct aml_value *); void aml_setvalue(struct aml_scope *, struct aml_value *, @@ -122,24 +127,6 @@ struct aml_node aml_root; struct aml_value *aml_global_lock; struct acpi_softc *dsdt_softc; -struct aml_value *aml_parsenamed(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsenamedscope(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsemath(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsecompare(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parseif(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsewhile(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsebufpkg(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsemethod(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsesimple(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsefieldunit(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsebufferfield(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsemisc3(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsemuxaction(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsemisc2(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsematch(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parseref(struct aml_scope *, int, struct aml_value *); -struct aml_value *aml_parsestring(struct aml_scope *, int, struct aml_value *); - /* Perfect Hash key */ #define HASH_OFF 6904 #define HASH_SIZE 179 @@ -152,139 +139,139 @@ struct aml_value *aml_parsestring(struct aml_scope *, int, struct aml_value *); struct aml_opcode **aml_ophash; struct aml_opcode aml_table[] = { /* Simple types */ - { AMLOP_ZERO, "Zero", "c", aml_parsesimple }, - { AMLOP_ONE, "One", "c", aml_parsesimple }, - { AMLOP_ONES, "Ones", "c", aml_parsesimple }, - { AMLOP_REVISION, "Revision", "R", aml_parsesimple }, - { AMLOP_BYTEPREFIX, ".Byte", "b", aml_parsesimple }, - { AMLOP_WORDPREFIX, ".Word", "w", aml_parsesimple }, - { AMLOP_DWORDPREFIX, ".DWord", "d", aml_parsesimple }, - { AMLOP_QWORDPREFIX, ".QWord", "q", aml_parsesimple }, - { AMLOP_STRINGPREFIX, ".String", "a", aml_parsesimple }, - { AMLOP_DEBUG, "DebugOp", "D", aml_parsesimple }, - { AMLOP_BUFFER, "Buffer", "piB", aml_parsebufpkg }, - { AMLOP_PACKAGE, "Package", "pbT", aml_parsebufpkg }, - { AMLOP_VARPACKAGE, "VarPackage", "piT", aml_parsebufpkg }, + { AMLOP_ZERO, "Zero", "c", }, + { AMLOP_ONE, "One", "c", }, + { AMLOP_ONES, "Ones", "c", }, + { AMLOP_REVISION, "Revision", "R", }, + { AMLOP_BYTEPREFIX, ".Byte", "b", }, + { AMLOP_WORDPREFIX, ".Word", "w", }, + { AMLOP_DWORDPREFIX, ".DWord", "d", }, + { AMLOP_QWORDPREFIX, ".QWord", "q", }, + { AMLOP_STRINGPREFIX, ".String", "a", }, + { AMLOP_DEBUG, "DebugOp", "D", }, + { AMLOP_BUFFER, "Buffer", "piB", }, + { AMLOP_PACKAGE, "Package", "pbT", }, + { AMLOP_VARPACKAGE, "VarPackage", "piT", }, /* Simple objects */ - { AMLOP_LOCAL0, "Local0", "L", aml_parseref }, - { AMLOP_LOCAL1, "Local1", "L", aml_parseref }, - { AMLOP_LOCAL2, "Local2", "L", aml_parseref }, - { AMLOP_LOCAL3, "Local3", "L", aml_parseref }, - { AMLOP_LOCAL4, "Local4", "L", aml_parseref }, - { AMLOP_LOCAL5, "Local5", "L", aml_parseref }, - { AMLOP_LOCAL6, "Local6", "L", aml_parseref }, - { AMLOP_LOCAL7, "Local7", "L", aml_parseref }, - { AMLOP_ARG0, "Arg0", "A", aml_parseref }, - { AMLOP_ARG1, "Arg1", "A", aml_parseref }, - { AMLOP_ARG2, "Arg2", "A", aml_parseref }, - { AMLOP_ARG3, "Arg3", "A", aml_parseref }, - { AMLOP_ARG4, "Arg4", "A", aml_parseref }, - { AMLOP_ARG5, "Arg5", "A", aml_parseref }, - { AMLOP_ARG6, "Arg6", "A", aml_parseref }, + { AMLOP_LOCAL0, "Local0", "L", }, + { AMLOP_LOCAL1, "Local1", "L", }, + { AMLOP_LOCAL2, "Local2", "L", }, + { AMLOP_LOCAL3, "Local3", "L", }, + { AMLOP_LOCAL4, "Local4", "L", }, + { AMLOP_LOCAL5, "Local5", "L", }, + { AMLOP_LOCAL6, "Local6", "L", }, + { AMLOP_LOCAL7, "Local7", "L", }, + { AMLOP_ARG0, "Arg0", "A", }, + { AMLOP_ARG1, "Arg1", "A", }, + { AMLOP_ARG2, "Arg2", "A", }, + { AMLOP_ARG3, "Arg3", "A", }, + { AMLOP_ARG4, "Arg4", "A", }, + { AMLOP_ARG5, "Arg5", "A", }, + { AMLOP_ARG6, "Arg6", "A", }, /* Control flow */ - { AMLOP_IF, "If", "pI", aml_parseif }, + { AMLOP_IF, "If", "piI", }, { AMLOP_ELSE, "Else", "pT" }, - { AMLOP_WHILE, "While", "piT", aml_parsewhile }, + { AMLOP_WHILE, "While", "pW", }, { AMLOP_BREAK, "Break", "" }, { AMLOP_CONTINUE, "Continue", "" }, - { AMLOP_RETURN, "Return", "t", aml_parseref }, - { AMLOP_FATAL, "Fatal", "bdi", aml_parsemisc2 }, - { AMLOP_NOP, "Nop", "", aml_parsesimple }, - { AMLOP_BREAKPOINT, "BreakPoint", "", aml_parsesimple }, + { AMLOP_RETURN, "Return", "t", }, + { AMLOP_FATAL, "Fatal", "bdi", }, + { AMLOP_NOP, "Nop", "", }, + { AMLOP_BREAKPOINT, "BreakPoint", "", }, /* Arithmetic operations */ - { AMLOP_INCREMENT, "Increment", "t", aml_parsemath }, - { AMLOP_DECREMENT, "Decrement", "t", aml_parsemath }, - { AMLOP_ADD, "Add", "iir", aml_parsemath }, - { AMLOP_SUBTRACT, "Subtract", "iir", aml_parsemath }, - { AMLOP_MULTIPLY, "Multiply", "iir", aml_parsemath }, - { AMLOP_DIVIDE, "Divide", "iirr", aml_parsemath }, - { AMLOP_SHL, "ShiftLeft", "iir", aml_parsemath }, - { AMLOP_SHR, "ShiftRight", "iir", aml_parsemath }, - { AMLOP_AND, "And", "iir", aml_parsemath }, - { AMLOP_NAND, "Nand", "iir", aml_parsemath }, - { AMLOP_OR, "Or", "iir", aml_parsemath }, - { AMLOP_NOR, "Nor", "iir", aml_parsemath }, - { AMLOP_XOR, "Xor", "iir", aml_parsemath }, - { AMLOP_NOT, "Not", "ir", aml_parsemath }, - { AMLOP_MOD, "Mod", "iir", aml_parsemath }, - { AMLOP_FINDSETLEFTBIT, "FindSetLeftBit", "ir", aml_parsemath }, - { AMLOP_FINDSETRIGHTBIT,"FindSetRightBit", "ir",aml_parsemath }, + { AMLOP_INCREMENT, "Increment", "t", }, + { AMLOP_DECREMENT, "Decrement", "t", }, + { AMLOP_ADD, "Add", "iir", }, + { AMLOP_SUBTRACT, "Subtract", "iir", }, + { AMLOP_MULTIPLY, "Multiply", "iir", }, + { AMLOP_DIVIDE, "Divide", "iirr", }, + { AMLOP_SHL, "ShiftLeft", "iir", }, + { AMLOP_SHR, "ShiftRight", "iir", }, + { AMLOP_AND, "And", "iir", }, + { AMLOP_NAND, "Nand", "iir", }, + { AMLOP_OR, "Or", "iir", }, + { AMLOP_NOR, "Nor", "iir", }, + { AMLOP_XOR, "Xor", "iir", }, + { AMLOP_NOT, "Not", "ir", }, + { AMLOP_MOD, "Mod", "iir", }, + { AMLOP_FINDSETLEFTBIT, "FindSetLeftBit", "ir", }, + { AMLOP_FINDSETRIGHTBIT,"FindSetRightBit", "ir",}, /* Logical test operations */ - { AMLOP_LAND, "LAnd", "ii", aml_parsemath }, - { AMLOP_LOR, "LOr", "ii", aml_parsemath }, - { AMLOP_LNOT, "LNot", "i", aml_parsemath }, - { AMLOP_LNOTEQUAL, "LNotEqual", "tt", aml_parsecompare }, - { AMLOP_LLESSEQUAL, "LLessEqual", "tt", aml_parsecompare }, - { AMLOP_LGREATEREQUAL, "LGreaterEqual", "tt", aml_parsecompare }, - { AMLOP_LEQUAL, "LEqual", "tt", aml_parsecompare }, - { AMLOP_LGREATER, "LGreater", "tt", aml_parsecompare }, - { AMLOP_LLESS, "LLess", "tt", aml_parsecompare }, + { AMLOP_LAND, "LAnd", "ii", }, + { AMLOP_LOR, "LOr", "ii", }, + { AMLOP_LNOT, "LNot", "i", }, + { AMLOP_LNOTEQUAL, "LNotEqual", "tt", }, + { AMLOP_LLESSEQUAL, "LLessEqual", "tt", }, + { AMLOP_LGREATEREQUAL, "LGreaterEqual", "tt", }, + { AMLOP_LEQUAL, "LEqual", "tt", }, + { AMLOP_LGREATER, "LGreater", "tt", }, + { AMLOP_LLESS, "LLess", "tt", }, /* Named objects */ - { AMLOP_NAMECHAR, ".NameRef", "n", aml_parsesimple }, - { AMLOP_ALIAS, "Alias", "nN", aml_parsenamed }, - { AMLOP_NAME, "Name", "Nt", aml_parsenamed }, - { AMLOP_EVENT, "Event", "N", aml_parsenamed }, - { AMLOP_MUTEX, "Mutex", "Nb", aml_parsenamed }, - { AMLOP_DATAREGION, "DataRegion", "Nttt", aml_parsenamed }, - { AMLOP_OPREGION, "OpRegion", "Nbii", aml_parsenamed }, - { AMLOP_SCOPE, "Scope", "pNT", aml_parsenamedscope }, - { AMLOP_DEVICE, "Device", "pNT", aml_parsenamedscope }, - { AMLOP_POWERRSRC, "Power Resource", "pNbwT", aml_parsenamedscope }, - { AMLOP_THERMALZONE, "ThermalZone", "pNT", aml_parsenamedscope }, - { AMLOP_PROCESSOR, "Processor", "pNbdbT", aml_parsenamedscope }, - { AMLOP_METHOD, "Method", "pNfM", aml_parsemethod }, + { AMLOP_NAMECHAR, ".NameRef", "n", }, + { AMLOP_ALIAS, "Alias", "nN", }, + { AMLOP_NAME, "Name", "Nt", }, + { AMLOP_EVENT, "Event", "N", }, + { AMLOP_MUTEX, "Mutex", "Nb", }, + { AMLOP_DATAREGION, "DataRegion", "Nttt", }, + { AMLOP_OPREGION, "OpRegion", "Nbii", }, + { AMLOP_SCOPE, "Scope", "pNT", }, + { AMLOP_DEVICE, "Device", "pNT", }, + { AMLOP_POWERRSRC, "Power Resource", "pNbwT",}, + { AMLOP_THERMALZONE, "ThermalZone", "pNT", }, + { AMLOP_PROCESSOR, "Processor", "pNbdbT", }, + { AMLOP_METHOD, "Method", "pNbM", }, /* Field operations */ - { AMLOP_FIELD, "Field", "pnfF", aml_parsefieldunit }, - { AMLOP_INDEXFIELD, "IndexField", "pntfF", aml_parsefieldunit }, - { AMLOP_BANKFIELD, "BankField", "pnnifF", aml_parsefieldunit }, - { AMLOP_CREATEFIELD, "CreateField", "tiiN", aml_parsebufferfield }, - { AMLOP_CREATEQWORDFIELD, "CreateQWordField","tiN", aml_parsebufferfield }, - { AMLOP_CREATEDWORDFIELD, "CreateDWordField","tiN", aml_parsebufferfield }, - { AMLOP_CREATEWORDFIELD, "CreateWordField", "tiN", aml_parsebufferfield }, - { AMLOP_CREATEBYTEFIELD, "CreateByteField", "tiN", aml_parsebufferfield }, - { AMLOP_CREATEBITFIELD, "CreateBitField", "tiN", aml_parsebufferfield }, + { AMLOP_FIELD, "Field", "pnbF", }, + { AMLOP_INDEXFIELD, "IndexField", "pnnbF",}, + { AMLOP_BANKFIELD, "BankField", "pnnibF",}, + { AMLOP_CREATEFIELD, "CreateField", "tiiN", }, + { AMLOP_CREATEQWORDFIELD, "CreateQWordField","tiN",}, + { AMLOP_CREATEDWORDFIELD, "CreateDWordField","tiN",}, + { AMLOP_CREATEWORDFIELD, "CreateWordField", "tiN",}, + { AMLOP_CREATEBYTEFIELD, "CreateByteField", "tiN",}, + { AMLOP_CREATEBITFIELD, "CreateBitField", "tiN", }, /* Conversion operations */ - { AMLOP_TOINTEGER, "ToInteger", "tr", aml_parsemath }, + { AMLOP_TOINTEGER, "ToInteger", "tr", }, { AMLOP_TOBUFFER, "ToBuffer", "tr", }, - { AMLOP_TODECSTRING, "ToDecString", "ir", aml_parsestring }, - { AMLOP_TOHEXSTRING, "ToHexString", "ir", aml_parsestring }, - { AMLOP_TOSTRING, "ToString", "t", aml_parsestring }, - { AMLOP_MID, "Mid", "tiir", aml_parsestring }, - { AMLOP_FROMBCD, "FromBCD", "ir", aml_parsemath }, - { AMLOP_TOBCD, "ToBCD", "ir", aml_parsemath }, + { AMLOP_TODECSTRING, "ToDecString", "ir", }, + { AMLOP_TOHEXSTRING, "ToHexString", "ir", }, + { AMLOP_TOSTRING, "ToString", "tir", }, + { AMLOP_MID, "Mid", "tiir", }, + { AMLOP_FROMBCD, "FromBCD", "ir", }, + { AMLOP_TOBCD, "ToBCD", "ir", }, /* Mutex/Signal operations */ - { AMLOP_ACQUIRE, "Acquire", "tw", aml_parsemuxaction }, - { AMLOP_RELEASE, "Release", "t", aml_parsemuxaction }, - { AMLOP_SIGNAL, "Signal", "t", aml_parsemuxaction }, - { AMLOP_WAIT, "Wait", "ti", aml_parsemuxaction }, - { AMLOP_RESET, "Reset", "t", aml_parsemuxaction }, + { AMLOP_ACQUIRE, "Acquire", "Sw", }, + { AMLOP_RELEASE, "Release", "S", }, + { AMLOP_SIGNAL, "Signal", "S", }, + { AMLOP_WAIT, "Wait", "Si", }, + { AMLOP_RESET, "Reset", "S", }, - { AMLOP_INDEX, "Index", "tir", aml_parseref }, - { AMLOP_DEREFOF, "DerefOf", "t", aml_parseref }, - { AMLOP_REFOF, "RefOf", "t", aml_parseref }, - { AMLOP_CONDREFOF, "CondRef", "nr", aml_parseref }, + { AMLOP_INDEX, "Index", "tir", }, + { AMLOP_DEREFOF, "DerefOf", "t", }, + { AMLOP_REFOF, "RefOf", "S", }, + { AMLOP_CONDREFOF, "CondRef", "SS", }, { AMLOP_LOADTABLE, "LoadTable", "tttttt" }, - { AMLOP_STALL, "Stall", "i", aml_parsemisc2 }, - { AMLOP_SLEEP, "Sleep", "i", aml_parsemisc2 }, - { AMLOP_LOAD, "Load", "nt", aml_parseref }, + { AMLOP_STALL, "Stall", "i", }, + { AMLOP_SLEEP, "Sleep", "i", }, + { AMLOP_LOAD, "Load", "nS", }, { AMLOP_UNLOAD, "Unload", "t" }, - { AMLOP_STORE, "Store", "tr", aml_parseref }, - { AMLOP_CONCAT, "Concat", "ttr", aml_parsestring }, + { AMLOP_STORE, "Store", "tS", }, + { AMLOP_CONCAT, "Concat", "ttr", }, { AMLOP_CONCATRES, "ConcatRes", "ttt" }, - { AMLOP_NOTIFY, "Notify", "ti", aml_parsemisc2 }, - { AMLOP_SIZEOF, "Sizeof", "t", aml_parsemisc3 }, - { AMLOP_MATCH, "Match", "tbibii", aml_parsematch }, - { AMLOP_OBJECTTYPE, "ObjectType", "t", aml_parsemisc3 }, - { AMLOP_COPYOBJECT, "CopyObject", "tr", aml_parseref }, + { AMLOP_NOTIFY, "Notify", "Si", }, + { AMLOP_SIZEOF, "Sizeof", "S", }, + { AMLOP_MATCH, "Match", "tbibii", }, + { AMLOP_OBJECTTYPE, "ObjectType", "S", }, + { AMLOP_COPYOBJECT, "CopyObject", "tS", }, }; int aml_pc(uint8_t *src) @@ -467,77 +454,11 @@ acpi_stall(int us) delay(us); } -int -acpi_mutex_acquire(struct aml_value *val, int timeout) -{ - /* XXX we currently do not have concurrency so assume mutex succeeds */ - dnprintf(50, "acpi_mutex_acquire\n"); - - return (0); -#if 0 - struct acpi_mutex *mtx = val->v_mutex; - int rv = 0, ts, tries = 0; - - if (val->type != AML_OBJTYPE_MUTEX) { - printf("acpi_mutex_acquire: invalid mutex\n"); - return (1); - } - - if (timeout == 0xffff) - timeout = 0; - - /* lock recursion be damned, panic if that happens */ - rw_enter_write(&mtx->amt_lock); - while (mtx->amt_ref_count) { - rw_exit_write(&mtx->amt_lock); - /* block access */ - ts = tsleep(mtx, PWAIT, mtx->amt_name, timeout / hz); - if (ts == EWOULDBLOCK) { - rv = 1; /* mutex not acquired */ - goto done; - } - tries++; - rw_enter_write(&mtx->amt_lock); - } - - mtx->amt_ref_count++; - rw_exit_write(&mtx->amt_lock); -done: - return (rv); -#endif -} - -void -acpi_mutex_release(struct aml_value *val) -{ - dnprintf(50, "acpi_mutex_release\n"); -#if 0 - struct acpi_mutex *mtx = val->v_mutex; - - /* sanity */ - if (val->type != AML_OBJTYPE_MUTEX) { - printf("acpi_mutex_acquire: invalid mutex\n"); - return; - } - - rw_enter_write(&mtx->amt_lock); - - if (mtx->amt_ref_count == 0) { - printf("acpi_mutex_release underflow %s\n", mtx->amt_name); - goto done; - } - - mtx->amt_ref_count--; - wakeup(mtx); /* wake all of them up */ -done: - rw_exit_write(&mtx->amt_lock); -#endif -} - /* * @@@: Misc utility functions */ +#ifdef ACPI_DEBUG void aml_dump(int len, u_int8_t *buf) { @@ -549,6 +470,7 @@ aml_dump(int len, u_int8_t *buf) } dnprintf(50, " }\n"); } +#endif /* Bit mangling code */ int @@ -570,27 +492,6 @@ aml_setbit(u_int8_t *pb, int bit, int val) *pb &= ~aml_bitmask(bit); } -/* Read/Write to hardware I/O fields */ -void -aml_gasio(struct acpi_softc *sc, int type, uint64_t base, uint64_t length, - int bitpos, int bitlen, int size, void *buf, int mode) -{ - dnprintf(10, "-- aml_gasio: %.2x" - " base:%llx len:%llx bpos:%.4x blen:%.4x sz:%.2x mode=%s\n", - type, base, length, bitpos, bitlen, size, - mode==ACPI_IOREAD?"read":"write"); - acpi_gasio(sc, mode, type, base+(bitpos>>3), - (size>>3), (bitlen>>3), buf); -#ifdef ACPI_DEBUG - while (bitlen > 0) { - dnprintf(10, "%.2x ", *(uint8_t *)buf); - buf++; - bitlen -=8; - } - dnprintf(10, "\n"); -#endif -} - /* * @@@: Notify functions */ @@ -668,21 +569,40 @@ void acpi_poll_notify(void) * @@@: Namespace functions */ -struct aml_node *__aml_search(struct aml_node *, uint8_t *); +struct aml_node *__aml_search(struct aml_node *, uint8_t *, int); void aml_delchildren(struct aml_node *); /* Search for a name in children nodes */ struct aml_node * -__aml_search(struct aml_node *root, uint8_t *nameseg) +__aml_search(struct aml_node *root, uint8_t *nameseg, int create) { + struct aml_node **sp, *node; + + /* XXX: Replace with SLIST/SIMPLEQ routines */ if (root == NULL) return NULL; - for (root = root->child; root; root = root->sibling) { - if (!memcmp(root->name, nameseg, AML_NAMESEG_LEN)) - return root; + //rw_enter_read(&aml_nslock); + for (sp = &root->child; *sp; sp = &(*sp)->sibling) { + if (!strncmp((*sp)->name, nameseg, AML_NAMESEG_LEN)) { + //rw_exit_read(&aml_nslock); + return *sp; } - return NULL; + } + //rw_exit_read(&aml_nslock); + if (create) { + node = acpi_os_malloc(sizeof(struct aml_node)); + memcpy((void *)node->name, nameseg, AML_NAMESEG_LEN); + node->value = aml_allocvalue(0,0,NULL); + node->value->node = node; + node->parent = root; + node->sibling = NULL; + + //rw_enter_write(&aml_nslock); + *sp = node; + //rw_exit_write(&aml_nslock); + } + return *sp; } /* Get absolute pathname of AML node */ @@ -772,7 +692,7 @@ aml_createname(struct aml_node *root, const void *vname, struct aml_value *value node = NULL; while (count-- && root) { /* Create new name if it does not exist */ - if ((node = __aml_search(root, name)) == NULL) { + if ((node = __aml_search(root, name, 0)) == NULL) { node = acpi_os_malloc(sizeof(struct aml_node)); memcpy((void *)node->name, name, AML_NAMESEG_LEN); @@ -793,57 +713,6 @@ aml_createname(struct aml_node *root, const void *vname, struct aml_value *value return node; } -/* Search namespace for a named node */ -struct aml_node * -aml_searchname(struct aml_node *root, const void *vname) -{ - struct aml_node *node; - uint8_t *name = (uint8_t *)vname; - int count; - - if (*name == AMLOP_ROOTCHAR) { - root = &aml_root; - name++; - } - while (*name == AMLOP_PARENTPREFIX && root) { - root = root->parent; - name++; - } - if (strlen(name) < AML_NAMESEG_LEN) { - aml_die("bad name"); - } - switch (*name) { - case 0x00: - return root; - case AMLOP_MULTINAMEPREFIX: - count = name[1]; - name += 2; - break; - case AMLOP_DUALNAMEPREFIX: - count = 2; - name += 1; - break; - default: - if (name[4] == '.') { - /* Called from user code */ - while (*name && (root = __aml_search(root, name)) != NULL) { - name += AML_NAMESEG_LEN+1; - } - return root; - } - /* Special case.. search relative for name */ - while (root && (node = __aml_search(root, name)) == NULL) { - root = root->parent; - } - return node; - } - /* Search absolute for name*/ - while (count-- && (root = __aml_search(root, name)) != NULL) { - name += AML_NAMESEG_LEN; - } - return root; -} - /* Free all children nodes/values */ void aml_delchildren(struct aml_node *node) @@ -869,39 +738,15 @@ aml_delchildren(struct aml_node *node) * @@@: Value functions */ -struct aml_value *aml_alloctmp(struct aml_scope *, int); struct aml_scope *aml_pushscope(struct aml_scope *, uint8_t *, uint8_t *, struct aml_node *); struct aml_scope *aml_popscope(struct aml_scope *); -int aml_parsenode(struct aml_scope *, struct aml_node *, - uint8_t *, uint8_t **, struct aml_value *); #define AML_LHS 0 #define AML_RHS 1 #define AML_DST 2 #define AML_DST2 3 -/* Allocate temporary storage in this scope */ -struct aml_value * -aml_alloctmp(struct aml_scope *scope, int narg) -{ - struct aml_vallist *tmp; - - /* Allocate array of temp values */ - tmp = (struct aml_vallist *)acpi_os_malloc(sizeof(struct aml_vallist) + - narg * sizeof(struct aml_value)); - - tmp->obj = (struct aml_value *)&tmp[1]; - tmp->nobj = narg; - - /* Link into scope */ - tmp->next = scope->tmpvals; - scope->tmpvals = tmp; - - /* Return array of values */ - return tmp->obj; -} - /* Allocate+push parser scope */ struct aml_scope * aml_pushscope(struct aml_scope *parent, uint8_t *start, uint8_t *end, @@ -947,94 +792,17 @@ aml_popscope(struct aml_scope *scope) return nscope; } -int -aml_parsenode(struct aml_scope *parent, struct aml_node *node, uint8_t *start, - uint8_t **end, struct aml_value *res) -{ - struct aml_scope *scope; - - /* Don't parse zero-length scope */ - if (start == *end) - return 0; - scope = aml_pushscope(parent, start, *end, node); - if (res == NULL) - res = aml_alloctmp(scope, 1); - while (scope != parent) { - while (scope->pos < scope->end) - aml_parseop(scope, res, 't'); - scope = aml_popscope(scope); - } - return 0; -} - /* * Field I/O code */ -void aml_setbufint(struct aml_value *, int, int, struct aml_value *); -void aml_getbufint(struct aml_value *, int, int, struct aml_value *); -void aml_fieldio(struct aml_scope *, struct aml_value *, struct aml_value *, int); void aml_unlockfield(struct aml_scope *, struct aml_value *); void aml_lockfield(struct aml_scope *, struct aml_value *); -/* Copy from a bufferfield to an integer/buffer */ -void -aml_setbufint(struct aml_value *dst, int bitpos, int bitlen, - struct aml_value *src) -{ - if (src->type != AML_OBJTYPE_BUFFER) { -#ifndef SMALL_KERNEL - aml_showvalue(src, 0); -#endif - aml_die("wrong setbufint type %d\n", src->type); - } -#if 1 - /* Return buffer type */ - _aml_setvalue(dst, AML_OBJTYPE_BUFFER, (bitlen+7)>>3, NULL); - aml_bufcpy(dst->v_buffer, 0, src->v_buffer, bitpos, bitlen); -#else - if (bitlen < aml_intlen) { - /* XXX: Endian issues?? */ - /* Return integer type */ - _aml_setvalue(dst, AML_OBJTYPE_INTEGER, 0, NULL); - aml_bufcpy(&dst->v_integer, 0, src->v_buffer, bitpos, bitlen); - } else { - /* Return buffer type */ - _aml_setvalue(dst, AML_OBJTYPE_BUFFER, (bitlen+7)>>3, NULL); - aml_bufcpy(dst->v_buffer, 0, src->v_buffer, bitpos, bitlen); - } -#endif -} - -/* Copy from a string/integer/buffer to a bufferfield */ -void -aml_getbufint(struct aml_value *src, int bitpos, int bitlen, - struct aml_value *dst) -{ - if (dst->type != AML_OBJTYPE_BUFFER) - aml_die("wrong getbufint type %d\n", src->type); - switch (src->type) { - case AML_OBJTYPE_INTEGER: - if (bitlen >= aml_intlen) - bitlen = aml_intlen; - aml_bufcpy(dst->v_buffer, bitpos, &src->v_integer, 0, bitlen); - break; - case AML_OBJTYPE_BUFFER: - if (bitlen >= 8*src->length) - bitlen = 8*src->length; - aml_bufcpy(dst->v_buffer, bitpos, src->v_buffer, 0, bitlen); - break; - case AML_OBJTYPE_STRING: - if (bitlen >= 8*src->length) - bitlen = 8*src->length; - aml_bufcpy(dst->v_buffer, bitpos, src->v_string, 0, bitlen); - break; - } -} - long acpi_acquire_global_lock(void*); long acpi_release_global_lock(void*); static long global_lock_count = 0; - +#define acpi_acquire_global_lock(x) 1 +#define acpi_release_global_lock(x) 0 void aml_lockfield(struct aml_scope *scope, struct aml_value *field) { @@ -1081,219 +849,10 @@ aml_unlockfield(struct aml_scope *scope, struct aml_value *field) return; } -void *aml_getbuffer(struct aml_value *, int *); - -void * -aml_getbuffer(struct aml_value *val, int *bitlen) -{ - switch (val->type) { - case AML_OBJTYPE_INTEGER: - case AML_OBJTYPE_STATICINT: - *bitlen = aml_intlen; - return (&val->v_integer); - - case AML_OBJTYPE_BUFFER: - case AML_OBJTYPE_STRING: - *bitlen = val->length<<3; - return (val->v_buffer); - - default: - aml_die("getvbi"); - } - - return (NULL); -} - -/* - * Buffer/Region: read/write to bitfields - */ -void -aml_fieldio(struct aml_scope *scope, struct aml_value *field, - struct aml_value *res, int mode) -{ - struct aml_value *pop, tf; - int bpos, blen, aligned, mask; - void *iobuf, *iobuf2; - uint64_t iobase; - - pop = field->v_field.ref1; - bpos = field->v_field.bitpos; - blen = field->v_field.bitlen; - - dnprintf(55,"--fieldio: %s [%s] bp:%.4x bl:%.4x\n", - mode == ACPI_IOREAD ? "rd" : "wr", - aml_nodename(field->node), bpos, blen); - - aml_lockfield(scope, field); - switch (field->v_field.type) { - case AMLOP_INDEXFIELD: - /* Set Index */ - memcpy(&tf, field->v_field.ref2, sizeof(struct aml_value)); - tf.v_field.bitpos += (bpos & 7); - tf.v_field.bitlen = blen; - - aml_setvalue(scope, pop, NULL, bpos>>3); - aml_fieldio(scope, &tf, res, mode); -#ifdef ACPI_DEBUG - dnprintf(55, "-- post indexfield %x,%x @ %x,%x\n", - bpos & 3, blen, - field->v_field.ref2->v_field.bitpos, - field->v_field.ref2->v_field.bitlen); - - iobuf = aml_getbuffer(res, &aligned); - aml_dump(aligned >> 3, iobuf); -#endif - break; - case AMLOP_BANKFIELD: - /* Set Bank */ - memcpy(&tf, field->v_field.ref2, sizeof(struct aml_value)); - tf.v_field.bitpos += (bpos & 7); - tf.v_field.bitlen = blen; - - aml_setvalue(scope, pop, NULL, field->v_field.ref3); - aml_fieldio(scope, &tf, res, mode); -#ifdef ACPI_DEBUG - dnprintf(55, "-- post bankfield %x,%x @ %x,%x\n", - bpos & 3, blen, - field->v_field.ref2->v_field.bitpos, - field->v_field.ref2->v_field.bitlen); - - iobuf = aml_getbuffer(res, &aligned); - aml_dump(aligned >> 3, iobuf); -#endif - break; - case AMLOP_FIELD: - /* This is an I/O field */ - if (pop->type != AML_OBJTYPE_OPREGION) - aml_die("Not an opregion\n"); - - /* Get field access size */ - switch (AML_FIELD_ACCESS(field->v_field.flags)) { - case AML_FIELD_ANYACC: - case AML_FIELD_BYTEACC: - mask = 7; - break; - case AML_FIELD_WORDACC: - mask = 15; - break; - case AML_FIELD_DWORDACC: - mask = 31; - break; - case AML_FIELD_QWORDACC: - mask = 63; - break; - } - - /* Pre-allocate return value for reads */ - if (mode == ACPI_IOREAD) - _aml_setvalue(res, AML_OBJTYPE_BUFFER, - (field->v_field.bitlen+7)>>3, NULL); - - /* Get aligned bitpos/bitlength */ - blen = ((bpos & mask) + blen + mask) & ~mask; - bpos = bpos & ~mask; - aligned = (bpos == field->v_field.bitpos && - blen == field->v_field.bitlen); - iobase = pop->v_opregion.iobase; - - /* Check for aligned reads/writes */ - if (aligned) { - iobuf = aml_getbuffer(res, &aligned); - aml_gasio(scope->sc, pop->v_opregion.iospace, - iobase, pop->v_opregion.iolen, bpos, blen, - mask + 1, iobuf, mode); -#ifdef ACPI_DEBUG - dnprintf(55, "aligned: %s @ %.4x:%.4x + %.4x\n", - mode == ACPI_IOREAD ? "rd" : "wr", - bpos, blen, aligned); - - aml_dump(blen >> 3, iobuf); -#endif - } - else if (mode == ACPI_IOREAD) { - iobuf = acpi_os_malloc(blen>>3); - aml_gasio(scope->sc, pop->v_opregion.iospace, - iobase, pop->v_opregion.iolen, bpos, blen, - mask + 1, iobuf, mode); - - /* ASSERT: res is buffer type as it was set above */ - aml_bufcpy(res->v_buffer, 0, iobuf, - field->v_field.bitpos & mask, - field->v_field.bitlen); - -#ifdef ACPI_DEBUG - dnprintf(55,"non-aligned read: %.4x:%.4x : ", - field->v_field.bitpos & mask, - field->v_field.bitlen); - - aml_dump(blen >> 3, iobuf); - dnprintf(55,"post-read: "); - aml_dump((field->v_field.bitlen+7)>>3, res->v_buffer); -#endif - acpi_os_free(iobuf); - } - else { - iobuf = acpi_os_malloc(blen >> 3); - switch (AML_FIELD_UPDATE(field->v_field.flags)) { - case AML_FIELD_WRITEASONES: - memset(iobuf, 0xFF, blen >> 3); - break; - case AML_FIELD_PRESERVE: - aml_gasio(scope->sc, pop->v_opregion.iospace, - iobase, pop->v_opregion.iolen, bpos, blen, - mask + 1, iobuf, ACPI_IOREAD); - break; - } - /* Copy into IOBUF */ - iobuf2 = aml_getbuffer(res, &aligned); - aml_bufcpy(iobuf, field->v_field.bitpos & mask, - iobuf2, 0, field->v_field.bitlen); - -#ifdef ACPI_DEBUG - dnprintf(55,"non-aligned write: %.4x:%.4x : ", - field->v_field.bitpos & mask, - field->v_field.bitlen); - - aml_dump(blen >> 3, iobuf); -#endif - aml_gasio(scope->sc, pop->v_opregion.iospace, - iobase, pop->v_opregion.iolen, bpos, blen, - mask + 1, iobuf, mode); - - acpi_os_free(iobuf); - } - /* Verify that I/O is in range */ -#if 0 - /* - * XXX: some I/O ranges are on dword boundaries, but their - * length is incorrect eg. dword access, but length of - * opregion is 2 bytes. - */ - if ((bpos+blen) >= (pop->v_opregion.iolen * 8)) { - aml_die("Out of bounds I/O!!! region:%x:%llx:%x %x\n", - pop->v_opregion.iospace, pop->v_opregion.iobase, - pop->v_opregion.iolen, bpos+blen); - } -#endif - break; - default: - /* This is a buffer field */ - if (mode == ACPI_IOREAD) - aml_setbufint(res, bpos, blen, pop); - else - aml_getbufint(res, bpos, blen, pop); - break; - } - aml_unlockfield(scope, field); -} - /* * @@@: Value set/compare/alloc/free routines */ int64_t aml_str2int(const char *, int); -struct aml_value *aml_derefvalue(struct aml_scope *, struct aml_value *, int); -#define aml_dereftarget(s, v) aml_derefvalue(s, v, ACPI_IOWRITE) -#define aml_derefterm(s, v, m) aml_derefvalue(s, v, ACPI_IOREAD) #ifndef SMALL_KERNEL void @@ -1335,8 +894,10 @@ aml_showvalue(struct aml_value *val, int lvl) val->v_field.bitpos, val->v_field.bitlen, val->v_field.ref1, val->v_field.ref2, aml_mnem(val->v_field.type, NULL)); - aml_showvalue(val->v_field.ref1, lvl); - aml_showvalue(val->v_field.ref2, lvl); + if (val->v_field.ref1) + printf(" ref1: %s\n", aml_nodename(val->v_field.ref1->node)); + if (val->v_field.ref2) + printf(" ref2: %s\n", aml_nodename(val->v_field.ref2->node)); break; case AML_OBJTYPE_MUTEX: printf(" mutex: %s ref: %d\n", @@ -1370,8 +931,8 @@ aml_showvalue(struct aml_value *val, int lvl) val->v_powerrsrc.pwr_level, val->v_powerrsrc.pwr_order); break; case AML_OBJTYPE_OBJREF: - printf(" objref: %p index:%x\n", val->v_objref.ref, - val->v_objref.index); + printf(" objref: %p index:%x opcode:%s\n", val->v_objref.ref, + val->v_objref.index, aml_mnem(val->v_objref.type, 0)); aml_showvalue(val->v_objref.ref, lvl); break; default: @@ -1380,105 +941,11 @@ aml_showvalue(struct aml_value *val, int lvl) } #endif /* SMALL_KERNEL */ -/* Perform DeRef on value. If ACPI_IOREAD, will perform buffer/IO field read */ -struct aml_value * -aml_derefvalue(struct aml_scope *scope, struct aml_value *ref, int mode) -{ - struct aml_node *node; - struct aml_value *tmp; - int64_t tmpint; - int argc, index; - - for (;;) { - switch (ref->type) { - case AML_OBJTYPE_NAMEREF: - node = aml_searchname(scope->node, ref->v_nameref); - if (node == NULL || node->value == NULL) - return ref; - ref = node->value; - break; - - case AML_OBJTYPE_OBJREF: - index = ref->v_objref.index; - ref = aml_dereftarget(scope, ref->v_objref.ref); - if (index != -1) { - if (index >= ref->length) - aml_die("index.buf out of bounds: " - "%d/%d\n", index, ref->length); - switch (ref->type) { - case AML_OBJTYPE_PACKAGE: - ref = ref->v_package[index]; - break; - case AML_OBJTYPE_STATICINT: - case AML_OBJTYPE_INTEGER: - /* Convert to temporary buffer */ - if (ref->node) - aml_die("named integer index\n"); - tmpint = ref->v_integer; - _aml_setvalue(ref, AML_OBJTYPE_BUFFER, - aml_intlen>>3, &tmpint); - /* FALLTHROUGH */ - case AML_OBJTYPE_BUFFER: - case AML_OBJTYPE_STRING: - /* Return contents at this index */ - tmp = aml_alloctmp(scope, 1); - if (mode == ACPI_IOREAD) { - /* Shortcut: return integer - * contents of buffer at index */ - _aml_setvalue(tmp, - AML_OBJTYPE_INTEGER, - ref->v_buffer[index], NULL); - } else { - _aml_setvalue(tmp, - AML_OBJTYPE_BUFFERFIELD, - 0, NULL); - tmp->v_field.type = - AMLOP_CREATEBYTEFIELD; - tmp->v_field.bitpos = index * 8; - tmp->v_field.bitlen = 8; - tmp->v_field.ref1 = ref; - aml_addref(ref); - } - return tmp; - default: - aml_die("unknown index type: %d", ref->type); - break; - } - } - break; - - case AML_OBJTYPE_METHOD: - /* Read arguments from current scope */ - argc = AML_METHOD_ARGCOUNT(ref->v_method.flags); - tmp = aml_alloctmp(scope, argc+1); - for (index = 0; index < argc; index++) { - aml_parseop(scope, &tmp[index], 't'); - aml_addref(&tmp[index]); - } - ref = aml_evalmethod(scope, ref->node, argc, tmp, &tmp[argc]); - break; - - case AML_OBJTYPE_BUFFERFIELD: - case AML_OBJTYPE_FIELDUNIT: - if (mode == ACPI_IOREAD) { - /* Read I/O field into temporary storage */ - tmp = aml_alloctmp(scope, 1); - aml_fieldio(scope, ref, tmp, ACPI_IOREAD); - return tmp; - } - return ref; - - default: - return ref; - } - - } -} - int64_t aml_str2int(const char *str, int radix) { /* XXX: fixme */ + aml_die("aml_str2int not implemented\n"); return 0; } @@ -1612,132 +1079,6 @@ aml_copyvalue(struct aml_value *lhs, struct aml_value *rhs) } } -int is_local(struct aml_scope *, struct aml_value *); - -int -is_local(struct aml_scope *scope, struct aml_value *val) -{ - int idx; - - if (val->stack == 0 || scope->locals == NULL) - return (0); - - idx = val->stack - AMLOP_LOCAL0; - if (idx < 0 || idx >= AML_MAX_LOCAL) - aml_die("Invalid stack value!"); - - return (val == &scope->locals[idx]); -} - -/* Guts of the code: Assign one value to another. LHS may contain a previous value */ -void -aml_setvalue(struct aml_scope *scope, struct aml_value *lhs, - struct aml_value *rhs, int64_t ival) -{ - struct aml_value tmpint; - - /* Use integer as result */ - memset(&tmpint, 0, sizeof(tmpint)); - if (rhs == NULL) { - rhs = _aml_setvalue(&tmpint, AML_OBJTYPE_INTEGER, ival, NULL); - } - else if (rhs->type == AML_OBJTYPE_BUFFERFIELD || - rhs->type == AML_OBJTYPE_FIELDUNIT) - { - aml_fieldio(scope, rhs, &tmpint, ACPI_IOREAD); - rhs = &tmpint; - } - - if (!is_local(scope, lhs)) - lhs = aml_dereftarget(scope, lhs); - - if (is_local(scope, lhs)) { - /* ACPI: Overwrite writing to LocalX */ - aml_freevalue(lhs); - } - - switch (lhs->type) { - case AML_OBJTYPE_UNINITIALIZED: - aml_copyvalue(lhs, rhs); - break; - case AML_OBJTYPE_BUFFERFIELD: - case AML_OBJTYPE_FIELDUNIT: - aml_fieldio(scope, lhs, rhs, ACPI_IOWRITE); - break; - case AML_OBJTYPE_DEBUGOBJ: -#ifdef ACPI_DEBUG - printf("-- debug --\n"); - aml_showvalue(rhs, 50); -#endif - break; - case AML_OBJTYPE_STATICINT: - if (lhs->node) { - lhs->v_integer = aml_val2int(rhs); - } - break; - case AML_OBJTYPE_INTEGER: - lhs->v_integer = aml_val2int(rhs); - break; - case AML_OBJTYPE_BUFFER: - { - char *buf; - int len; - - if (lhs->node) - dnprintf(40, "named.buffer\n"); - - if (rhs->type == AML_OBJTYPE_BUFFER) { - buf = rhs->v_buffer; - len = rhs->length; - } else if (rhs->type == AML_OBJTYPE_INTEGER || - rhs->type == AML_OBJTYPE_STATICINT) { - buf = (char *)&rhs->v_integer; - len = sizeof(rhs->v_integer); - } else if (rhs->type == AML_OBJTYPE_STRING) { - len = rhs->length + 1; - buf = rhs->v_string; - } else { - /* aml_showvalue(rhs); */ - aml_die("setvalue.buf : %x", aml_pc(scope->pos)); - } - if (lhs->length < len) - len = lhs->length; - else - memset(lhs->v_buffer, 0, lhs->length); - memcpy(lhs->v_buffer, buf, len); - /* XXX ACPI v30b 17.2.5.7 says truncate string "before - copying", so make sure the string is terminated */ - if (rhs->type == AML_OBJTYPE_STRING) - lhs->v_buffer[lhs->length - 1] = '\0'; - break; - } - case AML_OBJTYPE_STRING: - if (lhs->node) - dnprintf(40, "named string\n"); - aml_freevalue(lhs); - if (rhs->type == AML_OBJTYPE_STRING) - _aml_setvalue(lhs, AML_OBJTYPE_STRING, rhs->length, - rhs->v_string); - else if (rhs->type == AML_OBJTYPE_BUFFER) - _aml_setvalue(lhs, AML_OBJTYPE_STRING, rhs->length, - rhs->v_buffer); - else if (rhs->type == AML_OBJTYPE_INTEGER || rhs->type == AML_OBJTYPE_STATICINT) { - _aml_setvalue(lhs, AML_OBJTYPE_STRING, 10, NULL); - snprintf(lhs->v_string, lhs->length, "%lld", - rhs->v_integer); - } else { - /* aml_showvalue(rhs); */ - aml_die("setvalue.str"); - } - break; - default: - /* XXX: */ - dnprintf(10, "setvalue.unknown: %x", lhs->type); - break; - } - aml_freevalue(&tmpint); -} - /* Allocate dynamic AML value * type : Type of object to allocate (AML_OBJTYPE_XXXX) * ival : Integer value (action depends on type) @@ -1963,12 +1304,13 @@ aml_evalexpr(int64_t lhs, int64_t rhs, int opcode) break; } - dnprintf(50,"aml_evalexpr: %s %llx %llx = %llx\n", + dnprintf(15,"aml_evalexpr: %s %llx %llx = %llx\n", aml_mnem(opcode, NULL), lhs, rhs, res); return res; } +#if 0 int aml_cmpvalue(struct aml_value *lhs, struct aml_value *rhs, int opcode) { @@ -2005,6 +1347,7 @@ aml_cmpvalue(struct aml_value *lhs, struct aml_value *rhs, int opcode) } return aml_evalexpr(rc, 0, opcode); } +#endif /* * aml_bufcpy copies/shifts buffer data, special case for aligned transfers @@ -2029,137 +1372,12 @@ aml_bufcpy(void *pvDst, int dstPos, const void *pvSrc, int srcPos, int len) aml_setbit(pDst, idx + dstPos, aml_tstbit(pSrc, idx + srcPos)); } -struct aml_value * -aml_callmethod(struct aml_scope *scope, struct aml_value *val) -{ - while (scope->pos < scope->end) - aml_parseterm(scope, val); - return val; -} - -/* - * Evaluate an AML method - * - * Returns a copy of the result in res (must be freed by user) - */ -struct aml_value * -aml_evalmethod(struct aml_scope *parent, struct aml_node *node, - int argc, struct aml_value *argv, struct aml_value *res) -{ - struct aml_scope *scope; - - scope = aml_pushscope(parent, node->value->v_method.start, - node->value->v_method.end, node); - scope->args = argv; - scope->nargs = argc; - - if (res == NULL) - res = aml_alloctmp(scope, 1); - -#ifdef ACPI_DEBUG - dnprintf(10, "calling [%s] (%d args)\n", - aml_nodename(node), scope->nargs); - for (argc = 0; argc < scope->nargs; argc++) { - dnprintf(10, " arg%d: ", argc); - aml_showvalue(&scope->args[argc], 10); - } - node->value->v_method.fneval(scope, res); - dnprintf(10, "[%s] returns: ", aml_nodename(node)); - aml_showvalue(res, 10); -#else - node->value->v_method.fneval(scope, res); -#endif - /* Free any temporary children nodes */ - aml_delchildren(node); - aml_popscope(scope); - - return res; -} - /* * @@@: External API * * evaluate an AML node * Returns a copy of the value in res (must be freed by user) */ -int -aml_evalnode(struct acpi_softc *sc, struct aml_node *node, - int argc, struct aml_value *argv, struct aml_value *res) -{ - static int lastck; - struct aml_node *ref; - - if (res) - memset(res, 0, sizeof(struct aml_value)); - if (node == NULL || node->value == NULL) - return (ACPI_E_BADVALUE); - - switch (node->value->type) { - case AML_OBJTYPE_METHOD: - aml_evalmethod(NULL, node, argc, argv, res); - if (acpi_nalloc > lastck) { - /* Check if our memory usage has increased */ - dnprintf(10, "Leaked: [%s] %d\n", - aml_nodename(node), acpi_nalloc); - lastck = acpi_nalloc; - } - break; - case AML_OBJTYPE_STATICINT: - case AML_OBJTYPE_INTEGER: - case AML_OBJTYPE_STRING: - case AML_OBJTYPE_BUFFER: - case AML_OBJTYPE_PACKAGE: - case AML_OBJTYPE_EVENT: - case AML_OBJTYPE_DEVICE: - case AML_OBJTYPE_MUTEX: - case AML_OBJTYPE_OPREGION: - case AML_OBJTYPE_POWERRSRC: - case AML_OBJTYPE_PROCESSOR: - case AML_OBJTYPE_THERMZONE: - case AML_OBJTYPE_DEBUGOBJ: - if (res) - aml_copyvalue(res, node->value); - break; - case AML_OBJTYPE_NAMEREF: - if (res == NULL) - break; - if ((ref = aml_searchname(node, node->value->v_nameref)) != NULL) - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, ref); - else - aml_copyvalue(res, node->value); - break; - default: - break; - } - return (0); -} - -/* - * evaluate an AML name - * Returns a copy of the value in res (must be freed by user) - */ -int -aml_evalname(struct acpi_softc *sc, struct aml_node *parent, const char *name, - int argc, struct aml_value *argv, struct aml_value *res) -{ - return aml_evalnode(sc, aml_searchname(parent, name), argc, argv, res); -} - -int -aml_evalinteger(struct acpi_softc *sc, struct aml_node *parent, - const char *name, int argc, struct aml_value *argv, int64_t *ival) -{ - struct aml_value res; - - if (name != NULL) - parent = aml_searchname(parent, name); - if (aml_evalnode(sc, parent, argc, argv, &res) == 0) { - *ival = aml_val2int(&res); - aml_freevalue(&res); - return 0; - } - return 1; -} void aml_walknodes(struct aml_node *node, int mode, @@ -2312,58 +1530,6 @@ aml_parseend(struct aml_scope *scope) /* * @@@: Opcode utility functions */ -int aml_match(int, int64_t, struct aml_value *); -void aml_fixref(struct aml_value **); -int64_t aml_parseint(struct aml_scope *, int); -void aml_resize(struct aml_value *val, int newsize); - -void -aml_resize(struct aml_value *val, int newsize) -{ - void *oldptr; - int oldsize; - - if (val->length >= newsize) - return; - oldsize = val->length; - switch (val->type) { - case AML_OBJTYPE_BUFFER: - oldptr = val->v_buffer; - _aml_setvalue(val, val->type, newsize, NULL); - memcpy(val->v_buffer, oldptr, oldsize); - acpi_os_free(oldptr); - break; - case AML_OBJTYPE_STRING: - oldptr = val->v_string; - _aml_setvalue(val, val->type, newsize+1, NULL); - memcpy(val->v_string, oldptr, oldsize); - acpi_os_free(oldptr); - break; - } -} - - -int -aml_match(int op, int64_t mv1, struct aml_value *mv2) -{ - struct aml_value tmpint; - - memset(&tmpint, 0, sizeof(tmpint)); - _aml_setvalue(&tmpint, AML_OBJTYPE_INTEGER, mv1, NULL); - switch (op) { - case AML_MATCH_EQ: - return aml_cmpvalue(&tmpint, mv2, AMLOP_LEQUAL); - case AML_MATCH_LT: - return aml_cmpvalue(&tmpint, mv2, AMLOP_LLESS); - case AML_MATCH_LE: - return aml_cmpvalue(&tmpint, mv2, AMLOP_LLESSEQUAL); - case AML_MATCH_GE: - return aml_cmpvalue(&tmpint, mv2, AMLOP_LGREATEREQUAL); - case AML_MATCH_GT: - return aml_cmpvalue(&tmpint, mv2, AMLOP_LGREATER); - } - return (1); -} int amlop_delay; @@ -2397,6 +1563,9 @@ aml_getpciaddr(struct acpi_softc *sc, struct aml_node *root) } /* Fixup references for BufferFields/FieldUnits */ +#if 0 +void aml_fixref(struct aml_value **); + void aml_fixref(struct aml_value **res) { @@ -2410,900 +1579,14 @@ aml_fixref(struct aml_value **res) *res = oldres; } } - -int64_t -aml_parseint(struct aml_scope *scope, int opcode) -{ - uint8_t *np = scope->pos; - struct aml_value *tmpval; - int64_t rval; - - if (opcode == AML_ANYINT) - opcode = aml_parseopcode(scope); - switch (opcode) { - case AMLOP_ZERO: - rval = 0; - break; - case AMLOP_ONE: - rval = 1; - break; - case AMLOP_ONES: - rval = -1; - break; - case AMLOP_REVISION: - rval = AML_REVISION; - break; - case AMLOP_BYTEPREFIX: - np = scope->pos; - rval = *(uint8_t *)scope->pos; - scope->pos += 1; - break; - case AMLOP_WORDPREFIX: - np = scope->pos; - rval = aml_letohost16(*(uint16_t *)scope->pos); - scope->pos += 2; - break; - case AMLOP_DWORDPREFIX: - np = scope->pos; - rval = aml_letohost32(*(uint32_t *)scope->pos); - scope->pos += 4; - break; - case AMLOP_QWORDPREFIX: - np = scope->pos; - rval = aml_letohost64(*(uint64_t *)scope->pos); - scope->pos += 8; - break; - default: - scope->pos = np; - tmpval = aml_alloctmp(scope, 1); - aml_parseop(scope, tmpval, 'i'); - return aml_val2int(tmpval); - } - dnprintf(15, "%.4x: [%s] %s\n", aml_pc(scope->pos-opsize(opcode)), - aml_nodename(scope->node), aml_mnem(opcode, np)); - return rval; -} - -struct aml_value * -aml_evaltarget(struct aml_scope *scope, struct aml_value *res) -{ - return res; -} - -int -aml_evalterm(struct aml_scope *scope, struct aml_value *raw, - struct aml_value *dst) -{ - struct aml_value *deref; - - aml_freevalue(dst); - deref = aml_derefterm(scope, raw, 0); - aml_copyvalue(dst, deref); - return 0; -} - +#endif /* * @@@: Opcode functions */ -/* Parse named objects */ -struct aml_value * -aml_parsenamed(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *name; - int s, offs = 0; - - AML_CHECKSTACK(); - name = aml_parsename(scope); - - res = aml_allocvalue(AML_OBJTYPE_UNINITIALIZED, 0, NULL); - switch (opcode) { - case AMLOP_NAME: - aml_parseop(scope, res, 't'); - break; - case AMLOP_ALIAS: - _aml_setvalue(res, AML_OBJTYPE_NAMEREF, 0, name); - name = aml_parsename(scope); - break; - case AMLOP_EVENT: - _aml_setvalue(res, AML_OBJTYPE_EVENT, 0, NULL); - break; - case AMLOP_MUTEX: - /* XXX mutex is unused since we don't have concurrency */ - _aml_setvalue(res, AML_OBJTYPE_MUTEX, 0, NULL); - res->v_mutex = (struct acpi_mutex *)acpi_os_malloc( - sizeof(struct acpi_mutex)); - res->v_mutex->amt_synclevel = aml_parseint(scope, - AMLOP_BYTEPREFIX); - s = strlen(aml_getname(name)); - if (s > 4) - offs = s - 4; - strlcpy(res->v_mutex->amt_name, aml_getname(name) + offs, - ACPI_MTX_MAXNAME); - rw_init(&res->v_mutex->amt_lock, res->v_mutex->amt_name); - break; - case AMLOP_OPREGION: - _aml_setvalue(res, AML_OBJTYPE_OPREGION, 0, NULL); - res->v_opregion.iospace = aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_opregion.iobase = aml_parseint(scope, AML_ANYINT); - res->v_opregion.iolen = aml_parseint(scope, AML_ANYINT); - if (res->v_opregion.iospace == GAS_PCI_CFG_SPACE) { - res->v_opregion.iobase += aml_getpciaddr(dsdt_softc, - scope->node); - dnprintf(20, "got ioaddr: %s.%s:%llx\n", - aml_nodename(scope->node), aml_getname(name), - res->v_opregion.iobase); - } - break; - } - aml_createname(scope->node, name, res); - - return res; -} - -/* Parse Named objects with scope */ -struct aml_value * -aml_parsenamedscope(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *end, *name; - struct aml_node *node; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - name = aml_parsename(scope); - - switch (opcode) { - case AMLOP_DEVICE: - res = aml_allocvalue(AML_OBJTYPE_DEVICE, 0, NULL); - break; - case AMLOP_SCOPE: - res = NULL; - break; - case AMLOP_PROCESSOR: - res = aml_allocvalue(AML_OBJTYPE_PROCESSOR, 0, NULL); - res->v_processor.proc_id = aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_processor.proc_addr = aml_parseint(scope, AMLOP_DWORDPREFIX); - res->v_processor.proc_len = aml_parseint(scope, AMLOP_BYTEPREFIX); - break; - case AMLOP_POWERRSRC: - res = aml_allocvalue(AML_OBJTYPE_POWERRSRC, 0, NULL); - res->v_powerrsrc.pwr_level = aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_powerrsrc.pwr_order = aml_parseint(scope, AMLOP_BYTEPREFIX); - break; - case AMLOP_THERMALZONE: - res = aml_allocvalue(AML_OBJTYPE_THERMZONE, 0, NULL); - break; - } - node = aml_createname(scope->node, name, res); - aml_parsenode(scope, node, scope->pos, &end, NULL); - scope->pos = end; - - return res; -} - -/* Parse math opcodes */ -struct aml_value * -aml_parsemath(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg; - int64_t i1, i2, i3; - - tmparg = aml_alloctmp(scope, 1); - AML_CHECKSTACK(); - switch (opcode) { - case AMLOP_LNOT: - i2 = 0; - i1 = aml_parseint(scope, AML_ANYINT); - break; - case AMLOP_LAND: - case AMLOP_LOR: - i1 = aml_parseint(scope, AML_ANYINT); - i2 = aml_parseint(scope, AML_ANYINT); - break; - case AMLOP_NOT: - case AMLOP_TOBCD: - case AMLOP_FROMBCD: - case AMLOP_TOINTEGER: - case AMLOP_FINDSETLEFTBIT: - case AMLOP_FINDSETRIGHTBIT: - i2 = 0; - i1 = aml_parseint(scope, AML_ANYINT); - aml_parsetarget(scope, tmparg, NULL); - break; - case AMLOP_INCREMENT: - case AMLOP_DECREMENT: - aml_parsetarget(scope, tmparg, NULL); - i1 = aml_val2int(aml_derefterm(scope, tmparg, 0)); - i2 = 1; - break; - case AMLOP_DIVIDE: - i1 = aml_parseint(scope, AML_ANYINT); - i2 = aml_parseint(scope, AML_ANYINT); - - aml_parsetarget(scope, tmparg, NULL); // remainder - aml_setvalue(scope, tmparg, NULL, (i1 % i2)); - - aml_parsetarget(scope, tmparg, NULL); // quotient - break; - default: - i1 = aml_parseint(scope, AML_ANYINT); - i2 = aml_parseint(scope, AML_ANYINT); - aml_parsetarget(scope, tmparg, NULL); - break; - } - i3 = aml_evalexpr(i1, i2, opcode); - aml_setvalue(scope, res, NULL, i3); - aml_setvalue(scope, tmparg, NULL, i3); - return (res); -} - -/* Parse logical comparison opcodes */ -struct aml_value * -aml_parsecompare(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg; - int rc; - - AML_CHECKSTACK(); - tmparg = aml_alloctmp(scope, 2); - aml_parseterm(scope, &tmparg[AML_LHS]); - aml_parseterm(scope, &tmparg[AML_RHS]); - - /* Compare both values */ - rc = aml_cmpvalue(&tmparg[AML_LHS], &tmparg[AML_RHS], opcode); - aml_setvalue(scope, res, NULL, rc); - - return res; -} - -/* Parse IF/ELSE opcodes */ -struct aml_value * -aml_parseif(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - int64_t test; - uint8_t *end; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - test = aml_parseint(scope, AML_ANYINT); - - dnprintf(40, "@ iftest: %llx\n", test); - while (test && scope->pos < end) { - /* Parse if scope */ - aml_parseterm(scope, res); - } - if (scope->pos >= scope->end) - return res; - - if (*end == AMLOP_ELSE) { - scope->pos = ++end; - end = aml_parseend(scope); - while (!test && scope->pos < end) { - /* Parse ELSE scope */ - aml_parseterm(scope, res); - } - } - if (scope->pos < end) - scope->pos = end; - return res; -} - -struct aml_value * -aml_parsewhile(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *end, *start; - int test, cnt; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - start = scope->pos; - cnt = 0; - do { - test = 1; - if (scope->pos == start || scope->pos == end) { - scope->pos = start; - test = aml_parseint(scope, AML_ANYINT); - dnprintf(40, "@whiletest = %d %x\n", test, cnt++); - } else if (*scope->pos == AMLOP_BREAK) { - scope->pos++; - test = 0; - } else if (*scope->pos == AMLOP_CONTINUE) { - scope->pos = start; - } else { - aml_parseterm(scope, res); - } - } while (test && scope->pos <= end && cnt < 0x199); - /* XXX: shouldn't need breakout counter */ - - dnprintf(40, "Set While end : %x\n", cnt); - if (scope->pos < end) - scope->pos = end; - return res; -} - -/* Parse Buffer/Package opcodes */ -struct aml_value * -aml_parsebufpkg(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *end; - int len; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - len = aml_parseint(scope, (opcode == AMLOP_PACKAGE) ? - AMLOP_BYTEPREFIX : AML_ANYINT); - - switch (opcode) { - case AMLOP_BUFFER: - _aml_setvalue(res, AML_OBJTYPE_BUFFER, len, NULL); - if (scope->pos < end) { - memcpy(res->v_buffer, scope->pos, end-scope->pos); - } - if (len != end-scope->pos) { - dnprintf(99, "buffer: %.4x %.4x\n", len, end-scope->pos); - } - break; - case AMLOP_PACKAGE: - case AMLOP_VARPACKAGE: - _aml_setvalue(res, AML_OBJTYPE_PACKAGE, len, NULL); - for (len = 0; len < res->length && scope->pos < end; len++) { - aml_parseop(scope, res->v_package[len], 't'); - } - if (scope->pos != end) { - dnprintf(99, "Package not equiv!! %.4x %.4x %d of %d\n", - aml_pc(scope->pos), aml_pc(end), len, res->length); - } - break; - } - scope->pos = end; - return res; -} - -struct aml_value * -aml_parsemethod(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *end, *name; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - name = aml_parsename(scope); - - res = aml_allocvalue(AML_OBJTYPE_METHOD, 0, NULL); - res->v_method.flags = aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_method.start = scope->pos; - res->v_method.end = end; - res->v_method.fneval = aml_callmethod; - aml_createname(scope->node, name, res); - - scope->pos = end; - - return res; -} - -/* Parse simple type opcodes */ -struct aml_value * -aml_parsesimple(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_node *node; - - AML_CHECKSTACK(); - switch (opcode) { - case AMLOP_ZERO: - _aml_setvalue(res, AML_OBJTYPE_INTEGER+AML_STATIC, - aml_parseint(scope, opcode), NULL); - break; - case AMLOP_ONE: - case AMLOP_ONES: - case AMLOP_BYTEPREFIX: - case AMLOP_WORDPREFIX: - case AMLOP_DWORDPREFIX: - case AMLOP_QWORDPREFIX: - case AMLOP_REVISION: - _aml_setvalue(res, AML_OBJTYPE_INTEGER, - aml_parseint(scope, opcode), NULL); - break; - case AMLOP_DEBUG: - _aml_setvalue(res, AML_OBJTYPE_DEBUGOBJ, 0, NULL); - break; - case AMLOP_STRINGPREFIX: - _aml_setvalue(res, AML_OBJTYPE_STRING, -1, scope->pos); - scope->pos += res->length+1; - break; - case AMLOP_NAMECHAR: - _aml_setvalue(res, AML_OBJTYPE_NAMEREF, 0, NULL); - res->v_nameref = aml_parsename(scope); - node = aml_searchname(scope->node, res->v_nameref); - if (node && node->value) - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, node->value); - break; - } - return res; -} - -/* Parse field unit opcodes */ -struct aml_value * -aml_parsefieldunit(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - uint8_t *end, *name; - struct aml_value *fld; - - AML_CHECKSTACK(); - end = aml_parseend(scope); - - switch (opcode) { - case AMLOP_FIELD: - aml_parsetarget(scope, NULL, &res->v_field.ref1); - break; - case AMLOP_INDEXFIELD: - aml_parsetarget(scope, NULL, &res->v_field.ref1); - aml_parsetarget(scope, NULL, &res->v_field.ref2); - break; - case AMLOP_BANKFIELD: - aml_parsetarget(scope, NULL, &res->v_field.ref1); - aml_parsetarget(scope, NULL, &res->v_field.ref2); - res->v_field.ref3 = aml_parseint(scope, AML_ANYINT); - break; - } - res->v_field.flags = aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_field.type = opcode; - - aml_fixref(&res->v_field.ref1); - aml_fixref(&res->v_field.ref2); - - while (scope->pos < end) { - switch (*scope->pos) { - case 0x00: // reserved - scope->pos++; - res->v_field.bitlen = aml_parselength(scope); - break; - case 0x01: // attrib - scope->pos++; - /* XXX: do something with this */ - aml_parseint(scope, AMLOP_BYTEPREFIX); - aml_parseint(scope, AMLOP_BYTEPREFIX); - res->v_field.bitlen = 0; - break; - default: - name = aml_parsename(scope); - res->v_field.bitlen = aml_parselength(scope); - - /* Allocate new fieldunit */ - fld = aml_allocvalue(AML_OBJTYPE_FIELDUNIT, 0, NULL); - - /* Increase reference count on field */ - fld->v_field = res->v_field; - aml_addref(fld->v_field.ref1); - aml_addref(fld->v_field.ref2); - - aml_createname(scope->node, name, fld); - break; - } - res->v_field.bitpos += res->v_field.bitlen; - } - /* Delete redundant reference */ - aml_delref(&res->v_field.ref1); - aml_delref(&res->v_field.ref2); - return res; -} - -/* Parse CreateXXXField opcodes */ -struct aml_value * -aml_parsebufferfield(struct aml_scope *scope, int opcode, - struct aml_value *res) -{ - uint8_t *name; - - AML_CHECKSTACK(); - res = aml_allocvalue(AML_OBJTYPE_BUFFERFIELD, 0, NULL); - res->v_field.type = opcode; - aml_parsetarget(scope, NULL, &res->v_field.ref1); - res->v_field.bitpos = aml_parseint(scope, AML_ANYINT); - - aml_fixref(&res->v_field.ref1); - - switch (opcode) { - case AMLOP_CREATEFIELD: - res->v_field.bitlen = aml_parseint(scope, AML_ANYINT); - break; - case AMLOP_CREATEBITFIELD: - res->v_field.bitlen = 1; - break; - case AMLOP_CREATEBYTEFIELD: - res->v_field.bitlen = 8; - res->v_field.bitpos *= 8; - break; - case AMLOP_CREATEWORDFIELD: - res->v_field.bitlen = 16; - res->v_field.bitpos *= 8; - break; - case AMLOP_CREATEDWORDFIELD: - res->v_field.bitlen = 32; - res->v_field.bitpos *= 8; - break; - case AMLOP_CREATEQWORDFIELD: - res->v_field.bitlen = 64; - res->v_field.bitpos *= 8; - break; - } - name = aml_parsename(scope); - aml_createname(scope->node, name, res); - - return res; -} - -/* Parse Mutex/Event action */ -struct aml_value * -aml_parsemuxaction(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg; - int64_t i1; - int rv; - - AML_CHECKSTACK(); - - tmparg = aml_alloctmp(scope, 1); - aml_parsetarget(scope, tmparg, NULL); - switch (opcode) { - case AMLOP_ACQUIRE: - /* Assert: tmparg is AML_OBJTYPE_MUTEX */ - i1 = aml_parseint(scope, AMLOP_WORDPREFIX); - rv = acpi_mutex_acquire(tmparg->v_objref.ref, i1); - /* Return true if timed out */ - aml_setvalue(scope, res, NULL, rv); - break; - case AMLOP_RELEASE: - acpi_mutex_release(tmparg->v_objref.ref); - break; - - case AMLOP_WAIT: - /* Assert: tmparg is AML_OBJTYPE_EVENT */ - i1 = aml_parseint(scope, AML_ANYINT); - - /* Return true if timed out */ - aml_setvalue(scope, res, NULL, 0); - break; - case AMLOP_SIGNAL: - break; - case AMLOP_RESET: - break; - } - - return res; -} - -/* Parse Miscellaneous opcodes */ -struct aml_value * -aml_parsemisc2(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg, *dev; - int i1, i2, i3; - - AML_CHECKSTACK(); - - switch (opcode) { - case AMLOP_NOTIFY: - /* Assert: tmparg is nameref or objref */ - tmparg = aml_alloctmp(scope, 1); - aml_parseop(scope, tmparg, 'r'); - dev = aml_dereftarget(scope, tmparg); - - i1 = aml_parseint(scope, AML_ANYINT); - if (dev && dev->node) { - dnprintf(10, "Notify: [%s] %.2x\n", - aml_nodename(dev->node), i1); - aml_notify(dev->node, i1); - } - break; - case AMLOP_SLEEP: - i1 = aml_parseint(scope, AML_ANYINT); - dnprintf(50, "SLEEP: %x\n", i1); - if (i1) - acpi_sleep(i1); - else { - dnprintf(10, "acpi_sleep(0)\n"); - } - break; - case AMLOP_STALL: - i1 = aml_parseint(scope, AML_ANYINT); - dnprintf(50, "STALL: %x\n", i1); - if (i1) - acpi_stall(i1); - else { - dnprintf(10, "acpi_stall(0)\n"); - } - break; - case AMLOP_FATAL: - i1 = aml_parseint(scope, AMLOP_BYTEPREFIX); - i2 = aml_parseint(scope, AMLOP_DWORDPREFIX); - i3 = aml_parseint(scope, AML_ANYINT); - aml_die("FATAL: %x %x %x\n", i1, i2, i3); - break; - } - return res; -} - -/* Parse Miscellaneous opcodes */ -struct aml_value * -aml_parsemisc3(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg; - - AML_CHECKSTACK(); - tmparg = aml_alloctmp(scope, 1); - aml_parseterm(scope, tmparg); - switch (opcode) { - case AMLOP_SIZEOF: - aml_setvalue(scope, res, NULL, tmparg->length); - break; - case AMLOP_OBJECTTYPE: - aml_setvalue(scope, res, NULL, tmparg->type); - break; - } - - return res; -} - -/* Parse AMLOP_MATCH */ -struct aml_value * -aml_parsematch(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *pkg; - int op1, op2, idx, mv1, mv2; - - AML_CHECKSTACK(); - pkg = aml_parseterm(scope, NULL); - op1 = aml_parseint(scope, AMLOP_BYTEPREFIX); - mv1 = aml_parseint(scope, AML_ANYINT); - op2 = aml_parseint(scope, AMLOP_BYTEPREFIX); - mv2 = aml_parseint(scope, AML_ANYINT); - idx = aml_parseint(scope, AML_ANYINT); - - aml_setvalue(scope, res, NULL, -1); - while (idx < pkg->length) { - if (aml_match(op1, mv1, pkg->v_package[idx]) || - aml_match(op2, mv2, pkg->v_package[idx])) { - aml_setvalue(scope, res, NULL, idx); - break; - } - idx++; - } - aml_delref(&pkg); - return res; -} - -/* Parse referenced objects */ -struct aml_value * -aml_parseref(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmparg; - - AML_CHECKSTACK(); - - switch (opcode) { - case AMLOP_INDEX: - tmparg = aml_alloctmp(scope, 1); - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, NULL); - aml_parsetarget(scope, tmparg, NULL); - - res->v_objref.index = aml_parseint(scope, AML_ANYINT); - res->v_objref.ref = aml_dereftarget(scope, tmparg); - - aml_parsetarget(scope, tmparg, NULL); - aml_setvalue(scope, tmparg, res, 0); - break; - case AMLOP_DEREFOF: - aml_parseop(scope, res, 't'); - break; - case AMLOP_RETURN: - tmparg = aml_alloctmp(scope, 1); - aml_parseterm(scope, tmparg); - aml_setvalue(scope, res, tmparg, 0); - scope->pos = scope->end; - break; - case AMLOP_ARG0: - case AMLOP_ARG1: - case AMLOP_ARG2: - case AMLOP_ARG3: - case AMLOP_ARG4: - case AMLOP_ARG5: - case AMLOP_ARG6: - opcode -= AMLOP_ARG0; - if (scope->args == NULL || opcode >= scope->nargs) - aml_die("arg %d out of range", opcode); - - /* Create OBJREF to stack variable */ - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, - &scope->args[opcode]); - break; - case AMLOP_LOCAL0: - case AMLOP_LOCAL1: - case AMLOP_LOCAL2: - case AMLOP_LOCAL3: - case AMLOP_LOCAL4: - case AMLOP_LOCAL5: - case AMLOP_LOCAL6: - case AMLOP_LOCAL7: - opcode -= AMLOP_LOCAL0; - - /* No locals exist.. lazy allocate */ - if (scope->locals == NULL) { - dnprintf(10, "Lazy alloc locals\n"); - scope->locals = aml_alloctmp(scope, AML_MAX_LOCAL); - } - - /* Create OBJREF to stack variable */ - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, - &scope->locals[opcode]); - res->v_objref.ref->stack = opcode+AMLOP_LOCAL0; - break; - case AMLOP_LOAD: - tmparg = aml_alloctmp(scope, 2); - aml_parseop(scope, &tmparg[0], 't'); - aml_parseop(scope, &tmparg[1], 't'); - break; - case AMLOP_STORE: - tmparg = aml_alloctmp(scope, 1); - aml_parseterm(scope, res); - aml_parsetarget(scope, tmparg, NULL); - - while (tmparg->type == AML_OBJTYPE_OBJREF) { - if (tmparg->v_objref.index != -1) - break; - tmparg = tmparg->v_objref.ref; - } - aml_setvalue(scope, tmparg, res, 0); - break; - case AMLOP_REFOF: - _aml_setvalue(res, AML_OBJTYPE_OBJREF, -1, NULL); - aml_parsetarget(scope, NULL, &res->v_objref.ref); - break; - case AMLOP_CONDREFOF: - /* Returns true if object exists */ - tmparg = aml_alloctmp(scope, 2); - aml_parsetarget(scope, &tmparg[0], NULL); - aml_parsetarget(scope, &tmparg[1], NULL); - if (tmparg[0].type != AML_OBJTYPE_NAMEREF) { - /* Object exists */ - aml_freevalue(&tmparg[1]); - aml_setvalue(scope, &tmparg[1], &tmparg[0], 0); - aml_setvalue(scope, res, NULL, 1); - } else { - /* Object doesn't exist */ - aml_setvalue(scope, res, NULL, 0); - } - break; - } - - return res; -} - -struct aml_value * -aml_parsestring(struct aml_scope *scope, int opcode, struct aml_value *res) -{ - struct aml_value *tmpval; - int i1, i2; - - AML_CHECKSTACK(); - switch (opcode) { - case AMLOP_CONCAT: - tmpval = aml_alloctmp(scope, 4); - aml_parseterm(scope, &tmpval[AML_LHS]); - aml_parseterm(scope, &tmpval[AML_RHS]); - aml_parsetarget(scope, &tmpval[AML_DST], NULL); - if (tmpval[AML_LHS].type == AML_OBJTYPE_BUFFER && - tmpval[AML_RHS].type == AML_OBJTYPE_BUFFER) { - aml_resize(&tmpval[AML_LHS], - tmpval[AML_LHS].length+tmpval[AML_RHS].length); - memcpy(tmpval[AML_LHS].v_buffer+tmpval[AML_LHS].length, - tmpval[AML_RHS].v_buffer, tmpval[AML_RHS].length); - aml_setvalue(scope, &tmpval[AML_DST], &tmpval[AML_LHS], 0); - } else if (tmpval[AML_LHS].type == AML_OBJTYPE_STRING && - tmpval[AML_RHS].type == AML_OBJTYPE_STRING) { - aml_resize(&tmpval[AML_LHS], - tmpval[AML_LHS].length+tmpval[AML_RHS].length); - memcpy(tmpval[AML_LHS].v_string+tmpval[AML_LHS].length, - tmpval[AML_RHS].v_buffer, tmpval[AML_RHS].length); - aml_setvalue(scope, &tmpval[AML_DST], &tmpval[AML_LHS], 0); - } else { - aml_die("concat"); - } - break; - case AMLOP_MID: - tmpval = aml_alloctmp(scope, 2); - aml_parseterm(scope, &tmpval[0]); - i1 = aml_parseint(scope, AML_ANYINT); // start - i2 = aml_parseint(scope, AML_ANYINT); // length - aml_parsetarget(scope, &tmpval[1], NULL); - if (i1 > tmpval[0].length) - i1 = tmpval[0].length; - if (i1+i2 > tmpval[0].length) - i2 = tmpval[0].length-i1; - _aml_setvalue(res, AML_OBJTYPE_STRING, i2, tmpval[0].v_string+i1); - break; - case AMLOP_TODECSTRING: - case AMLOP_TOHEXSTRING: - i1 = aml_parseint(scope, AML_ANYINT); - _aml_setvalue(res, AML_OBJTYPE_STRING, 20, NULL); - snprintf(res->v_string, res->length, - ((opcode == AMLOP_TODECSTRING) ? "%d" : "%x"), i1); - break; - default: - aml_die("to_string"); - break; - } - - return res; -} - -struct aml_value * -aml_parseterm(struct aml_scope *scope, struct aml_value *res) -{ - struct aml_value *tmpres; - - /* If no value specified, allocate dynamic */ - if (res == NULL) - res = aml_allocvalue(AML_OBJTYPE_UNINITIALIZED, 0, NULL); - tmpres = aml_alloctmp(scope, 1); - aml_parseop(scope, tmpres, 't'); - aml_evalterm(scope, tmpres, res); - return res; -} - -struct aml_value * -aml_parsetarget(struct aml_scope *scope, struct aml_value *res, - struct aml_value **opt) -{ - struct aml_value *dummy; - - /* If no value specified, allocate dynamic */ - if (res == NULL) - res = aml_allocvalue(AML_OBJTYPE_UNINITIALIZED, 0, NULL); - aml_parseop(scope, res, 'r'); - if (opt == NULL) - opt = &dummy; - - *opt = aml_evaltarget(scope, res); - - return res; -} - int odp; -/* Main Opcode Parser/Evaluator */ -struct aml_value * -aml_parseop(struct aml_scope *scope, struct aml_value *res, int ctype) -{ - int opcode; - struct aml_opcode *htab; - struct aml_value *rv = NULL; - - if (odp++ > 25) - panic("depth"); - - aml_freevalue(res); - opcode = aml_parseopcode(scope); - dnprintf(15, "%.4x: [%s] %s\n", aml_pc(scope->pos-opsize(opcode)), - aml_nodename(scope->node), aml_mnem(opcode, scope->pos)); - delay(amlop_delay); - - htab = aml_findopcode(opcode); - if (htab && htab->handler) { - rv = htab->handler(scope, opcode, res); - } else { - /* No opcode handler */ - aml_die("Unknown opcode: %.4x @ %.4x", opcode, - aml_pc(scope->pos - opsize(opcode))); - } - if (ctype == 'i' && res->type != AML_OBJTYPE_INTEGER) { - rv = aml_derefterm(scope, res, 0); - aml_freevalue(res); - aml_copyvalue(res, rv); - } - odp--; - return rv; -} - const char hext[] = "0123456789ABCDEF"; const char * @@ -3342,6 +1625,7 @@ struct aml_blacklist { { NULL }, }; +#if 0 void aml_fixup_dsdt(u_int8_t *acpi_hdr, u_int8_t *base, int len) { @@ -3362,6 +1646,7 @@ aml_fixup_dsdt(u_int8_t *acpi_hdr, u_int8_t *base, int len) } } } +#endif /* * @@@: Default Object creation @@ -3401,23 +1686,16 @@ char *aml_valid_osi[] = { struct aml_value * aml_callosi(struct aml_scope *scope, struct aml_value *val) { - struct aml_value tmpstr, *arg; - int idx, result; - - /* Perform comparison with valid strings */ - result = 0; - memset(&tmpstr, 0, sizeof(tmpstr)); - tmpstr.type = AML_OBJTYPE_STRING; - arg = aml_derefvalue(scope, &scope->args[0], ACPI_IOREAD); + int idx, result=0; + struct aml_value *fa; + fa = scope->args[0].v_objref.ref; for (idx=0; !result && aml_valid_osi[idx] != NULL; idx++) { - tmpstr.v_string = aml_valid_osi[idx]; - tmpstr.length = strlen(tmpstr.v_string); - - result = aml_cmpvalue(arg, &tmpstr, AMLOP_LEQUAL); + dnprintf(10,"osi: %s,%s\n", fa->v_string, aml_valid_osi[idx]); + result = !strcmp(fa->v_string, aml_valid_osi[idx]); } - aml_setvalue(scope, val, NULL, result); - return val; + dnprintf(10,"@@ OSI found: %x\n", result); + return aml_allocvalue(AML_OBJTYPE_INTEGER, result, NULL); } void @@ -3431,6 +1709,10 @@ aml_create_defaultobjects() osstring[15] = 'w'; osstring[18] = 'N'; + strlcpy(aml_root.name, "\\", sizeof(aml_root.name)); + aml_root.value = aml_allocvalue(0, 0, NULL); + aml_root.value->node = &aml_root; + for (def = aml_defobj; def->name; def++) { /* Allocate object value + add to namespace */ tmp = aml_allocvalue(def->type, def->ival, def->bval); @@ -3554,6 +1836,7 @@ aml_foreachpkg(struct aml_value *pkg, int start, fn(pkg->v_package[idx], arg); } +#if 0 int acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) { @@ -3572,6 +1855,7 @@ acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) return (0); } +#endif /* * Walk nodes and perform fixups for nameref @@ -3644,3 +1928,2607 @@ aml_val_to_string(const struct aml_value *val) return (buffer); } + +/* + * XXX: NEW PARSER CODE GOES HERE + */ +struct aml_value *aml_xeval(struct aml_scope *, struct aml_value *, int, int, + struct aml_value *); +struct aml_value *aml_xparsesimple(struct aml_scope *, char, + struct aml_value *); +struct aml_value *aml_xparse(struct aml_scope *, int, const char *); + +struct aml_scope *aml_xfindscope(struct aml_scope *, int, int); +struct aml_scope *aml_xpushscope(struct aml_scope *, struct aml_value *, + struct aml_node *, int); +struct aml_scope *aml_xpopscope(struct aml_scope *); + +void aml_showstack(struct aml_scope *); +void aml_xaddref(struct aml_value *, const char *); +void aml_xdelref(struct aml_value **, const char *); +void aml_xconvert(struct aml_value *, struct aml_value **, int, int); +int64_t aml_hextoint(const char *); + +int aml_xmatchtest(int64_t, int64_t, int); +int aml_xmatch(struct aml_value *, int, int, int, int, int); + +int aml_xcompare(struct aml_value *, struct aml_value *, int); +void aml_xconcat(struct aml_value *, struct aml_value *, + struct aml_value **); +void aml_xconcatres(struct aml_value *, struct aml_value *, + struct aml_value **); +int aml_ccrlen(union acpi_resource *, void *); +void aml_xmid(struct aml_value *, int, int, struct aml_value **); + +void aml_xstore(struct aml_scope *, struct aml_value *, int64_t, + struct aml_value *); + +int +valid_acpihdr(void *buf, int len, const char *sig) +{ + struct acpi_table_header *hdr = buf; + + if (sig && strncmp(hdr->signature, sig, 4)) { + return 0; + } + if (len < hdr->length) { + return 0; + } + if (acpi_checksum(hdr, hdr->length) != 0) { + return 0; + } + return 1; +} + +/* + * Reference Count functions + */ +void +aml_xaddref(struct aml_value *val, const char *lbl) +{ + if (val == NULL) + return; + dnprintf(50, "XAddRef: %p %s:[%s] %d\n", + val, lbl, + val->node ? aml_nodename(val->node) : "INTERNAL", + val->refcnt); + val->refcnt++; +} + +/* Decrease reference counter */ +void +aml_xdelref(struct aml_value **pv, const char *lbl) +{ + struct aml_value *val; + + if (pv == NULL || *pv == NULL) + return; + val = *pv; + val->refcnt--; + if (val->refcnt == 0) { + dnprintf(50, "XDelRef: %p %s %2d [%s] %s\n", + val, lbl, + val->refcnt, + val->node ? aml_nodename(val->node) : "INTERNAL", + val->refcnt ? "" : "---------------- FREEING"); + + aml_freevalue(val); + acpi_os_free(val); + *pv = NULL; + } +} + +/* Walk list of parent scopes until we find one of 'type' + * If endscope is set, mark all intermediate scopes as invalid (used for Method/While) */ +struct aml_scope * +aml_xfindscope(struct aml_scope *scope, int type, int endscope) +{ + while (scope) { + if (endscope) + scope->pos = NULL; + if (scope->type == type) + break; + scope = scope->parent; + } + return scope; +} + +#ifdef ACPI_DEBUG +/* Dump AML Stack */ +void +aml_showstack(struct aml_scope *scope) +{ + int idx; + + dnprintf(10, "===== Stack %s:%s\n", aml_nodename(scope->node), + aml_mnem(scope->type, 0)); + scope = aml_xfindscope(scope, AMLOP_METHOD, 0); + if (scope == NULL) + return; + for (idx=0; scope->args && idx<7; idx++) { + if (scope->args[idx].type) { + dnprintf(10," Arg%d: ", idx); + aml_showvalue(scope->args[idx].v_objref.ref, 10); + } + } + for (idx=0; scope->locals && idx<8; idx++) { + if (scope->locals[idx].type) { + dnprintf(10," Local%d: ", idx); + aml_showvalue(&scope->locals[idx], 10); + } + } +} +#endif + +/* Create a new scope object */ +struct aml_scope * +aml_xpushscope(struct aml_scope *parent, struct aml_value *range, + struct aml_node *node, int type) +{ + struct aml_scope *scope; + uint8_t *start, *end; + + if (range->type == AML_OBJTYPE_METHOD) { + start = range->v_method.start; + end = range->v_method.end; + } + else { + start = range->v_buffer; + end = start + range->length; + if (start == end) { + return NULL; + } + } + scope = acpi_os_malloc(sizeof(struct aml_scope)); + if (scope == NULL) + return NULL; + + scope->node = node; + scope->start = start; + scope->end = end; + scope->pos = scope->start; + scope->parent = parent; + scope->type = type; + scope->sc = dsdt_softc; + + aml_lastscope = scope; + + return scope; +} + +/* Free a scope object and any children */ +struct aml_scope * +aml_xpopscope(struct aml_scope *scope) +{ + struct aml_scope *nscope; + int idx; + + if (scope == NULL) + return NULL; + + nscope = scope->parent; + + if (scope->type == AMLOP_METHOD) { + aml_delchildren(scope->node); + } + if (scope->locals) { + for (idx=0; idx<8; idx++) { + aml_freevalue(&scope->locals[idx]); + } + acpi_os_free(scope->locals); + scope->locals = NULL; + } + if (scope->args) { + for (idx=0; idx<7; idx++) { + aml_freevalue(&scope->args[idx]); + } + acpi_os_free(scope->args); + scope->args = NULL; + } + acpi_os_free(scope); + aml_lastscope = nscope; + + return nscope; +} + +/* Test AMLOP_MATCH codes */ +int +aml_xmatchtest(int64_t a, int64_t b, int op) +{ + switch (op) { + case AML_MATCH_TR: + return (1); + case AML_MATCH_EQ: + return (a == b); + case AML_MATCH_LT: + return (a < b); + case AML_MATCH_LE: + return (a <= b); + case AML_MATCH_GE: + return (a >= b); + case AML_MATCH_GT: + return (a > b); + } + return 0; +} + +/* Search a package for a matching value */ +int +aml_xmatch(struct aml_value *pkg, int index, + int op1, int v1, + int op2, int v2) +{ + struct aml_value *tmp; + int flag; + + while (index < pkg->length) { + /* Convert package value to integer */ + aml_xconvert(pkg->v_package[index], &tmp, + AML_OBJTYPE_INTEGER, 0); + + /* Perform test */ + flag = aml_xmatchtest(tmp->v_integer, v1, op1) && + aml_xmatchtest(tmp->v_integer, v2, op2); + aml_xdelref(&tmp, "xmatch"); + + if (flag) + return index; + index++; + } + return -1; +} + +/* + * Namespace functions + */ +void ns_xdis(struct aml_node *node, int n, uint8_t *pos, void *arg); +void ns_xcreate(struct aml_node *node, int n, uint8_t *pos, void *arg); +void ns_xsearch(struct aml_node *node, int n, uint8_t *pos, void *arg); +uint8_t *aml_xparsename(uint8_t *pos, struct aml_node *node, + void (*fn)(struct aml_node *, int, uint8_t *, void *), void *arg); + +/* Search for name in namespace */ +void +ns_xsearch(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + struct aml_value **rv = arg; + struct aml_node *rnode; + + /* If name search is relative, check up parent nodes */ + for (rnode=node; n == 1 && rnode; rnode=rnode->parent) { + if (__aml_search(rnode, pos, 0) != NULL) { + break; + } + } + while (n--) { + rnode = __aml_search(rnode, pos, 0); + pos += 4; + } + if (rnode != NULL) { + *rv = rnode->value; + return; + } + *rv = NULL; +} + +/* Create name in namespace */ +void +ns_xcreate(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + struct aml_value **rv = arg; + + while (n--) { + node = __aml_search(node, pos, 1); + pos += 4; + } + *rv = node->value; +} + +void +ns_xdis(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + printf(aml_nodename(node)); + while (n--) { + printf("%s%c%c%c%c", n ? "." : "", + pos[0], pos[1], pos[2], pos[3]); + pos+=4; + } +} + +uint8_t * +aml_xparsename(uint8_t *pos, struct aml_node *node, + void (*fn)(struct aml_node *, int, uint8_t *, void *), void *arg) +{ + uint8_t *rpos = pos; + struct aml_value **rv = arg; + + if (*pos == AMLOP_ROOTCHAR) { + node = &aml_root; + pos++; + } + while (*pos == AMLOP_PARENTPREFIX) { + node = node ? node->parent : &aml_root; + pos++; + } + if (*pos == 0) { + fn(node, 0, pos, arg); + pos++; + } + else if (*pos == AMLOP_MULTINAMEPREFIX) { + fn(node, pos[1], pos+2, arg); + pos += 2 + 4 * pos[1]; + } + else if (*pos == AMLOP_DUALNAMEPREFIX) { + fn(node, 2, pos+1, arg); + pos += 9; + } + else if (*pos == '_' || (*pos >= 'A' && *pos <= 'Z')) { + fn(node, 1, pos, arg); + pos += 4; + } + else { + printf("Invalid name!!!\n"); + } + if (rv && *rv == NULL) { + *rv = aml_allocvalue(AML_OBJTYPE_NAMEREF, 0, rpos); + } + return pos; +} + +/* + * Conversion routines + */ +int64_t +aml_hextoint(const char *str) +{ + int64_t v = 0; + char c; + + while (*str) { + if (*str >= '0' && *str <= '9') { + c = *(str++) - '0'; + } + else if (*str >= 'a' && *str <= 'f') { + c = *(str++) - 'a' + 10; + } + else if (*str >= 'A' && *str <= 'F') { + c = *(str++) - 'A' + 10; + } + else { + break; + } + v = (v << 4) + c; + } + return v; + +} + +void +aml_xconvert(struct aml_value *a, struct aml_value **b, int ctype, int mode) +{ + struct aml_value *c = NULL; + + /* Object is already this type */ + if (a->type == ctype) { + aml_xaddref(a, "XConvert"); + *b = a; + return; + } + switch (ctype) { + case AML_OBJTYPE_BUFFER: + dnprintf(10,"convert to buffer\n"); + switch (a->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, a->length, + &a->v_integer); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, a->length, + a->v_string); + break; + } + break; + case AML_OBJTYPE_INTEGER: + dnprintf(10,"convert to integer : %x\n", a->type); + switch (a->type) { + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + memcpy(&c->v_integer, a->v_buffer, + min(a->length, c->length)); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + c->v_integer = aml_hextoint(a->v_string); + break; + case AML_OBJTYPE_UNINITIALIZED: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + break; + } + break; + case AML_OBJTYPE_STRING: + dnprintf(10,"convert to string\n"); + switch (a->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_STRING, 20, NULL); + snprintf(c->v_string, c->length, (mode == 'x') ? + "0x%llx" : "%lld", a->v_integer); + break; + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_STRING, a->length, + a->v_buffer); + break; + } + break; + } + if (c == NULL) { +#ifndef SMALL_KERNEL + aml_showvalue(a, 0); +#endif + aml_die("Could not convert!!!\n"); + } + *b = c; +} + +int +aml_xcompare(struct aml_value *a1, struct aml_value *a2, int opcode) +{ + int rc = 0; + + /* Convert A2 to type of A1 */ + aml_xconvert(a2, &a2, a1->type, 0); + if (a1->type == AML_OBJTYPE_INTEGER) { + rc = aml_evalexpr(a1->v_integer, a2->v_integer, opcode); + } + else { + /* Perform String/Buffer comparison */ + rc = memcmp(a1->v_buffer, a2->v_buffer, + min(a1->length, a2->length)); + if (rc == 0) { + /* If buffers match, which one is longer */ + rc = a1->length - a2->length; + } + /* Perform comparison against zero */ + rc = aml_evalexpr(rc, 0, opcode); + } + /* Either deletes temp buffer, or decrease refcnt on original A2 */ + aml_xdelref(&a2, "xcompare"); + return rc; +} + +/* Concatenate two objects, returning pointer to new object */ +void +aml_xconcat(struct aml_value *a1, struct aml_value *a2, struct aml_value **res) +{ + struct aml_value *c; + + /* Convert arg2 to type of arg1 */ + aml_xconvert(a2, &a2, a1->type, 0); + switch (a1->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, + a1->length + a2->length, NULL); + memcpy(c->v_buffer, &a1->v_integer, a1->length); + memcpy(c->v_buffer+a1->length, &a2->v_integer, a2->length); + break; + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, + a1->length + a2->length, NULL); + memcpy(c->v_buffer, a1->v_buffer, a1->length); + memcpy(c->v_buffer+a1->length, a2->v_buffer, a2->length); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_STRING, + a1->length + a2->length, NULL); + memcpy(c->v_string, a1->v_string, a1->length); + memcpy(c->v_string+a1->length, a2->v_string, a2->length); + break; + default: + aml_die("concat type mismatch %d != %d\n", a1->type, a2->type); + break; + } + /* Either deletes temp buffer, or decrease refcnt on original A2 */ + aml_xdelref(&a2, "xconcat"); + *res = c; +} + +/* Calculate length of Resource Template */ +int +aml_ccrlen(union acpi_resource *rs, void *arg) +{ + int *plen = arg; + + *plen += AML_CRSLEN(rs); + return 0; +} + +/* Concatenate resource templates, returning pointer to new object */ +void +aml_xconcatres(struct aml_value *a1, struct aml_value *a2, struct aml_value **res) +{ + struct aml_value *c; + int l1 = 0, l2 = 0; + + if (a1->type != AML_OBJTYPE_BUFFER || a2->type != AML_OBJTYPE_BUFFER) { + aml_die("concatres: not buffers\n"); + } + + /* Walk a1, a2, get length minus end tags, concatenate buffers, add end tag */ + aml_parse_resource(a1->length, a1->v_buffer, aml_ccrlen, &l1); + aml_parse_resource(a2->length, a2->v_buffer, aml_ccrlen, &l2); + + /* Concatenate buffers, add end tag */ + c = aml_allocvalue(AML_OBJTYPE_BUFFER, l1+l2+2, NULL); + memcpy(c->v_buffer, a1->v_buffer, l1); + memcpy(c->v_buffer+l1, a2->v_buffer, l2); + c->v_buffer[l1+l2+0] = 0x79; + c->v_buffer[l1+l2+1] = 0x00; + + *res = c; +} + +/* Extract substring from string or buffer */ +void +aml_xmid(struct aml_value *src, int index, int length, struct aml_value **res) +{ + int idx; + + for (idx=index; idx<index+length; idx++) { + if (idx >= src->length) + break; + if (src->v_buffer[idx] == 0) + break; + } + aml_die("mid\n"); +} + +/* + * Field I/O utility functions + */ +void aml_xresolve(struct aml_scope *, struct aml_value *); +void *aml_xgetptr(struct aml_value *, int); +void aml_xgasio(int, uint64_t, int, void *, int, int, const char *); +void aml_xfldio(struct aml_scope *, struct aml_value *, + struct aml_value *, int); +void aml_xcreatefield(struct aml_value *, int, struct aml_value *, int, int, + struct aml_value *, int); +void aml_xparsefieldlist(struct aml_scope *, int, int, + struct aml_value *, struct aml_value *, int); +int aml_evalhid(struct aml_node *, struct aml_value *); + +#define GAS_PCI_CFG_SPACE_UNEVAL 0xCC + +int +aml_evalhid(struct aml_node *node, struct aml_value *val) +{ + if (aml_evalname(dsdt_softc, node, "_HID", 0, NULL, val)) + return (-1); + + /* Integer _HID: convert to EISA ID */ + if (val->type == AML_OBJTYPE_INTEGER) + _aml_setvalue(val, AML_OBJTYPE_STRING, -1, aml_eisaid(val->v_integer)); + return (0); +} + +int +aml_xgetpci(struct aml_node *node, int64_t *base) +{ + struct aml_node *pci_root; + struct aml_value hid; + int64_t v; + + *base = 0; + dnprintf(10,"RESOLVE PCI: %s\n", aml_nodename(node)); + for (pci_root=node->parent; pci_root; pci_root=pci_root->parent) { + /* PCI Root object will have _HID value */ + if (aml_evalhid(pci_root, &hid) == 0) { + aml_freevalue(&hid); + break; + } + } + if (!aml_evalinteger(NULL, node->parent, "_ADR", 0, NULL, &v)) + *base += (v << 16L); + if (!aml_evalinteger(NULL, pci_root, "_BBN", 0, NULL, &v)) + *base += (v << 48L); + return 0; +} + +void +aml_xresolve(struct aml_scope *scope, struct aml_value *val) +{ + int64_t base; + + if (val->type != AML_OBJTYPE_OPREGION || val->v_opregion.flag) + return; + if (val->v_opregion.iospace != GAS_PCI_CFG_SPACE) + return; + + /* Evaluate PCI Address */ + aml_xgetpci(val->node, &base); + val->v_opregion.iobase += base; + val->v_opregion.flag = 1; +} + +/* Perform IO to address space + * type = GAS_XXXX + * base = base address + * rlen = length in bytes to read/write + * buf = buffer + * mode = ACPI_IOREAD/ACPI_IOWRITE + * sz = access_size (bits) + */ +void +aml_xgasio(int type, uint64_t base, int rlen, void *buf, int mode, int sz, + const char *lbl) +{ + sz >>= 3; + acpi_gasio(dsdt_softc, mode, type, base, sz, rlen, buf); +#ifdef ACPI_DEBUG + { + int idx; + printf("%sio: [%s] ty:%x bs=%.8llx sz=%.4x rlen=%.4x ", + mode == ACPI_IOREAD ? "rd" : "wr", lbl, + type, base, sz, rlen); + for (idx=0; idx<rlen; idx++) { + printf("%.2x ", ((uint8_t *)buf)[idx]); + } + } + printf("\n"); +#endif +} + +void * +aml_xgetptr(struct aml_value *tmp, int blen) +{ + if (blen > aml_intlen) { + _aml_setvalue(tmp, AML_OBJTYPE_BUFFER, aml_bytelen(blen), 0); + return tmp->v_buffer; + } + _aml_setvalue(tmp, AML_OBJTYPE_INTEGER, 0, NULL); + return &tmp->v_integer; +} + +/* Read and Write BufferField and FieldUnit objects */ +void +aml_xfldio(struct aml_scope *scope, struct aml_value *fld, + struct aml_value *buf, int mode) +{ + struct aml_value tmp, *data; + int bpos, blen, preserve=1, mask, aligned, rlen, slen; + void *sptr, *dptr; + + switch (AML_FIELD_ACCESS(fld->v_field.flags)) { + case AML_FIELD_WORDACC: + mask=15; + break; + case AML_FIELD_DWORDACC: + mask=31; + break; + case AML_FIELD_QWORDACC: + mask=63; + break; + default: + mask=7; + break; + } + data = fld->v_field.ref1; + bpos = fld->v_field.bitpos; + blen = fld->v_field.bitlen; + rlen = aml_bytelen((bpos & 7) + blen); + aligned = !((bpos|blen)&mask); + preserve = AML_FIELD_UPDATE(fld->v_field.flags); + + dnprintf(30,"\nquick: %s: [%s] %.4x-%.4x msk=%.2x algn=%d prsrv=%d [%s]\n", + mode == ACPI_IOREAD ? "read from" : "write to", + aml_nodename(fld->node), + bpos, blen, mask, aligned, preserve, + aml_mnem(fld->v_field.type, 0)); + + memset(&tmp, 0, sizeof(tmp)); + if (fld->v_field.ref2 != NULL) { + /* Write index */ + dnprintf(30,"writing index fldio: %d\n", fld->v_field.ref3); + _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, + fld->v_field.ref3, NULL); + aml_xfldio(scope, fld->v_field.ref2, &tmp, ACPI_IOWRITE); + } + + /* Get pointer to Data Object */ + switch (data->type) { + case AML_OBJTYPE_BUFFER: + dptr = data->v_buffer; + break; + case AML_OBJTYPE_STRING: + dptr = data->v_string; + break; + case AML_OBJTYPE_INTEGER: + dptr = &data->v_integer; + break; + case AML_OBJTYPE_OPREGION: + /* Depending on size, allocate buffer or integer */ + aml_xresolve(scope, data); + dptr = aml_xgetptr(&tmp, rlen << 3); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + /* Set to integer for now.. */ + _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, 0x0, NULL); + dptr = &tmp.v_integer; + break; + default: + aml_die("jk XREAD/WRITE: unknown type: %x\n", data->type); + break; + } + + aml_lockfield(scope, fld); + if (mode == ACPI_IOREAD) { + sptr = aml_xgetptr(buf, blen); + switch (data->type) { + case AML_OBJTYPE_OPREGION: + /* Do GASIO into temp buffer, bitcopy into result */ + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOREAD, mask+1, + aml_nodename(fld->node)); + aml_bufcpy(sptr, 0, dptr, bpos & 7, blen); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + /* Do FieldIO into temp buffer, bitcopy into result */ + aml_xfldio(scope, data, &tmp, ACPI_IOREAD); + aml_bufcpy(sptr, 0, dptr, bpos & 7, blen); + break; + default: + /* bitcopy into result */ + aml_bufcpy(sptr, 0, dptr, bpos, blen); + break; + } + } + else { + switch (buf->type) { + case AML_OBJTYPE_INTEGER: + slen = aml_intlen; + break; + default: + slen = buf->length<<3; + break; + } + if (slen < blen) { +#ifndef SMALL_KERNEL + aml_showvalue(fld, 0); + aml_showvalue(buf, 0); +#endif + aml_die("BIG SOURCE %d %d %s", buf->length, blen>>3, ""); + } + if (buf->type != AML_OBJTYPE_INTEGER) + aml_die("writefield: not integer\n"); + sptr = &buf->v_integer; + + switch (data->type) { + case AML_OBJTYPE_OPREGION: + if (!aligned && preserve == AML_FIELD_PRESERVE) { + /* Preserve contents: read current value */ + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOREAD, mask+1, + aml_nodename(fld->node)); + } + /* Bitcopy data into temp buffer, write GAS */ + if (preserve == AML_FIELD_WRITEASONES) + memset(dptr, 0xFF, tmp.length); + aml_bufcpy(dptr, bpos & 7, sptr, 0, blen); + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOWRITE, mask+1, + aml_nodename(fld->node)); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + if (!aligned && preserve == AML_FIELD_PRESERVE) { + /* Preserve contents: read current value */ + aml_xfldio(scope, data, &tmp, ACPI_IOREAD); + if (tmp.type != AML_OBJTYPE_INTEGER) + dptr = tmp.v_buffer; + } + else { + dptr = aml_xgetptr(&tmp, rlen<<3); + } + /* Bitcopy data into temp buffer, write field */ + if (preserve == AML_FIELD_WRITEASONES) + memset(dptr, 0xFF, tmp.length); + aml_bufcpy(dptr, bpos & 7, sptr, 0, blen); + aml_xfldio(scope, data, &tmp, ACPI_IOWRITE); + break; + default: + if (blen > aml_intlen) { + aml_die("jk Big Buffer other!\n"); + } + aml_bufcpy(dptr, bpos, sptr, 0, blen); + break; + } + } + aml_freevalue(&tmp); + aml_unlockfield(scope, fld); +} + +/* Create Field Object data index + * AMLOP_FIELD n:OpRegion NULL + * AMLOP_INDEXFIELD n:Field n:Field + * AMLOP_BANKFIELD n:OpRegion n:Field + * AMLOP_CREATEFIELD t:Buffer NULL + * AMLOP_CREATEBITFIELD t:Buffer NULL + * AMLOP_CREATEBYTEFIELD t:Buffer NULL + * AMLOP_CREATEWORDFIELD t:Buffer NULL + * AMLOP_CREATEDWORDFIELD t:Buffer NULL + * AMLOP_CREATEQWORDFIELD t:Buffer NULL + * AMLOP_INDEX t:Buffer NULL + */ +void +aml_xcreatefield(struct aml_value *field, int opcode, + struct aml_value *data, int bpos, int blen, + struct aml_value *index, int indexval) +{ + dnprintf(10, "## %s(%s): %s %.4x-%.4x\n", + aml_mnem(opcode, 0), + blen > aml_intlen ? "BUF" : "INT", + aml_nodename(field->node), bpos, blen); + if (index) { + dnprintf(10, " index:%s:%.2x\n", aml_nodename(index->node), + indexval); + } + dnprintf(10, " data:%s\n", aml_nodename(data->node)); + field->type = (opcode == AMLOP_FIELD || + opcode == AMLOP_INDEXFIELD || + opcode == AMLOP_BANKFIELD) ? + AML_OBJTYPE_FIELDUNIT : + AML_OBJTYPE_BUFFERFIELD; + field->v_field.type = opcode; + field->v_field.bitpos = bpos; + field->v_field.bitlen = blen; + field->v_field.ref3 = indexval; + field->v_field.ref2 = index; + field->v_field.ref1 = data; + + /* Increase reference count */ + aml_xaddref(data, "Field.Data"); + aml_xaddref(index, "Field.Index"); +} + +/* Parse Field/IndexField/BankField scope */ +void +aml_xparsefieldlist(struct aml_scope *mscope, int opcode, int flags, + struct aml_value *data, struct aml_value *index, int indexval) +{ + struct aml_value *rv; + int bpos, blen; + + if (mscope == NULL) + return; + bpos = 0; + while (mscope->pos < mscope->end) { + switch (*mscope->pos) { + case 0x00: // reserved, length + mscope->pos++; + blen = aml_parselength(mscope); + break; + case 0x01: // flags + mscope->pos += 3; + blen = 0; + break; + default: // 4-byte name, length + mscope->pos = aml_xparsename(mscope->pos, mscope->node, + ns_xcreate, &rv); + blen = aml_parselength(mscope); + rv->v_field.flags = flags; + switch (opcode) { + case AMLOP_FIELD: + /* nbF */ + aml_xcreatefield(rv, opcode, data, bpos, + blen, NULL, 0); + break; + case AMLOP_INDEXFIELD: + /* nnbF */ + aml_xcreatefield(rv, opcode, data, bpos & 7, + blen, index, bpos>>3); + break; + case AMLOP_BANKFIELD: + /* nnibF */ + aml_xcreatefield(rv, opcode, data, bpos, + blen, index, indexval); + break; + } + break; + } + bpos += blen; + } +} + +/* + * Mutex/Event utility functions + */ +int acpi_xmutex_acquire(struct aml_scope *, struct aml_value *, int); +void acpi_xmutex_release(struct aml_scope *, struct aml_value *); +int acpi_xevent_wait(struct aml_scope *, struct aml_value *, int); +void acpi_xevent_signal(struct aml_scope *, struct aml_value *); +void acpi_xevent_reset(struct aml_scope *, struct aml_value *); + +int +acpi_xmutex_acquire(struct aml_scope *scope, struct aml_value *mtx, + int timeout) +{ + int err; + + if (mtx->v_mtx.owner == NULL || scope == mtx->v_mtx.owner) { + /* We are now the owner */ + mtx->v_mtx.owner = scope; + if (mtx == aml_global_lock) { + dnprintf(10,"LOCKING GLOBAL\n"); + err = acpi_acquire_global_lock(&dsdt_softc->sc_facs->global_lock); + } + dnprintf(5,"%s acquires mutex %s\n", scope->node->name, + mtx->node->name); + return 0; + } + else if (timeout == 0) { + return 1; + } + /* Wait for mutex */ + return 0; +} + +void +acpi_xmutex_release(struct aml_scope *scope, struct aml_value *mtx) +{ + int err; + + if (mtx == aml_global_lock) { + dnprintf(10,"UNLOCKING GLOBAL\n"); + err=acpi_release_global_lock(&dsdt_softc->sc_facs->global_lock); + } + dnprintf(5, "%s releases mutex %s\n", scope->node->name, + mtx->node->name); + mtx->v_mtx.owner = NULL; + /* Wakeup waiters */ +} + +int +acpi_xevent_wait(struct aml_scope *scope, struct aml_value *evt, int timeout) +{ + if (evt->v_evt.state == 1) { + /* Object is signaled */ + return 0; + } + else if (timeout == 0) { + /* Zero timeout */ + return 1; + } + /* Wait for timeout or signal */ + return 0; +} + +void +acpi_xevent_signal(struct aml_scope *scope, struct aml_value *evt) +{ + evt->v_evt.state = 1; + /* Wakeup waiters */ +} + +void +acpi_xevent_reset(struct aml_scope *scope, struct aml_value *evt) +{ + evt->v_evt.state = 0; +} + +/* Store result value into an object */ +void +aml_xstore(struct aml_scope *scope, struct aml_value *lhs , int64_t ival, + struct aml_value *rhs) +{ + struct aml_value tmp; + int mlen; + + /* Already set */ + if (lhs == rhs || lhs == NULL || lhs->type == AML_OBJTYPE_NOTARGET) { + return; + } + memset(&tmp, 0, sizeof(tmp)); + tmp.refcnt=99; + if (rhs == NULL) { + rhs = _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, ival, NULL); + } + if (rhs->type == AML_OBJTYPE_BUFFERFIELD || + rhs->type == AML_OBJTYPE_FIELDUNIT) { + aml_xfldio(scope, rhs, &tmp, ACPI_IOREAD); + rhs = &tmp; + } + while (lhs->type == AML_OBJTYPE_OBJREF) { + lhs = lhs->v_objref.ref; + } + switch (lhs->type) { + case AML_OBJTYPE_UNINITIALIZED: + aml_copyvalue(lhs, rhs); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + aml_xfldio(scope, lhs, rhs, ACPI_IOWRITE); + break; + case AML_OBJTYPE_DEBUGOBJ: + break; + case AML_OBJTYPE_INTEGER: + aml_xconvert(rhs, &rhs, lhs->type, 0); + lhs->v_integer = rhs->v_integer; + aml_xdelref(&rhs, "store.int"); + break; + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_STRING: + aml_xconvert(rhs, &rhs, lhs->type, 0); + if (lhs->length < rhs->length) { + dnprintf(10,"Overrun! %d,%d\n", lhs->length, rhs->length); + aml_freevalue(lhs); + _aml_setvalue(lhs, rhs->type, rhs->length, NULL); + } + mlen = min(lhs->length, rhs->length); + memset(lhs->v_buffer, 0x00, lhs->length); + memcpy(lhs->v_buffer, rhs->v_buffer, mlen); + aml_xdelref(&rhs, "store.bufstr"); + break; + case AML_OBJTYPE_PACKAGE: + /* Convert to LHS type, copy into LHS */ + if (rhs->type != AML_OBJTYPE_PACKAGE) { + aml_die("Copy non-package into package?"); + } + aml_freevalue(lhs); + aml_copyvalue(lhs, rhs); + break; + default: + aml_die("Store to default type! %x\n", lhs->type); + break; + } + aml_freevalue(&tmp); +} + +/* Disassembler routines */ +void aml_disprintf(void *arg, const char *fmt, ...); + +void +aml_disprintf(void *arg, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +void +aml_disasm(struct aml_scope *scope, int lvl, + void (*dbprintf)(void *, const char *, ...), + void *arg) +{ + int pc, opcode; + struct aml_opcode *htab; + uint64_t ival; + struct aml_value *rv, tmp; + uint8_t *end; + struct aml_scope *ms; + char *ch; + char mch[64]; + + if (dbprintf == NULL) + dbprintf = aml_disprintf; + + pc = aml_pc(scope->pos); + opcode = aml_parseopcode(scope); + htab = aml_findopcode(opcode); + + /* Display address + indent */ + if (lvl <= 0x7FFF) { + dbprintf(arg, "%.4x ", pc); + for (pc=0; pc<lvl; pc++) { + dbprintf(arg, " "); + } + } + ch = NULL; + switch (opcode) { + case AMLOP_NAMECHAR: + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xsearch, &rv); + if (rv->type == AML_OBJTYPE_NAMEREF) { + ch = "@@@"; + aml_xdelref(&rv, "disasm"); + break; + } + /* if this is a method, get arguments */ + strlcpy(mch, aml_nodename(rv->node), sizeof(mch)); + if (rv->type == AML_OBJTYPE_METHOD) { + strlcat(mch, "(", sizeof(mch)); + for (ival=0; ival<AML_METHOD_ARGCOUNT(rv->v_method.flags); ival++) { + strlcat(mch, ival ? ", %z" : "%z", + sizeof(mch)); + } + strlcat(mch, ")", sizeof(mch)); + } + ch = mch; + break; + + case AMLOP_ZERO: + case AMLOP_ONE: + case AMLOP_ONES: + case AMLOP_LOCAL0: + case AMLOP_LOCAL1: + case AMLOP_LOCAL2: + case AMLOP_LOCAL3: + case AMLOP_LOCAL4: + case AMLOP_LOCAL5: + case AMLOP_LOCAL6: + case AMLOP_LOCAL7: + case AMLOP_ARG0: + case AMLOP_ARG1: + case AMLOP_ARG2: + case AMLOP_ARG3: + case AMLOP_ARG4: + case AMLOP_ARG5: + case AMLOP_ARG6: + case AMLOP_NOP: + case AMLOP_REVISION: + case AMLOP_DEBUG: + case AMLOP_CONTINUE: + case AMLOP_BREAKPOINT: + case AMLOP_BREAK: + ch="%m"; + break; + case AMLOP_BYTEPREFIX: + ch="%b"; + break; + case AMLOP_WORDPREFIX: + ch="%w"; + break; + case AMLOP_DWORDPREFIX: + ch="%d"; + break; + case AMLOP_QWORDPREFIX: + ch="%q"; + break; + case AMLOP_STRINGPREFIX: + ch="%a"; + break; + + case AMLOP_INCREMENT: + case AMLOP_DECREMENT: + case AMLOP_LNOT: + case AMLOP_SIZEOF: + case AMLOP_DEREFOF: + case AMLOP_REFOF: + case AMLOP_OBJECTTYPE: + case AMLOP_UNLOAD: + case AMLOP_RELEASE: + case AMLOP_SIGNAL: + case AMLOP_RESET: + case AMLOP_STALL: + case AMLOP_SLEEP: + case AMLOP_RETURN: + ch="%m(%n)"; + break; + case AMLOP_OR: + case AMLOP_ADD: + case AMLOP_AND: + case AMLOP_NAND: + case AMLOP_XOR: + case AMLOP_SHL: + case AMLOP_SHR: + case AMLOP_NOR: + case AMLOP_MOD: + case AMLOP_SUBTRACT: + case AMLOP_MULTIPLY: + case AMLOP_INDEX: + case AMLOP_CONCAT: + case AMLOP_CONCATRES: + case AMLOP_TOSTRING: + ch="%m(%n, %n, %n)"; + break; + case AMLOP_CREATEBYTEFIELD: + case AMLOP_CREATEWORDFIELD: + case AMLOP_CREATEDWORDFIELD: + case AMLOP_CREATEQWORDFIELD: + case AMLOP_CREATEBITFIELD: + ch="%m(%n, %n, %N)"; + break; + case AMLOP_CREATEFIELD: + ch="%m(%n, %n, %n, %N)"; + break; + case AMLOP_DIVIDE: + case AMLOP_MID: + ch="%m(%n, %n, %n, %n)"; + break; + case AMLOP_LAND: + case AMLOP_LOR: + case AMLOP_LNOTEQUAL: + case AMLOP_LLESSEQUAL: + case AMLOP_LLESS: + case AMLOP_LEQUAL: + case AMLOP_LGREATEREQUAL: + case AMLOP_LGREATER: + case AMLOP_NOT: + case AMLOP_FINDSETLEFTBIT: + case AMLOP_FINDSETRIGHTBIT: + case AMLOP_TOINTEGER: + case AMLOP_TOBUFFER: + case AMLOP_TOHEXSTRING: + case AMLOP_TODECSTRING: + case AMLOP_FROMBCD: + case AMLOP_TOBCD: + case AMLOP_WAIT: + case AMLOP_LOAD: + case AMLOP_STORE: + case AMLOP_NOTIFY: + case AMLOP_COPYOBJECT: + ch="%m(%n, %n)"; + break; + case AMLOP_ACQUIRE: + ch = "%m(%n, %w)"; + break; + case AMLOP_CONDREFOF: + ch="%m(%R, %n)"; + break; + case AMLOP_ALIAS: + ch="%m(%n, %N)"; + break; + case AMLOP_NAME: + ch="%m(%N, %n)"; + break; + case AMLOP_EVENT: + ch="%m(%N)"; + break; + case AMLOP_MUTEX: + ch = "%m(%N, %b)"; + break; + case AMLOP_OPREGION: + ch = "%m(%N, %b, %n, %n)"; + break; + case AMLOP_DATAREGION: + ch="%m(%N, %n, %n, %n)"; + break; + case AMLOP_FATAL: + ch = "%m(%b, %d, %n)"; + break; + case AMLOP_IF: + case AMLOP_WHILE: + case AMLOP_SCOPE: + case AMLOP_THERMALZONE: + case AMLOP_VARPACKAGE: + end = aml_parseend(scope); + ch = "%m(%n) {\n%T}"; + break; + case AMLOP_DEVICE: + end = aml_parseend(scope); + ch = "%m(%N) {\n%T}"; + break; + case AMLOP_POWERRSRC: + end = aml_parseend(scope); + ch = "%m(%N, %b, %w) {\n%T}"; + break; + case AMLOP_PROCESSOR: + end = aml_parseend(scope); + ch = "%m(%N, %b, %d, %b) {\n%T}"; + break; + case AMLOP_METHOD: + end = aml_parseend(scope); + ch = "%m(%N, %b) {\n%T}"; + break; + case AMLOP_PACKAGE: + end = aml_parseend(scope); + ch = "%m(%b) {\n%T}"; + break; + case AMLOP_ELSE: + end = aml_parseend(scope); + ch = "%m {\n%T}"; + break; + case AMLOP_BUFFER: + end = aml_parseend(scope); + ch = "%m(%n) { %B }"; + break; + case AMLOP_INDEXFIELD: + end = aml_parseend(scope); + ch = "%m(%n, %n, %b) {\n%F}"; + break; + case AMLOP_BANKFIELD: + end = aml_parseend(scope); + ch = "%m(%n, %n, %n, %b) {\n%F}"; + break; + case AMLOP_FIELD: + end = aml_parseend(scope); + ch = "%m(%n, %b) {\n%F}"; + break; + case AMLOP_MATCH: + ch = "%m(%n, %b, %n, %b, %n, %n)"; + break; + case AMLOP_LOADTABLE: + ch = "%m(%n, %n, %n, %n, %n, %n)"; + break; + default: + aml_die("opcode = %x\n", opcode); + break; + } + + /* Parse printable buffer args */ + while (ch && *ch) { + char c; + + if (*ch != '%') { + dbprintf(arg,"%c", *(ch++)); + continue; + } + c = *(++ch); + switch (c) { + case 'b': + case 'w': + case 'd': + case 'q': + /* Parse simple object: don't allocate */ + aml_xparsesimple(scope, c, &tmp); + dbprintf(arg,"0x%llx", tmp.v_integer); + break; + case 'a': + dbprintf(arg, "\'%s\'", scope->pos); + scope->pos += strlen(scope->pos)+1; + break; + case 'N': + /* Create Name */ + rv = aml_xparsesimple(scope, c, NULL); + dbprintf(arg,aml_nodename(rv->node)); + break; + case 'm': + /* display mnemonic */ + dbprintf(arg,htab->mnem); + break; + case 'R': + /* Search name */ + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xdis, &rv); + break; + case 'z': + case 'n': + /* generic arg: recurse */ + aml_disasm(scope, lvl | 0x8000, dbprintf, arg); + break; + case 'B': + /* Buffer */ + scope->pos = end; + break; + case 'F': + /* Field List */ + tmp.v_buffer = scope->pos; + tmp.length = end - scope->pos; + + ms = aml_xpushscope(scope, &tmp, scope->node, 0); + while (ms && ms->pos < ms->end) { + if (*ms->pos == 0x00) { + ms->pos++; + aml_parselength(ms); + } + else if (*ms->pos == 0x01) { + ms->pos+=3; + } + else { + ms->pos = aml_xparsename(ms->pos, + ms->node, ns_xcreate, &rv); + aml_parselength(ms); + dbprintf(arg," %s\n", + aml_nodename(rv->node)); + } + } + aml_xpopscope(ms); + + /* Display address and closing bracket */ + dbprintf(arg,"%.4x ", aml_pc(scope->pos)); + for (pc=0; pc<(lvl & 0x7FFF); pc++) { + dbprintf(arg," "); + } + scope->pos = end; + break; + case 'T': + /* Scope: Termlist */ + tmp.v_buffer = scope->pos; + tmp.length = end - scope->pos; + + ms = aml_xpushscope(scope, &tmp, scope->node, 0); + while (ms && ms->pos < ms->end) { + aml_disasm(ms, (lvl + 1) & 0x7FFF, + dbprintf, arg); + } + aml_xpopscope(ms); + + /* Display address and closing bracket */ + dbprintf(arg,"%.4x ", aml_pc(scope->pos)); + for (pc=0; pc<(lvl & 0x7FFF); pc++) { + dbprintf(arg," "); + } + scope->pos = end; + break; + } + ch++; + } + if (lvl <= 0x7FFF) { + dbprintf(arg,"\n"); + } +} + +int aml_busy; + +/* Evaluate method or buffervalue objects */ +struct aml_value * +aml_xeval(struct aml_scope *scope, struct aml_value *my_ret, int ret_type, + int argc, struct aml_value *argv) +{ + struct aml_value *tmp = my_ret; + struct aml_scope *ms; + int idx; + + switch (tmp->type) { + case AML_OBJTYPE_METHOD: + dnprintf(10,"\n--== Eval Method [%s, %d args] to %c ==--\n", + aml_nodename(tmp->node), + AML_METHOD_ARGCOUNT(tmp->v_method.flags), + ret_type); + ms = aml_xpushscope(scope, tmp, tmp->node, AMLOP_METHOD); + ms->args = acpi_os_malloc(7 * sizeof(struct aml_value)); + + /* Parse method arguments */ + for (idx=0; idx<AML_METHOD_ARGCOUNT(tmp->v_method.flags); idx++) { + ms->args[idx].type = AML_OBJTYPE_OBJREF; + ms->args[idx].v_objref.type = AMLOP_ARG0 + idx; + if (argv) { + ms->args[idx].v_objref.ref = &argv[idx]; + argv[idx].refcnt = 99; + } + else { + ms->args[idx].v_objref.ref = + aml_xparse(scope, 't', "ARGX"); + } + } +#ifdef ACPI_DEBUG + aml_showstack(ms); +#endif + + /* Evaluate method scope */ + if (tmp->v_method.fneval != NULL) { + my_ret = tmp->v_method.fneval(ms, NULL); + } + else { + aml_xparse(ms, 'T', "METHEVAL"); + my_ret = ms->retv; + } + dnprintf(10,"\n--==Finished evaluating method: %s %c\n", + aml_nodename(tmp->node), ret_type); +#ifdef ACPI_DEBUG + aml_showvalue(my_ret, 0); + aml_showstack(ms); +#endif + aml_xpopscope(ms); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + my_ret = aml_allocvalue(0,0,NULL); + dnprintf(20,"quick: Convert Bufferfield to %c 0x%x\n", + ret_type, my_ret); + aml_xfldio(scope, tmp, my_ret, ACPI_IOREAD); + break; + } + if (ret_type == 'i' && my_ret && my_ret->type != AML_OBJTYPE_INTEGER) { +#ifndef SMALL_KERNEL + aml_showvalue(my_ret, 8-100); +#endif + aml_die("Not Integer"); + } + return my_ret; +} + +/* + * The following opcodes produce return values + * TOSTRING -> Str + * TOHEXSTR -> Str + * TODECSTR -> Str + * STRINGPFX -> Str + * BUFFER -> Buf + * CONCATRES -> Buf + * TOBUFFER -> Buf + * MID -> Buf|Str + * CONCAT -> Buf|Str + * PACKAGE -> Pkg + * VARPACKAGE -> Pkg + * LOCALx -> Obj + * ARGx -> Obj + * NAMECHAR -> Obj + * REFOF -> ObjRef + * INDEX -> ObjRef + * DEREFOF -> DataRefObj + * COPYOBJECT -> DataRefObj + * STORE -> DataRefObj + + * ZERO -> Int + * ONE -> Int + * ONES -> Int + * REVISION -> Int + * B/W/D/Q -> Int + * OR -> Int + * AND -> Int + * ADD -> Int + * NAND -> Int + * XOR -> Int + * SHL -> Int + * SHR -> Int + * NOR -> Int + * MOD -> Int + * SUBTRACT -> Int + * MULTIPLY -> Int + * DIVIDE -> Int + * NOT -> Int + * TOBCD -> Int + * FROMBCD -> Int + * FSLEFTBIT -> Int + * FSRIGHTBIT -> Int + * INCREMENT -> Int + * DECREMENT -> Int + * TOINTEGER -> Int + * MATCH -> Int + * SIZEOF -> Int + * OBJECTTYPE -> Int + * TIMER -> Int + + * CONDREFOF -> Bool + * ACQUIRE -> Bool + * WAIT -> Bool + * LNOT -> Bool + * LAND -> Bool + * LOR -> Bool + * LLESS -> Bool + * LEQUAL -> Bool + * LGREATER -> Bool + * LNOTEQUAL -> Bool + * LLESSEQUAL -> Bool + * LGREATEREQ -> Bool + + * LOADTABLE -> DDB + * DEBUG -> Debug + + * The following opcodes do not generate a return value: + * NOP + * BREAKPOINT + * RELEASE + * RESET + * SIGNAL + * NAME + * ALIAS + * OPREGION + * DATAREGION + * EVENT + * MUTEX + * SCOPE + * DEVICE + * THERMALZONE + * POWERRSRC + * PROCESSOR + * METHOD + * CREATEFIELD + * CREATEBITFIELD + * CREATEBYTEFIELD + * CREATEWORDFIELD + * CREATEDWORDFIELD + * CREATEQWORDFIELD + * FIELD + * INDEXFIELD + * BANKFIELD + * STALL + * SLEEP + * NOTIFY + * FATAL + * LOAD + * UNLOAD + * IF + * ELSE + * WHILE + * BREAK + * CONTINUE + */ + +/* Parse a simple object from AML Bytestream */ +struct aml_value * +aml_xparsesimple(struct aml_scope *scope, char ch, struct aml_value *rv) +{ + if (ch == AML_ARG_CREATENAME) { + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xcreate, &rv); + return rv; + } + else if (ch == AML_ARG_SEARCHNAME) { + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xsearch, &rv); + return rv; + } + if (rv == NULL) + rv = aml_allocvalue(0,0,NULL); + switch (ch) { + case AML_ARG_REVISION: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, AML_REVISION, NULL); + break; + case AML_ARG_DEBUG: + _aml_setvalue(rv, AML_OBJTYPE_DEBUGOBJ, 0, NULL); + break; + case AML_ARG_BYTE: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get8(scope->pos), NULL); + scope->pos += 1; + break; + case AML_ARG_WORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get16(scope->pos), NULL); + scope->pos += 2; + break; + case AML_ARG_DWORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get32(scope->pos), NULL); + scope->pos += 4; + break; + case AML_ARG_QWORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get64(scope->pos), NULL); + scope->pos += 8; + break; + case AML_ARG_STRING: + _aml_setvalue(rv, AML_OBJTYPE_STRING, -1, scope->pos); + scope->pos += rv->length+1; + break; + } + return rv; +} + +/* + * Main Opcode Parser/Evaluator + * + * ret_type is expected type for return value + * 'o' = Data Object (Int/Str/Buf/Pkg/Name) + * 'i' = Integer + * 't' = TermArg (Int/Str/Buf/Pkg) + * 'r' = Target (NamedObj/Local/Arg/Null) + * 'S' = SuperName (NamedObj/Local/Arg) + * 'T' = TermList + */ +#define aml_debugger(x) + +struct aml_value * +aml_xparse(struct aml_scope *scope, int ret_type, const char *stype) +{ + int opcode, idx, pc, optype[8]; + struct aml_opcode *htab; + struct aml_value *opargs[8], *my_ret, *tmp, *cname; + struct aml_scope *mscope; + const char *ch; + int64_t ival; + + my_ret = NULL; + if (scope == NULL || scope->pos >= scope->end) { + return NULL; + } + start: + if (odp++ > 125) + panic("depth"); + + /* --== Stage 0: Get Opcode ==-- */ + pc = aml_pc(scope->pos); + aml_debugger(scope); + + opcode = aml_parseopcode(scope); + delay(amlop_delay); + + htab = aml_findopcode(opcode); + if (htab == NULL) { + /* No opcode handler */ + aml_die("Unknown opcode: %.4x @ %.4x", opcode, + aml_pc(scope->pos - opsize(opcode))); + } + dnprintf(18,"%.4x %s\n", pc, aml_mnem(opcode, scope->pos)); + + /* --== Stage 1: Process opcode arguments ==-- */ + cname = NULL; + memset(opargs, 0, sizeof(opargs)); + memset(optype, 0, sizeof(optype)); + idx = 0; + for (ch = htab->args; *ch; ch++) { + struct aml_value *rv; + uint8_t *end; + + rv = NULL; + switch (*ch) { + case AML_ARG_OBJLEN: + end = aml_parseend(scope); + break; + case AML_ARG_IFELSE: + /* Special Case: IF-ELSE:piTbpT or IF:piT */ + ch = (*end == AMLOP_ELSE && end < scope->end) ? + "-TbpT" : "-T"; + break; + + /* Complex arguments */ + case 's': + case 'S': + case AML_ARG_TARGET: + case AML_ARG_TERMOBJ: + case AML_ARG_INTEGER: + if (*ch == 'r' && *scope->pos == AMLOP_ZERO) { + /* Special case: NULL Target */ + rv = aml_allocvalue(AML_OBJTYPE_NOTARGET, 0, NULL); + scope->pos++; + } + else { + rv = aml_xparse(scope, *ch, htab->mnem); + if (rv == NULL) + aml_die("NULL RESULT"); + } + break; + + /* Simple arguments */ + case AML_ARG_WHILE: + case AML_ARG_BUFFER: + case AML_ARG_METHOD: + case AML_ARG_FIELDLIST: + case AML_ARG_TERMOBJLIST: + rv = aml_allocvalue(AML_OBJTYPE_SCOPE, 0, NULL); + rv->v_buffer = scope->pos; + rv->length = end - scope->pos; + scope->pos = end; + break; + case AML_ARG_CONST: + rv = aml_allocvalue(AML_OBJTYPE_INTEGER, + (char)opcode, NULL); + break; + case AML_ARG_CREATENAME: + rv = aml_xparsesimple(scope, *ch, NULL); + cname = rv; + if (cname->type != 0 && opcode != AMLOP_SCOPE) + dnprintf(10, "%s value already exists %s\n", + aml_nodename(cname->node), + htab->mnem); + break; + case AML_ARG_SEARCHNAME: + rv = aml_xparsesimple(scope, *ch, NULL); + if (rv->type != AML_OBJTYPE_NAMEREF) + aml_xaddref(rv, "Search Name"); + break; + case AML_ARG_BYTE: + case AML_ARG_WORD: + case AML_ARG_DWORD: + case AML_ARG_QWORD: + case AML_ARG_DEBUG: + case AML_ARG_STRING: + case AML_ARG_REVISION: + rv = aml_xparsesimple(scope, *ch, NULL); + break; + case AML_ARG_STKLOCAL: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 0); + if (mscope->locals == NULL) { + mscope->locals = acpi_os_malloc(8 * sizeof(struct aml_value)); + } + rv = &mscope->locals[opcode - AMLOP_LOCAL0]; + if (rv->refcnt == 0) { + rv->refcnt++; + } + rv->stack = opcode; + rv->node = mscope->node; + break; + case AML_ARG_STKARG: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 0); + rv = mscope->args[opcode - AMLOP_ARG0].v_objref.ref; + break; + default: + aml_die("Unknown arg type: %c\n", *ch); + break; + } + if (rv != NULL) { + optype[idx] = *ch; + opargs[idx++] = rv; + } + } + + /* Check for Op(Src1,Src2,Src1) type operations */ + for (idx=0; optype[idx]; idx++) { + int jdx; + for (jdx=idx+1; optype[jdx]; jdx++) { + if (opargs[idx] == opargs[jdx]) { + dnprintf(12,"STORE SAME %s %d,%d -> [%s] ", + htab->mnem, idx, jdx, + aml_nodename(scope->node)); + } + } + } + + /* --== Stage 2: Process opcode ==-- */ + ival = 0; + my_ret = NULL; + mscope = NULL; + switch (opcode) { + case AMLOP_NOP: + case AMLOP_BREAKPOINT: + break; + case AMLOP_LOCAL0: + case AMLOP_LOCAL1: + case AMLOP_LOCAL2: + case AMLOP_LOCAL3: + case AMLOP_LOCAL4: + case AMLOP_LOCAL5: + case AMLOP_LOCAL6: + case AMLOP_LOCAL7: + my_ret = opargs[0]; + aml_xaddref(my_ret, htab->mnem); + if (ret_type == AML_ARG_INTEGER) { + /* Return copy of integer value */ + aml_xconvert(my_ret, &my_ret, AML_OBJTYPE_INTEGER, 0); + ival = my_ret->v_integer; + aml_xdelref(&my_ret, "local.int"); + my_ret = NULL; + } + else if (ret_type == AML_ARG_TARGET) { + /* Store to LocalX: free object */ + aml_freevalue(my_ret); + } + break; + case AMLOP_ARG0: + case AMLOP_ARG1: + case AMLOP_ARG2: + case AMLOP_ARG3: + case AMLOP_ARG4: + case AMLOP_ARG5: + case AMLOP_ARG6: + /* These are not allocated dynamically but do not have node */ + my_ret = opargs[0]; + aml_xaddref(my_ret, htab->mnem); + break; + case AMLOP_NAMECHAR: + /* opargs[0] = named object (node != NULL), or nameref */ + my_ret = opargs[0]; + if (my_ret->type == AML_OBJTYPE_OBJREF) { + my_ret = my_ret->v_objref.ref; + aml_xaddref(my_ret, "de-alias"); + } + if (ret_type == 'i' || ret_type == 't' || ret_type == 'T') { + /* Return TermArg or Integer: Evaluate object */ + my_ret = aml_xeval(scope, my_ret, ret_type, 0, NULL); + } + else if (my_ret->type == AML_OBJTYPE_METHOD) { + /* This should only happen with CondRef */ + dnprintf(12,"non-termarg method : %s\n", stype); + aml_xaddref(my_ret, "zoom"); + } + break; + + case AMLOP_ZERO: + case AMLOP_ONE: + case AMLOP_ONES: + case AMLOP_DEBUG: + case AMLOP_REVISION: + case AMLOP_BYTEPREFIX: + case AMLOP_WORDPREFIX: + case AMLOP_DWORDPREFIX: + case AMLOP_QWORDPREFIX: + case AMLOP_STRINGPREFIX: + my_ret = opargs[0]; + break; + + case AMLOP_BUFFER: + /* Buffer: iB => Buffer */ + my_ret = aml_allocvalue(AML_OBJTYPE_BUFFER, + opargs[0]->v_integer, NULL); + memcpy(my_ret->v_buffer, opargs[1]->v_buffer, + opargs[1]->length); + break; + case AMLOP_PACKAGE: + case AMLOP_VARPACKAGE: + /* Package/VarPackage: bT/iT => Package */ + my_ret = aml_allocvalue(AML_OBJTYPE_PACKAGE, + opargs[0]->v_integer, 0); + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_PACKAGE); + + for (idx=0; idx<my_ret->length; idx++) { + tmp = aml_xparse(mscope, 'o', "Package"); + if (tmp == NULL) { + continue; + } + if (tmp->node) { + /* Object is a named node: store as string */ + const char *nn = aml_nodename(tmp->node); + aml_xdelref(&tmp, "pkg.node"); + tmp = aml_allocvalue(AML_OBJTYPE_STRING, + -1, nn); + } + else if (tmp->type == AML_OBJTYPE_NAMEREF) { + const char *nn = aml_getname(tmp->v_nameref); + aml_xdelref(&tmp, "pkg.node"); + tmp = aml_allocvalue(AML_OBJTYPE_STRING, + -1, nn); + } + /* Package value already allocated; delete it + * and replace with pointer to return value */ + aml_xdelref(&my_ret->v_package[idx], "pkg/init"); + my_ret->v_package[idx] = tmp; + } + aml_xpopscope(mscope); + mscope = NULL; + break; + + /* Math/Logical operations */ + case AMLOP_OR: + case AMLOP_ADD: + case AMLOP_AND: + case AMLOP_NAND: + case AMLOP_XOR: + case AMLOP_SHL: + case AMLOP_SHR: + case AMLOP_NOR: + case AMLOP_MOD: + case AMLOP_SUBTRACT: + case AMLOP_MULTIPLY: + /* XXX: iir => I */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, opcode); + aml_xstore(scope, opargs[2], ival, NULL); + break; + case AMLOP_DIVIDE: + /* Divide: iirr => I */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, AMLOP_MOD); + aml_xstore(scope, opargs[2], ival, NULL); + + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, AMLOP_DIVIDE); + aml_xstore(scope, opargs[3], ival, NULL); + break; + case AMLOP_NOT: + case AMLOP_TOBCD: + case AMLOP_FROMBCD: + case AMLOP_FINDSETLEFTBIT: + case AMLOP_FINDSETRIGHTBIT: + /* XXX: ir => I */ + ival = aml_evalexpr(opargs[0]->v_integer, 0, opcode); + aml_xstore(scope, opargs[1], ival, NULL); + break; + case AMLOP_INCREMENT: + case AMLOP_DECREMENT: + /* Inc/Dec: S => I */ + my_ret = aml_xeval(scope, opargs[0], AML_ARG_INTEGER, 0, NULL); + ival = aml_evalexpr(my_ret->v_integer, 1, opcode); + aml_xstore(scope, opargs[0], ival, NULL); + break; + case AMLOP_LNOT: + /* LNot: i => Bool */ + ival = aml_evalexpr(opargs[0]->v_integer, 0, opcode); + break; + case AMLOP_LOR: + case AMLOP_LAND: + /* XXX: ii => Bool */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, opcode); + break; + case AMLOP_LLESS: + case AMLOP_LEQUAL: + case AMLOP_LGREATER: + case AMLOP_LNOTEQUAL: + case AMLOP_LLESSEQUAL: + case AMLOP_LGREATEREQUAL: + /* XXX: tt => Bool */ + ival = aml_xcompare(opargs[0], opargs[1], opcode); + break; + + /* Reference/Store operations */ + case AMLOP_CONDREFOF: + /* CondRef: rr => I */ + ival = 0; + if (opargs[0]->node != NULL) { + aml_freevalue(opargs[1]); + + /* Create Object Reference */ + _aml_setvalue(opargs[1], AML_OBJTYPE_OBJREF, 0, opargs[0]); + opargs[1]->v_objref.type = AMLOP_REFOF; + aml_xaddref(opargs[1], "CondRef"); + + /* Mark that we found it */ + ival = -1; + } + break; + case AMLOP_REFOF: + /* RefOf: r => ObjRef */ + my_ret = aml_allocvalue(AML_OBJTYPE_OBJREF, 0, opargs[0]); + my_ret->v_objref.type = AMLOP_REFOF; + aml_xaddref(my_ret->v_objref.ref, "RefOf"); + break; + case AMLOP_INDEX: + /* Index: tir => ObjRef */ + idx = opargs[1]->v_integer; + if (idx >= opargs[0]->length || idx < 0) { +#ifndef SMALL_KERNEL + aml_showvalue(opargs[0], 0); +#endif + aml_die("Index out of bounds %d/%d\n", idx, + opargs[0]->length); + } + switch (opargs[0]->type) { + case AML_OBJTYPE_PACKAGE: + /* Don't set opargs[0] to NULL */ + if (ret_type == 't' || ret_type == 'i' || ret_type == 'T') { + my_ret = opargs[0]->v_package[idx]; + aml_xaddref(my_ret, "Index.Package"); + } + else { + my_ret = aml_allocvalue(AML_OBJTYPE_OBJREF, 0, + opargs[0]->v_package[idx]); + my_ret->v_objref.type = AMLOP_PACKAGE; + aml_xaddref(my_ret->v_objref.ref, + "Index.Package"); + } + break; + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_STRING: + case AML_OBJTYPE_INTEGER: + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + if (ret_type == 't' || ret_type == 'i' || ret_type == 'T') { + dnprintf(12,"Index.Buf Term: %d = %x\n", + idx, tmp->v_buffer[idx]); + ival = tmp->v_buffer[idx]; + } + else { + dnprintf(12, "Index.Buf Targ\n"); + my_ret = aml_allocvalue(0,0,NULL); + aml_xcreatefield(my_ret, AMLOP_INDEX, tmp, + 8 * idx, 8, NULL, 0); + } + aml_xdelref(&tmp, "Index.BufStr"); + break; + default: + aml_die("Unknown index : %x\n", opargs[0]->type); + break; + } + aml_xstore(scope, opargs[2], ival, my_ret); + break; + case AMLOP_DEREFOF: + /* DerefOf: t:ObjRef => DataRefObj */ + if (opargs[0]->type == AML_OBJTYPE_OBJREF) { + my_ret = opargs[0]->v_objref.ref; + aml_xaddref(my_ret, "DerefOf"); + } + else { + my_ret = opargs[0]; + //aml_xaddref(my_ret, "DerefOf"); + } + break; + case AMLOP_COPYOBJECT: + /* CopyObject: t:DataRefObj, s:implename => DataRefObj */ + my_ret = opargs[0]; + aml_freevalue(opargs[1]); + aml_copyvalue(opargs[1], opargs[0]); + break; + case AMLOP_STORE: + /* Store: t:DataRefObj, S:upername => DataRefObj */ + my_ret = opargs[0]; + aml_xstore(scope, opargs[1], 0, opargs[0]); + break; + + /* Conversion */ + case AMLOP_TOINTEGER: + /* Source:CData, Result => Integer */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_INTEGER, 0); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOBUFFER: + /* Source:CData, Result => Buffer */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_BUFFER, 0); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOHEXSTRING: + /* Source:CData, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 'x'); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TODECSTRING: + /* Source:CData, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 'd'); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOSTRING: + /* Source:B, Length:I, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 0); + aml_die("tostring\n"); + break; + case AMLOP_CONCAT: + /* Source1:CData, Source2:CData, Result => CData */ + aml_xconcat(opargs[0], opargs[1], &my_ret); + aml_xstore(scope, opargs[2], 0, my_ret); + break; + case AMLOP_CONCATRES: + /* Concat two resource buffers: buf1, buf2, result => Buffer */ + aml_xconcatres(opargs[0], opargs[1], &my_ret); + aml_xstore(scope, opargs[2], 0, my_ret); + break; + case AMLOP_MID: + /* Source:BS, Index:I, Length:I, Result => BS */ + aml_xmid(opargs[0], opargs[1]->v_integer, + opargs[2]->v_integer, &my_ret); + aml_xstore(scope, opargs[3], 0, my_ret); + break; + case AMLOP_MATCH: + /* Match: Pkg, Op1, Val1, Op2, Val2, Index */ + ival = aml_xmatch(opargs[0], opargs[5]->v_integer, + opargs[1]->v_integer, opargs[2]->v_integer, + opargs[3]->v_integer, opargs[4]->v_integer); + break; + case AMLOP_SIZEOF: + /* Sizeof: S => i */ + ival = opargs[0]->length; + break; + case AMLOP_OBJECTTYPE: + /* ObjectType: S => i */ + ival = opargs[0]->type; + break; + + /* Mutex/Event handlers */ + case AMLOP_ACQUIRE: + /* Acquire: Sw => Bool */ + ival = acpi_xmutex_acquire(scope, opargs[0], + opargs[1]->v_integer); + break; + case AMLOP_RELEASE: + /* Release: S */ + acpi_xmutex_release(scope, opargs[0]); + break; + case AMLOP_WAIT: + /* Wait: Si => Bool */ + ival = acpi_xevent_wait(scope, opargs[0], + opargs[1]->v_integer); + break; + case AMLOP_RESET: + /* Reset: S */ + acpi_xevent_reset(scope, opargs[0]); + break; + case AMLOP_SIGNAL: + /* Signal: S */ + acpi_xevent_signal(scope, opargs[0]); + break; + + /* Named objects */ + case AMLOP_NAME: + /* Name: Nt */ + aml_freevalue(cname); + aml_copyvalue(cname, opargs[1]); + break; + case AMLOP_ALIAS: + /* Alias: nN */ + cname->type = AML_OBJTYPE_OBJREF; + cname->v_objref.type = AMLOP_ALIAS; + cname->v_objref.ref = opargs[0]; + while (cname->v_objref.ref->type == AML_OBJTYPE_OBJREF) { + /* Single indirection level */ + cname->v_objref.ref = cname->v_objref.ref->v_objref.ref; + } + aml_xaddref(cname->v_objref.ref, "Alias"); + break; + case AMLOP_OPREGION: + /* OpRegion: Nbii */ + cname->type = AML_OBJTYPE_OPREGION; + cname->v_opregion.iospace = opargs[1]->v_integer; + cname->v_opregion.iobase = opargs[2]->v_integer; + cname->v_opregion.iolen = opargs[3]->v_integer; + cname->v_opregion.flag = 0; + break; + case AMLOP_DATAREGION: + /* DataTableRegion: N,t:SigStr,t:OemIDStr,t:OemTableIDStr */ + cname->type = AML_OBJTYPE_OPREGION; + cname->v_opregion.iospace = GAS_SYSTEM_MEMORY; + cname->v_opregion.iobase = 0; + cname->v_opregion.iolen = 0; + aml_die("AML-DataTableRegion\n"); + break; + case AMLOP_EVENT: + /* Event: N */ + cname->type = AML_OBJTYPE_EVENT; + cname->v_integer = 0; + break; + case AMLOP_MUTEX: + /* Mutex: Nw */ + cname->type = AML_OBJTYPE_MUTEX; + cname->v_mtx.synclvl = opargs[1]->v_integer; + break; + case AMLOP_SCOPE: + /* Scope: NT */ + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_DEVICE: + /* Device: NT */ + cname->type = AML_OBJTYPE_DEVICE; + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_THERMALZONE: + /* ThermalZone: NT */ + cname->type = AML_OBJTYPE_THERMZONE; + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_POWERRSRC: + /* PowerRsrc: NbwT */ + cname->type = AML_OBJTYPE_POWERRSRC; + cname->v_powerrsrc.pwr_level = opargs[1]->v_integer; + cname->v_powerrsrc.pwr_order = opargs[2]->v_integer; + mscope = aml_xpushscope(scope, opargs[3], cname->node, opcode); + break; + case AMLOP_PROCESSOR: + /* Processor: NbdbT */ + cname->type = AML_OBJTYPE_PROCESSOR; + cname->v_processor.proc_id = opargs[1]->v_integer; + cname->v_processor.proc_addr = opargs[2]->v_integer; + cname->v_processor.proc_len = opargs[3]->v_integer; + mscope = aml_xpushscope(scope, opargs[4], cname->node, opcode); + break; + case AMLOP_METHOD: + /* Method: NbM */ + cname->type = AML_OBJTYPE_METHOD; + cname->v_method.flags = opargs[1]->v_integer; + cname->v_method.start = opargs[2]->v_buffer; + cname->v_method.end = cname->v_method.start + opargs[2]->length; + cname->v_method.base = aml_root.start; + break; + + /* Field objects */ + case AMLOP_CREATEFIELD: + /* Source:B, BitIndex:I, NumBits:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer, + opargs[2]->v_integer, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + break; + case AMLOP_CREATEBITFIELD: + /* Source:B, BitIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer, + 1, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + break; + case AMLOP_CREATEBYTEFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 8, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_BYTEACC; + break; + case AMLOP_CREATEWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 16, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_WORDACC; + break; + case AMLOP_CREATEDWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 32, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_DWORDACC; + break; + case AMLOP_CREATEQWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 64, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_QWORDACC; + break; + case AMLOP_FIELD: + /* Field: n:OpRegion, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[2], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[1]->v_integer, + opargs[0], NULL, 0); + break; + case AMLOP_INDEXFIELD: + /* IndexField: n:Index, n:Data, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[3], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[2]->v_integer, + opargs[1], opargs[0], 0); + break; + case AMLOP_BANKFIELD: + /* BankField: n:OpRegion, n:Field, i:Bank, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[4], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[3]->v_integer, + opargs[0], opargs[1], opargs[2]->v_integer); + break; + + /* Misc functions */ + case AMLOP_STALL: + /* Stall: i */ + acpi_stall(opargs[0]->v_integer); + break; + case AMLOP_SLEEP: + /* Sleep: i */ + acpi_sleep(opargs[0]->v_integer); + break; + case AMLOP_NOTIFY: + /* Notify: Si */ + dnprintf(50,"Notifying: %s %x\n", + aml_nodename(opargs[0]->node), + opargs[1]->v_integer); + aml_notify(opargs[0]->node, opargs[1]->v_integer); + break; + case AMLOP_TIMER: + /* Timer: => i */ + ival = 0xDEADBEEF; + break; + case AMLOP_FATAL: + /* Fatal: bdi */ + aml_die("AML FATAL ERROR: %x,%x,%x\n", + opargs[0]->v_integer, opargs[1]->v_integer, + opargs[2]->v_integer); + break; + case AMLOP_LOADTABLE: + /* LoadTable(Sig:Str, OEMID:Str, OEMTable:Str, [RootPath:Str], [ParmPath:Str], + [ParmData:DataRefObj]) => DDBHandle */ + aml_die("LoadTable"); + break; + case AMLOP_LOAD: + /* Load(Object:NameString, DDBHandle:SuperName) */ + tmp = opargs[0]; + if (tmp->type != AML_OBJTYPE_OPREGION || + tmp->v_opregion.iospace != GAS_SYSTEM_MEMORY) { + aml_die("LOAD: not a memory region!\n"); + } +#if 0 + /* Create buffer and read from memory */ + aml_xgasio(tmp->v_opregion.iospace, tmp->v_opregion.iobase, + tmp->v_opregion.iolen, + opargs[1], ACPI_IOREAD); + + /* Validate that this is a SSDT */ + if (!valid_acpihdr(opargs[1]->v_buffer, opargs[1]->length, + "SSDT")) { + aml_die("LOAD: Not a SSDT!\n"); + } + + /* Parse block */ + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_SCOPE); +#endif + break; + case AMLOP_UNLOAD: + /* DDBHandle */ + aml_die("Unload"); + break; + + /* Control Flow */ + case AMLOP_IF: + /* Arguments: iT or iTbT */ + if (opargs[0]->v_integer) { + dnprintf(10,"parse-if @ %.4x\n", pc); + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_IF); + } + else if (opargs[3] != NULL) { + dnprintf(10,"parse-else @ %.4x\n", pc); + mscope = aml_xpushscope(scope, opargs[3], scope->node, + AMLOP_ELSE); + } + break; + case AMLOP_WHILE: + mscope = aml_xpushscope(scope, opargs[0], scope->node, + AMLOP_WHILE); + while (mscope->pos != NULL) { + /* At beginning of scope.. reset and perform test */ + mscope->pos = mscope->start; + tmp = aml_xparse(mscope, AML_ARG_INTEGER, "While-Test"); + ival = tmp->v_integer; + aml_xdelref(&tmp, "while"); + + dnprintf(10,"@@@@@@ WHILE: %llx @ %x\n", ival, pc); + if (ival == 0) { + break; + } + aml_xparse(mscope, 'T', "While"); + } + aml_xpopscope(mscope); + mscope = NULL; + break; + case AMLOP_BREAK: + /* Break: Find While Scope parent, mark type as null */ + mscope = aml_xfindscope(scope, AMLOP_WHILE, 1); + mscope->pos = NULL; + mscope = NULL; + break; + case AMLOP_CONTINUE: + /* Find Scope.. mark all objects as invalid on way to root */ + mscope = aml_xfindscope(scope, AMLOP_WHILE, 1); + mscope->pos = mscope->start; + mscope = NULL; + break; + case AMLOP_RETURN: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 1); + if (mscope->retv) { + aml_die("already allocated\n"); + } + mscope->retv = aml_allocvalue(0,0,NULL); + aml_copyvalue(mscope->retv, opargs[0]); + mscope = NULL; + break; + default: + /* may be set direct result */ + aml_die("Unknown opcode: %x:%s\n", opcode, htab->mnem); + break; + } + if (mscope != NULL) { + aml_xparse(mscope, 'T', htab->mnem); + aml_xpopscope(mscope); + } + if ((ret_type == 'i' || ret_type == 't') && my_ret == NULL) { + dnprintf(10,"quick: %.4x [%s] allocating return integer = 0x%llx\n", + pc, htab->mnem, ival); + my_ret = aml_allocvalue(AML_OBJTYPE_INTEGER, ival, NULL); + } + if (ret_type == 'i' && my_ret && my_ret->type != AML_OBJTYPE_INTEGER) { + dnprintf(10,"quick: %.4x convert to integer %s -> %s\n", + pc, htab->mnem, stype); + } + if (my_ret != NULL) { + /* Display result */ + my_ret->stack = opcode; + dnprintf(20,"quick: %.4x %18s %c %.4x\n", pc, stype, + ret_type, my_ret->stack); + } + + /* End opcode: display/free arguments */ + for (idx=0; optype[idx] != 0; idx++) { + if (opargs[idx] == my_ret || optype[idx] == 'N') + opargs[idx] = NULL; + aml_xdelref(&opargs[idx], "oparg"); + } + odp--; + + /* If parsing whole scope and not done, start again */ + if (ret_type == 'T') { + aml_xdelref(&my_ret, "scope.loop"); + if (scope->pos && scope->pos < scope->end) + goto start; + } + dnprintf(50, ">>return [%s] %s %c %p\n", aml_nodename(scope->node), + stype, ret_type, my_ret); + return my_ret; +} + +int +acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) +{ + struct aml_scope *scope; + struct aml_value res; + + dsdt_softc = sc; + + aml_root.start = start; + memset(&res, 0, sizeof(res)); + res.type = AML_OBJTYPE_SCOPE; + res.length = length; + res.v_buffer = start; + + /* Push toplevel scope, parse AML */ + scope = aml_xpushscope(NULL, &res, &aml_root, AMLOP_SCOPE); + aml_busy++; + aml_xparse(scope, 'T', "TopLevel"); + aml_busy--; + aml_xpopscope(scope); + + return 0; +} + +/* + * @@@: External API + * + * evaluate an AML node + * Returns a copy of the value in res (must be freed by user) + */ +int +aml_evalnode(struct acpi_softc *sc, struct aml_node *node, + int argc, struct aml_value *argv, struct aml_value *res) +{ + struct aml_value *xres; + + if (node == NULL || node->value == NULL) + return (ACPI_E_BADVALUE); + if (res) + memset(res, 0, sizeof(*res)); + dnprintf(12,"EVALNODE: %s %d\n", aml_nodename(node), acpi_nalloc); + switch (node->value->type) { + case AML_OBJTYPE_INTEGER: + case AML_OBJTYPE_PACKAGE: + case AML_OBJTYPE_STRING: + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_PROCESSOR: + case AML_OBJTYPE_THERMZONE: + case AML_OBJTYPE_POWERRSRC: + if (res) + aml_copyvalue(res, node->value); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_METHOD: + aml_busy++; + xres = aml_xeval(NULL, node->value, 't', argc, argv); + aml_busy--; + if (res && xres) + aml_copyvalue(res, xres); + if (xres != node->value) + aml_xdelref(&xres, "EvalNode"); + break; + default: + return (-1); + } + return (0); +} + +/* + * evaluate an AML name + * Returns a copy of the value in res (must be freed by user) + */ +int +aml_evalname(struct acpi_softc *sc, struct aml_node *parent, const char *name, + int argc, struct aml_value *argv, struct aml_value *res) +{ + parent = aml_searchname(parent, name); + return aml_evalnode(sc, parent, argc, argv, res); +} + +/* + * evaluate an AML integer object + */ +int +aml_evalinteger(struct acpi_softc *sc, struct aml_node *parent, + const char *name, int argc, struct aml_value *argv, int64_t *ival) +{ + struct aml_value res; + int rc; + + parent = aml_searchname(parent, name); + rc = aml_evalnode(sc, parent, argc, argv, &res); + *ival = aml_val2int(&res); + aml_freevalue(&res); + + return rc; +} + +/* + * Search for an AML name in namespace.. root only + */ +struct aml_node * +aml_searchname(struct aml_node *root, const void *vname) +{ + char *name = (char *)vname; + + dnprintf(25,"Searchname: %s:%s = ", aml_nodename(root), vname); + if (*name == AMLOP_ROOTCHAR) { + root = &aml_root; + name++; + } + while (*name != 0) { + root = __aml_search(root, name, 0); + name += (name[4] == '.') ? 5 : 4; + } + dnprintf(25,"%p %s\n", root, aml_nodename(root)); + return root; +} + +/* + * Search for relative name + */ +struct aml_node * +aml_searchrel(struct aml_node *root, const void *vname) +{ + struct aml_node *res; + + while (root) { + res = aml_searchname(root, vname); + if (res != NULL) + return res; + root = root->parent; + } + return NULL; +} |