1*016d86eeSandvar /* $NetBSD: aml_evalobj.c,v 1.4 2024/07/31 20:15:33 andvar Exp $ */ 253e202c1Schristos 353e202c1Schristos /*- 453e202c1Schristos * Copyright (c) 1999 Takanori Watanabe 553e202c1Schristos * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 653e202c1Schristos * All rights reserved. 753e202c1Schristos * 853e202c1Schristos * Redistribution and use in source and binary forms, with or without 953e202c1Schristos * modification, are permitted provided that the following conditions 1053e202c1Schristos * are met: 1153e202c1Schristos * 1. Redistributions of source code must retain the above copyright 1253e202c1Schristos * notice, this list of conditions and the following disclaimer. 1353e202c1Schristos * 2. Redistributions in binary form must reproduce the above copyright 1453e202c1Schristos * notice, this list of conditions and the following disclaimer in the 1553e202c1Schristos * documentation and/or other materials provided with the distribution. 1653e202c1Schristos * 1753e202c1Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1853e202c1Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953e202c1Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053e202c1Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2153e202c1Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253e202c1Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353e202c1Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453e202c1Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553e202c1Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653e202c1Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753e202c1Schristos * SUCH DAMAGE. 2853e202c1Schristos * 2953e202c1Schristos * Id: aml_evalobj.c,v 1.27 2000/08/16 18:14:53 iwasaki Exp 3053e202c1Schristos * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_evalobj.c,v 1.4 2000/11/09 06:24:45 iwasaki Exp $ 3153e202c1Schristos */ 3253e202c1Schristos #include <sys/cdefs.h> 33*016d86eeSandvar __RCSID("$NetBSD: aml_evalobj.c,v 1.4 2024/07/31 20:15:33 andvar Exp $"); 3453e202c1Schristos 3553e202c1Schristos #include <sys/param.h> 3653e202c1Schristos 3753e202c1Schristos #include <acpi_common.h> 3853e202c1Schristos #include <aml/aml_amlmem.h> 3953e202c1Schristos #include <aml/aml_common.h> 4053e202c1Schristos #include <aml/aml_env.h> 4153e202c1Schristos #include <aml/aml_evalobj.h> 4253e202c1Schristos #include <aml/aml_name.h> 4353e202c1Schristos #include <aml/aml_obj.h> 4453e202c1Schristos #include <aml/aml_parse.h> 4553e202c1Schristos #include <aml/aml_region.h> 4653e202c1Schristos #include <aml/aml_status.h> 4753e202c1Schristos #include <aml/aml_store.h> 4853e202c1Schristos 4953e202c1Schristos #ifndef _KERNEL 5053e202c1Schristos #include <sys/param.h> 5153e202c1Schristos #include <sys/stat.h> 5253e202c1Schristos #include <sys/mman.h> 5353e202c1Schristos 5453e202c1Schristos #include <assert.h> 5553e202c1Schristos #include <err.h> 5653e202c1Schristos #include <fcntl.h> 5753e202c1Schristos #include <stdio.h> 5853e202c1Schristos #include <stdlib.h> 5953e202c1Schristos #include <string.h> 6053e202c1Schristos 6153e202c1Schristos #include "debug.h" 6253e202c1Schristos #else /* _KERNEL */ 6353e202c1Schristos #include <sys/systm.h> 6453e202c1Schristos #endif /* !_KERNEL */ 6553e202c1Schristos 6653e202c1Schristos static union aml_object *aml_eval_fieldobject(struct aml_environ *env, 6753e202c1Schristos struct aml_name *name); 6853e202c1Schristos 6953e202c1Schristos static union aml_object * 7053e202c1Schristos aml_eval_fieldobject(struct aml_environ *env, struct aml_name *name) 7153e202c1Schristos { 7253e202c1Schristos int num; 7353e202c1Schristos struct aml_name *oname,*wname; 7453e202c1Schristos struct aml_field *field; 7553e202c1Schristos struct aml_opregion *or; 7653e202c1Schristos union aml_object tobj; 7753e202c1Schristos 7853e202c1Schristos num = 0; 7953e202c1Schristos /* CANNOT OCCUR! */ 8053e202c1Schristos if (name == NULL || name->property == NULL || 8153e202c1Schristos name->property->type != aml_t_field) { 8253e202c1Schristos printf("????\n"); 8353e202c1Schristos env->stat = aml_stat_panic; 8453e202c1Schristos return (NULL); 8553e202c1Schristos } 8653e202c1Schristos field = &name->property->field; 8753e202c1Schristos oname = env->curname; 8853e202c1Schristos if (field->bitlen > 32) { 8953e202c1Schristos env->tempobject.type = aml_t_regfield; 9053e202c1Schristos } else { 9153e202c1Schristos env->tempobject.type = aml_t_num; 9253e202c1Schristos } 9353e202c1Schristos env->curname = name; 9453e202c1Schristos if (field->f.ftype == f_t_field) { 9553e202c1Schristos wname = aml_search_name(env, field->f.fld.regname); 9653e202c1Schristos if (wname == NULL || wname->property == NULL || 9753e202c1Schristos wname->property->type != aml_t_opregion) { 98*016d86eeSandvar AML_DEBUGPRINT("Inappropriate Type\n"); 9953e202c1Schristos env->stat = aml_stat_panic; 10053e202c1Schristos env->curname = oname; 10153e202c1Schristos return (NULL); 10253e202c1Schristos } 10353e202c1Schristos or = &wname->property->opregion; 10453e202c1Schristos if (env->tempobject.type == aml_t_regfield) { 10553e202c1Schristos env->tempobject.regfield.space = or->space; 10653e202c1Schristos env->tempobject.regfield.flags = field->flags; 10753e202c1Schristos env->tempobject.regfield.offset = or->offset; 10853e202c1Schristos env->tempobject.regfield.bitoffset = field->bitoffset; 10953e202c1Schristos env->tempobject.regfield.bitlen = field->bitlen; 11053e202c1Schristos } else { 11153e202c1Schristos env->tempobject.type = aml_t_num; 11253e202c1Schristos env->tempobject.num.number = aml_region_read(env, 11353e202c1Schristos or->space, field->flags, or->offset, 11453e202c1Schristos field->bitoffset, field->bitlen); 11553e202c1Schristos AML_DEBUGPRINT("[read(%d, 0x%x)->0x%x]", 11653e202c1Schristos or->space, or->offset + field->bitoffset / 8, 11753e202c1Schristos env->tempobject.num.number); 11853e202c1Schristos } 11953e202c1Schristos } else if (field->f.ftype == f_t_index) { 12053e202c1Schristos wname = aml_search_name(env, field->f.ifld.indexname); 12153e202c1Schristos tobj.type = aml_t_num; 12253e202c1Schristos tobj.num.number = field->bitoffset / 8;/* AccessType Boundary */ 12353e202c1Schristos aml_store_to_name(env, &tobj, wname); 12453e202c1Schristos wname = aml_search_name(env, field->f.ifld.dataname); 12553e202c1Schristos num = aml_objtonum(env, aml_eval_name(env, wname)); 12653e202c1Schristos env->tempobject.type = aml_t_num; 12753e202c1Schristos env->tempobject.num.number = (num >> (field->bitoffset & 7)) & 12853e202c1Schristos ((1 << field->bitlen) - 1); 12953e202c1Schristos } 13053e202c1Schristos env->curname = oname; 13153e202c1Schristos return (&env->tempobject); 13253e202c1Schristos } 13353e202c1Schristos 13453e202c1Schristos union aml_object * 13553e202c1Schristos aml_eval_objref(struct aml_environ *env, union aml_object *obj) 13653e202c1Schristos { 13753e202c1Schristos int offset; 13853e202c1Schristos union aml_object num1; 13953e202c1Schristos union aml_object *ref, *ret; 14053e202c1Schristos 14153e202c1Schristos ret = obj; 14253e202c1Schristos if (obj->objref.deref == 1) { 14353e202c1Schristos num1.type = aml_t_num; 14453e202c1Schristos offset = obj->objref.offset; 14553e202c1Schristos ref = obj->objref.ref; 14653e202c1Schristos if (ref == NULL) { 14753e202c1Schristos goto out; 14853e202c1Schristos } 14953e202c1Schristos switch (ref->type) { 15053e202c1Schristos case aml_t_package: 15153e202c1Schristos if (ref->package.elements > offset) { 15253e202c1Schristos ret = ref->package.objects[offset]; 15353e202c1Schristos } else { 15453e202c1Schristos num1.num.number = 0; 15553e202c1Schristos env->tempobject = num1; 15653e202c1Schristos ret = &env->tempobject; 15753e202c1Schristos } 15853e202c1Schristos break; 15953e202c1Schristos case aml_t_buffer: 16053e202c1Schristos if (ref->buffer.size > offset) { 16153e202c1Schristos num1.num.number = ref->buffer.data[offset] & 0xff; 16253e202c1Schristos } else { 16353e202c1Schristos num1.num.number = 0; 16453e202c1Schristos } 16553e202c1Schristos env->tempobject = num1; 16653e202c1Schristos ret = &env->tempobject; 16753e202c1Schristos break; 16853e202c1Schristos default: 16953e202c1Schristos break; 17053e202c1Schristos } 17153e202c1Schristos } 17253e202c1Schristos if (obj->objref.alias == 1) { 17353e202c1Schristos ret = aml_eval_name(env, obj->objref.nameref); 17453e202c1Schristos goto out; 17553e202c1Schristos } 17653e202c1Schristos out: 17753e202c1Schristos return (ret); 17853e202c1Schristos } 17953e202c1Schristos 18053e202c1Schristos /* 18153e202c1Schristos * Eval named object. 18253e202c1Schristos */ 18353e202c1Schristos union aml_object * 18453e202c1Schristos aml_eval_name(struct aml_environ *env, struct aml_name *aname) 18553e202c1Schristos { 18653e202c1Schristos int argnum, i; 18753e202c1Schristos int num; 18853e202c1Schristos struct aml_name *tmp; 18953e202c1Schristos struct aml_environ *copy; 19053e202c1Schristos struct aml_local_stack *stack; 19153e202c1Schristos union aml_object *obj, *ret; 19253e202c1Schristos union aml_object *src; 19353e202c1Schristos 19453e202c1Schristos ret = NULL; 19553e202c1Schristos if (aname == NULL || aname->property == NULL) { 19653e202c1Schristos return (NULL); 19753e202c1Schristos } 19853e202c1Schristos if (env->stat == aml_stat_panic) { 19953e202c1Schristos return (NULL); 20053e202c1Schristos } 20153e202c1Schristos copy = memman_alloc(aml_memman, memid_aml_environ); 20253e202c1Schristos if (copy == NULL) { 20353e202c1Schristos return (NULL); 20453e202c1Schristos } 20553e202c1Schristos ret = aname->property; 20653e202c1Schristos i = 0; 20753e202c1Schristos reevaluate: 20853e202c1Schristos if (i > 10) { 20953e202c1Schristos env->stat = aml_stat_panic; 21053e202c1Schristos printf("TOO MANY LOOP\n"); 21153e202c1Schristos ret = NULL; 21253e202c1Schristos goto out; 21353e202c1Schristos } 21453e202c1Schristos switch (aname->property->type) { 21553e202c1Schristos case aml_t_namestr: 21653e202c1Schristos tmp = aname; 21753e202c1Schristos aname = aml_search_name(env, aname->property->nstr.dp); 21853e202c1Schristos if (aname == NULL) { 21953e202c1Schristos aname = tmp; 22053e202c1Schristos } 22153e202c1Schristos i++; 22253e202c1Schristos goto reevaluate; 22353e202c1Schristos case aml_t_objref: 22453e202c1Schristos ret = aml_eval_objref(env, aname->property); 22553e202c1Schristos goto out; 22653e202c1Schristos case aml_t_num: 22753e202c1Schristos case aml_t_string: 22853e202c1Schristos case aml_t_buffer: 22953e202c1Schristos case aml_t_package: 23053e202c1Schristos case aml_t_debug: 23153e202c1Schristos ret = aname->property; 23253e202c1Schristos goto out; 23353e202c1Schristos case aml_t_field: 23453e202c1Schristos aml_free_objectcontent(&env->tempobject); 23553e202c1Schristos ret = aml_eval_fieldobject(env, aname); 23653e202c1Schristos goto out; 23753e202c1Schristos case aml_t_method: 23853e202c1Schristos aml_free_objectcontent(&env->tempobject); 23953e202c1Schristos argnum = aname->property->meth.argnum & 7; 24053e202c1Schristos *copy = *env; 24153e202c1Schristos copy->curname = aname; 24253e202c1Schristos copy->dp = aname->property->meth.from; 24353e202c1Schristos copy->end = aname->property->meth.to; 24453e202c1Schristos copy->stat = aml_stat_none; 24553e202c1Schristos stack = aml_local_stack_create(); 24653e202c1Schristos AML_DEBUGPRINT("("); 24753e202c1Schristos for (i = 0; i < argnum; i++) { 24853e202c1Schristos aml_local_stack_getArgX(stack, i)->property = 24953e202c1Schristos aml_copy_object(env, 25053e202c1Schristos aml_eval_name(env, 25153e202c1Schristos aml_parse_termobj(env, 0))); 25253e202c1Schristos if (i < argnum - 1) 25353e202c1Schristos AML_DEBUGPRINT(", "); 25453e202c1Schristos } 25553e202c1Schristos AML_DEBUGPRINT(")\n"); 25653e202c1Schristos aml_local_stack_push(stack); 25753e202c1Schristos if (env->stat == aml_stat_step) { 25853e202c1Schristos AML_DEBUGGER(env, copy); 25953e202c1Schristos } 26053e202c1Schristos tmp = aml_execute_method(copy); 26153e202c1Schristos obj = aml_eval_name(env, tmp); 26253e202c1Schristos if (copy->stat == aml_stat_panic) { 2631a03346fSmsaitoh AML_DEBUGPRINT("PANIC OCCURRED IN METHOD"); 26453e202c1Schristos env->stat = aml_stat_panic; 26553e202c1Schristos ret = NULL; 26653e202c1Schristos aml_local_stack_delete(aml_local_stack_pop()); 26753e202c1Schristos goto out; 26853e202c1Schristos } 26953e202c1Schristos if (aml_debug) { 27053e202c1Schristos aml_showobject(obj); 27153e202c1Schristos } 27253e202c1Schristos 27353e202c1Schristos if (tmp) 27453e202c1Schristos tmp->property = NULL; 27553e202c1Schristos aml_local_stack_delete(aml_local_stack_pop()); 27653e202c1Schristos if (obj) { 27753e202c1Schristos aml_create_local_object()->property = obj; 27853e202c1Schristos ret = obj; 27953e202c1Schristos } else { 28053e202c1Schristos env->tempobject.type = aml_t_num; 28153e202c1Schristos env->tempobject.num.number = 0; 28253e202c1Schristos } 28353e202c1Schristos 28453e202c1Schristos goto out; 28553e202c1Schristos case aml_t_bufferfield: 28653e202c1Schristos aml_free_objectcontent(&env->tempobject); 28753e202c1Schristos if (aname->property->bfld.bitlen > 32) { 28853e202c1Schristos ret = aname->property; 28953e202c1Schristos } else { 29053e202c1Schristos src = aname->property; 29153e202c1Schristos num = aml_bufferfield_read(src->bfld.origin, 29253e202c1Schristos src->bfld.bitoffset, src->bfld.bitlen); 29353e202c1Schristos env->tempobject.type = aml_t_num; 29453e202c1Schristos env->tempobject.num.number = num; 29553e202c1Schristos ret = &env->tempobject; 29653e202c1Schristos } 29753e202c1Schristos goto out; 29853e202c1Schristos default: 29953e202c1Schristos AML_DEBUGPRINT("I eval the object that I should not eval, %s%d", 30053e202c1Schristos aname->name, aname->property->type); 30153e202c1Schristos AML_SYSABORT(); 30253e202c1Schristos ret = NULL; 30353e202c1Schristos goto out; 30453e202c1Schristos } 30553e202c1Schristos out: 30653e202c1Schristos memman_free(aml_memman, memid_aml_environ, copy); 30753e202c1Schristos return (ret); 30853e202c1Schristos } 30953e202c1Schristos 31053e202c1Schristos /* 31153e202c1Schristos * Eval named object but env variable is not required and return 31253e202c1Schristos * status of evaluation (success is zero). This function is assumed 31353e202c1Schristos * to be called by aml_apply_foreach_found_objects(). 31453e202c1Schristos * Note that no arguments are passed if object is a method. 31553e202c1Schristos */ 31653e202c1Schristos 31753e202c1Schristos int 31853e202c1Schristos aml_eval_name_simple(struct aml_name *name, va_list ap) 31953e202c1Schristos { 32053e202c1Schristos struct aml_environ *env; 32153e202c1Schristos union aml_object *ret; 32253e202c1Schristos 32353e202c1Schristos if (name == NULL || name->property == NULL) { 32453e202c1Schristos return (1); 32553e202c1Schristos } 32653e202c1Schristos 32753e202c1Schristos env = memman_alloc(aml_memman, memid_aml_environ); 32853e202c1Schristos if (env == NULL) { 32953e202c1Schristos return (1); 33053e202c1Schristos } 33153e202c1Schristos bzero(env, sizeof(struct aml_environ)); 33253e202c1Schristos 33353e202c1Schristos aml_local_stack_push(aml_local_stack_create()); 33453e202c1Schristos 33553e202c1Schristos AML_DEBUGPRINT("Evaluating "); 33653e202c1Schristos aml_print_curname(name); 33753e202c1Schristos ret = aml_eval_name(env, name); 33853e202c1Schristos if (name->property->type != aml_t_method) { 33953e202c1Schristos AML_DEBUGPRINT("\n"); 34053e202c1Schristos if (aml_debug) { 34153e202c1Schristos aml_showobject(ret); 34253e202c1Schristos } 34353e202c1Schristos } 34453e202c1Schristos 34553e202c1Schristos aml_local_stack_delete(aml_local_stack_pop()); 34653e202c1Schristos 34753e202c1Schristos memman_free(aml_memman, memid_aml_environ, env); 34853e202c1Schristos return (0); 34953e202c1Schristos } 35053e202c1Schristos 35153e202c1Schristos int 35253e202c1Schristos aml_objtonum(struct aml_environ *env, union aml_object *obj) 35353e202c1Schristos { 35453e202c1Schristos 35553e202c1Schristos if (obj != NULL && obj->type == aml_t_num) { 35653e202c1Schristos return (obj->num.number); 35753e202c1Schristos } else { 35853e202c1Schristos env->stat = aml_stat_panic; 35953e202c1Schristos return (-1); 36053e202c1Schristos } 36153e202c1Schristos } 36253e202c1Schristos 36353e202c1Schristos struct aml_name * 36453e202c1Schristos aml_execute_method(struct aml_environ *env) 36553e202c1Schristos { 36653e202c1Schristos struct aml_name *name; 36753e202c1Schristos struct aml_name_group *newgrp; 36853e202c1Schristos 3697ac7d15dSdogcow newgrp = aml_new_name_group((void *)AML_NAME_GROUP_IN_METHOD); 37053e202c1Schristos 37153e202c1Schristos AML_DEBUGPRINT("["); 37253e202c1Schristos aml_print_curname(env->curname); 37353e202c1Schristos AML_DEBUGPRINT(" START]\n"); 37453e202c1Schristos 37553e202c1Schristos name = aml_parse_objectlist(env, 0); 37653e202c1Schristos AML_DEBUGPRINT("["); 37753e202c1Schristos aml_print_curname(env->curname); 37853e202c1Schristos AML_DEBUGPRINT(" END]\n"); 37953e202c1Schristos 38053e202c1Schristos aml_delete_name_group(newgrp); 38153e202c1Schristos return (name); 38253e202c1Schristos } 38353e202c1Schristos 38453e202c1Schristos union aml_object * 38553e202c1Schristos aml_invoke_method(struct aml_name *name, int argc, union aml_object *argv) 38653e202c1Schristos { 38753e202c1Schristos int i; 38853e202c1Schristos struct aml_name *tmp; 38953e202c1Schristos struct aml_environ *env; 39053e202c1Schristos struct aml_local_stack *stack; 39153e202c1Schristos union aml_object *retval; 39253e202c1Schristos union aml_object *obj; 39353e202c1Schristos 39453e202c1Schristos retval = NULL; 39553e202c1Schristos env = memman_alloc(aml_memman, memid_aml_environ); 39653e202c1Schristos if (env == NULL) { 39753e202c1Schristos return (NULL); 39853e202c1Schristos } 39953e202c1Schristos bzero(env, sizeof(struct aml_environ)); 40053e202c1Schristos 40153e202c1Schristos if (name != NULL && name->property != NULL && 40253e202c1Schristos name->property->type == aml_t_method) { 40353e202c1Schristos env->curname = name; 40453e202c1Schristos env->dp = name->property->meth.from; 40553e202c1Schristos env->end = name->property->meth.to; 40653e202c1Schristos AML_DEBUGGER(env, env); 40753e202c1Schristos stack = aml_local_stack_create(); 40853e202c1Schristos for (i = 0; i < argc; i++) { 40953e202c1Schristos aml_local_stack_getArgX(stack, i)->property = 41053e202c1Schristos aml_alloc_object(argv[i].type, &argv[i]); 41153e202c1Schristos } 41253e202c1Schristos aml_local_stack_push(stack); 41353e202c1Schristos obj = aml_eval_name(env, tmp = aml_execute_method(env)); 41453e202c1Schristos if (aml_debug) { 41553e202c1Schristos aml_showtree(name, 0); 41653e202c1Schristos } 41753e202c1Schristos 41853e202c1Schristos if (tmp) 41953e202c1Schristos tmp->property = NULL; 42053e202c1Schristos aml_local_stack_delete(aml_local_stack_pop()); 42153e202c1Schristos if (obj) { 42253e202c1Schristos aml_create_local_object()->property = obj; 42353e202c1Schristos retval = obj; 42453e202c1Schristos } 42553e202c1Schristos } 42653e202c1Schristos memman_free(aml_memman, memid_aml_environ, env); 42753e202c1Schristos return (retval); 42853e202c1Schristos } 42953e202c1Schristos 43053e202c1Schristos union aml_object * 43153e202c1Schristos aml_invoke_method_by_name(char *method, int argc, union aml_object *argv) 43253e202c1Schristos { 43353e202c1Schristos struct aml_name *name; 43453e202c1Schristos 43553e202c1Schristos name = aml_find_from_namespace(aml_get_rootname(), method); 43653e202c1Schristos if (name == NULL) { 43753e202c1Schristos return (NULL); 43853e202c1Schristos } 43953e202c1Schristos 44053e202c1Schristos return (aml_invoke_method(name, argc, argv)); 44153e202c1Schristos } 442