Home | History | Annotate | Download | only in AcpiTableDxe
      1 /** @file
      2   ACPI Sdt Protocol Driver
      3 
      4   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "AcpiTable.h"
     16 
     17 /**
     18   Construct node list according to the AML handle.
     19 
     20   @param[in]    AmlHandle            AML handle.
     21   @param[in]    AmlRootNodeList      AML root node list.
     22   @param[in]    AmlParentNodeList    AML parent node list.
     23 
     24   @retval       EFI_SUCCESS           Success.
     25   @retval       EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
     26 **/
     27 EFI_STATUS
     28 AmlConstructNodeList (
     29   IN EFI_AML_HANDLE      *AmlHandle,
     30   IN EFI_AML_NODE_LIST   *AmlRootNodeList,
     31   IN EFI_AML_NODE_LIST   *AmlParentNodeList
     32   );
     33 
     34 /**
     35   Create AML Node.
     36 
     37   @param[in]    NameSeg              AML NameSeg.
     38   @param[in]    Parent               AML parent node list.
     39   @param[in]    AmlByteEncoding      AML Byte Encoding.
     40 
     41   @return       AML Node.
     42 **/
     43 EFI_AML_NODE_LIST *
     44 AmlCreateNode (
     45   IN UINT8              *NameSeg,
     46   IN EFI_AML_NODE_LIST  *Parent,
     47   IN AML_BYTE_ENCODING  *AmlByteEncoding
     48   )
     49 {
     50   EFI_AML_NODE_LIST      *AmlNodeList;
     51 
     52   AmlNodeList = AllocatePool (sizeof(*AmlNodeList));
     53   ASSERT (AmlNodeList != NULL);
     54 
     55   AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE;
     56   CopyMem (AmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE);
     57   AmlNodeList->Buffer    = NULL;
     58   AmlNodeList->Size      = 0;
     59   InitializeListHead (&AmlNodeList->Link);
     60   InitializeListHead (&AmlNodeList->Children);
     61   AmlNodeList->Parent = Parent;
     62   AmlNodeList->AmlByteEncoding = AmlByteEncoding;
     63 
     64   return AmlNodeList;
     65 }
     66 
     67 /**
     68   Find the AML NameSeg in the children of AmlParentNodeList.
     69 
     70   @param[in]    NameSeg              AML NameSeg.
     71   @param[in]    AmlParentNodeList    AML parent node list.
     72   @param[in]    Create               TRUE means to create node if not found.
     73 
     74   @return       AmlChildNode whoes name is same as NameSeg.
     75 **/
     76 EFI_AML_NODE_LIST *
     77 AmlFindNodeInThis (
     78   IN UINT8               *NameSeg,
     79   IN EFI_AML_NODE_LIST   *AmlParentNodeList,
     80   IN BOOLEAN             Create
     81   )
     82 {
     83   EFI_AML_NODE_LIST      *CurrentAmlNodeList;
     84   LIST_ENTRY             *CurrentLink;
     85   LIST_ENTRY             *StartLink;
     86   EFI_AML_NODE_LIST      *AmlNodeList;
     87 
     88   StartLink   = &AmlParentNodeList->Children;
     89   CurrentLink = StartLink->ForwardLink;
     90 
     91   while (CurrentLink != StartLink) {
     92     CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
     93     //
     94     // AML name is same as the one stored
     95     //
     96     if (CompareMem (CurrentAmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE) == 0) {
     97       //
     98       // Good! Found it
     99       //
    100       return CurrentAmlNodeList;
    101     }
    102     CurrentLink = CurrentLink->ForwardLink;
    103   }
    104 
    105   //
    106   // Not found
    107   //
    108   if (!Create) {
    109     return NULL;
    110   }
    111 
    112   //
    113   // Create new node with NULL buffer - it means namespace not be returned.
    114   //
    115   AmlNodeList = AmlCreateNode (NameSeg, AmlParentNodeList, NULL);
    116   InsertTailList (&AmlParentNodeList->Children, &AmlNodeList->Link);
    117 
    118   return AmlNodeList;
    119 }
    120 
    121 /**
    122   Find the AML NameString in the children of AmlParentNodeList or AmlRootNodeList.
    123 
    124   @param[in]    NameString           AML NameString.
    125   @param[in]    AmlRootNodeList      AML root node list.
    126   @param[in]    AmlParentNodeList    AML parent node list.
    127   @param[in]    Create               TRUE means to create node if not found.
    128 
    129   @return       AmlChildNode whoes name is same as NameSeg.
    130 **/
    131 EFI_AML_NODE_LIST *
    132 AmlFindNodeInTheTree (
    133   IN UINT8               *NameString,
    134   IN EFI_AML_NODE_LIST   *AmlRootNodeList,
    135   IN EFI_AML_NODE_LIST   *AmlParentNodeList,
    136   IN BOOLEAN             Create
    137   )
    138 {
    139   UINT8               *Buffer;
    140   EFI_AML_NODE_LIST   *AmlNodeList;
    141   EFI_AML_NODE_LIST   *AmlCurrentNodeList;
    142   UINT8               Index;
    143   UINT8               SegCount;
    144 
    145   Buffer = NameString;
    146 
    147   //
    148   // Handle root or parent prefix
    149   //
    150   if (*Buffer == AML_ROOT_CHAR) {
    151     AmlCurrentNodeList = AmlRootNodeList;
    152     Buffer += 1;
    153   } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
    154     AmlCurrentNodeList = AmlParentNodeList;
    155     do {
    156       if (AmlCurrentNodeList->Parent != NULL) {
    157         AmlCurrentNodeList = AmlCurrentNodeList->Parent;
    158       } else {
    159         //
    160         // Only root has no parent
    161         //
    162         ASSERT (AmlCurrentNodeList == AmlRootNodeList);
    163       }
    164       Buffer += 1;
    165     } while (*Buffer == AML_PARENT_PREFIX_CHAR);
    166   } else {
    167     AmlCurrentNodeList = AmlParentNodeList;
    168   }
    169 
    170   //
    171   // Handle name segment
    172   //
    173   if (*Buffer == AML_DUAL_NAME_PREFIX) {
    174     Buffer += 1;
    175     SegCount = 2;
    176   } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
    177     Buffer += 1;
    178     SegCount = *Buffer;
    179     Buffer += 1;
    180   } else if (*Buffer == 0) {
    181     //
    182     // NULL name, only for Root
    183     //
    184     ASSERT (AmlCurrentNodeList == AmlRootNodeList);
    185     return AmlCurrentNodeList;
    186   } else {
    187     SegCount = 1;
    188   }
    189 
    190   //
    191   // Handle NamePath
    192   //
    193   Index = 0;
    194   do {
    195     AmlNodeList = AmlFindNodeInThis (Buffer, AmlCurrentNodeList, Create);
    196     if (AmlNodeList == NULL) {
    197       return NULL;
    198     }
    199     AmlCurrentNodeList = AmlNodeList;
    200     Buffer += AML_NAME_SEG_SIZE;
    201     Index ++;
    202   } while (Index < SegCount);
    203 
    204   return AmlNodeList;
    205 }
    206 
    207 /**
    208   Insert the NameString to the AmlNodeList.
    209 
    210   @param[in]    NameString           AML NameString.
    211   @param[in]    Buffer               Buffer for the Node.
    212   @param[in]    Size                 Size for the Node.
    213   @param[in]    AmlRootNodeList      AML root node list.
    214   @param[in]    AmlParentNodeList    AML parent node list.
    215 
    216   @return       AmlChildNode whoes name is NameString.
    217 **/
    218 EFI_AML_NODE_LIST *
    219 AmlInsertNodeToTree (
    220   IN UINT8               *NameString,
    221   IN VOID                *Buffer,
    222   IN UINTN               Size,
    223   IN EFI_AML_NODE_LIST   *AmlRootNodeList,
    224   IN EFI_AML_NODE_LIST   *AmlParentNodeList
    225   )
    226 {
    227   EFI_AML_NODE_LIST   *AmlNodeList;
    228 
    229   AmlNodeList = AmlFindNodeInTheTree (
    230                   NameString,
    231                   AmlRootNodeList,
    232                   AmlParentNodeList,
    233                   TRUE  // Find and Create
    234                   );
    235   ASSERT (AmlNodeList != NULL);
    236   if (AmlNodeList == NULL) {
    237     return NULL;
    238   }
    239 
    240   //
    241   // Check buffer
    242   //
    243   if (AmlNodeList->Buffer == NULL) {
    244     //
    245     // NULL means new added one or SCOPE_OP
    246     //
    247     if (*(UINT8 *)Buffer != AML_SCOPE_OP) {
    248       //
    249       // We need check if new one is SCOPE_OP, because SCOPE_OP just means namespace, not a real device.
    250       // We should not return SCOPE_OP.
    251       //
    252       AmlNodeList->Buffer = Buffer;
    253       AmlNodeList->Size   = Size;
    254       AmlNodeList->AmlByteEncoding = AmlSearchByOpByte (Buffer);
    255     }
    256     return AmlNodeList;
    257   }
    258 
    259   //
    260   // Already added
    261   //
    262   if (*(UINT8 *)Buffer == AML_SCOPE_OP) {
    263     //
    264     // The new one is SCOPE_OP, OK just return;
    265     //
    266     return AmlNodeList;
    267   }
    268 
    269   //
    270   // Oops!!!, There must be something wrong.
    271   //
    272   DEBUG ((EFI_D_ERROR, "AML: Override Happen - %a!\n", NameString));
    273   DEBUG ((EFI_D_ERROR, "AML: Existing Node - %x\n", AmlNodeList->Buffer));
    274   DEBUG ((EFI_D_ERROR, "AML: New Buffer - %x\n", Buffer));
    275 
    276   return NULL;
    277 }
    278 
    279 /**
    280   Construct child node list according to the AML handle.
    281 
    282   @param[in]    AmlHandle            AML handle.
    283   @param[in]    AmlRootNodeList      AML root node list.
    284   @param[in]    AmlParentNodeList    AML parent node list.
    285 
    286   @retval       EFI_SUCCESS           Success.
    287   @retval       EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
    288 **/
    289 EFI_STATUS
    290 AmlConstructNodeListForChild (
    291   IN EFI_AML_HANDLE      *AmlHandle,
    292   IN EFI_AML_NODE_LIST   *AmlRootNodeList,
    293   IN EFI_AML_NODE_LIST   *AmlParentNodeList
    294   )
    295 {
    296   AML_BYTE_ENCODING   *AmlByteEncoding;
    297   UINT8               *Buffer;
    298   UINTN               BufferSize;
    299   UINT8               *CurrentBuffer;
    300   EFI_AML_HANDLE      *AmlChildHandle;
    301   EFI_STATUS          Status;
    302 
    303   CurrentBuffer   = NULL;
    304   AmlChildHandle  = NULL;
    305   AmlByteEncoding = AmlHandle->AmlByteEncoding;
    306   Buffer          = AmlHandle->Buffer;
    307   BufferSize      = AmlHandle->Size;
    308 
    309   //
    310   // Check if we need recursively add node
    311   //
    312   if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
    313     //
    314     // No more node need to be added
    315     //
    316     return EFI_SUCCESS;
    317   }
    318 
    319   //
    320   // Do we need add node within METHOD?
    321   // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
    322   //
    323 
    324   //
    325   // Now, we get the last node.
    326   //
    327   Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);
    328   if (EFI_ERROR (Status)) {
    329     return EFI_INVALID_PARAMETER;
    330   }
    331 
    332   //
    333   // Go through all the reset buffer.
    334   //
    335   while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {
    336     //
    337     // Find the child node.
    338     //
    339     Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);
    340     if (EFI_ERROR (Status)) {
    341       //
    342       // No child found, break now.
    343       //
    344       break;
    345     }
    346 
    347     //
    348     // Good, find the child. Construct node recursively
    349     //
    350     Status = AmlConstructNodeList (
    351                AmlChildHandle,
    352                AmlRootNodeList,
    353                AmlParentNodeList
    354                );
    355     if (EFI_ERROR (Status)) {
    356       break;
    357     }
    358 
    359     //
    360     // Parse next one
    361     //
    362     CurrentBuffer += AmlChildHandle->Size;
    363 
    364     Close ((EFI_ACPI_HANDLE)AmlChildHandle);
    365   }
    366 
    367   return EFI_SUCCESS;
    368 }
    369 
    370 /**
    371   Construct node list according to the AML handle.
    372 
    373   @param[in]    AmlHandle            AML handle.
    374   @param[in]    AmlRootNodeList      AML root node list.
    375   @param[in]    AmlParentNodeList    AML parent node list.
    376 
    377   @retval       EFI_SUCCESS           Success.
    378   @retval       EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
    379 **/
    380 EFI_STATUS
    381 AmlConstructNodeList (
    382   IN EFI_AML_HANDLE      *AmlHandle,
    383   IN EFI_AML_NODE_LIST   *AmlRootNodeList,
    384   IN EFI_AML_NODE_LIST   *AmlParentNodeList
    385   )
    386 {
    387   VOID                *NameString;
    388   EFI_AML_NODE_LIST   *AmlNodeList;
    389 
    390   //
    391   // 1. Check if there is need to construct node for this OpCode.
    392   //
    393   if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {
    394     //
    395     // No need to construct node, so we just skip this OpCode.
    396     //
    397     return EFI_SUCCESS;
    398   }
    399 
    400   //
    401   // 2. Now, we need construct node for this OpCode.
    402   //
    403   NameString = AmlGetObjectName (AmlHandle);
    404   if (NameString == NULL) {
    405     return EFI_INVALID_PARAMETER;
    406   }
    407 
    408   //
    409   // Now, we need to insert node to the node list.
    410   // NOTE: The name here could be AML NameString. So the callee need parse it.
    411   //
    412   AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);
    413   ASSERT (AmlNodeList != NULL);
    414 
    415   //
    416   // 3. Ok, we need to parse the object list to see if there are more node to be added.
    417   //
    418   return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);
    419 }
    420 
    421 /**
    422   Destruct node list
    423 
    424   @param[in]    AmlParentNodeList    AML parent node list.
    425 **/
    426 VOID
    427 AmlDestructNodeList (
    428   IN EFI_AML_NODE_LIST *AmlParentNodeList
    429   )
    430 {
    431   EFI_AML_NODE_LIST      *CurrentAmlNodeList;
    432   LIST_ENTRY             *CurrentLink;
    433   LIST_ENTRY             *StartLink;
    434 
    435   //
    436   // Get the children link
    437   //
    438   StartLink   = &AmlParentNodeList->Children;
    439   CurrentLink = StartLink->ForwardLink;
    440 
    441   //
    442   // Go through all the children
    443   //
    444   while (CurrentLink != StartLink) {
    445     //
    446     // Destruct the child's list recursively
    447     //
    448     CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
    449     CurrentLink = CurrentLink->ForwardLink;
    450 
    451     //
    452     // Remove this child from list and free the node
    453     //
    454     RemoveEntryList (&(CurrentAmlNodeList->Link));
    455 
    456     AmlDestructNodeList (CurrentAmlNodeList);
    457   }
    458 
    459   //
    460   // Done.
    461   //
    462   FreePool (AmlParentNodeList);
    463   return ;
    464 }
    465 
    466 /**
    467   Dump node list
    468 
    469   @param[in]    AmlParentNodeList    AML parent node list.
    470   @param[in]    Level                Output debug level.
    471 **/
    472 VOID
    473 AmlDumpNodeInfo (
    474   IN EFI_AML_NODE_LIST *AmlParentNodeList,
    475   IN UINTN             Level
    476   )
    477 {
    478   EFI_AML_NODE_LIST      *CurrentAmlNodeList;
    479   volatile LIST_ENTRY    *CurrentLink;
    480   UINTN                  Index;
    481 
    482   CurrentLink = AmlParentNodeList->Children.ForwardLink;
    483 
    484   if (Level == 0) {
    485     DEBUG ((EFI_D_ERROR, "\\"));
    486   } else {
    487     for (Index = 0; Index < Level; Index++) {
    488       DEBUG ((EFI_D_ERROR, "    "));
    489     }
    490     AmlPrintNameSeg (AmlParentNodeList->Name);
    491   }
    492   DEBUG ((EFI_D_ERROR, "\n"));
    493 
    494   while (CurrentLink != &AmlParentNodeList->Children) {
    495     CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
    496     AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);
    497     CurrentLink = CurrentLink->ForwardLink;
    498   }
    499 
    500   return ;
    501 }
    502 
    503 /**
    504   Returns the handle of the ACPI object representing the specified ACPI AML path
    505 
    506   @param[in]    AmlHandle   Points to the handle of the object representing the starting point for the path search.
    507   @param[in]    AmlPath     Points to the ACPI AML path.
    508   @param[out]   Buffer      On return, points to the ACPI object which represents AcpiPath, relative to
    509                             HandleIn.
    510   @param[in]    FromRoot    TRUE means to find AML path from \ (Root) Node.
    511                             FALSE means to find AML path from this Node (The HandleIn).
    512 
    513   @retval EFI_SUCCESS           Success
    514   @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
    515 **/
    516 EFI_STATUS
    517 AmlFindPath (
    518   IN    EFI_AML_HANDLE  *AmlHandle,
    519   IN    UINT8           *AmlPath,
    520   OUT   VOID            **Buffer,
    521   IN    BOOLEAN         FromRoot
    522   )
    523 {
    524   EFI_AML_NODE_LIST   *AmlRootNodeList;
    525   EFI_STATUS          Status;
    526   EFI_AML_NODE_LIST   *AmlNodeList;
    527   UINT8               RootNameSeg[AML_NAME_SEG_SIZE];
    528   EFI_AML_NODE_LIST   *CurrentAmlNodeList;
    529   LIST_ENTRY          *CurrentLink;
    530 
    531   //
    532   // 1. create tree
    533   //
    534 
    535   //
    536   // Create root handle
    537   //
    538   RootNameSeg[0] = AML_ROOT_CHAR;
    539   RootNameSeg[1] = 0;
    540   AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);
    541 
    542   Status = AmlConstructNodeList (
    543              AmlHandle,
    544              AmlRootNodeList, // Root
    545              AmlRootNodeList  // Parent
    546              );
    547   if (EFI_ERROR (Status)) {
    548     return EFI_INVALID_PARAMETER;
    549   }
    550 
    551   DEBUG_CODE_BEGIN ();
    552   DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));
    553   AmlDumpNodeInfo (AmlRootNodeList, 0);
    554   DEBUG_CODE_END ();
    555 
    556   //
    557   // 2. Search the node in the tree
    558   //
    559   if (FromRoot) {
    560     //
    561     // Search from Root
    562     //
    563     CurrentAmlNodeList = AmlRootNodeList;
    564   } else {
    565     //
    566     // Search from this node, NOT ROOT.
    567     // Since we insert node to ROOT one by one, we just get the first node and search from it.
    568     //
    569     CurrentLink = AmlRootNodeList->Children.ForwardLink;
    570     if (CurrentLink != &AmlRootNodeList->Children) {
    571       //
    572       // First node
    573       //
    574       CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
    575     } else {
    576       //
    577       // No child
    578       //
    579       CurrentAmlNodeList = NULL;
    580     }
    581   }
    582 
    583   //
    584   // Search
    585   //
    586   if (CurrentAmlNodeList != NULL) {
    587     DEBUG_CODE_BEGIN ();
    588     DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));
    589     AmlPrintNameSeg (CurrentAmlNodeList->Name);
    590     DEBUG ((EFI_D_ERROR, "\n"));
    591     DEBUG_CODE_END ();
    592     AmlNodeList = AmlFindNodeInTheTree (
    593                     AmlPath,
    594                     AmlRootNodeList,    // Root
    595                     CurrentAmlNodeList, // Parent
    596                     FALSE
    597                     );
    598   } else {
    599     AmlNodeList = NULL;
    600   }
    601 
    602   *Buffer = NULL;
    603   Status = EFI_SUCCESS;
    604   if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {
    605     *Buffer = AmlNodeList->Buffer;
    606   }
    607 
    608   //
    609   // 3. free the tree
    610   //
    611   AmlDestructNodeList (AmlRootNodeList);
    612 
    613   return Status;
    614 }
    615