1/*	$NetBSD: aml_store.c,v 1.3 2021/09/03 22:33:18 andvar 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_store.c,v 1.22 2000/08/09 14:47:44 iwasaki Exp
30 *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_store.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $
31 */
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: aml_store.c,v 1.3 2021/09/03 22:33:18 andvar 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_region.h>
45#include <aml/aml_status.h>
46#include <aml/aml_store.h>
47
48#ifndef _KERNEL
49#include <assert.h>
50#include <stdio.h>
51#include <string.h>
52
53#include "debug.h"
54#else /* _KERNEL */
55#include <sys/systm.h>
56#endif /* !_KERNEL */
57
58static void
59aml_store_to_fieldname(struct aml_environ *env, union aml_object *obj,
60    struct aml_name *name)
61{
62	u_int8_t *buffer;
63	struct	aml_name *wname, *oname, *iname;
64	struct	aml_field *field;
65	struct	aml_opregion *or;
66	union	aml_object tobj, iobj, *tmpobj;
67
68	field = &name->property->field;
69	oname = env->curname;
70	iname = NULL;
71	env->curname = name->parent;
72	if (field->f.ftype == f_t_field) {
73		wname = aml_search_name(env, field->f.fld.regname);
74		if (wname == NULL ||
75		    wname->property == NULL ||
76		    wname->property->type != aml_t_opregion) {
77			AML_DEBUGPRINT("Inappropreate Type\n");
78			env->stat = aml_stat_panic;
79			env->curname = oname;
80			return;
81		}
82		or = &wname->property->opregion;
83		switch (obj->type) {
84		case aml_t_num:
85			aml_region_write(env, or->space, field->flags,
86			    obj->num.number, or->offset,
87			    field->bitoffset, field->bitlen);
88			AML_DEBUGPRINT("[write(%d, 0x%x, 0x%x)]",
89			    or->space, obj->num.number,
90			    or->offset + field->bitoffset / 8);
91			break;
92		case aml_t_buffer:
93		case aml_t_bufferfield:
94			if (obj->type == aml_t_buffer) {
95				buffer = obj->buffer.data;
96			} else {
97				buffer = obj->bfld.origin;
98				buffer += obj->bfld.bitoffset / 8;
99			}
100			aml_region_write_from_buffer(env, or->space,
101			    field->flags, buffer, or->offset, field->bitoffset,
102			    field->bitlen);
103			break;
104		case aml_t_regfield:
105			if (or->space != obj->regfield.space) {
106				AML_DEBUGPRINT("aml_store_to_fieldname: "
107					       "Different type of space\n");
108				break;
109			}
110			aml_region_bcopy(env, obj->regfield.space,
111			    obj->regfield.flags, obj->regfield.offset,
112			    obj->regfield.bitoffset, obj->regfield.bitlen,
113			    field->flags, or->offset, field->bitoffset,
114			    field->bitlen);
115			break;
116		default:
117			AML_DEBUGPRINT("aml_store_to_fieldname: "
118				       "Inappropreate Type of src object\n");
119			break;
120		}
121	} else if (field->f.ftype == f_t_index) {
122		iname = aml_search_name(env, field->f.ifld.indexname);
123		wname = aml_search_name(env, field->f.ifld.dataname);
124		iobj.type = aml_t_num;
125		iobj.num.number = field->bitoffset / 8;	/* AccessType Boundary */
126
127		/* read whole values of IndexField */
128		aml_store_to_name(env, &iobj, iname);
129		tmpobj = aml_eval_name(env, wname);
130
131		/* make the values to be written */
132		tobj.num = obj->num;
133 		tobj.num.number = aml_adjust_updatevalue(field->flags,
134 		    field->bitoffset & 7, field->bitlen,
135 		    tmpobj->num.number, obj->num.number);
136
137		/* write the values to IndexField */
138		aml_store_to_name(env, &iobj, iname);
139		aml_store_to_name(env, &tobj, wname);
140	}
141	env->curname = oname;
142}
143
144static void
145aml_store_to_buffer(struct aml_environ *env, union aml_object *obj,
146    union aml_object *buf, int offset)
147{
148	int	size;
149	int	bitlen;
150
151	switch (obj->type) {
152	case aml_t_num:
153		if (offset > buf->buffer.size) {
154			aml_realloc_object(buf, offset);
155		}
156		buf->buffer.data[offset] = obj->num.number & 0xff;
157		AML_DEBUGPRINT("[Store number 0x%x to buffer]",
158		    obj->num.number & 0xff);
159		break;
160	case aml_t_string:
161		size = strlen((const char *)obj->str.string);
162		if (buf->buffer.size - offset < size) {
163			aml_realloc_object(buf, offset + size + 1);
164		}
165		strcpy((char *)&buf->buffer.data[offset],
166		    (const char *)obj->str.string);
167		AML_DEBUGPRINT("[Store string to buffer]");
168		break;
169	case aml_t_buffer:
170		bzero(buf->buffer.data, buf->buffer.size);
171		if (obj->buffer.size > buf->buffer.size) {
172			size = buf->buffer.size;
173		} else {
174			size = obj->buffer.size;
175		}
176		bcopy(obj->buffer.data, buf->buffer.data, size);
177		break;
178	case aml_t_regfield:
179		bitlen = (buf->buffer.size - offset) * 8;
180		if (bitlen > obj->regfield.bitlen) {
181			bitlen = obj->regfield.bitlen;
182		}
183		aml_region_read_into_buffer(env, obj->regfield.space,
184		    obj->regfield.flags, obj->regfield.offset,
185		    obj->regfield.bitoffset, bitlen,
186		    buf->buffer.data + offset);
187		break;
188	default:
189		goto not_yet;
190	}
191	return;
192not_yet:
193	AML_DEBUGPRINT("[XXX not supported yet]");
194}
195
196
197void
198aml_store_to_object(struct aml_environ *env, union aml_object *src,
199    union aml_object * dest)
200{
201	u_int8_t *buffer, *srcbuf;
202	int	offset, bitlen;
203
204	switch (dest->type) {
205	case aml_t_num:
206		if (src->type == aml_t_num) {
207			dest->num = src->num;
208			AML_DEBUGPRINT("[Store number 0x%x]", src->num.number);
209		} else {
210			env->stat = aml_stat_panic;
211		}
212		break;
213	case aml_t_string:
214	case aml_t_package:
215		break;
216	case aml_t_buffer:
217		aml_store_to_buffer(env, src, dest, 0);
218		break;
219	case aml_t_bufferfield:
220		buffer = dest->bfld.origin;
221		offset = dest->bfld.bitoffset;
222		bitlen = dest->bfld.bitlen;
223
224		switch (src->type) {
225		case aml_t_num:
226			if (aml_bufferfield_write(src->num.number, buffer, offset, bitlen)) {
227				AML_DEBUGPRINT("aml_bufferfield_write() failed\n");
228			}
229			break;
230		case aml_t_buffer:
231		case aml_t_bufferfield:
232			if (src->type == aml_t_buffer) {
233				srcbuf = src->buffer.data;
234			} else {
235				srcbuf = src->bfld.origin;
236				srcbuf += src->bfld.bitoffset / 8;
237			}
238			bcopy(srcbuf, buffer, bitlen / 8);
239			break;
240		case aml_t_regfield:
241			aml_region_read_into_buffer(env, src->regfield.space,
242			    src->regfield.flags, src->regfield.offset,
243			    src->regfield.bitoffset, src->regfield.bitlen,
244			    buffer);
245			break;
246		default:
247			AML_DEBUGPRINT("not implemented yet");
248			break;
249		}
250		break;
251	case aml_t_debug:
252		aml_showobject(src);
253		break;
254	default:
255		AML_DEBUGPRINT("[Unimplemented %d]", dest->type);
256		break;
257	}
258}
259
260static void
261aml_store_to_objref(struct aml_environ *env, union aml_object *obj,
262    union aml_object *r)
263{
264	int	offset;
265	union	aml_object *ref;
266
267	if (r->objref.ref == NULL) {
268		r->objref.ref = aml_alloc_object(obj->type, NULL);	/* XXX */
269		r->objref.nameref->property = r->objref.ref;
270	}
271	ref = r->objref.ref;
272
273	switch (ref->type) {
274	case aml_t_buffer:
275		offset = r->objref.offset;
276		aml_store_to_buffer(env, obj, ref, r->objref.offset);
277		break;
278	case aml_t_package:
279		offset = r->objref.offset;
280		if (r->objref.ref->package.elements < offset) {
281			aml_realloc_object(ref, offset);
282		}
283		if (ref->package.objects[offset] == NULL) {
284			ref->package.objects[offset] = aml_copy_object(env, obj);
285		} else {
286			aml_store_to_object(env, obj, ref->package.objects[offset]);
287		}
288		break;
289	default:
290		aml_store_to_object(env, obj, ref);
291		break;
292	}
293}
294
295/*
296 * Store to Named object
297 */
298void
299aml_store_to_name(struct aml_environ *env, union aml_object *obj,
300    struct aml_name *name)
301{
302	struct	aml_name *wname;
303
304	if (env->stat == aml_stat_panic) {
305		return;
306	}
307	if (name == NULL || obj == NULL) {
308		AML_DEBUGPRINT("[Try to store non-existent name]");
309		return;
310	}
311	if (name->property == NULL) {
312		name->property = aml_copy_object(env, obj);
313		AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number);
314		return;
315	}
316	if (name->property->type == aml_t_namestr) {
317		wname = aml_search_name(env, name->property->nstr.dp);
318		name = wname;
319	}
320	if (name == NULL) {
321		env->stat = aml_stat_panic;
322		return;
323	}
324	if (name->property == NULL || name->property->type == aml_t_null) {
325		name->property = aml_copy_object(env, obj);
326		AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number);
327		return;
328	}
329	/* Writes to constant object are not allowed */
330	if (name->property != NULL && name->property->type == aml_t_num &&
331	    name->property->num.constant == 1) {
332		return;
333	}
334	/* try to dereference */
335	if (obj->type == aml_t_objref && obj->objref.deref == 0) {
336		AML_DEBUGPRINT("Source object isn't dereferenced yet, "
337			       "try to dereference anyway\n");
338		obj->objref.deref = 1;
339		obj = aml_eval_objref(env, obj);
340	}
341	switch (name->property->type) {
342	case aml_t_field:
343		aml_store_to_fieldname(env, obj, name);
344		break;
345	case aml_t_objref:
346		aml_store_to_objref(env, obj, name->property);
347		break;
348	case aml_t_num:
349		if (name == &env->tempname)
350			break;
351		/* FALLTHROUGH */
352	default:
353		aml_store_to_object(env, obj, name->property);
354		break;
355	}
356}
357