root/usr.sbin/acpitools/aml/aml_parse.c
/*      $NetBSD: aml_parse.c,v 1.6 2022/03/23 13:06:06 andvar Exp $     */

/*-
 * Copyright (c) 1999 Doug Rabson
 * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      Id: aml_parse.c,v 1.32 2000/08/12 15:20:45 iwasaki Exp 
 *      $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_parse.c,v 1.7 2001/10/23 14:54:15 takawata Exp $
 */
#include <sys/cdefs.h>
__RCSID("$NetBSD: aml_parse.c,v 1.6 2022/03/23 13:06:06 andvar Exp $");

#include <sys/param.h>

#include <acpi_common.h>
#include <aml/aml_amlmem.h>
#include <aml/aml_common.h>
#include <aml/aml_env.h>
#include <aml/aml_evalobj.h>
#include <aml/aml_name.h>
#include <aml/aml_obj.h>
#include <aml/aml_parse.h>
#include <aml/aml_status.h>
#include <aml/aml_store.h>

#ifndef _KERNEL
#include <sys/stat.h>
#include <sys/mman.h>

#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "debug.h"
#else /* _KERNEL */
#include <sys/systm.h>
#include <sys/bus.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#ifndef ACPI_NO_OSDFUNC_INLINE
#include <machine/acpica_osd.h>
#endif
#endif /* !_KERNEL */

static int               findsetleftbit(int num);
static int               findsetrightbit(int num);
static int               frombcd(int num);
static int               tobcd(int num);

static u_int32_t         aml_parse_pkglength(struct aml_environ *env);
static u_int8_t          aml_parse_bytedata(struct aml_environ *env);
static u_int16_t         aml_parse_worddata(struct aml_environ *env);
static u_int32_t         aml_parse_dworddata(struct aml_environ *env);
static u_int8_t         *aml_parse_namestring(struct aml_environ *env);
static void              aml_parse_defscope(struct aml_environ *env,
                                            int indent);
static union aml_object *aml_parse_defbuffer(struct aml_environ *env,
                                             int indent);
static struct aml_name  *aml_parse_concat_number(struct aml_environ *env,
                                                 int num1, int indent);
static struct aml_name  *aml_parse_concat_buffer(struct aml_environ *env,
                                                 union aml_object *obj,
                                                 int indent);
static struct aml_name  *aml_parse_concat_string(struct aml_environ *env,
                                                 union aml_object *obj,
                                                 int indent);
static struct aml_name  *aml_parse_concatop(struct aml_environ *env,
                                            int indent);
static union aml_object *aml_parse_defpackage(struct aml_environ *env,
                                              int indent);
static void              aml_parse_defmethod(struct aml_environ *env,
                                             int indent);
static void              aml_parse_defopregion(struct aml_environ *env,
                                               int indent);
static int               aml_parse_field(struct aml_environ *env,
                                         struct aml_field *template);
static void              aml_parse_fieldlist(struct aml_environ *env,
                                             struct aml_field *template,
                                             int indent);
static void              aml_parse_deffield(struct aml_environ *env,
                                            int indent);
static void              aml_parse_defindexfield(struct aml_environ *env,
                                                 int indent);
static void              aml_parse_defbankfield(struct aml_environ *env,
                                                int indent);
static void              aml_parse_defdevice(struct aml_environ *env,
                                             int indent);
static void              aml_parse_defprocessor(struct aml_environ *env,
                                                int indent);
static void              aml_parse_defpowerres(struct aml_environ *env,
                                               int indent);
static void              aml_parse_defthermalzone(struct aml_environ *env,
                                                  int indent);
static struct aml_name  *aml_parse_defelse(struct aml_environ *env,
                                           int indent, int num);
static struct aml_name  *aml_parse_defif(struct aml_environ *env,
                                         int indent);
static struct aml_name  *aml_parse_defwhile(struct aml_environ *env,
                                            int indent);
static void              aml_parse_defmutex(struct aml_environ *env,
                                            int indent);
static void              aml_createfield_generic(struct aml_environ *env,
                                                 union aml_object *srcbuf,
                                                 int idx, int len,
                                                 char *newname);
static void              aml_parse_defcreatefield(struct aml_environ *env,
                                                  int indent);

static int
findsetleftbit(int num)
{
        int     i, filter;

        filter = 0;
        for (i = 0; i < 32; i++) {
                filter = filter >> 1;
                filter |= 1 << 31;
                if (filter & num) {
                        break;
                }
        }
        i = (i == 32) ? 0 : i + 1;
        return (i);
}

static int
findsetrightbit(int num)
{
        int     i, filter;

        filter = 0;
        for (i = 0; i < 32; i++) {
                filter = filter << 1;
                filter |= 1;
                if (filter & num) {
                        break;
                }
        }
        i = (i == 32) ? 0 : i + 1;
        return (i);
}

static int
frombcd(int num)
{
        int     res, factor;

        res = 0;
        factor = 1;
        while (num != 0) {
                res += ((num & 0xf) * factor);
                num = num / 16;
                factor *= 10;
        }
        return (res);
}

static int
tobcd(int num)
{
        int     res, factor;

        res = 0;
        factor = 1;
        while (num != 0) {
                res += ((num % 10) * factor);
                num = num / 10;
                factor *= 16;
        }
        return (res);
}

static u_int32_t
aml_parse_pkglength(struct aml_environ *env)
{
        u_int8_t        *dp;
        u_int32_t       pkglength;

        dp = env->dp;
        pkglength = *dp++;
        switch (pkglength >> 6) {
        case 0:
                break;
        case 1:
                pkglength = (pkglength & 0xf) + (dp[0] << 4);
                dp += 1;
                break;
        case 2:
                pkglength = (pkglength & 0xf) + (dp[0] << 4) + (dp[1] << 12);
                dp += 2;
                break;
        case 3:
                pkglength = (pkglength & 0xf)
                    + (dp[0] << 4) + (dp[1] << 12) + (dp[2] << 20);
                dp += 3;
                break;
        }

        env->dp = dp;
        return (pkglength);
}

static u_int8_t
aml_parse_bytedata(struct aml_environ *env)
{
        u_int8_t        data;

        data = env->dp[0];
        env->dp++;
        return (data);
}

static u_int16_t
aml_parse_worddata(struct aml_environ *env)
{
        u_int16_t       data;

        data = env->dp[0] + (env->dp[1] << 8);
        env->dp += 2;
        return (data);
}

static u_int32_t
aml_parse_dworddata(struct aml_environ *env)
{
        u_int32_t       data;

        data = env->dp[0] + (env->dp[1] << 8) +
            (env->dp[2] << 16) + (env->dp[3] << 24);
        env->dp += 4;
        return (data);
}

static u_int8_t *
aml_parse_namestring(struct aml_environ *env)
{
        u_int8_t        *name;
        int             segcount;

        name = env->dp;
        if (env->dp[0] == '\\')
                env->dp++;
        else if (env->dp[0] == '^')
                while (env->dp[0] == '^')
                        env->dp++;
        if (env->dp[0] == 0x00) /* NullName */
                env->dp++;
        else if (env->dp[0] == 0x2e)    /* DualNamePrefix */
                env->dp += 1 + 4 + 4;   /* NameSeg, NameSeg */
        else if (env->dp[0] == 0x2f) {  /* MultiNamePrefix */
                segcount = env->dp[1];
                env->dp += 1 + 1 + segcount * 4;        /* segcount * NameSeg */
        } else
                env->dp += 4;   /* NameSeg */

        return (name);
}

