xref: /freebsd/sys/contrib/dev/acpica/components/executer/exstore.c (revision 7431dfd4580e850375fe5478d92ec770344db098)
1 /******************************************************************************
2  *
3  * Module Name: exstore - AML Interpreter object store support
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #define __EXSTORE_C__
45 
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acdispat.h>
49 #include <contrib/dev/acpica/include/acinterp.h>
50 #include <contrib/dev/acpica/include/amlcode.h>
51 #include <contrib/dev/acpica/include/acnamesp.h>
52 
53 
54 #define _COMPONENT          ACPI_EXECUTER
55         ACPI_MODULE_NAME    ("exstore")
56 
57 /* Local prototypes */
58 
59 static ACPI_STATUS
60 AcpiExStoreObjectToIndex (
61     ACPI_OPERAND_OBJECT     *ValDesc,
62     ACPI_OPERAND_OBJECT     *DestDesc,
63     ACPI_WALK_STATE         *WalkState);
64 
65 static ACPI_STATUS
66 AcpiExStoreDirectToNode (
67     ACPI_OPERAND_OBJECT     *SourceDesc,
68     ACPI_NAMESPACE_NODE     *Node,
69     ACPI_WALK_STATE         *WalkState);
70 
71 
72 /*******************************************************************************
73  *
74  * FUNCTION:    AcpiExStore
75  *
76  * PARAMETERS:  *SourceDesc         - Value to be stored
77  *              *DestDesc           - Where to store it. Must be an NS node
78  *                                    or ACPI_OPERAND_OBJECT of type
79  *                                    Reference;
80  *              WalkState           - Current walk state
81  *
82  * RETURN:      Status
83  *
84  * DESCRIPTION: Store the value described by SourceDesc into the location
85  *              described by DestDesc. Called by various interpreter
86  *              functions to store the result of an operation into
87  *              the destination operand -- not just simply the actual "Store"
88  *              ASL operator.
89  *
90  ******************************************************************************/
91 
92 ACPI_STATUS
93 AcpiExStore (
94     ACPI_OPERAND_OBJECT     *SourceDesc,
95     ACPI_OPERAND_OBJECT     *DestDesc,
96     ACPI_WALK_STATE         *WalkState)
97 {
98     ACPI_STATUS             Status = AE_OK;
99     ACPI_OPERAND_OBJECT     *RefDesc = DestDesc;
100 
101 
102     ACPI_FUNCTION_TRACE_PTR (ExStore, DestDesc);
103 
104 
105     /* Validate parameters */
106 
107     if (!SourceDesc || !DestDesc)
108     {
109         ACPI_ERROR ((AE_INFO, "Null parameter"));
110         return_ACPI_STATUS (AE_AML_NO_OPERAND);
111     }
112 
113     /* DestDesc can be either a namespace node or an ACPI object */
114 
115     if (ACPI_GET_DESCRIPTOR_TYPE (DestDesc) == ACPI_DESC_TYPE_NAMED)
116     {
117         /*
118          * Dest is a namespace node,
119          * Storing an object into a Named node.
120          */
121         Status = AcpiExStoreObjectToNode (SourceDesc,
122                     (ACPI_NAMESPACE_NODE *) DestDesc, WalkState,
123                     ACPI_IMPLICIT_CONVERSION);
124 
125         return_ACPI_STATUS (Status);
126     }
127 
128     /* Destination object must be a Reference or a Constant object */
129 
130     switch (DestDesc->Common.Type)
131     {
132     case ACPI_TYPE_LOCAL_REFERENCE:
133 
134         break;
135 
136     case ACPI_TYPE_INTEGER:
137 
138         /* Allow stores to Constants -- a Noop as per ACPI spec */
139 
140         if (DestDesc->Common.Flags & AOPOBJ_AML_CONSTANT)
141         {
142             return_ACPI_STATUS (AE_OK);
143         }
144 
145         /*lint -fallthrough */
146 
147     default:
148 
149         /* Destination is not a Reference object */
150 
151         ACPI_ERROR ((AE_INFO,
152             "Target is not a Reference or Constant object - %s [%p]",
153             AcpiUtGetObjectTypeName (DestDesc), DestDesc));
154 
155         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
156     }
157 
158     /*
159      * Examine the Reference class. These cases are handled:
160      *
161      * 1) Store to Name (Change the object associated with a name)
162      * 2) Store to an indexed area of a Buffer or Package
163      * 3) Store to a Method Local or Arg
164      * 4) Store to the debug object
165      */
166     switch (RefDesc->Reference.Class)
167     {
168     case ACPI_REFCLASS_REFOF:
169 
170         /* Storing an object into a Name "container" */
171 
172         Status = AcpiExStoreObjectToNode (SourceDesc,
173                     RefDesc->Reference.Object,
174                     WalkState, ACPI_IMPLICIT_CONVERSION);
175         break;
176 
177     case ACPI_REFCLASS_INDEX:
178 
179         /* Storing to an Index (pointer into a packager or buffer) */
180 
181         Status = AcpiExStoreObjectToIndex (SourceDesc, RefDesc, WalkState);
182         break;
183 
184     case ACPI_REFCLASS_LOCAL:
185     case ACPI_REFCLASS_ARG:
186 
187         /* Store to a method local/arg  */
188 
189         Status = AcpiDsStoreObjectToLocal (RefDesc->Reference.Class,
190                     RefDesc->Reference.Value, SourceDesc, WalkState);
191         break;
192 
193     case ACPI_REFCLASS_DEBUG:
194         /*
195          * Storing to the Debug object causes the value stored to be
196          * displayed and otherwise has no effect -- see ACPI Specification
197          */
198         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
199             "**** Write to Debug Object: Object %p %s ****:\n\n",
200             SourceDesc, AcpiUtGetObjectTypeName (SourceDesc)));
201 
202         ACPI_DEBUG_OBJECT (SourceDesc, 0, 0);
203         break;
204 
205     default:
206 
207         ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
208             RefDesc->Reference.Class));
209         ACPI_DUMP_ENTRY (RefDesc, ACPI_LV_INFO);
210 
211         Status = AE_AML_INTERNAL;
212         break;
213     }
214 
215     return_ACPI_STATUS (Status);
216 }
217 
218 
219 /*******************************************************************************
220  *
221  * FUNCTION:    AcpiExStoreObjectToIndex
222  *
223  * PARAMETERS:  *SourceDesc             - Value to be stored
224  *              *DestDesc               - Named object to receive the value
225  *              WalkState               - Current walk state
226  *
227  * RETURN:      Status
228  *
229  * DESCRIPTION: Store the object to indexed Buffer or Package element
230  *
231  ******************************************************************************/
232 
233 static ACPI_STATUS
234 AcpiExStoreObjectToIndex (
235     ACPI_OPERAND_OBJECT     *SourceDesc,
236     ACPI_OPERAND_OBJECT     *IndexDesc,
237     ACPI_WALK_STATE         *WalkState)
238 {
239     ACPI_STATUS             Status = AE_OK;
240     ACPI_OPERAND_OBJECT     *ObjDesc;
241     ACPI_OPERAND_OBJECT     *NewDesc;
242     UINT8                   Value = 0;
243     UINT32                  i;
244 
245 
246     ACPI_FUNCTION_TRACE (ExStoreObjectToIndex);
247 
248 
249     /*
250      * Destination must be a reference pointer, and
251      * must point to either a buffer or a package
252      */
253     switch (IndexDesc->Reference.TargetType)
254     {
255     case ACPI_TYPE_PACKAGE:
256         /*
257          * Storing to a package element. Copy the object and replace
258          * any existing object with the new object. No implicit
259          * conversion is performed.
260          *
261          * The object at *(IndexDesc->Reference.Where) is the
262          * element within the package that is to be modified.
263          * The parent package object is at IndexDesc->Reference.Object
264          */
265         ObjDesc = *(IndexDesc->Reference.Where);
266 
267         if (SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE &&
268             SourceDesc->Reference.Class == ACPI_REFCLASS_TABLE)
269         {
270             /* This is a DDBHandle, just add a reference to it */
271 
272             AcpiUtAddReference (SourceDesc);
273             NewDesc = SourceDesc;
274         }
275         else
276         {
277             /* Normal object, copy it */
278 
279             Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState);
280             if (ACPI_FAILURE (Status))
281             {
282                 return_ACPI_STATUS (Status);
283             }
284         }
285 
286         if (ObjDesc)
287         {
288             /* Decrement reference count by the ref count of the parent package */
289 
290             for (i = 0;
291                  i < ((ACPI_OPERAND_OBJECT *)
292                         IndexDesc->Reference.Object)->Common.ReferenceCount;
293                  i++)
294             {
295                 AcpiUtRemoveReference (ObjDesc);
296             }
297         }
298 
299         *(IndexDesc->Reference.Where) = NewDesc;
300 
301         /* Increment ref count by the ref count of the parent package-1 */
302 
303         for (i = 1;
304              i < ((ACPI_OPERAND_OBJECT *)
305                     IndexDesc->Reference.Object)->Common.ReferenceCount;
306              i++)
307         {
308             AcpiUtAddReference (NewDesc);
309         }
310 
311         break;
312 
313     case ACPI_TYPE_BUFFER_FIELD:
314         /*
315          * Store into a Buffer or String (not actually a real BufferField)
316          * at a location defined by an Index.
317          *
318          * The first 8-bit element of the source object is written to the
319          * 8-bit Buffer location defined by the Index destination object,
320          * according to the ACPI 2.0 specification.
321          */
322 
323         /*
324          * Make sure the target is a Buffer or String. An error should
325          * not happen here, since the ReferenceObject was constructed
326          * by the INDEX_OP code.
327          */
328         ObjDesc = IndexDesc->Reference.Object;
329         if ((ObjDesc->Common.Type != ACPI_TYPE_BUFFER) &&
330             (ObjDesc->Common.Type != ACPI_TYPE_STRING))
331         {
332             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
333         }
334 
335         /*
336          * The assignment of the individual elements will be slightly
337          * different for each source type.
338          */
339         switch (SourceDesc->Common.Type)
340         {
341         case ACPI_TYPE_INTEGER:
342 
343             /* Use the least-significant byte of the integer */
344 
345             Value = (UINT8) (SourceDesc->Integer.Value);
346             break;
347 
348         case ACPI_TYPE_BUFFER:
349         case ACPI_TYPE_STRING:
350 
351             /* Note: Takes advantage of common string/buffer fields */
352 
353             Value = SourceDesc->Buffer.Pointer[0];
354             break;
355 
356         default:
357 
358             /* All other types are invalid */
359 
360             ACPI_ERROR ((AE_INFO,
361                 "Source must be Integer/Buffer/String type, not %s",
362                 AcpiUtGetObjectTypeName (SourceDesc)));
363             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
364         }
365 
366         /* Store the source value into the target buffer byte */
367 
368         ObjDesc->Buffer.Pointer[IndexDesc->Reference.Value] = Value;
369         break;
370 
371     default:
372         ACPI_ERROR ((AE_INFO,
373             "Target is not a Package or BufferField"));
374         Status = AE_AML_OPERAND_TYPE;
375         break;
376     }
377 
378     return_ACPI_STATUS (Status);
379 }
380 
381 
382 /*******************************************************************************
383  *
384  * FUNCTION:    AcpiExStoreObjectToNode
385  *
386  * PARAMETERS:  SourceDesc              - Value to be stored
387  *              Node                    - Named object to receive the value
388  *              WalkState               - Current walk state
389  *              ImplicitConversion      - Perform implicit conversion (yes/no)
390  *
391  * RETURN:      Status
392  *
393  * DESCRIPTION: Store the object to the named object.
394  *
395  *              The Assignment of an object to a named object is handled here
396  *              The value passed in will replace the current value (if any)
397  *              with the input value.
398  *
399  *              When storing into an object the data is converted to the
400  *              target object type then stored in the object. This means
401  *              that the target object type (for an initialized target) will
402  *              not be changed by a store operation. A CopyObject can change
403  *              the target type, however.
404  *
405  *              The ImplicitConversion flag is set to NO/FALSE only when
406  *              storing to an ArgX -- as per the rules of the ACPI spec.
407  *
408  *              Assumes parameters are already validated.
409  *
410  ******************************************************************************/
411 
412 ACPI_STATUS
413 AcpiExStoreObjectToNode (
414     ACPI_OPERAND_OBJECT     *SourceDesc,
415     ACPI_NAMESPACE_NODE     *Node,
416     ACPI_WALK_STATE         *WalkState,
417     UINT8                   ImplicitConversion)
418 {
419     ACPI_STATUS             Status = AE_OK;
420     ACPI_OPERAND_OBJECT     *TargetDesc;
421     ACPI_OPERAND_OBJECT     *NewDesc;
422     ACPI_OBJECT_TYPE        TargetType;
423 
424 
425     ACPI_FUNCTION_TRACE_PTR (ExStoreObjectToNode, SourceDesc);
426 
427 
428     /* Get current type of the node, and object attached to Node */
429 
430     TargetType = AcpiNsGetType (Node);
431     TargetDesc = AcpiNsGetAttachedObject (Node);
432 
433     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
434         SourceDesc, AcpiUtGetObjectTypeName (SourceDesc),
435               Node, AcpiUtGetTypeName (TargetType)));
436 
437     /*
438      * Resolve the source object to an actual value
439      * (If it is a reference object)
440      */
441     Status = AcpiExResolveObject (&SourceDesc, TargetType, WalkState);
442     if (ACPI_FAILURE (Status))
443     {
444         return_ACPI_STATUS (Status);
445     }
446 
447     /* Do the actual store operation */
448 
449     switch (TargetType)
450     {
451     case ACPI_TYPE_INTEGER:
452     case ACPI_TYPE_STRING:
453     case ACPI_TYPE_BUFFER:
454         /*
455          * The simple data types all support implicit source operand
456          * conversion before the store.
457          */
458 
459         if ((WalkState->Opcode == AML_COPY_OP) ||
460             !ImplicitConversion)
461         {
462             /*
463              * However, CopyObject and Stores to ArgX do not perform
464              * an implicit conversion, as per the ACPI specification.
465              * A direct store is performed instead.
466              */
467             Status = AcpiExStoreDirectToNode (SourceDesc, Node,
468                 WalkState);
469             break;
470         }
471 
472         /* Store with implicit source operand conversion support */
473 
474         Status = AcpiExStoreObjectToObject (SourceDesc, TargetDesc,
475             &NewDesc, WalkState);
476         if (ACPI_FAILURE (Status))
477         {
478             return_ACPI_STATUS (Status);
479         }
480 
481         if (NewDesc != TargetDesc)
482         {
483             /*
484              * Store the new NewDesc as the new value of the Name, and set
485              * the Name's type to that of the value being stored in it.
486              * SourceDesc reference count is incremented by AttachObject.
487              *
488              * Note: This may change the type of the node if an explicit
489              * store has been performed such that the node/object type
490              * has been changed.
491              */
492             Status = AcpiNsAttachObject (Node, NewDesc,
493                 NewDesc->Common.Type);
494 
495             ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
496                 "Store %s into %s via Convert/Attach\n",
497                 AcpiUtGetObjectTypeName (SourceDesc),
498                 AcpiUtGetObjectTypeName (NewDesc)));
499         }
500         break;
501 
502     case ACPI_TYPE_BUFFER_FIELD:
503     case ACPI_TYPE_LOCAL_REGION_FIELD:
504     case ACPI_TYPE_LOCAL_BANK_FIELD:
505     case ACPI_TYPE_LOCAL_INDEX_FIELD:
506         /*
507          * For all fields, always write the source data to the target
508          * field. Any required implicit source operand conversion is
509          * performed in the function below as necessary. Note, field
510          * objects must retain their original type permanently.
511          */
512         Status = AcpiExWriteDataToField (SourceDesc, TargetDesc,
513             &WalkState->ResultObj);
514         break;
515 
516     default:
517         /*
518          * No conversions for all other types. Directly store a copy of
519          * the source object. This is the ACPI spec-defined behavior for
520          * the CopyObject operator.
521          *
522          * NOTE: For the Store operator, this is a departure from the
523          * ACPI spec, which states "If conversion is impossible, abort
524          * the running control method". Instead, this code implements
525          * "If conversion is impossible, treat the Store operation as
526          * a CopyObject".
527          */
528         Status = AcpiExStoreDirectToNode (SourceDesc, Node,
529             WalkState);
530         break;
531     }
532 
533     return_ACPI_STATUS (Status);
534 }
535 
536 
537 /*******************************************************************************
538  *
539  * FUNCTION:    AcpiExStoreDirectToNode
540  *
541  * PARAMETERS:  SourceDesc              - Value to be stored
542  *              Node                    - Named object to receive the value
543  *              WalkState               - Current walk state
544  *
545  * RETURN:      Status
546  *
547  * DESCRIPTION: "Store" an object directly to a node. This involves a copy
548  *              and an attach.
549  *
550  ******************************************************************************/
551 
552 static ACPI_STATUS
553 AcpiExStoreDirectToNode (
554     ACPI_OPERAND_OBJECT     *SourceDesc,
555     ACPI_NAMESPACE_NODE     *Node,
556     ACPI_WALK_STATE         *WalkState)
557 {
558     ACPI_STATUS             Status;
559     ACPI_OPERAND_OBJECT     *NewDesc;
560 
561 
562     ACPI_FUNCTION_TRACE (ExStoreDirectToNode);
563 
564 
565     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
566         "Storing [%s] (%p) directly into node [%s] (%p)"
567         " with no implicit conversion\n",
568         AcpiUtGetObjectTypeName (SourceDesc), SourceDesc,
569         AcpiUtGetTypeName (Node->Type), Node));
570 
571     /* Copy the source object to a new object */
572 
573     Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState);
574     if (ACPI_FAILURE (Status))
575     {
576         return_ACPI_STATUS (Status);
577     }
578 
579     /* Attach the new object to the node */
580 
581     Status = AcpiNsAttachObject (Node, NewDesc, NewDesc->Common.Type);
582     AcpiUtRemoveReference (NewDesc);
583     return_ACPI_STATUS (Status);
584 }
585