1 /*        $NetBSD: aml_store.c,v 1.5 2024/07/31 20:20:11 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.5 2024/07/31 20:20:11 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 
58 static void
aml_store_to_fieldname(struct aml_environ * env,union aml_object * obj,struct aml_name * name)59 aml_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("Inappropriate 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                                                "Inappropriate 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 
144 static void
aml_store_to_buffer(struct aml_environ * env,union aml_object * obj,union aml_object * buf,int offset)145 aml_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;
192 not_yet:
193           AML_DEBUGPRINT("[XXX not supported yet]");
194 }
195 
196 
197 void
aml_store_to_object(struct aml_environ * env,union aml_object * src,union aml_object * dest)198 aml_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 
260 static void
aml_store_to_objref(struct aml_environ * env,union aml_object * obj,union aml_object * r)261 aml_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  */
298 void
aml_store_to_name(struct aml_environ * env,union aml_object * obj,struct aml_name * name)299 aml_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