struct aml_name *
aml_parse_objectlist(struct aml_environ *env, int indent)
{
        union   aml_object *obj;

        obj = NULL;
        while (env->dp < env->end) {
                aml_print_indent(indent);
                obj = aml_eval_name(env, aml_parse_termobj(env, indent));
                AML_DEBUGPRINT("\n");
                if (env->stat == aml_stat_step) {
                        AML_DEBUGGER(env, env);
                        continue;
                }
                if (env->stat != aml_stat_none) {
                        env->tempname.property = obj;
                        return (&env->tempname);
                }
        }
        return (NULL);
}

#define AML_CREATE_NAME(amlname, env, namestr, ret) do {                \
        amlname = aml_create_name(env, namestr);                        \
        if (env->stat == aml_stat_panic)                                \
                return ret;                                             \
} while(0)

#define AML_COPY_OBJECT(dest, env, src, ret) do {                       \
        dest = aml_copy_object(env, src);                               \
        if (dest == NULL) {                                             \
                env->stat = aml_stat_panic;                             \
                return ret;                                             \
        }                                                               \
} while(0)

#define AML_ALLOC_OBJECT(dest, env, type, ret) do {                     \
        dest = aml_alloc_object(type, NULL);                            \
        if (dest == NULL) {                                             \
                env->stat= aml_stat_panic;                              \
                return ret;                                             \
        }                                                               \
} while(0)

static void
aml_parse_defscope(struct aml_environ *env, int indent)
{
        u_int8_t        *start, *end, *oend;
        u_int8_t        *name;
        u_int32_t       pkglength;
        struct  aml_name *oname;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);

        AML_DEBUGPRINT("Scope(");
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        AML_DEBUGPRINT(") {\n");
        oname = env->curname;
        AML_CREATE_NAME(env->curname, env, name,);
        oend = env->end;
        env->end = end = start + pkglength;
        aml_parse_objectlist(env, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        AML_SYSASSERT(env->dp == env->end);
        env->dp = end;
        env->end = oend;
        env->curname = oname;
        env->stat = aml_stat_none;
}

static union aml_object *
aml_parse_defbuffer(struct aml_environ *env, int indent)
{
        u_int8_t        *start;
        u_int8_t        *end;
        u_int8_t        *buffer;
        u_int32_t       pkglength;
        int     size1, size2, size;
        union   aml_object *obj;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        end = start + pkglength;

        AML_DEBUGPRINT("Buffer(");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));
        size1 = aml_objtonum(env, obj);
        size2 = end - env->dp;
        size = (size1 < size2) ? size1 : size2;
        if (size1 > 0) {
                buffer = memman_alloc_flexsize(aml_memman, size1);
                if (buffer == NULL) {
                        AML_DEBUGPRINT("NO MEMORY\n");
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                bzero(buffer, size1);
                bcopy(env->dp, buffer, size);
        } else {
                buffer = NULL;
        }

        obj = &env->tempobject;
        obj->type = aml_t_buffer;
        obj->buffer.size = size1;
        obj->buffer.data = buffer;
        AML_DEBUGPRINT(") ");
        env->dp = end;

        return (obj);
}

static struct aml_name *
aml_parse_concat_number(struct aml_environ *env, int num1, int indent)
{
        int     num2;
        struct  aml_name *destname;
        union   aml_object *obj;

        num2 = aml_objtonum(env, aml_eval_name(env,
                aml_parse_termobj(env, indent)));
        AML_DEBUGPRINT(", ");
        destname = aml_parse_termobj(env, indent);
        AML_DEBUGPRINT(")");
        obj = &env->tempobject;
        obj->type = aml_t_buffer;
        obj->buffer.size = 2;
        obj->buffer.data = memman_alloc_flexsize(aml_memman, 2);
        if (obj->buffer.data == NULL) {
                env->stat = aml_stat_panic;
                return (NULL);
        }
        obj->buffer.data[0] = num1 & 0xff;
        obj->buffer.data[1] = num2 & 0xff;
        aml_store_to_name(env, obj, destname);
        return (&env->tempname);
}

static struct aml_name *
aml_parse_concat_buffer(struct aml_environ *env, union aml_object *obj,
    int indent)
{
        union   aml_object *tmpobj, *tmpobj2, *resobj;
        struct  aml_name *destname;

        tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent));
        AML_DEBUGPRINT(", ");
        if (tmpobj->type != aml_t_buffer) {
                env->stat = aml_stat_panic;
                return (NULL);
        }
        AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL);
        destname = aml_parse_termobj(env, indent);
        AML_DEBUGPRINT(")");
        resobj = &env->tempobject;
        env->tempname.property = resobj;
        resobj->buffer.type = aml_t_buffer;
        resobj->buffer.size = tmpobj2->buffer.size + obj->buffer.size;
        if (resobj->buffer.size > 0) {
                resobj->buffer.data = memman_alloc_flexsize(aml_memman,
                    resobj->buffer.size);
                if (resobj->buffer.data == NULL) {
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                bcopy(obj->buffer.data, resobj->buffer.data, obj->buffer.size);
                bcopy(tmpobj2->buffer.data,
                    resobj->buffer.data + obj->buffer.size,
                    tmpobj2->buffer.size);
        } else {
                resobj->buffer.data = NULL;
        }
        aml_free_object(&tmpobj2);
        aml_store_to_name(env, resobj, destname);
        return (&env->tempname);
}

static struct aml_name *
aml_parse_concat_string(struct aml_environ *env, union aml_object *obj,
    int indent)
{
        int     len;
        union   aml_object *tmpobj, *tmpobj2, *resobj;
        struct  aml_name *destname;

        tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent));
        AML_DEBUGPRINT(", ");
        if (tmpobj->type != aml_t_string) {
                env->stat = aml_stat_panic;
                return (NULL);
        }
        AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL);
        destname = aml_parse_termobj(env, indent);
        AML_DEBUGPRINT(")");
        resobj = &env->tempobject;
        env->tempname.property = resobj;
        resobj->type = aml_t_buffer;
        resobj->str.needfree = 1;
        len = strlen((const char *)obj->str.string) +
            strlen((const char *)tmpobj2->str.string) + 1;
        if (len > 0) {
                resobj->str.string = memman_alloc_flexsize(aml_memman, len);
                if (resobj->str.string == NULL) {
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                strlcpy((char *)resobj->str.string, (const char *)obj->str.string, len);
                strlcat((char *)resobj->str.string, (const char *)tmpobj->str.string, len);
        } else {
                resobj->str.string = NULL;
        }
        aml_free_object(&tmpobj2);
        aml_store_to_name(env, resobj, destname);
        return (&env->tempname);
}

static struct aml_name *
aml_parse_concatop(struct aml_environ *env, int indent)
{
        union   aml_object *obj, *tmpobj;
        struct  aml_name *aname;

        AML_DEBUGPRINT("Concat(");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));
        AML_DEBUGPRINT(", ");
        switch (obj->type) {
        case aml_t_num:
                aname = aml_parse_concat_number(env, aml_objtonum(env, obj), indent);
                break;

        case aml_t_buffer:
                /* obj may be temporal object */
                AML_COPY_OBJECT(tmpobj, env, obj, NULL);
                aname = aml_parse_concat_buffer(env, obj, indent);
                aml_free_object(&tmpobj);
                break;

        case aml_t_string:
                /* obj may be temporal object */
                AML_COPY_OBJECT(tmpobj, env, obj, NULL);
                aname = aml_parse_concat_string(env, obj, indent);
                aml_free_object(&tmpobj);
                break;

        default:
                env->stat = aml_stat_panic;
                aname = NULL;
                break;
        }

        AML_DEBUGPRINT("\n");
        return (aname);
}

