1 /******************************************************************************
   2  *
   3  * Module Name: dmdeferred - Disassembly of deferred AML opcodes
   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 
  45 #include "acpi.h"
  46 #include "accommon.h"
  47 #include "acdispat.h"
  48 #include "amlcode.h"
  49 #include "acdisasm.h"
  50 #include "acparser.h"
  51 
  52 #define _COMPONENT          ACPI_CA_DISASSEMBLER
  53         ACPI_MODULE_NAME    ("dmdeferred")
  54 
  55 
  56 /* Local prototypes */
  57 
  58 static ACPI_STATUS
  59 AcpiDmDeferredParse (
  60     ACPI_PARSE_OBJECT       *Op,
  61     UINT8                   *Aml,
  62     UINT32                  AmlLength);
  63 
  64 
  65 /******************************************************************************
  66  *
  67  * FUNCTION:    AcpiDmParseDeferredOps
  68  *
  69  * PARAMETERS:  Root                - Root of the parse tree
  70  *
  71  * RETURN:      Status
  72  *
  73  * DESCRIPTION: Parse the deferred opcodes (Methods, regions, etc.)
  74  *
  75  *****************************************************************************/
  76 
  77 ACPI_STATUS
  78 AcpiDmParseDeferredOps (
  79     ACPI_PARSE_OBJECT       *Root)
  80 {
  81     const ACPI_OPCODE_INFO  *OpInfo;
  82     ACPI_PARSE_OBJECT       *Op = Root;
  83     ACPI_STATUS             Status;
  84 
  85 
  86     ACPI_FUNCTION_ENTRY ();
  87 
  88 
  89     /* Traverse the entire parse tree */
  90 
  91     while (Op)
  92     {
  93         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
  94         if (!(OpInfo->Flags & AML_DEFER))
  95         {
  96             Op = AcpiPsGetDepthNext (Root, Op);
  97             continue;
  98         }
  99 
 100         /* Now we know we have a deferred opcode */
 101 
 102         switch (Op->Common.AmlOpcode)
 103         {
 104         case AML_METHOD_OP:
 105         case AML_BUFFER_OP:
 106         case AML_PACKAGE_OP:
 107         case AML_VAR_PACKAGE_OP:
 108 
 109             Status = AcpiDmDeferredParse (Op, Op->Named.Data, Op->Named.Length);
 110             if (ACPI_FAILURE (Status))
 111             {
 112                 return (Status);
 113             }
 114             break;
 115 
 116         /* We don't need to do anything for these deferred opcodes */
 117 
 118         case AML_REGION_OP:
 119         case AML_DATA_REGION_OP:
 120         case AML_CREATE_QWORD_FIELD_OP:
 121         case AML_CREATE_DWORD_FIELD_OP:
 122         case AML_CREATE_WORD_FIELD_OP:
 123         case AML_CREATE_BYTE_FIELD_OP:
 124         case AML_CREATE_BIT_FIELD_OP:
 125         case AML_CREATE_FIELD_OP:
 126         case AML_BANK_FIELD_OP:
 127 
 128             break;
 129 
 130         default:
 131 
 132             ACPI_ERROR ((AE_INFO, "Unhandled deferred AML opcode [0x%.4X]",
 133                  Op->Common.AmlOpcode));
 134             break;
 135         }
 136 
 137         Op = AcpiPsGetDepthNext (Root, Op);
 138     }
 139 
 140     return (AE_OK);
 141 }
 142 
 143 
 144 /******************************************************************************
 145  *
 146  * FUNCTION:    AcpiDmDeferredParse
 147  *
 148  * PARAMETERS:  Op                  - Root Op of the deferred opcode
 149  *              Aml                 - Pointer to the raw AML
 150  *              AmlLength           - Length of the AML
 151  *
 152  * RETURN:      Status
 153  *
 154  * DESCRIPTION: Parse one deferred opcode
 155  *              (Methods, operation regions, etc.)
 156  *
 157  *****************************************************************************/
 158 
 159 static ACPI_STATUS
 160 AcpiDmDeferredParse (
 161     ACPI_PARSE_OBJECT       *Op,
 162     UINT8                   *Aml,
 163     UINT32                  AmlLength)
 164 {
 165     ACPI_WALK_STATE         *WalkState;
 166     ACPI_STATUS             Status;
 167     ACPI_PARSE_OBJECT       *SearchOp;
 168     ACPI_PARSE_OBJECT       *StartOp;
 169     UINT32                  BaseAmlOffset;
 170     ACPI_PARSE_OBJECT       *NewRootOp;
 171     ACPI_PARSE_OBJECT       *ExtraOp;
 172 
 173 
 174     ACPI_FUNCTION_TRACE (DmDeferredParse);
 175 
 176 
 177     if (!Aml || !AmlLength)
 178     {
 179         return_ACPI_STATUS (AE_OK);
 180     }
 181 
 182     ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Parsing deferred opcode %s [%4.4s]\n",
 183         Op->Common.AmlOpName, (char *) &Op->Named.Name));
 184 
 185     /* Need a new walk state to parse the AML */
 186 
 187     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
 188     if (!WalkState)
 189     {
 190         return_ACPI_STATUS (AE_NO_MEMORY);
 191     }
 192 
 193     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, Aml,
 194         AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
 195     if (ACPI_FAILURE (Status))
 196     {
 197         return_ACPI_STATUS (Status);
 198     }
 199 
 200     /* Parse the AML for this deferred opcode */
 201 
 202     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
 203     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
 204     Status = AcpiPsParseAml (WalkState);
 205 
 206     /*
 207      * We need to update all of the AML offsets, since the parser thought
 208      * that the method began at offset zero. In reality, it began somewhere
 209      * within the ACPI table, at the BaseAmlOffset. Walk the entire tree that
 210      * was just created and update the AmlOffset in each Op.
 211      */
 212     BaseAmlOffset = (Op->Common.Value.Arg)->Common.AmlOffset + 1;
 213     StartOp = (Op->Common.Value.Arg)->Common.Next;
 214     SearchOp = StartOp;
 215 
 216     while (SearchOp)
 217     {
 218         SearchOp->Common.AmlOffset += BaseAmlOffset;
 219         SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp);
 220     }
 221 
 222     /*
 223      * For Buffer and Package opcodes, link the newly parsed subtree
 224      * into the main parse tree
 225      */
 226     switch (Op->Common.AmlOpcode)
 227     {
 228     case AML_BUFFER_OP:
 229     case AML_PACKAGE_OP:
 230     case AML_VAR_PACKAGE_OP:
 231 
 232         switch (Op->Common.AmlOpcode)
 233         {
 234         case AML_PACKAGE_OP:
 235 
 236             ExtraOp = Op->Common.Value.Arg;
 237             NewRootOp = ExtraOp->Common.Next;
 238             ACPI_FREE (ExtraOp);
 239             break;
 240 
 241         case AML_VAR_PACKAGE_OP:
 242         case AML_BUFFER_OP:
 243         default:
 244 
 245             NewRootOp = Op->Common.Value.Arg;
 246             break;
 247         }
 248 
 249         Op->Common.Value.Arg = NewRootOp->Common.Value.Arg;
 250 
 251         /* Must point all parents to the main tree */
 252 
 253         StartOp = Op;
 254         SearchOp = StartOp;
 255         while (SearchOp)
 256         {
 257             if (SearchOp->Common.Parent == NewRootOp)
 258             {
 259                 SearchOp->Common.Parent = Op;
 260             }
 261 
 262             SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp);
 263         }
 264 
 265         ACPI_FREE (NewRootOp);
 266         break;
 267 
 268     default:
 269 
 270         break;
 271     }
 272 
 273     return_ACPI_STATUS (AE_OK);
 274 }