1 /******************************************************************************
   2  *
   3  * Module Name: exstore - AML Interpreter object store support
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2011, 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 "acpi.h"
  47 #include "accommon.h"
  48 #include "acdispat.h"
  49 #include "acinterp.h"
  50 #include "amlcode.h"
  51 #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 
  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 an 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 
  86 ACPI_STATUS
  87 AcpiExStore (
  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         break;
 128 
 129     case ACPI_TYPE_INTEGER:
 130 
 131         /* Allow stores to Constants -- a Noop as per ACPI spec */
 132 
 133         if (DestDesc->Common.Flags & AOPOBJ_AML_CONSTANT)
 134         {
 135             return_ACPI_STATUS (AE_OK);
 136         }
 137 
 138         /*lint -fallthrough */
 139 
 140     default:
 141 
 142         /* Destination is not a Reference object */
 143 
 144         ACPI_ERROR ((AE_INFO,
 145             "Target is not a Reference or Constant object - %s [%p]",
 146             AcpiUtGetObjectTypeName (DestDesc), DestDesc));
 147 
 148         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 149     }
 150 
 151     /*
 152      * Examine the Reference class. These cases are handled:
 153      *
 154      * 1) Store to Name (Change the object associated with a name)
 155      * 2) Store to an indexed area of a Buffer or Package
 156      * 3) Store to a Method Local or Arg
 157      * 4) Store to the debug object
 158      */
 159     switch (RefDesc->Reference.Class)
 160     {
 161     case ACPI_REFCLASS_REFOF:
 162 
 163         /* Storing an object into a Name "container" */
 164 
 165         Status = AcpiExStoreObjectToNode (SourceDesc,
 166                     RefDesc->Reference.Object,
 167                     WalkState, ACPI_IMPLICIT_CONVERSION);
 168         break;
 169 
 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 
 179     case ACPI_REFCLASS_LOCAL:
 180     case ACPI_REFCLASS_ARG:
 181 
 182         /* Store to a method local/arg  */
 183 
 184         Status = AcpiDsStoreObjectToLocal (RefDesc->Reference.Class,
 185                     RefDesc->Reference.Value, SourceDesc, WalkState);
 186         break;
 187 
 188 
 189     case ACPI_REFCLASS_DEBUG:
 190 
 191         /*
 192          * Storing to the Debug object causes the value stored to be
 193          * displayed and otherwise has no effect -- see ACPI Specification
 194          */
 195         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 196             "**** Write to Debug Object: Object %p %s ****:\n\n",
 197             SourceDesc, AcpiUtGetObjectTypeName (SourceDesc)));
 198 
 199         ACPI_DEBUG_OBJECT (SourceDesc, 0, 0);
 200         break;
 201 
 202 
 203     default:
 204 
 205         ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
 206             RefDesc->Reference.Class));
 207         ACPI_DUMP_ENTRY (RefDesc, ACPI_LV_INFO);
 208 
 209         Status = AE_AML_INTERNAL;
 210         break;
 211     }
 212 
 213     return_ACPI_STATUS (Status);
 214 }
 215 
 216 
 217 /*******************************************************************************
 218  *
 219  * FUNCTION:    AcpiExStoreObjectToIndex
 220  *
 221  * PARAMETERS:  *SourceDesc             - Value to be stored
 222  *              *DestDesc               - Named object to receive the value
 223  *              WalkState               - Current walk state
 224  *
 225  * RETURN:      Status
 226  *
 227  * DESCRIPTION: Store the object to indexed Buffer or Package element
 228  *
 229  ******************************************************************************/
 230 
 231 static ACPI_STATUS
 232 AcpiExStoreObjectToIndex (
 233     ACPI_OPERAND_OBJECT     *SourceDesc,
 234     ACPI_OPERAND_OBJECT     *IndexDesc,
 235     ACPI_WALK_STATE         *WalkState)
 236 {
 237     ACPI_STATUS             Status = AE_OK;
 238     ACPI_OPERAND_OBJECT     *ObjDesc;
 239     ACPI_OPERAND_OBJECT     *NewDesc;
 240     UINT8                   Value = 0;
 241     UINT32                  i;
 242 
 243 
 244     ACPI_FUNCTION_TRACE (ExStoreObjectToIndex);
 245 
 246 
 247     /*
 248      * Destination must be a reference pointer, and
 249      * must point to either a buffer or a package
 250      */
 251     switch (IndexDesc->Reference.TargetType)
 252     {
 253     case ACPI_TYPE_PACKAGE:
 254         /*
 255          * Storing to a package element. Copy the object and replace
 256          * any existing object with the new object. No implicit
 257          * conversion is performed.
 258          *
 259          * The object at *(IndexDesc->Reference.Where) is the
 260          * element within the package that is to be modified.
 261          * The parent package object is at IndexDesc->Reference.Object
 262          */
 263         ObjDesc = *(IndexDesc->Reference.Where);
 264 
 265         if (SourceDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE &&
 266             SourceDesc->Reference.Class == ACPI_REFCLASS_TABLE)
 267         {
 268             /* This is a DDBHandle, just add a reference to it */
 269 
 270             AcpiUtAddReference (SourceDesc);
 271             NewDesc = SourceDesc;
 272         }
 273         else
 274         {
 275             /* Normal object, copy it */
 276 
 277             Status = AcpiUtCopyIobjectToIobject (SourceDesc, &NewDesc, WalkState);
 278             if (ACPI_FAILURE (Status))
 279             {
 280                 return_ACPI_STATUS (Status);
 281             }
 282         }
 283 
 284         if (ObjDesc)
 285         {
 286             /* Decrement reference count by the ref count of the parent package */
 287 
 288             for (i = 0;
 289                  i < ((ACPI_OPERAND_OBJECT *)
 290                         IndexDesc->Reference.Object)->Common.ReferenceCount;
 291                  i++)
 292             {
 293                 AcpiUtRemoveReference (ObjDesc);
 294             }
 295         }
 296 
 297         *(IndexDesc->Reference.Where) = NewDesc;
 298 
 299         /* Increment ref count by the ref count of the parent package-1 */
 300 
 301         for (i = 1;
 302              i < ((ACPI_OPERAND_OBJECT *)
 303                     IndexDesc->Reference.Object)->Common.ReferenceCount;
 304              i++)
 305         {
 306             AcpiUtAddReference (NewDesc);
 307         }
 308 
 309         break;
 310 
 311 
 312     case ACPI_TYPE_BUFFER_FIELD:
 313 
 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 
 372     default:
 373         ACPI_ERROR ((AE_INFO,
 374             "Target is not a Package or BufferField"));
 375         Status = AE_AML_OPERAND_TYPE;
 376         break;
 377     }
 378 
 379     return_ACPI_STATUS (Status);
 380 }
 381 
 382 
 383 /*******************************************************************************
 384  *
 385  * FUNCTION:    AcpiExStoreObjectToNode
 386  *
 387  * PARAMETERS:  SourceDesc              - Value to be stored
 388  *              Node                    - Named object to receive the value
 389  *              WalkState               - Current walk state
 390  *              ImplicitConversion      - Perform implicit conversion (yes/no)
 391  *
 392  * RETURN:      Status
 393  *
 394  * DESCRIPTION: Store the object to the named object.
 395  *
 396  *              The Assignment of an object to a named object is handled here
 397  *              The value passed in will replace the current value (if any)
 398  *              with the input value.
 399  *
 400  *              When storing into an object the data is converted to the
 401  *              target object type then stored in the object.  This means
 402  *              that the target object type (for an initialized target) will
 403  *              not be changed by a store operation.
 404  *
 405  *              Assumes parameters are already validated.
 406  *
 407  ******************************************************************************/
 408 
 409 ACPI_STATUS
 410 AcpiExStoreObjectToNode (
 411     ACPI_OPERAND_OBJECT     *SourceDesc,
 412     ACPI_NAMESPACE_NODE     *Node,
 413     ACPI_WALK_STATE         *WalkState,
 414     UINT8                   ImplicitConversion)
 415 {
 416     ACPI_STATUS             Status = AE_OK;
 417     ACPI_OPERAND_OBJECT     *TargetDesc;
 418     ACPI_OPERAND_OBJECT     *NewDesc;
 419     ACPI_OBJECT_TYPE        TargetType;
 420 
 421 
 422     ACPI_FUNCTION_TRACE_PTR (ExStoreObjectToNode, SourceDesc);
 423 
 424 
 425     /* Get current type of the node, and object attached to Node */
 426 
 427     TargetType = AcpiNsGetType (Node);
 428     TargetDesc = AcpiNsGetAttachedObject (Node);
 429 
 430     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
 431         SourceDesc, AcpiUtGetObjectTypeName (SourceDesc),
 432               Node, AcpiUtGetTypeName (TargetType)));
 433 
 434     /*
 435      * Resolve the source object to an actual value
 436      * (If it is a reference object)
 437      */
 438     Status = AcpiExResolveObject (&SourceDesc, TargetType, WalkState);
 439     if (ACPI_FAILURE (Status))
 440     {
 441         return_ACPI_STATUS (Status);
 442     }
 443 
 444     /* If no implicit conversion, drop into the default case below */
 445 
 446     if ((!ImplicitConversion) ||
 447           ((WalkState->Opcode == AML_COPY_OP) &&
 448            (TargetType != ACPI_TYPE_LOCAL_REGION_FIELD) &&
 449            (TargetType != ACPI_TYPE_LOCAL_BANK_FIELD) &&
 450            (TargetType != ACPI_TYPE_LOCAL_INDEX_FIELD)))
 451     {
 452         /*
 453          * Force execution of default (no implicit conversion). Note:
 454          * CopyObject does not perform an implicit conversion, as per the ACPI
 455          * spec -- except in case of region/bank/index fields -- because these
 456          * objects must retain their original type permanently.
 457          */
 458         TargetType = ACPI_TYPE_ANY;
 459     }
 460 
 461     /* Do the actual store operation */
 462 
 463     switch (TargetType)
 464     {
 465     case ACPI_TYPE_BUFFER_FIELD:
 466     case ACPI_TYPE_LOCAL_REGION_FIELD:
 467     case ACPI_TYPE_LOCAL_BANK_FIELD:
 468     case ACPI_TYPE_LOCAL_INDEX_FIELD:
 469 
 470         /* For fields, copy the source data to the target field. */
 471 
 472         Status = AcpiExWriteDataToField (SourceDesc, TargetDesc,
 473                     &WalkState->ResultObj);
 474         break;
 475 
 476 
 477     case ACPI_TYPE_INTEGER:
 478     case ACPI_TYPE_STRING:
 479     case ACPI_TYPE_BUFFER:
 480 
 481         /*
 482          * These target types are all of type Integer/String/Buffer, and
 483          * therefore support implicit conversion before the store.
 484          *
 485          * Copy and/or convert the source object to a new target object
 486          */
 487         Status = AcpiExStoreObjectToObject (SourceDesc, TargetDesc,
 488                     &NewDesc, WalkState);
 489         if (ACPI_FAILURE (Status))
 490         {
 491             return_ACPI_STATUS (Status);
 492         }
 493 
 494         if (NewDesc != TargetDesc)
 495         {
 496             /*
 497              * Store the new NewDesc as the new value of the Name, and set
 498              * the Name's type to that of the value being stored in it.
 499              * SourceDesc reference count is incremented by AttachObject.
 500              *
 501              * Note: This may change the type of the node if an explicit store
 502              * has been performed such that the node/object type has been
 503              * changed.
 504              */
 505             Status = AcpiNsAttachObject (Node, NewDesc, NewDesc->Common.Type);
 506 
 507             ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 508                 "Store %s into %s via Convert/Attach\n",
 509                 AcpiUtGetObjectTypeName (SourceDesc),
 510                 AcpiUtGetObjectTypeName (NewDesc)));
 511         }
 512         break;
 513 
 514 
 515     default:
 516 
 517         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 518             "Storing %s (%p) directly into node (%p) with no implicit conversion\n",
 519             AcpiUtGetObjectTypeName (SourceDesc), SourceDesc, Node));
 520 
 521         /* No conversions for all other types.  Just attach the source object */
 522 
 523         Status = AcpiNsAttachObject (Node, SourceDesc,
 524                     SourceDesc->Common.Type);
 525         break;
 526     }
 527 
 528     return_ACPI_STATUS (Status);
 529 }
 530 
 531