static union aml_object *
aml_parse_defpackage(struct aml_environ *env, int indent)
{
        u_int8_t        numelements;
        u_int8_t        *start;
        u_int32_t       pkglength;
        int             i;
        struct  aml_environ *copy;
        struct  aml_name *tmpname;
        union   aml_object *obj, **objects;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        numelements = aml_parse_bytedata(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return (NULL);
        }
        if (numelements > 0) {
                objects = memman_alloc_flexsize(aml_memman,
                    numelements * sizeof(union aml_object *));
                if (objects == NULL) {
                        env->stat = aml_stat_panic;
                        return (NULL);
                } else {
                        bzero(objects, numelements * sizeof(union aml_object *));
                }
        } else {
                objects = NULL;
        }

        *copy = *env;
        env->dp = copy->end = start + pkglength;
        AML_DEBUGPRINT("Package() {\n");
        i = 0;
        while ((copy->dp < copy->end) && (i < numelements)) {
                aml_print_indent(indent + 1);
                tmpname = aml_parse_termobj(copy, indent + 1);

                if (tmpname != NULL) {
                        objects[i] = aml_copy_object(copy, tmpname->property);
                }
                AML_DEBUGPRINT(",\n");
                i++;
        }
        aml_free_objectcontent(&copy->tempobject);

        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        obj = &env->tempobject;
        obj->type = aml_t_package;
        obj->package.elements = numelements;
        obj->package.objects = objects;

        memman_free(aml_memman, memid_aml_environ, copy);
        return (obj);
}

