xref: /netbsd-src/usr.sbin/acpitools/aml/aml_store.c (revision 74b6b0adc8be769c28e13ff3e9c42e233d792cc8)
1*74b6b0adSandvar /*	$NetBSD: aml_store.c,v 1.5 2024/07/31 20:20:11 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_store.c,v 1.22 2000/08/09 14:47:44 iwasaki Exp
3053e202c1Schristos  *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_store.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $
3153e202c1Schristos  */
3253e202c1Schristos #include <sys/cdefs.h>
33*74b6b0adSandvar __RCSID("$NetBSD: aml_store.c,v 1.5 2024/07/31 20:20:11 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_region.h>
4553e202c1Schristos #include <aml/aml_status.h>
4653e202c1Schristos #include <aml/aml_store.h>
4753e202c1Schristos 
4853e202c1Schristos #ifndef _KERNEL
4953e202c1Schristos #include <assert.h>
5053e202c1Schristos #include <stdio.h>
5153e202c1Schristos #include <string.h>
5253e202c1Schristos 
5353e202c1Schristos #include "debug.h"
5453e202c1Schristos #else /* _KERNEL */
5553e202c1Schristos #include <sys/systm.h>
5653e202c1Schristos #endif /* !_KERNEL */
5753e202c1Schristos 
5853e202c1Schristos static void
5953e202c1Schristos aml_store_to_fieldname(struct aml_environ *env, union aml_object *obj,
6053e202c1Schristos     struct aml_name *name)
6153e202c1Schristos {
6253e202c1Schristos 	u_int8_t *buffer;
6353e202c1Schristos 	struct	aml_name *wname, *oname, *iname;
6453e202c1Schristos 	struct	aml_field *field;
6553e202c1Schristos 	struct	aml_opregion *or;
6653e202c1Schristos 	union	aml_object tobj, iobj, *tmpobj;
6753e202c1Schristos 
6853e202c1Schristos 	field = &name->property->field;
6953e202c1Schristos 	oname = env->curname;
7053e202c1Schristos 	iname = NULL;
7153e202c1Schristos 	env->curname = name->parent;
7253e202c1Schristos 	if (field->f.ftype == f_t_field) {
7353e202c1Schristos 		wname = aml_search_name(env, field->f.fld.regname);
7453e202c1Schristos 		if (wname == NULL ||
7553e202c1Schristos 		    wname->property == NULL ||
7653e202c1Schristos 		    wname->property->type != aml_t_opregion) {
77016d86eeSandvar 			AML_DEBUGPRINT("Inappropriate Type\n");
7853e202c1Schristos 			env->stat = aml_stat_panic;
7953e202c1Schristos 			env->curname = oname;
8053e202c1Schristos 			return;
8153e202c1Schristos 		}
8253e202c1Schristos 		or = &wname->property->opregion;
8353e202c1Schristos 		switch (obj->type) {
8453e202c1Schristos 		case aml_t_num:
8553e202c1Schristos 			aml_region_write(env, or->space, field->flags,
8653e202c1Schristos 			    obj->num.number, or->offset,
8753e202c1Schristos 			    field->bitoffset, field->bitlen);
8853e202c1Schristos 			AML_DEBUGPRINT("[write(%d, 0x%x, 0x%x)]",
8953e202c1Schristos 			    or->space, obj->num.number,
9053e202c1Schristos 			    or->offset + field->bitoffset / 8);
9153e202c1Schristos 			break;
9253e202c1Schristos 		case aml_t_buffer:
9353e202c1Schristos 		case aml_t_bufferfield:
9453e202c1Schristos 			if (obj->type == aml_t_buffer) {
9553e202c1Schristos 				buffer = obj->buffer.data;
9653e202c1Schristos 			} else {
9753e202c1Schristos 				buffer = obj->bfld.origin;
9853e202c1Schristos 				buffer += obj->bfld.bitoffset / 8;
9953e202c1Schristos 			}
10053e202c1Schristos 			aml_region_write_from_buffer(env, or->space,
10153e202c1Schristos 			    field->flags, buffer, or->offset, field->bitoffset,
10253e202c1Schristos 			    field->bitlen);
10353e202c1Schristos 			break;
10453e202c1Schristos 		case aml_t_regfield:
10553e202c1Schristos 			if (or->space != obj->regfield.space) {
10653e202c1Schristos 				AML_DEBUGPRINT("aml_store_to_fieldname: "
10753e202c1Schristos 					       "Different type of space\n");
10853e202c1Schristos 				break;
10953e202c1Schristos 			}
11053e202c1Schristos 			aml_region_bcopy(env, obj->regfield.space,
11153e202c1Schristos 			    obj->regfield.flags, obj->regfield.offset,
11253e202c1Schristos 			    obj->regfield.bitoffset, obj->regfield.bitlen,
11353e202c1Schristos 			    field->flags, or->offset, field->bitoffset,
11453e202c1Schristos 			    field->bitlen);
11553e202c1Schristos 			break;
11653e202c1Schristos 		default:
11753e202c1Schristos 			AML_DEBUGPRINT("aml_store_to_fieldname: "
118*74b6b0adSandvar 				       "Inappropriate Type of src object\n");
11953e202c1Schristos 			break;
12053e202c1Schristos 		}
12153e202c1Schristos 	} else if (field->f.ftype == f_t_index) {
12253e202c1Schristos 		iname = aml_search_name(env, field->f.ifld.indexname);
12353e202c1Schristos 		wname = aml_search_name(env, field->f.ifld.dataname);
12453e202c1Schristos 		iobj.type = aml_t_num;
12553e202c1Schristos 		iobj.num.number = field->bitoffset / 8;	/* AccessType Boundary */
12653e202c1Schristos 
12753e202c1Schristos 		/* read whole values of IndexField */
12853e202c1Schristos 		aml_store_to_name(env, &iobj, iname);
12953e202c1Schristos 		tmpobj = aml_eval_name(env, wname);
13053e202c1Schristos 
13153e202c1Schristos 		/* make the values to be written */
13253e202c1Schristos 		tobj.num = obj->num;
13353e202c1Schristos  		tobj.num.number = aml_adjust_updatevalue(field->flags,
13453e202c1Schristos  		    field->bitoffset & 7, field->bitlen,
13553e202c1Schristos  		    tmpobj->num.number, obj->num.number);
13653e202c1Schristos 
13753e202c1Schristos 		/* write the values to IndexField */
13853e202c1Schristos 		aml_store_to_name(env, &iobj, iname);
13953e202c1Schristos 		aml_store_to_name(env, &tobj, wname);
14053e202c1Schristos 	}
14153e202c1Schristos 	env->curname = oname;
14253e202c1Schristos }
14353e202c1Schristos 
14453e202c1Schristos static void
14553e202c1Schristos aml_store_to_buffer(struct aml_environ *env, union aml_object *obj,
14653e202c1Schristos     union aml_object *buf, int offset)
14753e202c1Schristos {
14853e202c1Schristos 	int	size;
14953e202c1Schristos 	int	bitlen;
15053e202c1Schristos 
15153e202c1Schristos 	switch (obj->type) {
15253e202c1Schristos 	case aml_t_num:
15353e202c1Schristos 		if (offset > buf->buffer.size) {
15453e202c1Schristos 			aml_realloc_object(buf, offset);
15553e202c1Schristos 		}
15653e202c1Schristos 		buf->buffer.data[offset] = obj->num.number & 0xff;
15753e202c1Schristos 		AML_DEBUGPRINT("[Store number 0x%x to buffer]",
15853e202c1Schristos 		    obj->num.number & 0xff);
15953e202c1Schristos 		break;
16053e202c1Schristos 	case aml_t_string:
16153e202c1Schristos 		size = strlen((const char *)obj->str.string);
16253e202c1Schristos 		if (buf->buffer.size - offset < size) {
16353e202c1Schristos 			aml_realloc_object(buf, offset + size + 1);
16453e202c1Schristos 		}
16553e202c1Schristos 		strcpy((char *)&buf->buffer.data[offset],
16653e202c1Schristos 		    (const char *)obj->str.string);
16753e202c1Schristos 		AML_DEBUGPRINT("[Store string to buffer]");
16853e202c1Schristos 		break;
16953e202c1Schristos 	case aml_t_buffer:
17053e202c1Schristos 		bzero(buf->buffer.data, buf->buffer.size);
17153e202c1Schristos 		if (obj->buffer.size > buf->buffer.size) {
17253e202c1Schristos 			size = buf->buffer.size;
17353e202c1Schristos 		} else {
17453e202c1Schristos 			size = obj->buffer.size;
17553e202c1Schristos 		}
17653e202c1Schristos 		bcopy(obj->buffer.data, buf->buffer.data, size);
17753e202c1Schristos 		break;
17853e202c1Schristos 	case aml_t_regfield:
17953e202c1Schristos 		bitlen = (buf->buffer.size - offset) * 8;
18053e202c1Schristos 		if (bitlen > obj->regfield.bitlen) {
18153e202c1Schristos 			bitlen = obj->regfield.bitlen;
18253e202c1Schristos 		}
18353e202c1Schristos 		aml_region_read_into_buffer(env, obj->regfield.space,
18453e202c1Schristos 		    obj->regfield.flags, obj->regfield.offset,
18553e202c1Schristos 		    obj->regfield.bitoffset, bitlen,
18653e202c1Schristos 		    buf->buffer.data + offset);
18753e202c1Schristos 		break;
18853e202c1Schristos 	default:
18953e202c1Schristos 		goto not_yet;
19053e202c1Schristos 	}
19153e202c1Schristos 	return;
19253e202c1Schristos not_yet:
19353e202c1Schristos 	AML_DEBUGPRINT("[XXX not supported yet]");
19453e202c1Schristos }
19553e202c1Schristos 
19653e202c1Schristos 
19753e202c1Schristos void
19853e202c1Schristos aml_store_to_object(struct aml_environ *env, union aml_object *src,
19953e202c1Schristos     union aml_object * dest)
20053e202c1Schristos {
20153e202c1Schristos 	u_int8_t *buffer, *srcbuf;
20253e202c1Schristos 	int	offset, bitlen;
20353e202c1Schristos 
20453e202c1Schristos 	switch (dest->type) {
20553e202c1Schristos 	case aml_t_num:
20653e202c1Schristos 		if (src->type == aml_t_num) {
20753e202c1Schristos 			dest->num = src->num;
20853e202c1Schristos 			AML_DEBUGPRINT("[Store number 0x%x]", src->num.number);
20953e202c1Schristos 		} else {
21053e202c1Schristos 			env->stat = aml_stat_panic;
21153e202c1Schristos 		}
21253e202c1Schristos 		break;
21353e202c1Schristos 	case aml_t_string:
21453e202c1Schristos 	case aml_t_package:
21553e202c1Schristos 		break;
21653e202c1Schristos 	case aml_t_buffer:
21753e202c1Schristos 		aml_store_to_buffer(env, src, dest, 0);
21853e202c1Schristos 		break;
21953e202c1Schristos 	case aml_t_bufferfield:
22053e202c1Schristos 		buffer = dest->bfld.origin;
22153e202c1Schristos 		offset = dest->bfld.bitoffset;
22253e202c1Schristos 		bitlen = dest->bfld.bitlen;
22353e202c1Schristos 
22453e202c1Schristos 		switch (src->type) {
22553e202c1Schristos 		case aml_t_num:
22653e202c1Schristos 			if (aml_bufferfield_write(src->num.number, buffer, offset, bitlen)) {
22753e202c1Schristos 				AML_DEBUGPRINT("aml_bufferfield_write() failed\n");
22853e202c1Schristos 			}
22953e202c1Schristos 			break;
23053e202c1Schristos 		case aml_t_buffer:
23153e202c1Schristos 		case aml_t_bufferfield:
23253e202c1Schristos 			if (src->type == aml_t_buffer) {
23353e202c1Schristos 				srcbuf = src->buffer.data;
23453e202c1Schristos 			} else {
23553e202c1Schristos 				srcbuf = src->bfld.origin;
23653e202c1Schristos 				srcbuf += src->bfld.bitoffset / 8;
23753e202c1Schristos 			}
23853e202c1Schristos 			bcopy(srcbuf, buffer, bitlen / 8);
23953e202c1Schristos 			break;
24053e202c1Schristos 		case aml_t_regfield:
24153e202c1Schristos 			aml_region_read_into_buffer(env, src->regfield.space,
24253e202c1Schristos 			    src->regfield.flags, src->regfield.offset,
24353e202c1Schristos 			    src->regfield.bitoffset, src->regfield.bitlen,
24453e202c1Schristos 			    buffer);
24553e202c1Schristos 			break;
24653e202c1Schristos 		default:
24753e202c1Schristos 			AML_DEBUGPRINT("not implemented yet");
24853e202c1Schristos 			break;
24953e202c1Schristos 		}
25053e202c1Schristos 		break;
25153e202c1Schristos 	case aml_t_debug:
25253e202c1Schristos 		aml_showobject(src);
25353e202c1Schristos 		break;
25453e202c1Schristos 	default:
25553e202c1Schristos 		AML_DEBUGPRINT("[Unimplemented %d]", dest->type);
25653e202c1Schristos 		break;
25753e202c1Schristos 	}
25853e202c1Schristos }
25953e202c1Schristos 
26053e202c1Schristos static void
26153e202c1Schristos aml_store_to_objref(struct aml_environ *env, union aml_object *obj,
26253e202c1Schristos     union aml_object *r)
26353e202c1Schristos {
26453e202c1Schristos 	int	offset;
26553e202c1Schristos 	union	aml_object *ref;
26653e202c1Schristos 
26753e202c1Schristos 	if (r->objref.ref == NULL) {
26853e202c1Schristos 		r->objref.ref = aml_alloc_object(obj->type, NULL);	/* XXX */
26953e202c1Schristos 		r->objref.nameref->property = r->objref.ref;
27053e202c1Schristos 	}
27153e202c1Schristos 	ref = r->objref.ref;
27253e202c1Schristos 
27353e202c1Schristos 	switch (ref->type) {
27453e202c1Schristos 	case aml_t_buffer:
27553e202c1Schristos 		offset = r->objref.offset;
27653e202c1Schristos 		aml_store_to_buffer(env, obj, ref, r->objref.offset);
27753e202c1Schristos 		break;
27853e202c1Schristos 	case aml_t_package:
27953e202c1Schristos 		offset = r->objref.offset;
28053e202c1Schristos 		if (r->objref.ref->package.elements < offset) {
28153e202c1Schristos 			aml_realloc_object(ref, offset);
28253e202c1Schristos 		}
28353e202c1Schristos 		if (ref->package.objects[offset] == NULL) {
28453e202c1Schristos 			ref->package.objects[offset] = aml_copy_object(env, obj);
28553e202c1Schristos 		} else {
28653e202c1Schristos 			aml_store_to_object(env, obj, ref->package.objects[offset]);
28753e202c1Schristos 		}
28853e202c1Schristos 		break;
28953e202c1Schristos 	default:
29053e202c1Schristos 		aml_store_to_object(env, obj, ref);
29153e202c1Schristos 		break;
29253e202c1Schristos 	}
29353e202c1Schristos }
29453e202c1Schristos 
29553e202c1Schristos /*
29653e202c1Schristos  * Store to Named object
29753e202c1Schristos  */
29853e202c1Schristos void
29953e202c1Schristos aml_store_to_name(struct aml_environ *env, union aml_object *obj,
30053e202c1Schristos     struct aml_name *name)
30153e202c1Schristos {
30253e202c1Schristos 	struct	aml_name *wname;
30353e202c1Schristos 
30453e202c1Schristos 	if (env->stat == aml_stat_panic) {
30553e202c1Schristos 		return;
30653e202c1Schristos 	}
30753e202c1Schristos 	if (name == NULL || obj == NULL) {
30811850c9eSandvar 		AML_DEBUGPRINT("[Try to store non-existent name]");
30953e202c1Schristos 		return;
31053e202c1Schristos 	}
31153e202c1Schristos 	if (name->property == NULL) {
31253e202c1Schristos 		name->property = aml_copy_object(env, obj);
31353e202c1Schristos 		AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number);
31453e202c1Schristos 		return;
31553e202c1Schristos 	}
31653e202c1Schristos 	if (name->property->type == aml_t_namestr) {
31753e202c1Schristos 		wname = aml_search_name(env, name->property->nstr.dp);
31853e202c1Schristos 		name = wname;
31953e202c1Schristos 	}
32053e202c1Schristos 	if (name == NULL) {
32153e202c1Schristos 		env->stat = aml_stat_panic;
32253e202c1Schristos 		return;
32353e202c1Schristos 	}
32453e202c1Schristos 	if (name->property == NULL || name->property->type == aml_t_null) {
32553e202c1Schristos 		name->property = aml_copy_object(env, obj);
32653e202c1Schristos 		AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number);
32753e202c1Schristos 		return;
32853e202c1Schristos 	}
32953e202c1Schristos 	/* Writes to constant object are not allowed */
33053e202c1Schristos 	if (name->property != NULL && name->property->type == aml_t_num &&
33153e202c1Schristos 	    name->property->num.constant == 1) {
33253e202c1Schristos 		return;
33353e202c1Schristos 	}
33453e202c1Schristos 	/* try to dereference */
33553e202c1Schristos 	if (obj->type == aml_t_objref && obj->objref.deref == 0) {
33653e202c1Schristos 		AML_DEBUGPRINT("Source object isn't dereferenced yet, "
33753e202c1Schristos 			       "try to dereference anyway\n");
33853e202c1Schristos 		obj->objref.deref = 1;
33953e202c1Schristos 		obj = aml_eval_objref(env, obj);
34053e202c1Schristos 	}
34153e202c1Schristos 	switch (name->property->type) {
34253e202c1Schristos 	case aml_t_field:
34353e202c1Schristos 		aml_store_to_fieldname(env, obj, name);
34453e202c1Schristos 		break;
34553e202c1Schristos 	case aml_t_objref:
34653e202c1Schristos 		aml_store_to_objref(env, obj, name->property);
34753e202c1Schristos 		break;
34853e202c1Schristos 	case aml_t_num:
34953e202c1Schristos 		if (name == &env->tempname)
35053e202c1Schristos 			break;
351fbffadb9Smrg 		/* FALLTHROUGH */
35253e202c1Schristos 	default:
35353e202c1Schristos 		aml_store_to_object(env, obj, name->property);
35453e202c1Schristos 		break;
35553e202c1Schristos 	}
35653e202c1Schristos }
357