1/******************************************************************************
2 *
3 * Module Name: exstore - AML Interpreter object store support
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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
59static ACPI_STATUS
60AcpiExStoreObjectToIndex (
61    ACPI_OPERAND_OBJECT     *ValDesc,
62    ACPI_OPERAND_OBJECT     *DestDesc,
63    ACPI_WALK_STATE         *WalkState);
64
65
66/*******************************************************************************
67 *
68 * FUNCTION:    AcpiExStore
69 *
70 * PARAMETERS:  *SourceDesc         - Value to be stored
71 *              *DestDesc           - Where to store it. Must be an NS node
72 *                                    or ACPI_OPERAND_OBJECT of type
73 *                                    Reference;
74 *              WalkState           - Current walk state
75 *
76 * RETURN:      Status
77 *
78 * DESCRIPTION: Store the value described by SourceDesc into the location
79 *              described by DestDesc. Called by various interpreter
80 *              functions to store the result of an operation into
81 *              the destination operand -- not just simply the actual "Store"
82 *              ASL operator.
83 *
84 ******************************************************************************/
85
86ACPI_STATUS
87AcpiExStore (
88    ACPI_OPERAND_OBJECT     *SourceDesc,
89    ACPI_OPERAND_OBJECT     *DestDesc,
90    ACPI_WALK_STATE         *WalkState)
91{
92    ACPI_STATUS             Status = AE_OK;
93    ACPI_OPERAND_OBJECT     *RefDesc = DestDesc;
94
95
96    ACPI_FUNCTION_TRACE_PTR (ExStore, DestDesc);
97
98
99    /* Validate parameters */
100
101    if (!SourceDesc || !DestDesc)
102    {
103        ACPI_ERROR ((AE_INFO, "Null parameter"));
104        return_ACPI_STATUS (AE_AML_NO_OPERAND);
105    }
106
107    /* DestDesc can be either a namespace node or an ACPI object */
108
109    if (ACPI_GET_DESCRIPTOR_TYPE (DestDesc) == ACPI_DESC_TYPE_NAMED)
110    {
111        /*
112         * Dest is a namespace node,
113         * Storing an object into a Named node.
114         */
115        Status = AcpiExStoreObjectToNode (SourceDesc,
116                    (ACPI_NAMESPACE_NODE *) DestDesc, WalkState,
117                    ACPI_IMPLICIT_CONVERSION);
118
119        return_ACPI_STATUS (Status);
120    }
121
122    /* Destination object must be a Reference or a Constant object */
123
124    switch (DestDesc->Common.Type)
125    {
126    case ACPI_TYPE_LOCAL_REFERENCE:
127
128        break;
129
130    case ACPI_TYPE_INTEGER:
131
132        /* Allow stores to Constants -- a Noop as per ACPI spec */
133
134        if (DestDesc->Common.Flags & AOPOBJ_AML_CONSTANT)
135        {
136            return_ACPI_STATUS (AE_OK);
137        }
138
139        /*lint -fallthrough */
140
141    default:
142
143        /* Destination is not a Reference object */
144
145        ACPI_ERROR ((AE_INFO,
146            "Target is not a Reference or Constant object - %s [%p]",
147            AcpiUtGetObjectTypeName (DestDesc), DestDesc));
148
149        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
150    }
151
152    /*
153     * Examine the Reference class. These cases are handled:
154     *
155     * 1) Store to Name (Change the object associated with a name)
156     * 2) Store to an indexed area of a Buffer or Package
157     * 3) Store to a Method Local or Arg
158     * 4) Store to the debug object
159     */
160    switch (RefDesc->Reference.Class)
161    {
162    case ACPI_REFCLASS_REFOF:
163
164        /* Storing an object into a Name "container" */
165
166        Status = AcpiExStoreObjectToNode (SourceDesc,
167                    RefDesc->Reference.Object,
168                    WalkState, ACPI_IMPLICIT_CONVERSION);
169        break;
170
171    case ACPI_REFCLASS_INDEX:
172
173        /* Storing to an Index (pointer into a packager or buffer) */
174
175        Status = AcpiExStoreObjectToIndex (SourceDesc, RefDesc, WalkState);
176        break;
177
178    case ACPI_REFCLASS_LOCAL:
179    case ACPI_REFCLASS_ARG:
180
181        /* Store to a method local/arg  */
182
183        Status = AcpiDsStoreObjectToLocal (RefDesc->Reference.Class,
184                    RefDesc->Reference.Value, SourceDesc, WalkState);
185        break;
186
187    case ACPI_REFCLASS_DEBUG:
188        /*
189         * Storing to the Debug object causes the value stored to be
190         * displayed and otherwise has no effect -- see ACPI Specification
191         */
192        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
193            "**** Write to Debug Object: Object %p %s ****:\n\n",
194            SourceDesc, AcpiUtGetObjectTypeName (SourceDesc)));
195
196        ACPI_DEBUG_OBJECT (SourceDesc, 0, 0);
197        break;
198
199    default:
200
201        ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
202            RefDesc->Reference.Class));
203        ACPI_DUMP_ENTRY (RefDesc, ACPI_LV_INFO);
204
205        Status = AE_AML_INTERNAL;
206        break;
207    }
208
209    return_ACPI_STATUS (Status);
210}
211
212
213/*******************************************************************************
214 *
215 * FUNCTION:    AcpiExStoreObjectToIndex
216 *
217 * PARAMETERS:  *SourceDesc             - Value to be stored
218 *              *DestDesc               - Named object to receive the value
219 *              WalkState               - Current walk state
220 *
221 * RETURN:      Status
222 *
223 * DESCRIPTION: Store the object to indexed Buffer or Package element
224 *
225 ******************************************************************************/
226
227static ACPI_STATUS
228AcpiExStoreObjectToIndex (
229    ACPI_OPERAND_OBJECT     *SourceDesc,
230    ACPI_OPERAND_OBJECT     *IndexDesc,
231    ACPI_WALK_STATE         *WalkState)
232{
233    ACPI_STATUS             Status = AE_OK;
234    ACPI_OPERAND_OBJECT     *ObjDesc;
235    ACPI_OPERAND_OBJECT     *NewDesc;
236    UINT8                   Value = 0;
237    UINT32                  i;
238
239
240    ACPI_FUNCTION_TRACE (ExStoreObjectToIndex);
241
242
243    /*
244     * Destination must be a reference pointer, and
245     * must point to either a buffer or a package
246     */
247    switch (IndexDesc->Reference.TargetType)
248    {
249    case ACPI_TYPE_PACKAGE:
250        /*
251         * Storing to a package element. Copy the object and replace
252         * any existing object with the new object. No implicit
253         * conversion is performed.
254         *
255         * The object at *(IndexDesc->Reference.Where) is the
256         * element within the package that is to be modified.
257         * The parent package object is at IndexDesc->Reference.Object
258         */
259        ObjDesc = *(IndexDesc->Reference.Where);
260
261        if (SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE &&
262            SourceDesc->Reference.Class == ACPI_REFCLASS_TABLE)
263        {
264            /* This is a DDBHandle, just add a reference to it */
265
266            AcpiUtAddReference (SourceDesc);
267            NewDesc = SourceDesc;
268        }
269        else
270        {
271            /* Normal object, copy it */
272
273            Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState);
274            if (ACPI_FAILURE (Status))
275            {
276                return_ACPI_STATUS (Status);
277            }
278        }
279
280        if (ObjDesc)
281        {
282            /* Decrement reference count by the ref count of the parent package */
283
284            for (i = 0;
285                 i < ((ACPI_OPERAND_OBJECT *)
286                        IndexDesc->Reference.Object)->Common.ReferenceCount;
287                 i++)
288            {
289                AcpiUtRemoveReference (ObjDesc);
290            }
291        }
292
293        *(IndexDesc->Reference.Where) = NewDesc;
294
295        /* Increment ref count by the ref count of the parent package-1 */
296
297        for (i = 1;
298             i < ((ACPI_OPERAND_OBJECT *)
299                    IndexDesc->Reference.Object)->Common.ReferenceCount;
300             i++)
301        {
302            AcpiUtAddReference (NewDesc);
303        }
304
305        break;
306
307    case ACPI_TYPE_BUFFER_FIELD:
308        /*
309         * Store into a Buffer or String (not actually a real BufferField)
310         * at a location defined by an Index.
311         *
312         * The first 8-bit element of the source object is written to the
313         * 8-bit Buffer location defined by the Index destination object,
314         * according to the ACPI 2.0 specification.
315         */
316
317        /*
318         * Make sure the target is a Buffer or String. An error should
319         * not happen here, since the ReferenceObject was constructed
320         * by the INDEX_OP code.
321         */
322        ObjDesc = IndexDesc->Reference.Object;
323        if ((ObjDesc->Common.Type != ACPI_TYPE_BUFFER) &&
324            (ObjDesc->Common.Type != ACPI_TYPE_STRING))
325        {
326            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
327        }
328
329        /*
330         * The assignment of the individual elements will be slightly
331         * different for each source type.
332         */
333        switch (SourceDesc->Common.Type)
334        {
335        case ACPI_TYPE_INTEGER:
336
337            /* Use the least-significant byte of the integer */
338
339            Value = (UINT8) (SourceDesc->Integer.Value);
340            break;
341
342        case ACPI_TYPE_BUFFER:
343        case ACPI_TYPE_STRING:
344
345            /* Note: Takes advantage of common string/buffer fields */
346
347            Value = SourceDesc->Buffer.Pointer[0];
348            break;
349
350        default:
351
352            /* All other types are invalid */
353
354            ACPI_ERROR ((AE_INFO,
355                "Source must be Integer/Buffer/String type, not %s",
356                AcpiUtGetObjectTypeName (SourceDesc)));
357            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
358        }
359
360        /* Store the source value into the target buffer byte */
361
362        ObjDesc->Buffer.Pointer[IndexDesc->Reference.Value] = Value;
363        break;
364
365    default:
366        ACPI_ERROR ((AE_INFO,
367            "Target is not a Package or BufferField"));
368        Status = AE_AML_OPERAND_TYPE;
369        break;
370    }
371
372    return_ACPI_STATUS (Status);
373}
374
375
376/*******************************************************************************
377 *
378 * FUNCTION:    AcpiExStoreObjectToNode
379 *
380 * PARAMETERS:  SourceDesc              - Value to be stored
381 *              Node                    - Named object to receive the value
382 *              WalkState               - Current walk state
383 *              ImplicitConversion      - Perform implicit conversion (yes/no)
384 *
385 * RETURN:      Status
386 *
387 * DESCRIPTION: Store the object to the named object.
388 *
389 *              The Assignment of an object to a named object is handled here
390 *              The value passed in will replace the current value (if any)
391 *              with the input value.
392 *
393 *              When storing into an object the data is converted to the
394 *              target object type then stored in the object. This means
395 *              that the target object type (for an initialized target) will
396 *              not be changed by a store operation.
397 *
398 *              Assumes parameters are already validated.
399 *
400 ******************************************************************************/
401
402ACPI_STATUS
403AcpiExStoreObjectToNode (
404    ACPI_OPERAND_OBJECT     *SourceDesc,
405    ACPI_NAMESPACE_NODE     *Node,
406    ACPI_WALK_STATE         *WalkState,
407    UINT8                   ImplicitConversion)
408{
409    ACPI_STATUS             Status = AE_OK;
410    ACPI_OPERAND_OBJECT     *TargetDesc;
411    ACPI_OPERAND_OBJECT     *NewDesc;
412    ACPI_OBJECT_TYPE        TargetType;
413
414
415    ACPI_FUNCTION_TRACE_PTR (ExStoreObjectToNode, SourceDesc);
416
417
418    /* Get current type of the node, and object attached to Node */
419
420    TargetType = AcpiNsGetType (Node);
421    TargetDesc = AcpiNsGetAttachedObject (Node);
422
423    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
424        SourceDesc, AcpiUtGetObjectTypeName (SourceDesc),
425              Node, AcpiUtGetTypeName (TargetType)));
426
427    /*
428     * Resolve the source object to an actual value
429     * (If it is a reference object)
430     */
431    Status = AcpiExResolveObject (&SourceDesc, TargetType, WalkState);
432    if (ACPI_FAILURE (Status))
433    {
434        return_ACPI_STATUS (Status);
435    }
436
437    /* If no implicit conversion, drop into the default case below */
438
439    if ((!ImplicitConversion) ||
440          ((WalkState->Opcode == AML_COPY_OP) &&
441           (TargetType != ACPI_TYPE_LOCAL_REGION_FIELD) &&
442           (TargetType != ACPI_TYPE_LOCAL_BANK_FIELD) &&
443           (TargetType != ACPI_TYPE_LOCAL_INDEX_FIELD)))
444    {
445        /*
446         * Force execution of default (no implicit conversion). Note:
447         * CopyObject does not perform an implicit conversion, as per the ACPI
448         * spec -- except in case of region/bank/index fields -- because these
449         * objects must retain their original type permanently.
450         */
451        TargetType = ACPI_TYPE_ANY;
452    }
453
454    /* Do the actual store operation */
455
456    switch (TargetType)
457    {
458    case ACPI_TYPE_BUFFER_FIELD:
459    case ACPI_TYPE_LOCAL_REGION_FIELD:
460    case ACPI_TYPE_LOCAL_BANK_FIELD:
461    case ACPI_TYPE_LOCAL_INDEX_FIELD:
462
463        /* For fields, copy the source data to the target field. */
464
465        Status = AcpiExWriteDataToField (SourceDesc, TargetDesc,
466                    &WalkState->ResultObj);
467        break;
468
469    case ACPI_TYPE_INTEGER:
470    case ACPI_TYPE_STRING:
471    case ACPI_TYPE_BUFFER:
472        /*
473         * These target types are all of type Integer/String/Buffer, and
474         * therefore support implicit conversion before the store.
475         *
476         * Copy and/or convert the source object to a new target object
477         */
478        Status = AcpiExStoreObjectToObject (SourceDesc, TargetDesc,
479                    &NewDesc, WalkState);
480        if (ACPI_FAILURE (Status))
481        {
482            return_ACPI_STATUS (Status);
483        }
484
485        if (NewDesc != TargetDesc)
486        {
487            /*
488             * Store the new NewDesc as the new value of the Name, and set
489             * the Name's type to that of the value being stored in it.
490             * SourceDesc reference count is incremented by AttachObject.
491             *
492             * Note: This may change the type of the node if an explicit store
493             * has been performed such that the node/object type has been
494             * changed.
495             */
496            Status = AcpiNsAttachObject (Node, NewDesc, NewDesc->Common.Type);
497
498            ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
499                "Store %s into %s via Convert/Attach\n",
500                AcpiUtGetObjectTypeName (SourceDesc),
501                AcpiUtGetObjectTypeName (NewDesc)));
502        }
503        break;
504
505    default:
506
507        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
508            "Storing [%s] (%p) directly into node [%s] (%p)"
509            " with no implicit conversion\n",
510            AcpiUtGetObjectTypeName (SourceDesc), SourceDesc,
511            AcpiUtGetObjectTypeName (TargetDesc), Node));
512
513        /*
514         * No conversions for all other types. Directly store a copy of
515         * the source object. NOTE: This is a departure from the ACPI
516         * spec, which states "If conversion is impossible, abort the
517         * running control method".
518         *
519         * This code implements "If conversion is impossible, treat the
520         * Store operation as a CopyObject".
521         */
522        Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState);
523        if (ACPI_FAILURE (Status))
524        {
525            return_ACPI_STATUS (Status);
526        }
527
528        Status = AcpiNsAttachObject (Node, NewDesc, NewDesc->Common.Type);
529        AcpiUtRemoveReference (NewDesc);
530        break;
531    }
532
533    return_ACPI_STATUS (Status);
534}
535