static void
aml_parse_defmethod(struct aml_environ *env, int indent)
{
        u_int8_t        flags;
        u_int8_t        *start;
        u_int32_t       pkglength;
        char    *name;
        struct  aml_environ *copy;
        struct  aml_method *meth;
        struct  aml_name *aname;
        union   aml_object *aobj;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("Method(");
        name = (char *)aml_parse_namestring(env);
        aml_print_namestring((unsigned char *)name);
        AML_CREATE_NAME(aname, env, (unsigned char *)name,);
        if (aname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                goto out;
        }
        AML_ALLOC_OBJECT(aobj, env, aml_t_method,);
        meth = &aobj->meth;
        aname->property = aobj;
        flags = *env->dp++;

        if (flags) {
                AML_DEBUGPRINT(", %d", flags);
        }
        AML_DEBUGPRINT(") {\n");
        *copy = *env;
        meth->argnum = flags;
        meth->from = env->dp;
        meth->to = env->dp = copy->end = start + pkglength;
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
out:
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defopregion(struct aml_environ *env, int indent)
{
        u_int8_t        *name;
        struct  aml_name *aname;
        struct  aml_opregion *opregion;
        union   aml_object *obj;
        const char      *regions[] = {
                "SystemMemory",
                "SystemIO",
                "PCI_Config",
                "EmbeddedControl",
                "SMBus",
        };

        AML_DEBUGPRINT("OperationRegion(");
        /* Name */
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        AML_CREATE_NAME(aname, env, name,);
        if (aname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                return;
        }
        AML_ALLOC_OBJECT(aname->property, env, aml_t_opregion,);
        opregion = &aname->property->opregion;
        opregion->space = *env->dp;
        AML_DEBUGPRINT(", %s, ", regions[*env->dp]);    /* Space */
        env->dp++;
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* Offset */
        opregion->offset = aml_objtonum(env, obj);
        AML_DEBUGPRINT(", ");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* Length */
        opregion->length = aml_objtonum(env, obj);
        AML_DEBUGPRINT(")");
}

static const char       *accessnames[] = {
        "AnyAcc",
        "ByteAcc",
        "WordAcc",
        "DWordAcc",
        "BlockAcc",
        "SMBSendRecvAcc",
        "SMBQuickAcc"
};

static int
aml_parse_field(struct aml_environ *env, struct aml_field *template)
{
        u_int8_t        *name;
        u_int8_t        acc, attribute;
        u_int32_t       width;
        struct  aml_name *aname;
        struct  aml_field *prop;

        switch (*env->dp) {
        case '\\':
        case '^':
        case 'A'...'Z':
        case '_':
        case '.':  
        case '/':
                name = aml_parse_namestring(env);
                width = aml_parse_pkglength(env);
                template->bitlen = width;
                aml_print_namestring(name);
                AML_CREATE_NAME(aname, env, name, 0);
                /* Alignment */
                if (width == 16) {
                        template->bitoffset += 15;
                        template->bitoffset &= (~15);
                }
                if (width == 32) {
                        template->bitoffset += 31;
                        template->bitoffset &= (~31);
                } else if ((width & 7) == 0) {
                        template->bitoffset += 7;
                        template->bitoffset &= (~7);
                } else if ((width > 32) && (width & 7) != 0) {
                        AML_DEBUGPRINT("??? Can I treat it?\n");
                }
                if (aname->property != NULL) {
                        env->stat = aml_stat_panic;
                        AML_DEBUGPRINT("Already Defined \n");
                        return (0);
                }
                AML_ALLOC_OBJECT(aname->property, env, aml_t_field, 0);
                prop = &aname->property->field;
                *prop = *template;
                template->bitoffset += width;
                AML_DEBUGPRINT(",\t%d", width);
                break;
        case 0x00:
                env->dp++;
                width = aml_parse_pkglength(env);
                template->bitoffset += width;
                AML_DEBUGPRINT("Offset(0x%x)", template->bitoffset);
                break;
        case 0x01:
                acc = env->dp[1];
                attribute = env->dp[2];
                env->dp += 3;
                AML_DEBUGPRINT("AccessAs(%s, %d)", accessnames[acc], attribute);
                template->bitoffset = attribute;
                template->flags = (template->flags | 0xf0) | acc;
                break;
        }
        return (template->bitoffset);
}

static void
aml_parse_fieldlist(struct aml_environ *env, struct aml_field *template,
    int indent)
{

        while (env->dp < env->end) {
                aml_print_indent(indent);
                (void)aml_parse_field(env, template);
                if (env->dp < env->end) {
                        AML_DEBUGPRINT(",\n");
                } else {
                        AML_DEBUGPRINT("\n");
                }
        }
}

static void
aml_parse_deffield(struct aml_environ *env, int indent)
{
        u_int8_t        flags;
        u_int8_t        *start, *name;
        u_int32_t       pkglength;
        struct  aml_environ *copy;
        struct  aml_field fieldtemplate;
        static  const char *lockrules[] = {"NoLock", "Lock"};
        static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                             "WriteAsZeros", "*Error*"};

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("Field(");
        aml_print_namestring(name = aml_parse_namestring(env));
        fieldtemplate.type = aml_t_field;
        flags = aml_parse_bytedata(env);
        fieldtemplate.flags = flags;

        *copy = *env;
        env->dp = copy->end = start + pkglength;
        fieldtemplate.bitoffset = 0;
        fieldtemplate.bitlen = 0;
        fieldtemplate.f.ftype = f_t_field;
        fieldtemplate.f.fld.regname = name;
        AML_DEBUGPRINT(", %s, %s, %s) {\n",
            accessnames[flags & 0xf],
            lockrules[(flags >> 4) & 1],
            updaterules[(flags >> 5) & 3]);
        aml_parse_fieldlist(copy, &fieldtemplate, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);

        AML_SYSASSERT(copy->dp == copy->end);
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defindexfield(struct aml_environ *env, int indent)
{
        u_int8_t        flags;
        u_int8_t        *start, *iname, *dname;
        u_int32_t       pkglength;
        struct  aml_environ *copy;
        struct  aml_field template;
        static  const char *lockrules[] = {"NoLock", "Lock"};
        static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                             "WriteAsZeros", "*Error*"};

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("IndexField(");
        aml_print_namestring(iname = aml_parse_namestring(env));        /* Name1 */
        AML_DEBUGPRINT(", ");
        aml_print_namestring(dname = aml_parse_namestring(env));        /* Name2 */
        template.type = aml_t_field;
        template.flags = flags = aml_parse_bytedata(env);
        template.bitoffset = 0;
        template.bitlen = 0;
        template.f.ftype = f_t_index;
        template.f.ifld.indexname = iname;
        template.f.ifld.dataname = dname;
        AML_DEBUGPRINT(", %s, %s, %s) {\n",
            accessnames[flags & 0xf],
            lockrules[(flags >> 4) & 1],
            updaterules[(flags >> 5) & 3]);
        *copy = *env;
        env->dp = copy->end = start + pkglength;
        aml_parse_fieldlist(copy, &template, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);

        AML_SYSASSERT(copy->dp == copy->end);
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defbankfield(struct aml_environ *env, int indent)
{
        u_int8_t        flags;
        u_int8_t        *start, *rname, *bname;
        u_int32_t       pkglength, bankvalue;
        struct  aml_environ *copy;
        struct  aml_field template;
        union   aml_object *obj;
        static  const char *lockrules[] = {"NoLock", "Lock"};
        static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                             "WriteAsZeros", "*Error*"};

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("BankField(");
        aml_print_namestring(rname = aml_parse_namestring(env));        /* Name1 */
        AML_DEBUGPRINT(", ");
        aml_print_namestring(bname = aml_parse_namestring(env));        /* Name2 */
        AML_DEBUGPRINT(", ");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* BankValue */
        bankvalue = aml_objtonum(env, obj);
        template.type = aml_t_field;
        template.flags = flags = aml_parse_bytedata(env);
        template.bitoffset = 0;
        template.bitlen = 0;
        template.f.ftype = f_t_bank;
        template.f.bfld.regname = rname;
        template.f.bfld.bankname = bname;
        template.f.bfld.bankvalue = bankvalue;
        *copy = *env;
        env->dp = copy->end = start + pkglength;
        AML_DEBUGPRINT(", %s, %s, %s) {\n",
            accessnames[flags & 0xf],
            lockrules[(flags >> 4) & 1],
            updaterules[(flags >> 5) & 3]);
        aml_parse_fieldlist(copy, &template, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");

        aml_free_objectcontent(&copy->tempobject);
        AML_SYSASSERT(copy->dp == copy->end);
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defdevice(struct aml_environ *env, int indent)
{
        u_int8_t        *start;
        u_int8_t        *name;
        u_int32_t       pkglength;
        struct  aml_environ *copy;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("Device(");
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        AML_DEBUGPRINT(") {\n");
        *copy = *env;
        AML_CREATE_NAME(copy->curname, env, name,);
        if (copy->curname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                goto out;
        }
        AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_device,);
        env->dp = copy->end = start + pkglength;
        aml_parse_objectlist(copy, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);

        AML_SYSASSERT(copy->dp == copy->end);
out:
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defprocessor(struct aml_environ *env, int indent)
{
        u_int8_t        *start;
        u_int8_t        *name;
        u_int32_t       pkglength;
        struct  aml_environ *copy;
        struct  aml_processor *proc;
        union   aml_object *obj;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_ALLOC_OBJECT(obj, env, aml_t_processor,);
        proc = &obj->proc;
        AML_DEBUGPRINT("Processor(");
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        proc->id = aml_parse_bytedata(env);
        proc->addr = aml_parse_dworddata(env);
        proc->len = aml_parse_bytedata(env);
        AML_DEBUGPRINT(", %d, 0x%x, 0x%x) {\n", proc->id, proc->addr, proc->len);
        *copy = *env;
        AML_CREATE_NAME(copy->curname, env, name,);
        if (copy->curname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                goto out;
        }
        copy->curname->property = obj;
        env->dp = copy->end = start + pkglength;
        aml_parse_objectlist(copy, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);

        AML_SYSASSERT(copy->dp == copy->end);
out:
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defpowerres(struct aml_environ *env, int indent)
{
        u_int8_t        *start;
        u_int8_t        *name;
        u_int32_t       pkglength;
        struct  aml_environ *copy;
        struct  aml_powerres *pres;
        union   aml_object *obj;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("PowerResource(");
        AML_ALLOC_OBJECT(obj, env, aml_t_powerres,);
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        pres = &obj->pres;
        pres->level = aml_parse_bytedata(env);
        pres->order = aml_parse_worddata(env);
        AML_DEBUGPRINT(", %d, %d) {\n", pres->level, pres->order);
        *copy = *env;
        AML_CREATE_NAME(copy->curname, env, name,);
        if (copy->curname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                goto out;
        }
        copy->curname->property = obj;
        env->dp = copy->end = start + pkglength;

        aml_parse_objectlist(copy, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);

        AML_SYSASSERT(copy->dp == copy->end);
out:
        memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defthermalzone(struct aml_environ *env, int indent)
{
        u_int8_t        *start;
        u_int8_t        *name;
        u_int32_t       pkglength;
        struct  aml_environ *copy;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        copy = memman_alloc(aml_memman, memid_aml_environ);
        if (copy == NULL) {
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT("ThermalZone(");
        name = aml_parse_namestring(env);
        aml_print_namestring(name);
        AML_DEBUGPRINT(") {\n");
        *copy = *env;
        AML_CREATE_NAME(copy->curname, env, name,);
        if (copy->curname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                goto out;
        }
        AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_therm,);
        env->dp = copy->end = start + pkglength;
        aml_parse_objectlist(copy, indent + 1);
        aml_print_indent(indent);
        AML_DEBUGPRINT("}");
        aml_free_objectcontent(&copy->tempobject);
        AML_SYSASSERT(copy->dp == copy->end);
out:
        memman_free(aml_memman, memid_aml_environ, copy);
}

static struct aml_name *
aml_parse_defelse(struct aml_environ *env, int indent, int num)
{
        u_int8_t        *start, *end, *oend;
        u_int32_t       pkglength;
        struct  aml_name *aname;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        oend = env->end;
        env->end = end = start + pkglength;
        aname = NULL;

        AML_DEBUGPRINT("Else {\n");
        if (num == 0) {
                aname = aml_parse_objectlist(env, indent + 1);
                aml_print_indent(indent);
        }
        AML_DEBUGPRINT("}");

        env->dp = end;
        env->end = oend;
        return (aname);
}

static struct aml_name *
aml_parse_defif(struct aml_environ *env, int indent)
{
        u_int8_t        *start, *end, *oend;
        u_int32_t       pkglength;
        int     num;
        struct  aml_name *aname, *aname1;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        aname = NULL;

        AML_DEBUGPRINT("If(");
        num = aml_objtonum(env, aml_eval_name
            (env, aml_parse_termobj(env, indent)));
        oend = env->end;
        end = start + pkglength;
        AML_DEBUGPRINT(")");
        if (num) {
                AML_DEBUGPRINT("{\n");
                env->end = end;
                aname = aml_parse_objectlist(env, indent + 1);
                aml_print_indent(indent);
                AML_DEBUGPRINT("}");
        }
        env->dp = end;
        env->end = oend;
        if ((end < oend) && *(env->dp) == 0xa1) {
                env->dp++;
                aname1 = aml_parse_defelse(env, indent, num);
                aname = (num == 0) ? aname1 : aname;
        }
        return (aname);
}

static struct aml_name *
aml_parse_defwhile(struct aml_environ *env, int indent)
{
        u_int8_t        *start, *end, *oend;
        u_int32_t       pkglength;
        int     num;
        struct  aml_name *aname;

        start = env->dp;
        pkglength = aml_parse_pkglength(env);
        oend = env->end;
        end = start + pkglength;
        aname = NULL;
        for (;;) {
                env->dp = start;
                aml_parse_pkglength(env);
                AML_DEBUGPRINT("While(");
                num = aml_objtonum(env, aml_eval_name
                    (env, aml_parse_termobj(env, indent)));
                AML_DEBUGPRINT(")");
                if (num == 0) {
                        break;
                }
                AML_DEBUGPRINT(" {\n");
                env->end = end;
                aname = aml_parse_objectlist(env, indent + 1);
                if (env->stat == aml_stat_step) {
                        AML_DEBUGGER(env, env);
                        continue;
                }
                if (env->stat != aml_stat_none)
                        break;
                aml_print_indent(indent);
                AML_DEBUGPRINT("}");
        }
        AML_DEBUGPRINT("\n");
        env->dp = end;
        env->end = oend;
        if (env->stat == aml_stat_break) {
                env->stat = aml_stat_none;
                aname = NULL;
        }
        return (aname);
}

static void
aml_parse_defmutex(struct aml_environ *env, int indent)
{
        char    *name;
        struct  aml_name *aname;
        struct  aml_mutex *mut;

        /* MutexOp */
        AML_DEBUGPRINT("Mutex(");
        name = (char *)aml_parse_namestring(env);
        aml_print_namestring((unsigned char *)name);
        AML_CREATE_NAME(aname, env, (unsigned char *)name,);
        if (aname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                return;
        }
        AML_ALLOC_OBJECT(aname->property, env, aml_t_mutex,);
        mut = &aname->property->mutex;
        mut->level = *env->dp++;
        STAILQ_INIT(&mut->queue);
        AML_DEBUGPRINT(", %d)", mut->level);
}

static void
aml_createfield_generic(struct aml_environ *env,
    union aml_object *srcbuf, int idx,
    int len, char *newname)
{
        struct  aml_bufferfield *field;
        struct  aml_name *aname;

        if (srcbuf == NULL || srcbuf->type != aml_t_buffer) {
                AML_DEBUGPRINT("Not Buffer assigned,");
                env->stat = aml_stat_panic;
                return;
        }
        AML_CREATE_NAME(aname, env, (unsigned char *)newname,);
        if (aname->property != NULL) {
                env->stat = aml_stat_panic;
                AML_DEBUGPRINT("Already Defined \n");
                return;
        }
        AML_ALLOC_OBJECT(aname->property, env, aml_t_bufferfield,);
        field = &aname->property->bfld;
        field->bitoffset = idx;
        field->bitlen = len;
        field->origin = srcbuf->buffer.data;
}

static void
aml_parse_defcreatefield(struct aml_environ *env, int indent)
{
        int     idx, len;
        char    *newname;
        union   aml_object *obj, *srcbuf;

        /* CreateFieldOp */
        AML_DEBUGPRINT("CreateField(");
        srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent));
        if (srcbuf == &env->tempobject) {
                AML_DEBUGPRINT("NONAMED BUFFER\n");
                env->stat = aml_stat_panic;
                return;
        }
        AML_DEBUGPRINT(", ");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));
        idx = aml_objtonum(env, obj);
        AML_DEBUGPRINT(", ");
        obj = aml_eval_name(env, aml_parse_termobj(env, indent));
        len = aml_objtonum(env, obj);
        AML_DEBUGPRINT(", ");
        newname = (char *)aml_parse_namestring(env);
        aml_print_namestring((unsigned char *)newname);
        aml_createfield_generic(env, srcbuf, idx, len, newname);
        AML_DEBUGPRINT(") ");
}

