1/*	$NetBSD: aml_evalobj.c,v 1.1 2007/01/14 04:36:13 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1999 Takanori Watanabe
5 * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	Id: aml_evalobj.c,v 1.27 2000/08/16 18:14:53 iwasaki Exp
30 *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_evalobj.c,v 1.4 2000/11/09 06:24:45 iwasaki Exp $
31 */
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: aml_evalobj.c,v 1.1 2007/01/14 04:36:13 christos Exp $");
34
35#include <sys/param.h>
36
37#include <acpi_common.h>
38#include <aml/aml_amlmem.h>
39#include <aml/aml_common.h>
40#include <aml/aml_env.h>
41#include <aml/aml_evalobj.h>
42#include <aml/aml_name.h>
43#include <aml/aml_obj.h>
44#include <aml/aml_parse.h>
45#include <aml/aml_region.h>
46#include <aml/aml_status.h>
47#include <aml/aml_store.h>
48
49#ifndef _KERNEL
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/mman.h>
53
54#include <assert.h>
55#include <err.h>
56#include <fcntl.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60
61#include "debug.h"
62#else /* _KERNEL */
63#include <sys/systm.h>
64#endif /* !_KERNEL */
65
66static union aml_object	*aml_eval_fieldobject(struct aml_environ *env,
67					      struct aml_name *name);
68
69static union aml_object *
70aml_eval_fieldobject(struct aml_environ *env, struct aml_name *name)
71{
72	int	num;
73	struct	aml_name *oname,*wname;
74	struct	aml_field *field;
75	struct	aml_opregion *or;
76	union	aml_object tobj;
77
78	num = 0;
79	/* CANNOT OCCUR! */
80	if (name == NULL || name->property == NULL ||
81	    name->property->type != aml_t_field) {
82		printf("????\n");
83		env->stat = aml_stat_panic;
84		return (NULL);
85	}
86	field = &name->property->field;
87	oname = env->curname;
88	if (field->bitlen > 32) {
89		env->tempobject.type = aml_t_regfield;
90	} else {
91		env->tempobject.type = aml_t_num;
92	}
93	env->curname = name;
94	if (field->f.ftype == f_t_field) {
95		wname = aml_search_name(env, field->f.fld.regname);
96		if (wname == NULL || wname->property == NULL ||
97		    wname->property->type != aml_t_opregion) {
98			AML_DEBUGPRINT("Inappropreate Type\n");
99			env->stat = aml_stat_panic;
100			env->curname = oname;
101			return (NULL);
102		}
103		or = &wname->property->opregion;
104		if (env->tempobject.type == aml_t_regfield) {
105			env->tempobject.regfield.space = or->space;
106			env->tempobject.regfield.flags = field->flags;
107			env->tempobject.regfield.offset = or->offset;
108			env->tempobject.regfield.bitoffset = field->bitoffset;
109			env->tempobject.regfield.bitlen = field->bitlen;
110		} else {
111			env->tempobject.type = aml_t_num;
112			env->tempobject.num.number = aml_region_read(env,
113			    or->space, field->flags, or->offset,
114			    field->bitoffset, field->bitlen);
115			AML_DEBUGPRINT("[read(%d, 0x%x)->0x%x]",
116			    or->space, or->offset + field->bitoffset / 8,
117			    env->tempobject.num.number);
118		}
119	} else if (field->f.ftype == f_t_index) {
120		wname = aml_search_name(env, field->f.ifld.indexname);
121		tobj.type = aml_t_num;
122		tobj.num.number = field->bitoffset / 8;/* AccessType Boundary */
123		aml_store_to_name(env, &tobj, wname);
124		wname = aml_search_name(env, field->f.ifld.dataname);
125		num = aml_objtonum(env, aml_eval_name(env, wname));
126		env->tempobject.type = aml_t_num;
127		env->tempobject.num.number = (num >> (field->bitoffset & 7)) &
128		    ((1 << field->bitlen) - 1);
129	}
130	env->curname = oname;
131	return (&env->tempobject);
132}
133
134union aml_object *
135aml_eval_objref(struct aml_environ *env, union aml_object *obj)
136{
137	int	offset;
138	union	aml_object num1;
139	union	aml_object *ref, *ret;
140
141	ret = obj;
142	if (obj->objref.deref == 1) {
143		num1.type = aml_t_num;
144		offset = obj->objref.offset;
145		ref = obj->objref.ref;
146		if (ref == NULL) {
147			goto out;
148		}
149		switch (ref->type) {
150		case aml_t_package:
151			if (ref->package.elements > offset) {
152				ret = ref->package.objects[offset];
153			} else {
154				num1.num.number = 0;
155				env->tempobject = num1;
156				ret = &env->tempobject;
157			}
158			break;
159		case aml_t_buffer:
160			if (ref->buffer.size > offset) {
161				num1.num.number = ref->buffer.data[offset] & 0xff;
162			} else {
163				num1.num.number = 0;
164			}
165			env->tempobject = num1;
166			ret = &env->tempobject;
167			break;
168		default:
169			break;
170		}
171	}
172	if (obj->objref.alias == 1) {
173		ret = aml_eval_name(env, obj->objref.nameref);
174		goto out;
175	}
176out:
177	return (ret);
178}
179
180/*
181 * Eval named object.
182 */
183union aml_object *
184aml_eval_name(struct aml_environ *env, struct aml_name *aname)
185{
186	int	argnum, i;
187	int	num;
188	struct	aml_name *tmp;
189	struct	aml_environ *copy;
190	struct	aml_local_stack *stack;
191	union	aml_object *obj, *ret;
192	union	aml_object *src;
193
194	ret = NULL;
195	if (aname == NULL || aname->property == NULL) {
196		return (NULL);
197	}
198	if (env->stat == aml_stat_panic) {
199		return (NULL);
200	}
201	copy = memman_alloc(aml_memman, memid_aml_environ);
202	if (copy == NULL) {
203		return (NULL);
204	}
205	ret = aname->property;
206	i = 0;
207reevaluate:
208	if (i > 10) {
209		env->stat = aml_stat_panic;
210		printf("TOO MANY LOOP\n");
211		ret = NULL;
212		goto out;
213	}
214	switch (aname->property->type) {
215	case aml_t_namestr:
216		tmp = aname;
217		aname = aml_search_name(env, aname->property->nstr.dp);
218		if (aname == NULL) {
219			aname = tmp;
220		}
221		i++;
222		goto reevaluate;
223	case aml_t_objref:
224		ret = aml_eval_objref(env, aname->property);
225		goto out;
226	case aml_t_num:
227	case aml_t_string:
228	case aml_t_buffer:
229	case aml_t_package:
230	case aml_t_debug:
231		ret = aname->property;
232		goto out;
233	case aml_t_field:
234		aml_free_objectcontent(&env->tempobject);
235		ret = aml_eval_fieldobject(env, aname);
236		goto out;
237	case aml_t_method:
238		aml_free_objectcontent(&env->tempobject);
239		argnum = aname->property->meth.argnum & 7;
240		*copy = *env;
241		copy->curname = aname;
242		copy->dp = aname->property->meth.from;
243		copy->end = aname->property->meth.to;
244		copy->stat = aml_stat_none;
245		stack = aml_local_stack_create();
246		AML_DEBUGPRINT("(");
247		for (i = 0; i < argnum; i++) {
248			aml_local_stack_getArgX(stack, i)->property =
249			    aml_copy_object(env,
250				aml_eval_name(env,
251				    aml_parse_termobj(env, 0)));
252			if (i < argnum - 1)
253				AML_DEBUGPRINT(", ");
254		}
255		AML_DEBUGPRINT(")\n");
256		aml_local_stack_push(stack);
257		if (env->stat == aml_stat_step) {
258			AML_DEBUGGER(env, copy);
259		}
260		tmp = aml_execute_method(copy);
261		obj = aml_eval_name(env, tmp);
262		if (copy->stat == aml_stat_panic) {
263			AML_DEBUGPRINT("PANIC OCCURED IN METHOD");
264			env->stat = aml_stat_panic;
265			ret = NULL;
266			aml_local_stack_delete(aml_local_stack_pop());
267			goto out;
268		}
269		if (aml_debug) {
270			aml_showobject(obj);
271		}
272
273		if (tmp)
274			tmp->property = NULL;
275		aml_local_stack_delete(aml_local_stack_pop());
276		if (obj) {
277			aml_create_local_object()->property = obj;
278			ret = obj;
279		} else {
280			env->tempobject.type = aml_t_num;
281			env->tempobject.num.number = 0;
282		}
283
284		goto out;
285	case aml_t_bufferfield:
286		aml_free_objectcontent(&env->tempobject);
287		if (aname->property->bfld.bitlen > 32) {
288			ret = aname->property;
289		} else {
290			src = aname->property;
291			num = aml_bufferfield_read(src->bfld.origin,
292			    src->bfld.bitoffset, src->bfld.bitlen);
293			env->tempobject.type = aml_t_num;
294			env->tempobject.num.number = num;
295			ret = &env->tempobject;
296		}
297		goto out;
298	default:
299		AML_DEBUGPRINT("I eval the object that I should not eval, %s%d",
300		    aname->name, aname->property->type);
301		AML_SYSABORT();
302		ret = NULL;
303		goto out;
304	}
305out:
306	memman_free(aml_memman, memid_aml_environ, copy);
307	return (ret);
308}
309
310/*
311 * Eval named object but env variable is not required and return
312 * status of evaluation (success is zero).  This function is assumed
313 * to be called by aml_apply_foreach_found_objects().
314 * Note that no arguments are passed if object is a method.
315 */
316
317int
318aml_eval_name_simple(struct aml_name *name, va_list ap)
319{
320	struct	aml_environ *env;
321	union	aml_object *ret;
322
323	if (name == NULL || name->property == NULL) {
324		return (1);
325	}
326
327	env = memman_alloc(aml_memman, memid_aml_environ);
328	if (env == NULL) {
329		return (1);
330	}
331	bzero(env, sizeof(struct aml_environ));
332
333	aml_local_stack_push(aml_local_stack_create());
334
335	AML_DEBUGPRINT("Evaluating ");
336	aml_print_curname(name);
337	ret = aml_eval_name(env, name);
338	if (name->property->type != aml_t_method) {
339		AML_DEBUGPRINT("\n");
340		if (aml_debug) {
341			aml_showobject(ret);
342		}
343	}
344
345	aml_local_stack_delete(aml_local_stack_pop());
346
347	memman_free(aml_memman, memid_aml_environ, env);
348	return (0);
349}
350
351int
352aml_objtonum(struct aml_environ *env, union aml_object *obj)
353{
354
355	if (obj != NULL && obj->type == aml_t_num) {
356		return (obj->num.number);
357	} else {
358		env->stat = aml_stat_panic;
359		return (-1);
360	}
361}
362
363struct aml_name *
364aml_execute_method(struct aml_environ *env)
365{
366	struct	aml_name *name;
367	struct	aml_name_group *newgrp;
368
369	newgrp = aml_new_name_group((void *)AML_NAME_GROUP_IN_METHOD);
370
371	AML_DEBUGPRINT("[");
372	aml_print_curname(env->curname);
373	AML_DEBUGPRINT(" START]\n");
374
375	name = aml_parse_objectlist(env, 0);
376	AML_DEBUGPRINT("[");
377	aml_print_curname(env->curname);
378	AML_DEBUGPRINT(" END]\n");
379
380	aml_delete_name_group(newgrp);
381	return (name);
382}
383
384union aml_object *
385aml_invoke_method(struct aml_name *name, int argc, union aml_object *argv)
386{
387	int	i;
388	struct	aml_name *tmp;
389	struct	aml_environ *env;
390	struct	aml_local_stack *stack;
391	union	aml_object *retval;
392	union	aml_object *obj;
393
394	retval = NULL;
395	env = memman_alloc(aml_memman, memid_aml_environ);
396	if (env == NULL) {
397		return (NULL);
398	}
399	bzero(env, sizeof(struct aml_environ));
400
401	if (name != NULL && name->property != NULL &&
402	    name->property->type == aml_t_method) {
403		env->curname = name;
404		env->dp = name->property->meth.from;
405		env->end = name->property->meth.to;
406		AML_DEBUGGER(env, env);
407		stack = aml_local_stack_create();
408		for (i = 0; i < argc; i++) {
409			aml_local_stack_getArgX(stack, i)->property =
410			    aml_alloc_object(argv[i].type, &argv[i]);
411		}
412		aml_local_stack_push(stack);
413		obj = aml_eval_name(env, tmp = aml_execute_method(env));
414		if (aml_debug) {
415			aml_showtree(name, 0);
416		}
417
418		if (tmp)
419			tmp->property = NULL;
420		aml_local_stack_delete(aml_local_stack_pop());
421		if (obj) {
422			aml_create_local_object()->property = obj;
423			retval = obj;
424		}
425	}
426	memman_free(aml_memman, memid_aml_environ, env);
427	return (retval);
428}
429
430union aml_object *
431aml_invoke_method_by_name(char *method, int argc, union aml_object *argv)
432{
433	struct	aml_name *name;
434
435	name = aml_find_from_namespace(aml_get_rootname(), method);
436	if (name == NULL) {
437		return (NULL);
438	}
439
440	return (aml_invoke_method(name, argc, argv));
441}
442