NetBSD/usr.sbin/acpitools/aml/aml_evalobj.c

442 lines
11 KiB
C

/* $NetBSD: aml_evalobj.c,v 1.3 2021/12/10 11:09:52 msaitoh Exp $ */
/*-
* Copyright (c) 1999 Takanori Watanabe
* 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_evalobj.c,v 1.27 2000/08/16 18:14:53 iwasaki Exp
* $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_evalobj.c,v 1.4 2000/11/09 06:24:45 iwasaki Exp $
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: aml_evalobj.c,v 1.3 2021/12/10 11:09:52 msaitoh 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_region.h>
#include <aml/aml_status.h>
#include <aml/aml_store.h>
#ifndef _KERNEL
#include <sys/param.h>
#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 "debug.h"
#else /* _KERNEL */
#include <sys/systm.h>
#endif /* !_KERNEL */
static union aml_object *aml_eval_fieldobject(struct aml_environ *env,
struct aml_name *name);
static union aml_object *
aml_eval_fieldobject(struct aml_environ *env, struct aml_name *name)
{
int num;
struct aml_name *oname,*wname;
struct aml_field *field;
struct aml_opregion *or;
union aml_object tobj;
num = 0;
/* CANNOT OCCUR! */
if (name == NULL || name->property == NULL ||
name->property->type != aml_t_field) {
printf("????\n");
env->stat = aml_stat_panic;
return (NULL);
}
field = &name->property->field;
oname = env->curname;
if (field->bitlen > 32) {
env->tempobject.type = aml_t_regfield;
} else {
env->tempobject.type = aml_t_num;
}
env->curname = name;
if (field->f.ftype == f_t_field) {
wname = aml_search_name(env, field->f.fld.regname);
if (wname == NULL || wname->property == NULL ||
wname->property->type != aml_t_opregion) {
AML_DEBUGPRINT("Inappropreate Type\n");
env->stat = aml_stat_panic;
env->curname = oname;
return (NULL);
}
or = &wname->property->opregion;
if (env->tempobject.type == aml_t_regfield) {
env->tempobject.regfield.space = or->space;
env->tempobject.regfield.flags = field->flags;
env->tempobject.regfield.offset = or->offset;
env->tempobject.regfield.bitoffset = field->bitoffset;
env->tempobject.regfield.bitlen = field->bitlen;
} else {
env->tempobject.type = aml_t_num;
env->tempobject.num.number = aml_region_read(env,
or->space, field->flags, or->offset,
field->bitoffset, field->bitlen);
AML_DEBUGPRINT("[read(%d, 0x%x)->0x%x]",
or->space, or->offset + field->bitoffset / 8,
env->tempobject.num.number);
}
} else if (field->f.ftype == f_t_index) {
wname = aml_search_name(env, field->f.ifld.indexname);
tobj.type = aml_t_num;
tobj.num.number = field->bitoffset / 8;/* AccessType Boundary */
aml_store_to_name(env, &tobj, wname);
wname = aml_search_name(env, field->f.ifld.dataname);
num = aml_objtonum(env, aml_eval_name(env, wname));
env->tempobject.type = aml_t_num;
env->tempobject.num.number = (num >> (field->bitoffset & 7)) &
((1 << field->bitlen) - 1);
}
env->curname = oname;
return (&env->tempobject);
}
union aml_object *
aml_eval_objref(struct aml_environ *env, union aml_object *obj)
{
int offset;
union aml_object num1;
union aml_object *ref, *ret;
ret = obj;
if (obj->objref.deref == 1) {
num1.type = aml_t_num;
offset = obj->objref.offset;
ref = obj->objref.ref;
if (ref == NULL) {
goto out;
}
switch (ref->type) {
case aml_t_package:
if (ref->package.elements > offset) {
ret = ref->package.objects[offset];
} else {
num1.num.number = 0;
env->tempobject = num1;
ret = &env->tempobject;
}
break;
case aml_t_buffer:
if (ref->buffer.size > offset) {
num1.num.number = ref->buffer.data[offset] & 0xff;
} else {
num1.num.number = 0;
}
env->tempobject = num1;
ret = &env->tempobject;
break;
default:
break;
}
}
if (obj->objref.alias == 1) {
ret = aml_eval_name(env, obj->objref.nameref);
goto out;
}
out:
return (ret);
}
/*
* Eval named object.
*/
union aml_object *
aml_eval_name(struct aml_environ *env, struct aml_name *aname)
{
int argnum, i;
int num;
struct aml_name *tmp;
struct aml_environ *copy;
struct aml_local_stack *stack;
union aml_object *obj, *ret;
union aml_object *src;
ret = NULL;
if (aname == NULL || aname->property == NULL) {
return (NULL);
}
if (env->stat == aml_stat_panic) {
return (NULL);
}
copy = memman_alloc(aml_memman, memid_aml_environ);
if (copy == NULL) {
return (NULL);
}
ret = aname->property;
i = 0;
reevaluate:
if (i > 10) {
env->stat = aml_stat_panic;
printf("TOO MANY LOOP\n");
ret = NULL;
goto out;
}
switch (aname->property->type) {
case aml_t_namestr:
tmp = aname;
aname = aml_search_name(env, aname->property->nstr.dp);
if (aname == NULL) {
aname = tmp;
}
i++;
goto reevaluate;
case aml_t_objref:
ret = aml_eval_objref(env, aname->property);
goto out;
case aml_t_num:
case aml_t_string:
case aml_t_buffer:
case aml_t_package:
case aml_t_debug:
ret = aname->property;
goto out;
case aml_t_field:
aml_free_objectcontent(&env->tempobject);
ret = aml_eval_fieldobject(env, aname);
goto out;
case aml_t_method:
aml_free_objectcontent(&env->tempobject);
argnum = aname->property->meth.argnum & 7;
*copy = *env;
copy->curname = aname;
copy->dp = aname->property->meth.from;
copy->end = aname->property->meth.to;
copy->stat = aml_stat_none;
stack = aml_local_stack_create();
AML_DEBUGPRINT("(");
for (i = 0; i < argnum; i++) {
aml_local_stack_getArgX(stack, i)->property =
aml_copy_object(env,
aml_eval_name(env,
aml_parse_termobj(env, 0)));
if (i < argnum - 1)
AML_DEBUGPRINT(", ");
}
AML_DEBUGPRINT(")\n");
aml_local_stack_push(stack);
if (env->stat == aml_stat_step) {
AML_DEBUGGER(env, copy);
}
tmp = aml_execute_method(copy);
obj = aml_eval_name(env, tmp);
if (copy->stat == aml_stat_panic) {
AML_DEBUGPRINT("PANIC OCCURRED IN METHOD");
env->stat = aml_stat_panic;
ret = NULL;
aml_local_stack_delete(aml_local_stack_pop());
goto out;
}
if (aml_debug) {
aml_showobject(obj);
}
if (tmp)
tmp->property = NULL;
aml_local_stack_delete(aml_local_stack_pop());
if (obj) {
aml_create_local_object()->property = obj;
ret = obj;
} else {
env->tempobject.type = aml_t_num;
env->tempobject.num.number = 0;
}
goto out;
case aml_t_bufferfield:
aml_free_objectcontent(&env->tempobject);
if (aname->property->bfld.bitlen > 32) {
ret = aname->property;
} else {
src = aname->property;
num = aml_bufferfield_read(src->bfld.origin,
src->bfld.bitoffset, src->bfld.bitlen);
env->tempobject.type = aml_t_num;
env->tempobject.num.number = num;
ret = &env->tempobject;
}
goto out;
default:
AML_DEBUGPRINT("I eval the object that I should not eval, %s%d",
aname->name, aname->property->type);
AML_SYSABORT();
ret = NULL;
goto out;
}
out:
memman_free(aml_memman, memid_aml_environ, copy);
return (ret);
}
/*
* Eval named object but env variable is not required and return
* status of evaluation (success is zero). This function is assumed
* to be called by aml_apply_foreach_found_objects().
* Note that no arguments are passed if object is a method.
*/
int
aml_eval_name_simple(struct aml_name *name, va_list ap)
{
struct aml_environ *env;
union aml_object *ret;
if (name == NULL || name->property == NULL) {
return (1);
}
env = memman_alloc(aml_memman, memid_aml_environ);
if (env == NULL) {
return (1);
}
bzero(env, sizeof(struct aml_environ));
aml_local_stack_push(aml_local_stack_create());
AML_DEBUGPRINT("Evaluating ");
aml_print_curname(name);
ret = aml_eval_name(env, name);
if (name->property->type != aml_t_method) {
AML_DEBUGPRINT("\n");
if (aml_debug) {
aml_showobject(ret);
}
}
aml_local_stack_delete(aml_local_stack_pop());
memman_free(aml_memman, memid_aml_environ, env);
return (0);
}
int
aml_objtonum(struct aml_environ *env, union aml_object *obj)
{
if (obj != NULL && obj->type == aml_t_num) {
return (obj->num.number);
} else {
env->stat = aml_stat_panic;
return (-1);
}
}
struct aml_name *
aml_execute_method(struct aml_environ *env)
{
struct aml_name *name;
struct aml_name_group *newgrp;
newgrp = aml_new_name_group((void *)AML_NAME_GROUP_IN_METHOD);
AML_DEBUGPRINT("[");
aml_print_curname(env->curname);
AML_DEBUGPRINT(" START]\n");
name = aml_parse_objectlist(env, 0);
AML_DEBUGPRINT("[");
aml_print_curname(env->curname);
AML_DEBUGPRINT(" END]\n");
aml_delete_name_group(newgrp);
return (name);
}
union aml_object *
aml_invoke_method(struct aml_name *name, int argc, union aml_object *argv)
{
int i;
struct aml_name *tmp;
struct aml_environ *env;
struct aml_local_stack *stack;
union aml_object *retval;
union aml_object *obj;
retval = NULL;
env = memman_alloc(aml_memman, memid_aml_environ);
if (env == NULL) {
return (NULL);
}
bzero(env, sizeof(struct aml_environ));
if (name != NULL && name->property != NULL &&
name->property->type == aml_t_method) {
env->curname = name;
env->dp = name->property->meth.from;
env->end = name->property->meth.to;
AML_DEBUGGER(env, env);
stack = aml_local_stack_create();
for (i = 0; i < argc; i++) {
aml_local_stack_getArgX(stack, i)->property =
aml_alloc_object(argv[i].type, &argv[i]);
}
aml_local_stack_push(stack);
obj = aml_eval_name(env, tmp = aml_execute_method(env));
if (aml_debug) {
aml_showtree(name, 0);
}
if (tmp)
tmp->property = NULL;
aml_local_stack_delete(aml_local_stack_pop());
if (obj) {
aml_create_local_object()->property = obj;
retval = obj;
}
}
memman_free(aml_memman, memid_aml_environ, env);
return (retval);
}
union aml_object *
aml_invoke_method_by_name(char *method, int argc, union aml_object *argv)
{
struct aml_name *name;
name = aml_find_from_namespace(aml_get_rootname(), method);
if (name == NULL) {
return (NULL);
}
return (aml_invoke_method(name, argc, argv));
}