/*
 * Returns Named object or parser buffer. The object need not be free because
 * it returns preallocated buffer in env or Contain of named object.  If You
 * need to preserve object, create a copy and then store.  And The object
 * returned from this function is not valid after another call is
 * shared, tempolary buffer may be shared.
 */
struct aml_name *
aml_parse_termobj(struct aml_environ *env, int indent)
{
        u_int8_t        opcode;
        u_int8_t        *name;
        int     value;
        int     num1, num2;
        int     len;
        int     match1, match2, i, pkgval, start;
        int     widthindex, idx;
        char    *newname;
        struct  aml_name *aname;
        struct  aml_name *destname1, *destname2;
        struct  aml_name *tmpname, *srcname;
        struct  aml_name *src;
        union   aml_object *ret;
        union   aml_object *tmpobj;
        union   aml_object anum;
        union   aml_object *objref;
        union   aml_object *srcobj;
        union   aml_object *obj;
        union   aml_object *srcbuf;
        static int      widthtbl[4] = {32, 16, 8, 1};
        const char      *opname[4] = {"CreateDWordField", "CreateWordField",
                                      "CreateByteField", "CreateBitField"};

        aname = &env->tempname;
        ret = &env->tempobject;
        anum.type = aml_t_num;
        aname->property = ret;
        aml_free_objectcontent(ret);
        if (env->stat == aml_stat_panic) {
                /*
                 * If previously parser panic , parsing next instruction is
                 * prohibited.
                 */
                return (NULL);
        }
        aname = NULL;
        opcode = *env->dp++;
        switch (opcode) {
        case '\\':
        case '^':
        case 'A' ... 'Z':
        case '_':
        case '.':
        case '/':
                env->dp--;
                ret->type = aml_t_namestr;
                ret->nstr.dp = aml_parse_namestring(env);
                aml_print_namestring(ret->nstr.dp);
                aname = &env->tempname;
                break;
        case 0x0a:              /* BytePrefix */
                ret->type = aml_t_num;
                value = aml_parse_bytedata(env);
                ret->num.number = value;
                AML_DEBUGPRINT("0x%x", value);
                aname = &env->tempname;
                break;
        case 0x0b:              /* WordPrefix */
                ret->type = aml_t_num;
                value = aml_parse_worddata(env);
                ret->num.number = value;
                AML_DEBUGPRINT("0x%x", value);
                aname = &env->tempname;
                break;
        case 0x0c:              /* DWordPrefix */
                ret->type = aml_t_num;
                value = aml_parse_dworddata(env);
                ret->num.number = value;
                AML_DEBUGPRINT("0x%x", value);
                aname = &env->tempname;
                break;
        case 0x0d:              /* StringPrefix */
                ret->type = aml_t_string;
                ret->str.string = env->dp;
                len = strlen((const char *)env->dp);
                ret->str.needfree = 0;
                AML_DEBUGPRINT("\"%s\"", (const char *)ret->str.string);
                env->dp += (len + 1);
                aname = &env->tempname;
                break;
        case 0x00:              /* ZeroOp */
                ret->type = aml_t_num;
                ret->num.number = 0;
                ret->num.constant = 1;
                AML_DEBUGPRINT("Zero");
                aname = &env->tempname;
                break;
        case 0x01:              /* OneOp */
                ret->type = aml_t_num;
                ret->num.number = 1;
                ret->num.constant = 1;
                AML_DEBUGPRINT("One");
                aname = &env->tempname;
                break;
        case 0xff:              /* OnesOp */
                ret->type = aml_t_num;
                ret->num.number = 0xffffffff;
                ret->num.constant = 1;
                AML_DEBUGPRINT("Ones");
                aname = &env->tempname;
                break;
        case 0x06:              /* AliasOp */
                AML_DEBUGPRINT("Alias(");
                tmpname = aml_parse_termobj(env, indent);
                if (env->stat == aml_stat_panic) {
                        return (NULL);
                }
                if (tmpname->property == NULL ||
                    tmpname->property->type != aml_t_namestr) {
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                /*
                 * XXX if srcname is deleted after this object, what
                 * shall I do?
                 */
                srcname = aml_search_name(env, tmpname->property->nstr.dp);
                AML_DEBUGPRINT(", ");
                name = aml_parse_namestring(env);
                aml_print_namestring(name);
                AML_CREATE_NAME(aname, env, name, 0);
                if (aname->property != NULL) {
                        env->stat = aml_stat_panic;
                        AML_DEBUGPRINT("Already Defined \n");
                        aml_print_curname(aname);
                        return (NULL);
                }
                AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL);
                objref = aname->property;
                objref->objref.nameref = srcname;
                objref->objref.ref = srcname->property;
                objref->objref.offset = -1;
                objref->objref.alias = 1;       /* Yes, this is an alias */
                AML_DEBUGPRINT(")");
                /* shut the interpreter up during the namespace initializing */
                return (NULL);
        case 0x08:              /* NameOp */
                AML_DEBUGPRINT("Name(");
                name = aml_parse_namestring(env);
                aml_print_namestring(name);
                AML_CREATE_NAME(aname, env, name, 0);
                if (env->stat == aml_stat_panic) {
                        AML_DEBUGPRINT("Already Defined \n");
                        aml_print_curname(aname);
                        return (NULL);
                }
                AML_DEBUGPRINT(", ");
                AML_COPY_OBJECT(aname->property, env,
                    aml_eval_name(env,
                        aml_parse_termobj(env, indent)),
                    NULL);
                AML_DEBUGPRINT(")");
                break;
        case 0x10:              /* ScopeOp */
                aml_parse_defscope(env, indent);
                break;
        case 0x11:              /* BufferOp */
                aname = &env->tempname;
                aname->property = aml_parse_defbuffer(env, indent);
                break;
        case 0x12:              /* PackageOp */
                aname = &env->tempname;
                aname->property = aml_parse_defpackage(env, indent);
                break;
        case 0x14:              /* MethodOp */
                aml_parse_defmethod(env, indent);
                break;
        case 0x5b:              /* ExtOpPrefix */
                opcode = *env->dp++;
                switch (opcode) {
                case 0x01:
                        aml_parse_defmutex(env, indent);
                        break;
                case 0x02:      /* EventOp */
                        AML_DEBUGPRINT("Event(");
                        name = aml_parse_namestring(env);
                        aml_print_namestring(name);
                        AML_CREATE_NAME(aname, env, name, 0);
                        if (aname->property != NULL) {
                                env->stat = aml_stat_panic;
                                AML_DEBUGPRINT("Already Defined \n");
                                return (NULL);
                        }
                        AML_ALLOC_OBJECT(aname->property, env, aml_t_event, NULL);
                        AML_DEBUGPRINT(")");
                        return (NULL);
                        break;
                case 0x12:      /* CondRefOfOp */
                        AML_DEBUGPRINT("CondRefOf(");
                        src = aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(", ");
                        if (src == &env->tempname || src == NULL) {
                                aml_parse_termobj(env, indent);
                                AML_DEBUGPRINT(")");
                                anum.num.number = 0xffffffff;
                                env->tempobject.num = anum.num;
                                aname = &env->tempname;
                                break;
                        }
                        AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL);
                        if (src->property == NULL ||
                            src->property->type != aml_t_namestr) {
                                objref->objref.nameref = src;
                        } else {
                                objref->objref.nameref = aml_create_local_object();
                        }
                        objref->objref.ref = src->property;
                        objref->objref.offset = -1;     /* different from IndexOp */
                        
                        destname1 = aml_parse_termobj(env, indent);
                        aml_store_to_name(env, objref, destname1);
                        anum.num.number = 0;
                        env->tempobject.num = anum.num;
                        aname = &env->tempname;
                        AML_DEBUGPRINT(")");
                        break;
                case 0x13:
                        aml_parse_defcreatefield(env, indent);
                        break;
                case 0x20:      /* LoadOp *//* XXX Not Impremented */
                        AML_DEBUGPRINT("Load(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(", ");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x21:      /* StallOp */
                        AML_DEBUGPRINT("Stall(");
                        num1 = aml_objtonum(env, aml_eval_name(env,
                            aml_parse_termobj(env, indent)));
                        AML_DEBUGPRINT(")");
                        AML_STALL(num1);
                        break;
                case 0x22:      /* SleepOp */
                        AML_DEBUGPRINT("Sleep(");
                        num1 = aml_objtonum(env, aml_eval_name(env,
                            aml_parse_termobj(env, indent)));
                        AML_SLEEP(0, num1);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x23:      /* AcquireOp *//* XXX Not yet */
                        AML_DEBUGPRINT("Acquire(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(", 0x%x)", aml_parse_worddata(env));
                        break;
                case 0x24:      /* SignalOp *//* XXX Not yet */
                        AML_DEBUGPRINT("Signal(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x25:      /* WaitOp *//* XXX Not yet impremented */
                        AML_DEBUGPRINT("Wait(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(", ");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x26:      /* ResetOp *//* XXX Not yet impremented */
                        AML_DEBUGPRINT("Reset(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x27:      /* ReleaseOp *//* XXX Not yet impremented */
                        AML_DEBUGPRINT("Release(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
#define NUMOP2(opname, operation) do {                                  \
        AML_DEBUGPRINT(opname);                                         \
        AML_DEBUGPRINT("(");                                            \
        num1 = aml_objtonum(env, aml_eval_name(env,                     \
            aml_parse_termobj(env, indent)));                           \
        AML_DEBUGPRINT(", ");                                           \
        anum.num.number = operation (num1);                             \
        destname1 = aml_parse_termobj(env, indent);                     \
        AML_DEBUGPRINT(")");                                            \
        aml_store_to_name(env, &anum, destname1);                       \
        env->tempobject.num = anum.num;                                 \
        env->tempname.property = &env->tempobject;                      \
        aname = &env->tempname;                                         \
} while(0)

                case 0x28:      /* FromBCDOp */
                        NUMOP2("FromBCD", frombcd);
                        break;
                case 0x29:      /* ToBCDOp */
                        NUMOP2("ToBCD", tobcd);
                        break;
                case 0x2a:      /* UnloadOp *//* XXX Not yet impremented */
                        AML_DEBUGPRINT("Unload(");
                        aml_parse_termobj(env, indent);
                        AML_DEBUGPRINT(")");
                        break;
                case 0x30:
                        env->tempobject.type = aml_t_num;
                        env->tempobject.num.number = 0;
                        env->tempobject.num.constant = 1;
                        AML_DEBUGPRINT("Revision");
                        break;
                case 0x31:
                        env->tempobject.type = aml_t_debug;
                        aname = &env->tempname;
                        AML_DEBUGPRINT("Debug");
                        break;
                case 0x32:      /* FatalOp */
                        AML_DEBUGPRINT("Fatal(");
                        AML_DEBUGPRINT("0x%x, ", aml_parse_bytedata(env));
                        AML_DEBUGPRINT("0x%x, ", aml_parse_dworddata(env));
                        aml_parse_termobj(env, indent);
                        env->stat = aml_stat_panic;
                        AML_DEBUGPRINT(")");
                        break;
                case 0x80:      /* OpRegionOp */
                        aml_parse_defopregion(env, indent);
                        break;
                case 0x81:      /* FieldOp */
                        aml_parse_deffield(env, indent);
                        break;
                case 0x82:      /* DeviceOp */
                        aml_parse_defdevice(env, indent);
                        break;
                case 0x83:      /* ProcessorOp */
                        aml_parse_defprocessor(env, indent);
                        break;
                case 0x84:      /* PowerResOp */
                        aml_parse_defpowerres(env, indent);
                        break;
                case 0x85:      /* ThermalZoneOp */
                        aml_parse_defthermalzone(env, indent);
                        break;
                case 0x86:      /* IndexFieldOp */
                        aml_parse_defindexfield(env, indent);
                        break;
                case 0x87:      /* BankFieldOp */
                        aml_parse_defbankfield(env, indent);
                        break;
                default:
                        AML_SYSERRX(1, "strange opcode 0x5b, 0x%x\n", opcode);
                        AML_SYSABORT();
                }
                break;
        case 0x68 ... 0x6e:     /* ArgN */
                AML_DEBUGPRINT("Arg%d", opcode - 0x68);
                return (aml_local_stack_getArgX(NULL, opcode - 0x68));
                break;
        case 0x60 ... 0x67:
                AML_DEBUGPRINT("Local%d", opcode - 0x60);
                return (aml_local_stack_getLocalX(opcode - 0x60));
                break;
        case 0x70:              /* StoreOp */
                AML_DEBUGPRINT("Store(");
                aname = aml_create_local_object();
                AML_COPY_OBJECT(tmpobj, env,
                    aml_eval_name(env,  aml_parse_termobj(env, indent)), NULL);
                aname->property = tmpobj;
                AML_DEBUGPRINT(", ");
                destname1 = aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(")");
                /* XXX
                 * temporary object may change during aml_store_to_name()
                 * operation, so we make a copy of it on stack.
                 */
                if (destname1 == &env->tempname &&
                    destname1->property == &env->tempobject) {
                        destname1 = aml_create_local_object();
                        AML_COPY_OBJECT(destname1->property, env,
                            &env->tempobject, NULL);
                }
                aml_store_to_name(env, tmpobj, destname1);
                if (env->stat == aml_stat_panic) {
                        AML_DEBUGPRINT("StoreOp failed");
                        return (NULL);
                }
                aname = aml_create_local_object();
                AML_COPY_OBJECT(tmpobj, env, destname1->property, NULL);
                aname->property = tmpobj;
                if (tmpobj == NULL) {
                        printf("???");
                        break;
                }
                break;
        case 0x71:              /* RefOfOp */
                AML_DEBUGPRINT("RefOf(");
                src = aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(")");

                aname = aml_create_local_object();
                AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL);
                objref = aname->property;
                if (src->property == NULL ||
                    src->property->type != aml_t_namestr) {
                        objref->objref.nameref = src;
                } else {
                        objref->objref.nameref = aml_create_local_object();
                }
                objref->objref.ref = src->property;
                objref->objref.offset = -1;     /* different from IndexOp */
                break;

#define NUMOP3_2(opname, oparation, ope2) do {                          \
        AML_DEBUGPRINT(opname);                                         \
        AML_DEBUGPRINT("(");                                            \
        num1 = aml_objtonum(env, aml_eval_name(env,                     \
            aml_parse_termobj(env, indent)));                           \
        AML_DEBUGPRINT(", ");                                           \
        num2 = aml_objtonum(env, aml_eval_name(env,                     \
            aml_parse_termobj(env, indent)));                           \
        AML_DEBUGPRINT(", ");                                           \
        anum.num.number = ope2(num1 oparation num2);                    \
        destname1 = aml_parse_termobj(env, indent);                     \
        AML_DEBUGPRINT(")");                                            \
        aml_store_to_name(env, &anum, destname1);                       \
        env->tempobject.num = anum.num;                                 \
        env->tempname.property = &env->tempobject;                      \
        aname = &env->tempname;                                         \
} while(0)

#define NUMOP3(opname, operation)       NUMOP3_2(opname, operation, )
#define NUMOPN3(opname, operation)      NUMOP3_2(opname, operation, ~)

        case 0x72:              /* AddOp */
                NUMOP3("Add", +);
                break;
        case 0x73:              /* ConcatOp  */
                aname = aml_parse_concatop(env, indent);
                break;
        case 0x74:              /* SubtractOp */
                NUMOP3("Subtract", -);
                break;
        case 0x75:              /* IncrementOp */
                AML_DEBUGPRINT("Increment(");
                aname = aml_parse_termobj(env, indent);
                num1 = aml_objtonum(env, aml_eval_name(env, aname));
                num1++;
                anum.num.number = num1;
                AML_DEBUGPRINT(")");
                aml_store_to_name(env, &anum, aname);
                aname = &env->tempname;
                env->tempobject.num = anum.num;
                break;
        case 0x76:              /* DecrementOp */
                AML_DEBUGPRINT("Decrement(");
                aname = aml_parse_termobj(env, indent);
                num1 = aml_objtonum(env, aml_eval_name(env, aname));
                num1--;
                anum.num.number = num1;
                AML_DEBUGPRINT(")");
                aml_store_to_name(env, &anum, aname);
                aname = &env->tempname;
                env->tempobject.num = anum.num;
                break;
        case 0x77:              /* MultiplyOp */
                NUMOP3("Multiply", *);
                break;
        case 0x78:              /* DivideOp */
                AML_DEBUGPRINT("Divide(");
                num1 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                AML_DEBUGPRINT(", ");
                num2 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                AML_DEBUGPRINT(", ");
                anum.num.number = num1 % num2;
                destname1 = aml_parse_termobj(env, indent);
                aml_store_to_name(env, &anum, destname1);
                AML_DEBUGPRINT(", ");
                anum.num.number = num1 / num2;
                destname2 = aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(")");
                aml_store_to_name(env, &anum, destname2);
                env->tempobject.num = anum.num;
                aname = &env->tempname;
                break;
        case 0x79:              /* ShiftLeftOp */
                NUMOP3("ShiftLeft", <<);
                break;
        case 0x7a:              /* ShiftRightOp */
                NUMOP3("ShiftRight", >>);
                break;
        case 0x7b:              /* AndOp */
                NUMOP3("And", &);
                break;
        case 0x7c:              /* NAndOp */
                NUMOPN3("NAnd", &);
                break;
        case 0x7d:              /* OrOp */
                NUMOP3("Or", |);
                break;
        case 0x7e:              /* NOrOp */
                NUMOPN3("NOr", |);
                break;
        case 0x7f:              /* XOrOp */
                NUMOP3("XOr", ^);
                break;
        case 0x80:              /* NotOp */
                NUMOP2("Not", ~);
                break;
        case 0x81:              /* FindSetLeftBitOp */
                NUMOP2("FindSetLeftBit", findsetleftbit);
                break;
        case 0x82:              /* FindSetRightBitOp */
                NUMOP2("FindSetRightBit", findsetrightbit);
                break;
        case 0x83:              /* DerefOp */
                AML_DEBUGPRINT("DerefOf(");
                objref = aml_eval_name(env, aml_parse_termobj(env, indent));
                AML_DEBUGPRINT(")");

                if (objref->objref.ref == NULL) {
                        env->tempname.property = objref->objref.ref;
                        aname = &env->tempname;
                        break;
                }
                switch (objref->objref.ref->type) {
                case aml_t_package:
                case aml_t_buffer:
                        if (objref->objref.offset < 0) {
                                env->tempname.property = objref->objref.ref;
                        } else {
                                objref->objref.deref = 1;
                                env->tempname.property = objref;
                        }
                        break;
                default:
                        env->tempname.property = objref->objref.ref;
                        break;
                }

                aname = &env->tempname;
                break;
        case 0x86:              /* NotifyOp *//* XXX Not yet impremented */
                AML_DEBUGPRINT("Notify(");
                aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(", ");
                aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(")");
                break;
        case 0x87:              /* SizeOfOp */
                AML_DEBUGPRINT("SizeOf(");
                aname = aml_parse_termobj(env, indent);
                tmpobj = aml_eval_name(env, aname);

                AML_DEBUGPRINT(")");
                num1 = 0;
                switch (tmpobj->type) {
                case aml_t_buffer:
                        num1 = tmpobj->buffer.size;
                        break;
                case aml_t_string:
                        num1 = strlen((const char *)tmpobj->str.string);
                        break;
                case aml_t_package:
                        num1 = tmpobj->package.elements;
                        break;
                default:
                        AML_DEBUGPRINT("Args of SizeOf should be "
                                       "buffer/string/package only\n");
                        break;
                }

                anum.num.number = num1;
                env->tempobject.num = anum.num;
                aname = &env->tempname;
                break;
        case 0x88:              /* IndexOp */
                AML_DEBUGPRINT("Index(");
                srcobj = aml_eval_name(env, aml_parse_termobj(env, indent));
                AML_DEBUGPRINT(", ");
                num1 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                AML_DEBUGPRINT(", ");
                destname1 = aml_parse_termobj(env, indent);
                AML_DEBUGPRINT(")");
                aname = aml_create_local_object();
                switch (srcobj->type) {
                case aml_t_package:
                case aml_t_buffer:
                        AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL);
                        aname->property = objref;
                        objref->objref.ref = srcobj;
                        objref->objref.offset = num1;
                        objref->objref.deref = 0;
                        break;
                default:
                        AML_DEBUGPRINT("Arg0 of Index should be either "
                                       "buffer or package\n");
                        return (aname);
                }

                aml_store_to_name(env, objref, destname1);
                break;
        case 0x89:              /* MatchOp *//* XXX Not yet Impremented */
                AML_DEBUGPRINT("Match(");
                AML_COPY_OBJECT(obj, env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)), NULL);
                if (obj->type != aml_t_package) {
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                anum.num.number = 0xffffffff;
                match1 = *env->dp;
                AML_DEBUGPRINT(", %d", *env->dp);
                env->dp++;
                num1 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                match2 = *env->dp;
                AML_DEBUGPRINT(", %d", *env->dp);
                env->dp++;
                num2 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                AML_DEBUGPRINT(", ");
                start = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));

