1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: exstore - AML Interpreter object store support |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acdispat.h" |
13 | #include "acinterp.h" |
14 | #include "amlcode.h" |
15 | #include "acnamesp.h" |
16 | |
17 | #define _COMPONENT ACPI_EXECUTER |
18 | ACPI_MODULE_NAME("exstore" ) |
19 | |
20 | /* Local prototypes */ |
21 | static acpi_status |
22 | acpi_ex_store_object_to_index(union acpi_operand_object *val_desc, |
23 | union acpi_operand_object *dest_desc, |
24 | struct acpi_walk_state *walk_state); |
25 | |
26 | static acpi_status |
27 | acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, |
28 | struct acpi_namespace_node *node, |
29 | struct acpi_walk_state *walk_state); |
30 | |
31 | /******************************************************************************* |
32 | * |
33 | * FUNCTION: acpi_ex_store |
34 | * |
35 | * PARAMETERS: *source_desc - Value to be stored |
36 | * *dest_desc - Where to store it. Must be an NS node |
37 | * or union acpi_operand_object of type |
38 | * Reference; |
39 | * walk_state - Current walk state |
40 | * |
41 | * RETURN: Status |
42 | * |
43 | * DESCRIPTION: Store the value described by source_desc into the location |
44 | * described by dest_desc. Called by various interpreter |
45 | * functions to store the result of an operation into |
46 | * the destination operand -- not just simply the actual "Store" |
47 | * ASL operator. |
48 | * |
49 | ******************************************************************************/ |
50 | |
51 | acpi_status |
52 | acpi_ex_store(union acpi_operand_object *source_desc, |
53 | union acpi_operand_object *dest_desc, |
54 | struct acpi_walk_state *walk_state) |
55 | { |
56 | acpi_status status = AE_OK; |
57 | union acpi_operand_object *ref_desc = dest_desc; |
58 | |
59 | ACPI_FUNCTION_TRACE_PTR(ex_store, dest_desc); |
60 | |
61 | /* Validate parameters */ |
62 | |
63 | if (!source_desc || !dest_desc) { |
64 | ACPI_ERROR((AE_INFO, "Null parameter" )); |
65 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
66 | } |
67 | |
68 | /* dest_desc can be either a namespace node or an ACPI object */ |
69 | |
70 | if (ACPI_GET_DESCRIPTOR_TYPE(dest_desc) == ACPI_DESC_TYPE_NAMED) { |
71 | /* |
72 | * Dest is a namespace node, |
73 | * Storing an object into a Named node. |
74 | */ |
75 | status = acpi_ex_store_object_to_node(source_desc, |
76 | node: (struct |
77 | acpi_namespace_node *) |
78 | dest_desc, walk_state, |
79 | ACPI_IMPLICIT_CONVERSION); |
80 | |
81 | return_ACPI_STATUS(status); |
82 | } |
83 | |
84 | /* Destination object must be a Reference or a Constant object */ |
85 | |
86 | switch (dest_desc->common.type) { |
87 | case ACPI_TYPE_LOCAL_REFERENCE: |
88 | |
89 | break; |
90 | |
91 | case ACPI_TYPE_INTEGER: |
92 | |
93 | /* Allow stores to Constants -- a Noop as per ACPI spec */ |
94 | |
95 | if (dest_desc->common.flags & AOPOBJ_AML_CONSTANT) { |
96 | return_ACPI_STATUS(AE_OK); |
97 | } |
98 | |
99 | ACPI_FALLTHROUGH; |
100 | |
101 | default: |
102 | |
103 | /* Destination is not a Reference object */ |
104 | |
105 | ACPI_ERROR((AE_INFO, |
106 | "Target is not a Reference or Constant object - [%s] %p" , |
107 | acpi_ut_get_object_type_name(dest_desc), |
108 | dest_desc)); |
109 | |
110 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
111 | } |
112 | |
113 | /* |
114 | * Examine the Reference class. These cases are handled: |
115 | * |
116 | * 1) Store to Name (Change the object associated with a name) |
117 | * 2) Store to an indexed area of a Buffer or Package |
118 | * 3) Store to a Method Local or Arg |
119 | * 4) Store to the debug object |
120 | */ |
121 | switch (ref_desc->reference.class) { |
122 | case ACPI_REFCLASS_REFOF: |
123 | |
124 | /* Storing an object into a Name "container" */ |
125 | |
126 | status = acpi_ex_store_object_to_node(source_desc, |
127 | node: ref_desc->reference. |
128 | object, walk_state, |
129 | ACPI_IMPLICIT_CONVERSION); |
130 | break; |
131 | |
132 | case ACPI_REFCLASS_INDEX: |
133 | |
134 | /* Storing to an Index (pointer into a packager or buffer) */ |
135 | |
136 | status = |
137 | acpi_ex_store_object_to_index(val_desc: source_desc, dest_desc: ref_desc, |
138 | walk_state); |
139 | break; |
140 | |
141 | case ACPI_REFCLASS_LOCAL: |
142 | case ACPI_REFCLASS_ARG: |
143 | |
144 | /* Store to a method local/arg */ |
145 | |
146 | status = |
147 | acpi_ds_store_object_to_local(type: ref_desc->reference.class, |
148 | index: ref_desc->reference.value, |
149 | src_desc: source_desc, walk_state); |
150 | break; |
151 | |
152 | case ACPI_REFCLASS_DEBUG: |
153 | /* |
154 | * Storing to the Debug object causes the value stored to be |
155 | * displayed and otherwise has no effect -- see ACPI Specification |
156 | */ |
157 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
158 | "**** Write to Debug Object: Object %p [%s] ****:\n\n" , |
159 | source_desc, |
160 | acpi_ut_get_object_type_name(source_desc))); |
161 | |
162 | ACPI_DEBUG_OBJECT(source_desc, 0, 0); |
163 | break; |
164 | |
165 | default: |
166 | |
167 | ACPI_ERROR((AE_INFO, "Unknown Reference Class 0x%2.2X" , |
168 | ref_desc->reference.class)); |
169 | ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO); |
170 | |
171 | status = AE_AML_INTERNAL; |
172 | break; |
173 | } |
174 | |
175 | return_ACPI_STATUS(status); |
176 | } |
177 | |
178 | /******************************************************************************* |
179 | * |
180 | * FUNCTION: acpi_ex_store_object_to_index |
181 | * |
182 | * PARAMETERS: *source_desc - Value to be stored |
183 | * *dest_desc - Named object to receive the value |
184 | * walk_state - Current walk state |
185 | * |
186 | * RETURN: Status |
187 | * |
188 | * DESCRIPTION: Store the object to indexed Buffer or Package element |
189 | * |
190 | ******************************************************************************/ |
191 | |
192 | static acpi_status |
193 | acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, |
194 | union acpi_operand_object *index_desc, |
195 | struct acpi_walk_state *walk_state) |
196 | { |
197 | acpi_status status = AE_OK; |
198 | union acpi_operand_object *obj_desc; |
199 | union acpi_operand_object *new_desc; |
200 | u8 value = 0; |
201 | u32 i; |
202 | |
203 | ACPI_FUNCTION_TRACE(ex_store_object_to_index); |
204 | |
205 | /* |
206 | * Destination must be a reference pointer, and |
207 | * must point to either a buffer or a package |
208 | */ |
209 | switch (index_desc->reference.target_type) { |
210 | case ACPI_TYPE_PACKAGE: |
211 | /* |
212 | * Storing to a package element. Copy the object and replace |
213 | * any existing object with the new object. No implicit |
214 | * conversion is performed. |
215 | * |
216 | * The object at *(index_desc->Reference.Where) is the |
217 | * element within the package that is to be modified. |
218 | * The parent package object is at index_desc->Reference.Object |
219 | */ |
220 | obj_desc = *(index_desc->reference.where); |
221 | |
222 | if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE && |
223 | source_desc->reference.class == ACPI_REFCLASS_TABLE) { |
224 | |
225 | /* This is a DDBHandle, just add a reference to it */ |
226 | |
227 | acpi_ut_add_reference(object: source_desc); |
228 | new_desc = source_desc; |
229 | } else { |
230 | /* Normal object, copy it */ |
231 | |
232 | status = |
233 | acpi_ut_copy_iobject_to_iobject(source_desc, |
234 | dest_desc: &new_desc, |
235 | walk_state); |
236 | if (ACPI_FAILURE(status)) { |
237 | return_ACPI_STATUS(status); |
238 | } |
239 | } |
240 | |
241 | if (obj_desc) { |
242 | |
243 | /* Decrement reference count by the ref count of the parent package */ |
244 | |
245 | for (i = 0; i < ((union acpi_operand_object *) |
246 | index_desc->reference.object)->common. |
247 | reference_count; i++) { |
248 | acpi_ut_remove_reference(object: obj_desc); |
249 | } |
250 | } |
251 | |
252 | *(index_desc->reference.where) = new_desc; |
253 | |
254 | /* Increment ref count by the ref count of the parent package-1 */ |
255 | |
256 | for (i = 1; i < ((union acpi_operand_object *) |
257 | index_desc->reference.object)->common. |
258 | reference_count; i++) { |
259 | acpi_ut_add_reference(object: new_desc); |
260 | } |
261 | |
262 | break; |
263 | |
264 | case ACPI_TYPE_BUFFER_FIELD: |
265 | /* |
266 | * Store into a Buffer or String (not actually a real buffer_field) |
267 | * at a location defined by an Index. |
268 | * |
269 | * The first 8-bit element of the source object is written to the |
270 | * 8-bit Buffer location defined by the Index destination object, |
271 | * according to the ACPI 2.0 specification. |
272 | */ |
273 | |
274 | /* |
275 | * Make sure the target is a Buffer or String. An error should |
276 | * not happen here, since the reference_object was constructed |
277 | * by the INDEX_OP code. |
278 | */ |
279 | obj_desc = index_desc->reference.object; |
280 | if ((obj_desc->common.type != ACPI_TYPE_BUFFER) && |
281 | (obj_desc->common.type != ACPI_TYPE_STRING)) { |
282 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
283 | } |
284 | |
285 | /* |
286 | * The assignment of the individual elements will be slightly |
287 | * different for each source type. |
288 | */ |
289 | switch (source_desc->common.type) { |
290 | case ACPI_TYPE_INTEGER: |
291 | |
292 | /* Use the least-significant byte of the integer */ |
293 | |
294 | value = (u8) (source_desc->integer.value); |
295 | break; |
296 | |
297 | case ACPI_TYPE_BUFFER: |
298 | case ACPI_TYPE_STRING: |
299 | |
300 | /* Note: Takes advantage of common string/buffer fields */ |
301 | |
302 | value = source_desc->buffer.pointer[0]; |
303 | break; |
304 | |
305 | default: |
306 | |
307 | /* All other types are invalid */ |
308 | |
309 | ACPI_ERROR((AE_INFO, |
310 | "Source must be type [Integer/Buffer/String], found [%s]" , |
311 | acpi_ut_get_object_type_name(source_desc))); |
312 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
313 | } |
314 | |
315 | /* Store the source value into the target buffer byte */ |
316 | |
317 | obj_desc->buffer.pointer[index_desc->reference.value] = value; |
318 | break; |
319 | |
320 | default: |
321 | ACPI_ERROR((AE_INFO, |
322 | "Target is not of type [Package/BufferField]" )); |
323 | status = AE_AML_TARGET_TYPE; |
324 | break; |
325 | } |
326 | |
327 | return_ACPI_STATUS(status); |
328 | } |
329 | |
330 | /******************************************************************************* |
331 | * |
332 | * FUNCTION: acpi_ex_store_object_to_node |
333 | * |
334 | * PARAMETERS: source_desc - Value to be stored |
335 | * node - Named object to receive the value |
336 | * walk_state - Current walk state |
337 | * implicit_conversion - Perform implicit conversion (yes/no) |
338 | * |
339 | * RETURN: Status |
340 | * |
341 | * DESCRIPTION: Store the object to the named object. |
342 | * |
343 | * The assignment of an object to a named object is handled here. |
344 | * The value passed in will replace the current value (if any) |
345 | * with the input value. |
346 | * |
347 | * When storing into an object the data is converted to the |
348 | * target object type then stored in the object. This means |
349 | * that the target object type (for an initialized target) will |
350 | * not be changed by a store operation. A copy_object can change |
351 | * the target type, however. |
352 | * |
353 | * The implicit_conversion flag is set to NO/FALSE only when |
354 | * storing to an arg_x -- as per the rules of the ACPI spec. |
355 | * |
356 | * Assumes parameters are already validated. |
357 | * |
358 | ******************************************************************************/ |
359 | |
360 | acpi_status |
361 | acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, |
362 | struct acpi_namespace_node *node, |
363 | struct acpi_walk_state *walk_state, |
364 | u8 implicit_conversion) |
365 | { |
366 | acpi_status status = AE_OK; |
367 | union acpi_operand_object *target_desc; |
368 | union acpi_operand_object *new_desc; |
369 | acpi_object_type target_type; |
370 | |
371 | ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc); |
372 | |
373 | /* Get current type of the node, and object attached to Node */ |
374 | |
375 | target_type = acpi_ns_get_type(node); |
376 | target_desc = acpi_ns_get_attached_object(node); |
377 | |
378 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n" , |
379 | source_desc, |
380 | acpi_ut_get_object_type_name(source_desc), node, |
381 | acpi_ut_get_type_name(target_type))); |
382 | |
383 | /* Only limited target types possible for everything except copy_object */ |
384 | |
385 | if (walk_state->opcode != AML_COPY_OBJECT_OP) { |
386 | /* |
387 | * Only copy_object allows all object types to be overwritten. For |
388 | * target_ref(s), there are restrictions on the object types that |
389 | * are allowed. |
390 | * |
391 | * Allowable operations/typing for Store: |
392 | * |
393 | * 1) Simple Store |
394 | * Integer --> Integer (Named/Local/Arg) |
395 | * String --> String (Named/Local/Arg) |
396 | * Buffer --> Buffer (Named/Local/Arg) |
397 | * Package --> Package (Named/Local/Arg) |
398 | * |
399 | * 2) Store with implicit conversion |
400 | * Integer --> String or Buffer (Named) |
401 | * String --> Integer or Buffer (Named) |
402 | * Buffer --> Integer or String (Named) |
403 | */ |
404 | switch (target_type) { |
405 | case ACPI_TYPE_PACKAGE: |
406 | /* |
407 | * Here, can only store a package to an existing package. |
408 | * Storing a package to a Local/Arg is OK, and handled |
409 | * elsewhere. |
410 | */ |
411 | if (walk_state->opcode == AML_STORE_OP) { |
412 | if (source_desc->common.type != |
413 | ACPI_TYPE_PACKAGE) { |
414 | ACPI_ERROR((AE_INFO, |
415 | "Cannot assign type [%s] to [Package] " |
416 | "(source must be type Pkg)" , |
417 | acpi_ut_get_object_type_name |
418 | (source_desc))); |
419 | |
420 | return_ACPI_STATUS(AE_AML_TARGET_TYPE); |
421 | } |
422 | break; |
423 | } |
424 | |
425 | ACPI_FALLTHROUGH; |
426 | |
427 | case ACPI_TYPE_DEVICE: |
428 | case ACPI_TYPE_EVENT: |
429 | case ACPI_TYPE_MUTEX: |
430 | case ACPI_TYPE_REGION: |
431 | case ACPI_TYPE_POWER: |
432 | case ACPI_TYPE_PROCESSOR: |
433 | case ACPI_TYPE_THERMAL: |
434 | |
435 | ACPI_ERROR((AE_INFO, |
436 | "Target must be [Buffer/Integer/String/Reference]" |
437 | ", found [%s] (%4.4s)" , |
438 | acpi_ut_get_type_name(node->type), |
439 | node->name.ascii)); |
440 | |
441 | return_ACPI_STATUS(AE_AML_TARGET_TYPE); |
442 | |
443 | default: |
444 | break; |
445 | } |
446 | } |
447 | |
448 | /* |
449 | * Resolve the source object to an actual value |
450 | * (If it is a reference object) |
451 | */ |
452 | status = acpi_ex_resolve_object(source_desc_ptr: &source_desc, target_type, walk_state); |
453 | if (ACPI_FAILURE(status)) { |
454 | return_ACPI_STATUS(status); |
455 | } |
456 | |
457 | /* Do the actual store operation */ |
458 | |
459 | switch (target_type) { |
460 | /* |
461 | * The simple data types all support implicit source operand |
462 | * conversion before the store. |
463 | */ |
464 | case ACPI_TYPE_INTEGER: |
465 | case ACPI_TYPE_STRING: |
466 | case ACPI_TYPE_BUFFER: |
467 | |
468 | if ((walk_state->opcode == AML_COPY_OBJECT_OP) || |
469 | !implicit_conversion) { |
470 | /* |
471 | * However, copy_object and Stores to arg_x do not perform |
472 | * an implicit conversion, as per the ACPI specification. |
473 | * A direct store is performed instead. |
474 | */ |
475 | status = |
476 | acpi_ex_store_direct_to_node(source_desc, node, |
477 | walk_state); |
478 | break; |
479 | } |
480 | |
481 | /* Store with implicit source operand conversion support */ |
482 | |
483 | status = |
484 | acpi_ex_store_object_to_object(source_desc, dest_desc: target_desc, |
485 | new_desc: &new_desc, walk_state); |
486 | if (ACPI_FAILURE(status)) { |
487 | return_ACPI_STATUS(status); |
488 | } |
489 | |
490 | if (new_desc != target_desc) { |
491 | /* |
492 | * Store the new new_desc as the new value of the Name, and set |
493 | * the Name's type to that of the value being stored in it. |
494 | * source_desc reference count is incremented by attach_object. |
495 | * |
496 | * Note: This may change the type of the node if an explicit |
497 | * store has been performed such that the node/object type |
498 | * has been changed. |
499 | */ |
500 | status = |
501 | acpi_ns_attach_object(node, object: new_desc, |
502 | type: new_desc->common.type); |
503 | |
504 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
505 | "Store type [%s] into [%s] via Convert/Attach\n" , |
506 | acpi_ut_get_object_type_name |
507 | (source_desc), |
508 | acpi_ut_get_object_type_name |
509 | (new_desc))); |
510 | } |
511 | break; |
512 | |
513 | case ACPI_TYPE_BUFFER_FIELD: |
514 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
515 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
516 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
517 | /* |
518 | * For all fields, always write the source data to the target |
519 | * field. Any required implicit source operand conversion is |
520 | * performed in the function below as necessary. Note, field |
521 | * objects must retain their original type permanently. |
522 | */ |
523 | status = acpi_ex_write_data_to_field(source_desc, obj_desc: target_desc, |
524 | result_desc: &walk_state->result_obj); |
525 | break; |
526 | |
527 | default: |
528 | /* |
529 | * copy_object operator: No conversions for all other types. |
530 | * Instead, directly store a copy of the source object. |
531 | * |
532 | * This is the ACPI spec-defined behavior for the copy_object |
533 | * operator. (Note, for this default case, all normal |
534 | * Store/Target operations exited above with an error). |
535 | */ |
536 | status = |
537 | acpi_ex_store_direct_to_node(source_desc, node, walk_state); |
538 | break; |
539 | } |
540 | |
541 | return_ACPI_STATUS(status); |
542 | } |
543 | |
544 | /******************************************************************************* |
545 | * |
546 | * FUNCTION: acpi_ex_store_direct_to_node |
547 | * |
548 | * PARAMETERS: source_desc - Value to be stored |
549 | * node - Named object to receive the value |
550 | * walk_state - Current walk state |
551 | * |
552 | * RETURN: Status |
553 | * |
554 | * DESCRIPTION: "Store" an object directly to a node. This involves a copy |
555 | * and an attach. |
556 | * |
557 | ******************************************************************************/ |
558 | |
559 | static acpi_status |
560 | acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, |
561 | struct acpi_namespace_node *node, |
562 | struct acpi_walk_state *walk_state) |
563 | { |
564 | acpi_status status; |
565 | union acpi_operand_object *new_desc; |
566 | |
567 | ACPI_FUNCTION_TRACE(ex_store_direct_to_node); |
568 | |
569 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
570 | "Storing [%s] (%p) directly into node [%s] (%p)" |
571 | " with no implicit conversion\n" , |
572 | acpi_ut_get_object_type_name(source_desc), |
573 | source_desc, acpi_ut_get_type_name(node->type), |
574 | node)); |
575 | |
576 | /* Copy the source object to a new object */ |
577 | |
578 | status = |
579 | acpi_ut_copy_iobject_to_iobject(source_desc, dest_desc: &new_desc, walk_state); |
580 | if (ACPI_FAILURE(status)) { |
581 | return_ACPI_STATUS(status); |
582 | } |
583 | |
584 | /* Attach the new object to the node */ |
585 | |
586 | status = acpi_ns_attach_object(node, object: new_desc, type: new_desc->common.type); |
587 | acpi_ut_remove_reference(object: new_desc); |
588 | return_ACPI_STATUS(status); |
589 | } |
590 | |