#define MATCHOP(opnum, arg1, arg2)      ((opnum == 0) ? (1) :           \
    (opnum == 1) ? ((arg1) == (arg2))   :                               \
    (opnum == 2) ? ((arg1) <= (arg2))   :                               \
    (opnum == 3) ? ((arg1) <  (arg2))   :                               \
    (opnum == 4) ? ((arg1) >= (arg2))   :                               \
    (opnum == 5) ? ((arg1) >  (arg2))   : 0 )

                for (i = start; i < obj->package.elements; i++) {
                        pkgval = aml_objtonum(env, obj->package.objects[i]);
                        if (MATCHOP(match1, pkgval, num1) &&
                            MATCHOP(match2, pkgval, num2)) {
                                anum.num.number = i;
                                break;
                        }
                }
                AML_DEBUGPRINT(")");
                aml_free_object(&obj);
                aname = &env->tempname;
                env->tempname.property = &env->tempobject;
                env->tempobject.num = anum.num;
                break;
#undef MATCHOP
        case 0x8a ... 0x8d:     /* CreateDWordFieldOp */
                widthindex = *(env->dp - 1) - 0x8a;
                AML_DEBUGPRINT("%s(", opname[widthindex]);
                srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent));
                if (srcbuf == &env->tempobject) {
                        AML_DEBUGPRINT("NOT NAMEDBUF\n");
                        env->stat = aml_stat_panic;
                        return (NULL);
                }
                AML_DEBUGPRINT(", ");
                idx = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                if (widthindex != 3) {
                        idx *= 8;
                }
                AML_DEBUGPRINT(", ");
                newname = (char *)aml_parse_namestring(env);
                aml_print_namestring((unsigned char *)newname);
                aml_createfield_generic(env, srcbuf, idx,
                    widthtbl[widthindex], newname);
                AML_DEBUGPRINT(")");
                break;
        case 0x8e:              /* ObjectTypeOp */
                AML_DEBUGPRINT("ObjectType(");
                aname = aml_parse_termobj(env, indent);
                if (aname == NULL) {
                        env->tempobject.type = aml_t_num;
                        env->tempobject.num.number = aml_t_null;
                } else {
                        env->tempobject.type = aml_t_num;
                        env->tempobject.num.number = aname->property->type;
                }
                aname = &env->tempname;
                AML_DEBUGPRINT(")");
                break;

#define CMPOP(opname,operation) do {                                    \
        AML_DEBUGPRINT(opname);                                         \
        AML_DEBUGPRINT("(");                                            \
        num1 = aml_objtonum(env, aml_eval_name(env,                     \
            aml_parse_termobj(env, indent)));                           \
        AML_DEBUGPRINT(", ");                                           \
        num2 = aml_objtonum(env, aml_eval_name(env,                     \
            aml_parse_termobj(env, indent)));                           \
        aname = &env->tempname;                                         \
        env->tempobject.type = aml_t_num;                               \
        env->tempobject.num.number = (num1 operation num2) ? 0xffffffff : 0;    \
        aname->property = &env->tempobject;                             \
        AML_DEBUGPRINT(")");                                            \
} while(0)

        case 0x90:
                CMPOP("LAnd", &&);
                break;
        case 0x91:
                CMPOP("LOr", ||);
                break;
        case 0x92:
                AML_DEBUGPRINT("LNot(");
                num1 = aml_objtonum(env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)));
                aname = &env->tempname;
                env->tempobject.type = aml_t_num;
                env->tempobject.num.number = (!num1) ? 0xffffffff : 0;
                aname->property = &env->tempobject;
                AML_DEBUGPRINT(")");
                break;
        case 0x93:
                CMPOP("LEqual", ==);
                break;
        case 0x94:
                CMPOP("LGreater", >);
                break;
        case 0x95:
                CMPOP("LLess", <);
                break;
        case 0xa0:              /* IfOp */
                aname = aml_parse_defif(env, indent);
                break;
#if 0

        case 0xa1:              /* ElseOp should not be treated in Main parser
                                 * But If Op */
                aml_parse_defelse(env, indent);
                break;
#endif
        case 0xa2:              /* WhileOp */
                aname = aml_parse_defwhile(env, indent);
                break;
        case 0xa3:              /* NoopOp */
                AML_DEBUGPRINT("Noop");
                break;
        case 0xa5:              /* BreakOp */
                AML_DEBUGPRINT("Break");
                env->stat = aml_stat_break;
                break;
        case 0xa4:              /* ReturnOp */
                AML_DEBUGPRINT("Return(");
                AML_COPY_OBJECT(env->tempname.property, env, aml_eval_name(env,
                    aml_parse_termobj(env, indent)), NULL);
                aname = &env->tempname;
                env->stat = aml_stat_return;
                AML_DEBUGPRINT(")");
                break;
        case 0xcc:              /* BreakPointOp */
                /* XXX Not Yet Impremented (Not need?) */
                AML_DEBUGPRINT("BreakPoint");
                break;
        default:
                AML_SYSERRX(1, "strange opcode 0x%x\n", opcode);
                AML_SYSABORT();
        }

        return (aname);
}