Home | History | Annotate | Download | only in SectionExtraction
      1 /** @file
      2   Section Extraction Protocol implementation.
      3 
      4   Stream database is implemented as a linked list of section streams,
      5   where each stream contains a linked list of children, which may be leaves or
      6   encapsulations.
      7 
      8   Children that are encapsulations generate new stream entries
      9   when they are created.  Streams can also be created by calls to
     10   SEP->OpenSectionStream().
     11 
     12   The database is only created far enough to return the requested data from
     13   any given stream, or to determine that the requested data is not found.
     14 
     15   If a GUIDed encapsulation is encountered, there are three possiblilites.
     16 
     17   1) A support protocol is found, in which the stream is simply processed with
     18      the support protocol.
     19 
     20   2) A support protocol is not found, but the data is available to be read
     21      without processing.  In this case, the database is built up through the
     22      recursions to return the data, and a RPN event is set that will enable
     23      the stream in question to be refreshed if and when the required section
     24      extraction protocol is published.This insures the AuthenticationStatus
     25      does not become stale in the cache.
     26 
     27   3) A support protocol is not found, and the data is not available to be read
     28      without it.  This results in EFI_PROTOCOL_ERROR.
     29 
     30 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
     31 This program and the accompanying materials
     32 are licensed and made available under the terms and conditions of the BSD License
     33 which accompanies this distribution.  The full text of the license may be found at
     34 http://opensource.org/licenses/bsd-license.php
     35 
     36 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     37 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     38 
     39 **/
     40 
     41 #include "DxeMain.h"
     42 
     43 //
     44 // Local defines and typedefs
     45 //
     46 #define CORE_SECTION_CHILD_SIGNATURE  SIGNATURE_32('S','X','C','S')
     47 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
     48   CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
     49 
     50 typedef struct {
     51   UINT32                      Signature;
     52   LIST_ENTRY                  Link;
     53   UINT32                      Type;
     54   UINT32                      Size;
     55   //
     56   // StreamBase + OffsetInStream == pointer to section header in stream.  The
     57   // stream base is always known when walking the sections within.
     58   //
     59   UINT32                      OffsetInStream;
     60   //
     61   // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
     62   // encapsulating section.  Otherwise, it contains the stream handle
     63   // of the encapsulated stream.  This handle is ALWAYS produced any time an
     64   // encapsulating child is encountered, irrespective of whether the
     65   // encapsulated stream is processed further.
     66   //
     67   UINTN                       EncapsulatedStreamHandle;
     68   EFI_GUID                    *EncapsulationGuid;
     69   //
     70   // If the section REQUIRES an extraction protocol, register for RPN
     71   // when the required GUIDed extraction protocol becomes available.
     72   //
     73   EFI_EVENT                   Event;
     74 } CORE_SECTION_CHILD_NODE;
     75 
     76 #define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
     77 #define STREAM_NODE_FROM_LINK(Node) \
     78   CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
     79 
     80 typedef struct {
     81   UINT32                      Signature;
     82   LIST_ENTRY                  Link;
     83   UINTN                       StreamHandle;
     84   UINT8                       *StreamBuffer;
     85   UINTN                       StreamLength;
     86   LIST_ENTRY                  Children;
     87   //
     88   // Authentication status is from GUIDed encapsulations.
     89   //
     90   UINT32                      AuthenticationStatus;
     91 } CORE_SECTION_STREAM_NODE;
     92 
     93 #define NULL_STREAM_HANDLE    0
     94 
     95 typedef struct {
     96   CORE_SECTION_CHILD_NODE     *ChildNode;
     97   CORE_SECTION_STREAM_NODE    *ParentStream;
     98   VOID                        *Registration;
     99 } RPN_EVENT_CONTEXT;
    100 
    101 
    102 /**
    103   The ExtractSection() function processes the input section and
    104   allocates a buffer from the pool in which it returns the section
    105   contents. If the section being extracted contains
    106   authentication information (the section's
    107   GuidedSectionHeader.Attributes field has the
    108   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
    109   returned in AuthenticationStatus must reflect the results of
    110   the authentication operation. Depending on the algorithm and
    111   size of the encapsulated data, the time that is required to do
    112   a full authentication may be prohibitively long for some
    113   classes of systems. To indicate this, use
    114   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
    115   the security policy driver (see the Platform Initialization
    116   Driver Execution Environment Core Interface Specification for
    117   more details and the GUID definition). If the
    118   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
    119   database, then, if possible, full authentication should be
    120   skipped and the section contents simply returned in the
    121   OutputBuffer. In this case, the
    122   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
    123   must be set on return. ExtractSection() is callable only from
    124   TPL_NOTIFY and below. Behavior of ExtractSection() at any
    125   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
    126   defined in RaiseTPL() in the UEFI 2.0 specification.
    127 
    128 
    129   @param This         Indicates the
    130                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
    131   @param InputSection Buffer containing the input GUIDed section
    132                       to be processed. OutputBuffer OutputBuffer
    133                       is allocated from boot services pool
    134                       memory and contains the new section
    135                       stream. The caller is responsible for
    136                       freeing this buffer.
    137   @param OutputBuffer *OutputBuffer is allocated from boot services
    138                       pool memory and contains the new section stream.
    139                       The caller is responsible for freeing this buffer.
    140   @param OutputSize   A pointer to a caller-allocated UINTN in
    141                       which the size of OutputBuffer allocation
    142                       is stored. If the function returns
    143                       anything other than EFI_SUCCESS, the value
    144                       of OutputSize is undefined.
    145 
    146   @param AuthenticationStatus A pointer to a caller-allocated
    147                               UINT32 that indicates the
    148                               authentication status of the
    149                               output buffer. If the input
    150                               section's
    151                               GuidedSectionHeader.Attributes
    152                               field has the
    153                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
    154                               bit as clear, AuthenticationStatus
    155                               must return zero. Both local bits
    156                               (19:16) and aggregate bits (3:0)
    157                               in AuthenticationStatus are
    158                               returned by ExtractSection().
    159                               These bits reflect the status of
    160                               the extraction operation. The bit
    161                               pattern in both regions must be
    162                               the same, as the local and
    163                               aggregate authentication statuses
    164                               have equivalent meaning at this
    165                               level. If the function returns
    166                               anything other than EFI_SUCCESS,
    167                               the value of AuthenticationStatus
    168                               is undefined.
    169 
    170 
    171   @retval EFI_SUCCESS          The InputSection was successfully
    172                                processed and the section contents were
    173                                returned.
    174 
    175   @retval EFI_OUT_OF_RESOURCES The system has insufficient
    176                                resources to process the
    177                                request.
    178 
    179   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
    180                                 not match this instance of the
    181                                 GUIDed Section Extraction
    182                                 Protocol.
    183 
    184 **/
    185 EFI_STATUS
    186 EFIAPI
    187 CustomGuidedSectionExtract (
    188   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
    189   IN CONST  VOID                                   *InputSection,
    190   OUT       VOID                                   **OutputBuffer,
    191   OUT       UINTN                                  *OutputSize,
    192   OUT       UINT32                                 *AuthenticationStatus
    193   );
    194 
    195 //
    196 // Module globals
    197 //
    198 LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
    199 
    200 EFI_HANDLE mSectionExtractionHandle = NULL;
    201 
    202 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
    203   CustomGuidedSectionExtract
    204 };
    205 
    206 
    207 /**
    208   Entry point of the section extraction code. Initializes an instance of the
    209   section extraction interface and installs it on a new handle.
    210 
    211   @param  ImageHandle   A handle for the image that is initializing this driver
    212   @param  SystemTable   A pointer to the EFI system table
    213 
    214   @retval EFI_SUCCESS           Driver initialized successfully
    215   @retval EFI_OUT_OF_RESOURCES  Could not allocate needed resources
    216 
    217 **/
    218 EFI_STATUS
    219 EFIAPI
    220 InitializeSectionExtraction (
    221   IN EFI_HANDLE                   ImageHandle,
    222   IN EFI_SYSTEM_TABLE             *SystemTable
    223   )
    224 {
    225   EFI_STATUS                         Status;
    226   EFI_GUID                           *ExtractHandlerGuidTable;
    227   UINTN                              ExtractHandlerNumber;
    228 
    229   //
    230   // Get custom extract guided section method guid list
    231   //
    232   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
    233 
    234   Status = EFI_SUCCESS;
    235   //
    236   // Install custom guided extraction protocol
    237   //
    238   while (ExtractHandlerNumber-- > 0) {
    239     Status = CoreInstallProtocolInterface (
    240               &mSectionExtractionHandle,
    241               &ExtractHandlerGuidTable [ExtractHandlerNumber],
    242               EFI_NATIVE_INTERFACE,
    243               &mCustomGuidedSectionExtractionProtocol
    244               );
    245     ASSERT_EFI_ERROR (Status);
    246   }
    247 
    248   return Status;
    249 }
    250 
    251 
    252 /**
    253   Check if a stream is valid.
    254 
    255   @param  SectionStream          The section stream to be checked
    256   @param  SectionStreamLength    The length of section stream
    257 
    258   @return A boolean value indicating the validness of the section stream.
    259 
    260 **/
    261 BOOLEAN
    262 IsValidSectionStream (
    263   IN  VOID              *SectionStream,
    264   IN  UINTN             SectionStreamLength
    265   )
    266 {
    267   UINTN                       TotalLength;
    268   UINTN                       SectionLength;
    269   EFI_COMMON_SECTION_HEADER   *SectionHeader;
    270   EFI_COMMON_SECTION_HEADER   *NextSectionHeader;
    271 
    272   TotalLength = 0;
    273   SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
    274 
    275   while (TotalLength < SectionStreamLength) {
    276     if (IS_SECTION2 (SectionHeader)) {
    277       SectionLength = SECTION2_SIZE (SectionHeader);
    278     } else {
    279       SectionLength = SECTION_SIZE (SectionHeader);
    280     }
    281     TotalLength += SectionLength;
    282 
    283     if (TotalLength == SectionStreamLength) {
    284       return TRUE;
    285     }
    286 
    287     //
    288     // Move to the next byte following the section...
    289     //
    290     SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
    291 
    292     //
    293     // Figure out where the next section begins
    294     //
    295     NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
    296     TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
    297     SectionHeader = NextSectionHeader;
    298   }
    299 
    300   ASSERT (FALSE);
    301   return FALSE;
    302 }
    303 
    304 
    305 /**
    306   Worker function.  Constructor for section streams.
    307 
    308   @param  SectionStreamLength    Size in bytes of the section stream.
    309   @param  SectionStream          Buffer containing the new section stream.
    310   @param  AllocateBuffer         Indicates whether the stream buffer is to be
    311                                  copied or the input buffer is to be used in
    312                                  place. AuthenticationStatus- Indicates the
    313                                  default authentication status for the new
    314                                  stream.
    315   @param  AuthenticationStatus   A pointer to a caller-allocated UINT32 that
    316                                  indicates the authentication status of the
    317                                  output buffer. If the input section's
    318                                  GuidedSectionHeader.Attributes field
    319                                  has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
    320                                  bit as clear, AuthenticationStatus must return
    321                                  zero. Both local bits (19:16) and aggregate
    322                                  bits (3:0) in AuthenticationStatus are returned
    323                                  by ExtractSection(). These bits reflect the
    324                                  status of the extraction operation. The bit
    325                                  pattern in both regions must be the same, as
    326                                  the local and aggregate authentication statuses
    327                                  have equivalent meaning at this level. If the
    328                                  function returns anything other than
    329                                  EFI_SUCCESS, the value of *AuthenticationStatus
    330                                  is undefined.
    331   @param  SectionStreamHandle    A pointer to a caller allocated section stream
    332                                  handle.
    333 
    334   @retval EFI_SUCCESS            Stream was added to stream database.
    335   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
    336 
    337 **/
    338 EFI_STATUS
    339 OpenSectionStreamEx (
    340   IN     UINTN                                     SectionStreamLength,
    341   IN     VOID                                      *SectionStream,
    342   IN     BOOLEAN                                   AllocateBuffer,
    343   IN     UINT32                                    AuthenticationStatus,
    344      OUT UINTN                                     *SectionStreamHandle
    345   )
    346 {
    347   CORE_SECTION_STREAM_NODE    *NewStream;
    348   EFI_TPL                     OldTpl;
    349 
    350   //
    351   // Allocate a new stream
    352   //
    353   NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
    354   if (NewStream == NULL) {
    355     return EFI_OUT_OF_RESOURCES;
    356   }
    357 
    358   if (AllocateBuffer) {
    359     //
    360     // if we're here, we're double buffering, allocate the buffer and copy the
    361     // data in
    362     //
    363     if (SectionStreamLength > 0) {
    364       NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
    365       if (NewStream->StreamBuffer == NULL) {
    366         CoreFreePool (NewStream);
    367         return EFI_OUT_OF_RESOURCES;
    368       }
    369       //
    370       // Copy in stream data
    371       //
    372       CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
    373     } else {
    374       //
    375       // It's possible to have a zero length section stream.
    376       //
    377       NewStream->StreamBuffer = NULL;
    378     }
    379   } else {
    380     //
    381     // If were here, the caller has supplied the buffer (it's an internal call)
    382     // so just assign the buffer.  This happens when we open section streams
    383     // as a result of expanding an encapsulating section.
    384     //
    385     NewStream->StreamBuffer = SectionStream;
    386   }
    387 
    388   //
    389   // Initialize the rest of the section stream
    390   //
    391   NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
    392   NewStream->StreamHandle = (UINTN) NewStream;
    393   NewStream->StreamLength = SectionStreamLength;
    394   InitializeListHead (&NewStream->Children);
    395   NewStream->AuthenticationStatus = AuthenticationStatus;
    396 
    397   //
    398   // Add new stream to stream list
    399   //
    400   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
    401   InsertTailList (&mStreamRoot, &NewStream->Link);
    402   CoreRestoreTpl (OldTpl);
    403 
    404   *SectionStreamHandle = NewStream->StreamHandle;
    405 
    406   return EFI_SUCCESS;
    407 }
    408 
    409 
    410 /**
    411   SEP member function.  This function creates and returns a new section stream
    412   handle to represent the new section stream.
    413 
    414   @param  SectionStreamLength    Size in bytes of the section stream.
    415   @param  SectionStream          Buffer containing the new section stream.
    416   @param  SectionStreamHandle    A pointer to a caller allocated UINTN that on
    417                                  output contains the new section stream handle.
    418 
    419   @retval EFI_SUCCESS            The section stream is created successfully.
    420   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
    421   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
    422                                  of last section.
    423 
    424 **/
    425 EFI_STATUS
    426 EFIAPI
    427 OpenSectionStream (
    428   IN     UINTN                                     SectionStreamLength,
    429   IN     VOID                                      *SectionStream,
    430      OUT UINTN                                     *SectionStreamHandle
    431   )
    432 {
    433   //
    434   // Check to see section stream looks good...
    435   //
    436   if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
    437     return EFI_INVALID_PARAMETER;
    438   }
    439 
    440   return OpenSectionStreamEx (
    441            SectionStreamLength,
    442            SectionStream,
    443            FALSE,
    444            0,
    445            SectionStreamHandle
    446            );
    447 }
    448 
    449 
    450 
    451 /**
    452   Worker function.  Determine if the input stream:child matches the input type.
    453 
    454   @param  Stream                 Indicates the section stream associated with the
    455                                  child
    456   @param  Child                  Indicates the child to check
    457   @param  SearchType             Indicates the type of section to check against
    458                                  for
    459   @param  SectionDefinitionGuid  Indicates the GUID to check against if the type
    460                                  is EFI_SECTION_GUID_DEFINED
    461 
    462   @retval TRUE                   The child matches
    463   @retval FALSE                  The child doesn't match
    464 
    465 **/
    466 BOOLEAN
    467 ChildIsType (
    468   IN CORE_SECTION_STREAM_NODE *Stream,
    469   IN CORE_SECTION_CHILD_NODE  *Child,
    470   IN EFI_SECTION_TYPE         SearchType,
    471   IN EFI_GUID                 *SectionDefinitionGuid
    472   )
    473 {
    474   EFI_GUID_DEFINED_SECTION    *GuidedSection;
    475 
    476   if (SearchType == EFI_SECTION_ALL) {
    477     return TRUE;
    478   }
    479   if (Child->Type != SearchType) {
    480     return FALSE;
    481   }
    482   if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
    483     return TRUE;
    484   }
    485   GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
    486   if (IS_SECTION2 (GuidedSection)) {
    487     return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *) GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
    488   } else {
    489     return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
    490   }
    491 }
    492 
    493 /**
    494   Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
    495 
    496   @param GuidedSectionGuid          The Guided Section GUID.
    497   @param GuidedSectionExtraction    A pointer to the pointer to the supported Guided Section Extraction Protocol
    498                                     for the Guided Section.
    499 
    500   @return TRUE      The GuidedSectionGuid could be identified, and the pointer to
    501                     the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
    502   @return FALSE     The GuidedSectionGuid could not be identified, or
    503                     the Guided Section Extraction Protocol has not been installed yet.
    504 
    505 **/
    506 BOOLEAN
    507 VerifyGuidedSectionGuid (
    508   IN  EFI_GUID                                  *GuidedSectionGuid,
    509   OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL    **GuidedSectionExtraction
    510   )
    511 {
    512   EFI_GUID              *GuidRecorded;
    513   VOID                  *Interface;
    514   EFI_STATUS            Status;
    515 
    516   Interface = NULL;
    517 
    518   //
    519   // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
    520   //
    521   Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **) &GuidRecorded);
    522   if (Status == EFI_SUCCESS) {
    523     if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
    524       //
    525       // Found the recorded GuidedSectionGuid.
    526       //
    527       Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **) &Interface);
    528       if (!EFI_ERROR (Status) && Interface != NULL) {
    529         //
    530         // Found the supported Guided Section Extraction Porotocol for the Guided Section.
    531         //
    532         *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *) Interface;
    533         return TRUE;
    534       }
    535       return FALSE;
    536     }
    537   }
    538 
    539   return FALSE;
    540 }
    541 
    542 /**
    543   RPN callback function. Initializes the section stream
    544   when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
    545 
    546   @param Event               The event that fired
    547   @param RpnContext          A pointer to the context that allows us to identify
    548                              the relevent encapsulation.
    549 **/
    550 VOID
    551 EFIAPI
    552 NotifyGuidedExtraction (
    553   IN   EFI_EVENT   Event,
    554   IN   VOID        *RpnContext
    555   )
    556 {
    557   EFI_STATUS                              Status;
    558   EFI_GUID_DEFINED_SECTION                *GuidedHeader;
    559   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *GuidedExtraction;
    560   VOID                                    *NewStreamBuffer;
    561   UINTN                                   NewStreamBufferSize;
    562   UINT32                                  AuthenticationStatus;
    563   RPN_EVENT_CONTEXT                       *Context;
    564 
    565   Context = RpnContext;
    566 
    567   GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
    568   ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
    569 
    570   if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
    571     return;
    572   }
    573 
    574   Status = GuidedExtraction->ExtractSection (
    575                                GuidedExtraction,
    576                                GuidedHeader,
    577                                &NewStreamBuffer,
    578                                &NewStreamBufferSize,
    579                                &AuthenticationStatus
    580                                );
    581   ASSERT_EFI_ERROR (Status);
    582 
    583   //
    584   // Make sure we initialize the new stream with the correct
    585   // authentication status for both aggregate and local status fields.
    586   //
    587   if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
    588     //
    589     // OR in the parent stream's aggregate status.
    590     //
    591     AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
    592   } else {
    593     //
    594     // since there's no authentication data contributed by the section,
    595     // just inherit the full value from our immediate parent.
    596     //
    597     AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
    598   }
    599 
    600   Status = OpenSectionStreamEx (
    601              NewStreamBufferSize,
    602              NewStreamBuffer,
    603              FALSE,
    604              AuthenticationStatus,
    605              &Context->ChildNode->EncapsulatedStreamHandle
    606              );
    607   ASSERT_EFI_ERROR (Status);
    608 
    609   //
    610   //  Close the event when done.
    611   //
    612   gBS->CloseEvent (Event);
    613   Context->ChildNode->Event = NULL;
    614   FreePool (Context);
    615 }
    616 
    617 /**
    618   Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
    619 
    620   @param ParentStream        Indicates the parent of the ecnapsulation section (child)
    621   @param ChildNode           Indicates the child node that is the encapsulation section.
    622 
    623 **/
    624 VOID
    625 CreateGuidedExtractionRpnEvent (
    626   IN CORE_SECTION_STREAM_NODE      *ParentStream,
    627   IN CORE_SECTION_CHILD_NODE       *ChildNode
    628   )
    629 {
    630   RPN_EVENT_CONTEXT *Context;
    631 
    632   //
    633   // Allocate new event structure and context
    634   //
    635   Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
    636   ASSERT (Context != NULL);
    637 
    638   Context->ChildNode = ChildNode;
    639   Context->ParentStream = ParentStream;
    640 
    641   Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
    642                                 Context->ChildNode->EncapsulationGuid,
    643                                 TPL_NOTIFY,
    644                                 NotifyGuidedExtraction,
    645                                 Context,
    646                                 &Context->Registration
    647                                 );
    648 }
    649 
    650 /**
    651   Worker function.  Constructor for new child nodes.
    652 
    653   @param  Stream                 Indicates the section stream in which to add the
    654                                  child.
    655   @param  ChildOffset            Indicates the offset in Stream that is the
    656                                  beginning of the child section.
    657   @param  ChildNode              Indicates the Callee allocated and initialized
    658                                  child.
    659 
    660   @retval EFI_SUCCESS            Child node was found and returned.
    661                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
    662   @retval EFI_PROTOCOL_ERROR     Encapsulation sections produce new stream
    663                                  handles when the child node is created.  If the
    664                                  section type is GUID defined, and the extraction
    665                                  GUID does not exist, and producing the stream
    666                                  requires the GUID, then a protocol error is
    667                                  generated and no child is produced. Values
    668                                  returned by OpenSectionStreamEx.
    669 
    670 **/
    671 EFI_STATUS
    672 CreateChildNode (
    673   IN     CORE_SECTION_STREAM_NODE              *Stream,
    674   IN     UINT32                                ChildOffset,
    675   OUT    CORE_SECTION_CHILD_NODE               **ChildNode
    676   )
    677 {
    678   EFI_STATUS                                   Status;
    679   EFI_COMMON_SECTION_HEADER                    *SectionHeader;
    680   EFI_COMPRESSION_SECTION                      *CompressionHeader;
    681   EFI_GUID_DEFINED_SECTION                     *GuidedHeader;
    682   EFI_DECOMPRESS_PROTOCOL                      *Decompress;
    683   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL       *GuidedExtraction;
    684   VOID                                         *NewStreamBuffer;
    685   VOID                                         *ScratchBuffer;
    686   UINT32                                       ScratchSize;
    687   UINTN                                        NewStreamBufferSize;
    688   UINT32                                       AuthenticationStatus;
    689   VOID                                         *CompressionSource;
    690   UINT32                                       CompressionSourceSize;
    691   UINT32                                       UncompressedLength;
    692   UINT8                                        CompressionType;
    693   UINT16                                       GuidedSectionAttributes;
    694 
    695   CORE_SECTION_CHILD_NODE                      *Node;
    696 
    697   SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
    698 
    699   //
    700   // Allocate a new node
    701   //
    702   *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
    703   Node = *ChildNode;
    704   if (Node == NULL) {
    705     return EFI_OUT_OF_RESOURCES;
    706   }
    707 
    708   //
    709   // Now initialize it
    710   //
    711   Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
    712   Node->Type = SectionHeader->Type;
    713   if (IS_SECTION2 (SectionHeader)) {
    714     Node->Size = SECTION2_SIZE (SectionHeader);
    715   } else {
    716     Node->Size = SECTION_SIZE (SectionHeader);
    717   }
    718   Node->OffsetInStream = ChildOffset;
    719   Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
    720   Node->EncapsulationGuid = NULL;
    721 
    722   //
    723   // If it's an encapsulating section, then create the new section stream also
    724   //
    725   switch (Node->Type) {
    726     case EFI_SECTION_COMPRESSION:
    727       //
    728       // Get the CompressionSectionHeader
    729       //
    730       if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
    731         CoreFreePool (Node);
    732         return EFI_NOT_FOUND;
    733       }
    734 
    735       CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
    736 
    737       if (IS_SECTION2 (CompressionHeader)) {
    738         CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
    739         CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
    740         UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->UncompressedLength;
    741         CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->CompressionType;
    742       } else {
    743         CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
    744         CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
    745         UncompressedLength = CompressionHeader->UncompressedLength;
    746         CompressionType = CompressionHeader->CompressionType;
    747       }
    748 
    749       //
    750       // Allocate space for the new stream
    751       //
    752       if (UncompressedLength > 0) {
    753         NewStreamBufferSize = UncompressedLength;
    754         NewStreamBuffer = AllocatePool (NewStreamBufferSize);
    755         if (NewStreamBuffer == NULL) {
    756           CoreFreePool (Node);
    757           return EFI_OUT_OF_RESOURCES;
    758         }
    759 
    760         if (CompressionType == EFI_NOT_COMPRESSED) {
    761           //
    762           // stream is not actually compressed, just encapsulated.  So just copy it.
    763           //
    764           CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
    765         } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
    766           //
    767           // Only support the EFI_SATNDARD_COMPRESSION algorithm.
    768           //
    769 
    770           //
    771           // Decompress the stream
    772           //
    773           Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
    774           ASSERT_EFI_ERROR (Status);
    775           ASSERT (Decompress != NULL);
    776 
    777           Status = Decompress->GetInfo (
    778                                  Decompress,
    779                                  CompressionSource,
    780                                  CompressionSourceSize,
    781                                  (UINT32 *)&NewStreamBufferSize,
    782                                  &ScratchSize
    783                                  );
    784           if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
    785             CoreFreePool (Node);
    786             CoreFreePool (NewStreamBuffer);
    787             if (!EFI_ERROR (Status)) {
    788               Status = EFI_BAD_BUFFER_SIZE;
    789             }
    790             return Status;
    791           }
    792 
    793           ScratchBuffer = AllocatePool (ScratchSize);
    794           if (ScratchBuffer == NULL) {
    795             CoreFreePool (Node);
    796             CoreFreePool (NewStreamBuffer);
    797             return EFI_OUT_OF_RESOURCES;
    798           }
    799 
    800           Status = Decompress->Decompress (
    801                                  Decompress,
    802                                  CompressionSource,
    803                                  CompressionSourceSize,
    804                                  NewStreamBuffer,
    805                                  (UINT32)NewStreamBufferSize,
    806                                  ScratchBuffer,
    807                                  ScratchSize
    808                                  );
    809           CoreFreePool (ScratchBuffer);
    810           if (EFI_ERROR (Status)) {
    811             CoreFreePool (Node);
    812             CoreFreePool (NewStreamBuffer);
    813             return Status;
    814           }
    815         }
    816       } else {
    817         NewStreamBuffer = NULL;
    818         NewStreamBufferSize = 0;
    819       }
    820 
    821       Status = OpenSectionStreamEx (
    822                  NewStreamBufferSize,
    823                  NewStreamBuffer,
    824                  FALSE,
    825                  Stream->AuthenticationStatus,
    826                  &Node->EncapsulatedStreamHandle
    827                  );
    828       if (EFI_ERROR (Status)) {
    829         CoreFreePool (Node);
    830         CoreFreePool (NewStreamBuffer);
    831         return Status;
    832       }
    833       break;
    834 
    835     case EFI_SECTION_GUID_DEFINED:
    836       GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
    837       if (IS_SECTION2 (GuidedHeader)) {
    838         Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->SectionDefinitionGuid);
    839         GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->Attributes;
    840       } else {
    841         Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
    842         GuidedSectionAttributes = GuidedHeader->Attributes;
    843       }
    844       if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
    845         //
    846         // NewStreamBuffer is always allocated by ExtractSection... No caller
    847         // allocation here.
    848         //
    849         Status = GuidedExtraction->ExtractSection (
    850                                      GuidedExtraction,
    851                                      GuidedHeader,
    852                                      &NewStreamBuffer,
    853                                      &NewStreamBufferSize,
    854                                      &AuthenticationStatus
    855                                      );
    856         if (EFI_ERROR (Status)) {
    857           CoreFreePool (*ChildNode);
    858           return EFI_PROTOCOL_ERROR;
    859         }
    860 
    861         //
    862         // Make sure we initialize the new stream with the correct
    863         // authentication status for both aggregate and local status fields.
    864         //
    865         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
    866           //
    867           // OR in the parent stream's aggregate status.
    868           //
    869           AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
    870         } else {
    871           //
    872           // since there's no authentication data contributed by the section,
    873           // just inherit the full value from our immediate parent.
    874           //
    875           AuthenticationStatus = Stream->AuthenticationStatus;
    876         }
    877 
    878         Status = OpenSectionStreamEx (
    879                    NewStreamBufferSize,
    880                    NewStreamBuffer,
    881                    FALSE,
    882                    AuthenticationStatus,
    883                    &Node->EncapsulatedStreamHandle
    884                    );
    885         if (EFI_ERROR (Status)) {
    886           CoreFreePool (*ChildNode);
    887           CoreFreePool (NewStreamBuffer);
    888           return Status;
    889         }
    890       } else {
    891         //
    892         // There's no GUIDed section extraction protocol available.
    893         //
    894         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
    895           //
    896           // If the section REQUIRES an extraction protocol, register for RPN
    897           // when the required GUIDed extraction protocol becomes available.
    898           //
    899           CreateGuidedExtractionRpnEvent (Stream, Node);
    900         } else {
    901           //
    902           // Figure out the proper authentication status
    903           //
    904           AuthenticationStatus = Stream->AuthenticationStatus;
    905 
    906           if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
    907             AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
    908           }
    909 
    910           if (IS_SECTION2 (GuidedHeader)) {
    911             Status = OpenSectionStreamEx (
    912                        SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
    913                        (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
    914                        TRUE,
    915                        AuthenticationStatus,
    916                        &Node->EncapsulatedStreamHandle
    917                        );
    918           } else {
    919             Status = OpenSectionStreamEx (
    920                        SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
    921                        (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
    922                        TRUE,
    923                        AuthenticationStatus,
    924                        &Node->EncapsulatedStreamHandle
    925                        );
    926           }
    927           if (EFI_ERROR (Status)) {
    928             CoreFreePool (Node);
    929             return Status;
    930           }
    931         }
    932       }
    933 
    934       break;
    935 
    936     default:
    937 
    938       //
    939       // Nothing to do if it's a leaf
    940       //
    941       break;
    942   }
    943 
    944   //
    945   // Last, add the new child node to the stream
    946   //
    947   InsertTailList (&Stream->Children, &Node->Link);
    948 
    949   return EFI_SUCCESS;
    950 }
    951 
    952 
    953 /**
    954   Worker function  Recursively searches / builds section stream database
    955   looking for requested section.
    956 
    957   @param  SourceStream           Indicates the section stream in which to do the
    958                                  search.
    959   @param  SearchType             Indicates the type of section to search for.
    960   @param  SectionInstance        Indicates which instance of section to find.
    961                                  This is an in/out parameter to deal with
    962                                  recursions.
    963   @param  SectionDefinitionGuid  Guid of section definition
    964   @param  FoundChild             Output indicating the child node that is found.
    965   @param  FoundStream            Output indicating which section stream the child
    966                                  was found in.  If this stream was generated as a
    967                                  result of an encapsulation section, the
    968                                  streamhandle is visible within the SEP driver
    969                                  only.
    970   @param  AuthenticationStatus   Indicates the authentication status of the found section.
    971 
    972   @retval EFI_SUCCESS            Child node was found and returned.
    973                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
    974   @retval EFI_NOT_FOUND          Requested child node does not exist.
    975   @retval EFI_PROTOCOL_ERROR     a required GUIDED section extraction protocol
    976                                  does not exist
    977 
    978 **/
    979 EFI_STATUS
    980 FindChildNode (
    981   IN     CORE_SECTION_STREAM_NODE                   *SourceStream,
    982   IN     EFI_SECTION_TYPE                           SearchType,
    983   IN OUT UINTN                                      *SectionInstance,
    984   IN     EFI_GUID                                   *SectionDefinitionGuid,
    985   OUT    CORE_SECTION_CHILD_NODE                    **FoundChild,
    986   OUT    CORE_SECTION_STREAM_NODE                   **FoundStream,
    987   OUT    UINT32                                     *AuthenticationStatus
    988   )
    989 {
    990   CORE_SECTION_CHILD_NODE                       *CurrentChildNode;
    991   CORE_SECTION_CHILD_NODE                       *RecursedChildNode;
    992   CORE_SECTION_STREAM_NODE                      *RecursedFoundStream;
    993   UINT32                                        NextChildOffset;
    994   EFI_STATUS                                    ErrorStatus;
    995   EFI_STATUS                                    Status;
    996 
    997   CurrentChildNode = NULL;
    998   ErrorStatus = EFI_NOT_FOUND;
    999 
   1000   if (SourceStream->StreamLength == 0) {
   1001     return EFI_NOT_FOUND;
   1002   }
   1003 
   1004   if (IsListEmpty (&SourceStream->Children) &&
   1005       SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
   1006     //
   1007     // This occurs when a section stream exists, but no child sections
   1008     // have been parsed out yet.  Therefore, extract the first child and add it
   1009     // to the list of children so we can get started.
   1010     // Section stream may contain an array of zero or more bytes.
   1011     // So, its size should be >= the size of commen section header.
   1012     //
   1013     Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
   1014     if (EFI_ERROR (Status)) {
   1015       return Status;
   1016     }
   1017   }
   1018 
   1019   //
   1020   // At least one child has been parsed out of the section stream.  So, walk
   1021   // through the sections that have already been parsed out looking for the
   1022   // requested section, if necessary, continue parsing section stream and
   1023   // adding children until either the requested section is found, or we run
   1024   // out of data
   1025   //
   1026   CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
   1027 
   1028   for (;;) {
   1029     ASSERT (CurrentChildNode != NULL);
   1030     if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
   1031       //
   1032       // The type matches, so check the instance count to see if it's the one we want
   1033       //
   1034       (*SectionInstance)--;
   1035       if (*SectionInstance == 0) {
   1036         //
   1037         // Got it!
   1038         //
   1039         *FoundChild = CurrentChildNode;
   1040         *FoundStream = SourceStream;
   1041         *AuthenticationStatus = SourceStream->AuthenticationStatus;
   1042         return EFI_SUCCESS;
   1043       }
   1044     }
   1045 
   1046     if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
   1047       //
   1048       // If the current node is an encapsulating node, recurse into it...
   1049       //
   1050       Status = FindChildNode (
   1051                 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
   1052                 SearchType,
   1053                 SectionInstance,
   1054                 SectionDefinitionGuid,
   1055                 &RecursedChildNode,
   1056                 &RecursedFoundStream,
   1057                 AuthenticationStatus
   1058                 );
   1059       //
   1060       // If the status is not EFI_SUCCESS, just save the error code and continue
   1061       // to find the request child node in the rest stream.
   1062       //
   1063       if (*SectionInstance == 0) {
   1064         ASSERT_EFI_ERROR (Status);
   1065         *FoundChild = RecursedChildNode;
   1066         *FoundStream = RecursedFoundStream;
   1067         return EFI_SUCCESS;
   1068       } else {
   1069         ErrorStatus = Status;
   1070       }
   1071     } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
   1072       //
   1073       // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
   1074       // because a required GUIDED section extraction protocol does not exist.
   1075       // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
   1076       //
   1077       ErrorStatus = EFI_PROTOCOL_ERROR;
   1078     }
   1079 
   1080     if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
   1081       //
   1082       // We haven't found the child node we're interested in yet, but there's
   1083       // still more nodes that have already been parsed so get the next one
   1084       // and continue searching..
   1085       //
   1086       CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
   1087     } else {
   1088       //
   1089       // We've exhausted children that have already been parsed, so see if
   1090       // there's any more data and continue parsing out more children if there
   1091       // is.
   1092       //
   1093       NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
   1094       //
   1095       // Round up to 4 byte boundary
   1096       //
   1097       NextChildOffset += 3;
   1098       NextChildOffset &= ~(UINTN) 3;
   1099       if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
   1100         //
   1101         // There's an unparsed child remaining in the stream, so create a new child node
   1102         //
   1103         Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
   1104         if (EFI_ERROR (Status)) {
   1105           return Status;
   1106         }
   1107       } else {
   1108         ASSERT (EFI_ERROR (ErrorStatus));
   1109         return ErrorStatus;
   1110       }
   1111     }
   1112   }
   1113 }
   1114 
   1115 
   1116 /**
   1117   Worker function.  Search stream database for requested stream handle.
   1118 
   1119   @param  SearchHandle           Indicates which stream to look for.
   1120   @param  FoundStream            Output pointer to the found stream.
   1121 
   1122   @retval EFI_SUCCESS            StreamHandle was found and *FoundStream contains
   1123                                  the stream node.
   1124   @retval EFI_NOT_FOUND          SearchHandle was not found in the stream
   1125                                  database.
   1126 
   1127 **/
   1128 EFI_STATUS
   1129 FindStreamNode (
   1130   IN  UINTN                                     SearchHandle,
   1131   OUT CORE_SECTION_STREAM_NODE                  **FoundStream
   1132   )
   1133 {
   1134   CORE_SECTION_STREAM_NODE                      *StreamNode;
   1135 
   1136   if (!IsListEmpty (&mStreamRoot)) {
   1137     StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
   1138     for (;;) {
   1139       if (StreamNode->StreamHandle == SearchHandle) {
   1140         *FoundStream = StreamNode;
   1141         return EFI_SUCCESS;
   1142       } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
   1143         break;
   1144       } else {
   1145         StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
   1146       }
   1147     }
   1148   }
   1149 
   1150   return EFI_NOT_FOUND;
   1151 }
   1152 
   1153 
   1154 /**
   1155   SEP member function.  Retrieves requested section from section stream.
   1156 
   1157   @param  SectionStreamHandle   The section stream from which to extract the
   1158                                 requested section.
   1159   @param  SectionType           A pointer to the type of section to search for.
   1160   @param  SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
   1161                                 then SectionDefinitionGuid indicates which of
   1162                                 these types of sections to search for.
   1163   @param  SectionInstance       Indicates which instance of the requested
   1164                                 section to return.
   1165   @param  Buffer                Double indirection to buffer.  If *Buffer is
   1166                                 non-null on input, then the buffer is caller
   1167                                 allocated.  If Buffer is NULL, then the buffer
   1168                                 is callee allocated.  In either case, the
   1169                                 requried buffer size is returned in *BufferSize.
   1170   @param  BufferSize            On input, indicates the size of *Buffer if
   1171                                 *Buffer is non-null on input.  On output,
   1172                                 indicates the required size (allocated size if
   1173                                 callee allocated) of *Buffer.
   1174   @param  AuthenticationStatus  A pointer to a caller-allocated UINT32 that
   1175                                 indicates the authentication status of the
   1176                                 output buffer. If the input section's
   1177                                 GuidedSectionHeader.Attributes field
   1178                                 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
   1179                                 bit as clear, AuthenticationStatus must return
   1180                                 zero. Both local bits (19:16) and aggregate
   1181                                 bits (3:0) in AuthenticationStatus are returned
   1182                                 by ExtractSection(). These bits reflect the
   1183                                 status of the extraction operation. The bit
   1184                                 pattern in both regions must be the same, as
   1185                                 the local and aggregate authentication statuses
   1186                                 have equivalent meaning at this level. If the
   1187                                 function returns anything other than
   1188                                 EFI_SUCCESS, the value of *AuthenticationStatus
   1189                                 is undefined.
   1190   @param  IsFfs3Fv              Indicates the FV format.
   1191 
   1192   @retval EFI_SUCCESS           Section was retrieved successfully
   1193   @retval EFI_PROTOCOL_ERROR    A GUID defined section was encountered in the
   1194                                 section stream with its
   1195                                 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
   1196                                 but there was no corresponding GUIDed Section
   1197                                 Extraction Protocol in the handle database.
   1198                                 *Buffer is unmodified.
   1199   @retval EFI_NOT_FOUND         An error was encountered when parsing the
   1200                                 SectionStream.  This indicates the SectionStream
   1201                                 is not correctly formatted.
   1202   @retval EFI_NOT_FOUND         The requested section does not exist.
   1203   @retval EFI_OUT_OF_RESOURCES  The system has insufficient resources to process
   1204                                 the request.
   1205   @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
   1206   @retval EFI_WARN_TOO_SMALL    The size of the caller allocated input buffer is
   1207                                 insufficient to contain the requested section.
   1208                                 The input buffer is filled and section contents
   1209                                 are truncated.
   1210 
   1211 **/
   1212 EFI_STATUS
   1213 EFIAPI
   1214 GetSection (
   1215   IN UINTN                                              SectionStreamHandle,
   1216   IN EFI_SECTION_TYPE                                   *SectionType,
   1217   IN EFI_GUID                                           *SectionDefinitionGuid,
   1218   IN UINTN                                              SectionInstance,
   1219   IN VOID                                               **Buffer,
   1220   IN OUT UINTN                                          *BufferSize,
   1221   OUT UINT32                                            *AuthenticationStatus,
   1222   IN BOOLEAN                                            IsFfs3Fv
   1223   )
   1224 {
   1225   CORE_SECTION_STREAM_NODE                              *StreamNode;
   1226   EFI_TPL                                               OldTpl;
   1227   EFI_STATUS                                            Status;
   1228   CORE_SECTION_CHILD_NODE                               *ChildNode;
   1229   CORE_SECTION_STREAM_NODE                              *ChildStreamNode;
   1230   UINTN                                                 CopySize;
   1231   UINT32                                                ExtractedAuthenticationStatus;
   1232   UINTN                                                 Instance;
   1233   UINT8                                                 *CopyBuffer;
   1234   UINTN                                                 SectionSize;
   1235   EFI_COMMON_SECTION_HEADER                             *Section;
   1236 
   1237 
   1238   ChildStreamNode = NULL;
   1239   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
   1240   Instance = SectionInstance + 1;
   1241 
   1242   //
   1243   // Locate target stream
   1244   //
   1245   Status = FindStreamNode (SectionStreamHandle, &StreamNode);
   1246   if (EFI_ERROR (Status)) {
   1247     Status = EFI_INVALID_PARAMETER;
   1248     goto GetSection_Done;
   1249   }
   1250 
   1251   //
   1252   // Found the stream, now locate and return the appropriate section
   1253   //
   1254   if (SectionType == NULL) {
   1255     //
   1256     // SectionType == NULL means return the WHOLE section stream...
   1257     //
   1258     CopySize = StreamNode->StreamLength;
   1259     CopyBuffer = StreamNode->StreamBuffer;
   1260     *AuthenticationStatus = StreamNode->AuthenticationStatus;
   1261   } else {
   1262     //
   1263     // There's a requested section type, so go find it and return it...
   1264     //
   1265     Status = FindChildNode (
   1266                StreamNode,
   1267                *SectionType,
   1268                &Instance,
   1269                SectionDefinitionGuid,
   1270                &ChildNode,
   1271                &ChildStreamNode,
   1272                &ExtractedAuthenticationStatus
   1273                );
   1274     if (EFI_ERROR (Status)) {
   1275       goto GetSection_Done;
   1276     }
   1277 
   1278     Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
   1279 
   1280     if (IS_SECTION2 (Section)) {
   1281       ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
   1282       if (!IsFfs3Fv) {
   1283         DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
   1284         Status = EFI_NOT_FOUND;
   1285         goto GetSection_Done;
   1286       }
   1287       CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
   1288       CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);
   1289     } else {
   1290       CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
   1291       CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);
   1292     }
   1293     *AuthenticationStatus = ExtractedAuthenticationStatus;
   1294   }
   1295 
   1296   SectionSize = CopySize;
   1297   if (*Buffer != NULL) {
   1298     //
   1299     // Caller allocated buffer.  Fill to size and return required size...
   1300     //
   1301     if (*BufferSize < CopySize) {
   1302       Status = EFI_WARN_BUFFER_TOO_SMALL;
   1303       CopySize = *BufferSize;
   1304     }
   1305   } else {
   1306     //
   1307     // Callee allocated buffer.  Allocate buffer and return size.
   1308     //
   1309     *Buffer = AllocatePool (CopySize);
   1310     if (*Buffer == NULL) {
   1311       Status = EFI_OUT_OF_RESOURCES;
   1312       goto GetSection_Done;
   1313     }
   1314   }
   1315   CopyMem (*Buffer, CopyBuffer, CopySize);
   1316   *BufferSize = SectionSize;
   1317 
   1318 GetSection_Done:
   1319   CoreRestoreTpl (OldTpl);
   1320 
   1321   return Status;
   1322 }
   1323 
   1324 
   1325 /**
   1326   Worker function.  Destructor for child nodes.
   1327 
   1328   @param  ChildNode              Indicates the node to destroy
   1329 
   1330 **/
   1331 VOID
   1332 FreeChildNode (
   1333   IN  CORE_SECTION_CHILD_NODE                   *ChildNode
   1334   )
   1335 {
   1336   ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
   1337   //
   1338   // Remove the child from it's list
   1339   //
   1340   RemoveEntryList (&ChildNode->Link);
   1341 
   1342   if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
   1343     //
   1344     // If it's an encapsulating section, we close the resulting section stream.
   1345     // CloseSectionStream will free all memory associated with the stream.
   1346     //
   1347     CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
   1348   }
   1349 
   1350   if (ChildNode->Event != NULL) {
   1351     gBS->CloseEvent (ChildNode->Event);
   1352   }
   1353 
   1354   //
   1355   // Last, free the child node itself
   1356   //
   1357   CoreFreePool (ChildNode);
   1358 }
   1359 
   1360 
   1361 /**
   1362   SEP member function.  Deletes an existing section stream
   1363 
   1364   @param  StreamHandleToClose    Indicates the stream to close
   1365   @param  FreeStreamBuffer       TRUE - Need to free stream buffer;
   1366                                  FALSE - No need to free stream buffer.
   1367 
   1368   @retval EFI_SUCCESS            The section stream is closed sucessfully.
   1369   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
   1370   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
   1371                                  of last section.
   1372 
   1373 **/
   1374 EFI_STATUS
   1375 EFIAPI
   1376 CloseSectionStream (
   1377   IN  UINTN                                     StreamHandleToClose,
   1378   IN  BOOLEAN                                   FreeStreamBuffer
   1379   )
   1380 {
   1381   CORE_SECTION_STREAM_NODE                      *StreamNode;
   1382   EFI_TPL                                       OldTpl;
   1383   EFI_STATUS                                    Status;
   1384   LIST_ENTRY                                    *Link;
   1385   CORE_SECTION_CHILD_NODE                       *ChildNode;
   1386 
   1387   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
   1388 
   1389   //
   1390   // Locate target stream
   1391   //
   1392   Status = FindStreamNode (StreamHandleToClose, &StreamNode);
   1393   if (!EFI_ERROR (Status)) {
   1394     //
   1395     // Found the stream, so close it
   1396     //
   1397     RemoveEntryList (&StreamNode->Link);
   1398     while (!IsListEmpty (&StreamNode->Children)) {
   1399       Link = GetFirstNode (&StreamNode->Children);
   1400       ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
   1401       FreeChildNode (ChildNode);
   1402     }
   1403     if (FreeStreamBuffer) {
   1404       CoreFreePool (StreamNode->StreamBuffer);
   1405     }
   1406     CoreFreePool (StreamNode);
   1407     Status = EFI_SUCCESS;
   1408   } else {
   1409     Status = EFI_INVALID_PARAMETER;
   1410   }
   1411 
   1412   CoreRestoreTpl (OldTpl);
   1413   return Status;
   1414 }
   1415 
   1416 
   1417 /**
   1418   The ExtractSection() function processes the input section and
   1419   allocates a buffer from the pool in which it returns the section
   1420   contents. If the section being extracted contains
   1421   authentication information (the section's
   1422   GuidedSectionHeader.Attributes field has the
   1423   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
   1424   returned in AuthenticationStatus must reflect the results of
   1425   the authentication operation. Depending on the algorithm and
   1426   size of the encapsulated data, the time that is required to do
   1427   a full authentication may be prohibitively long for some
   1428   classes of systems. To indicate this, use
   1429   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
   1430   the security policy driver (see the Platform Initialization
   1431   Driver Execution Environment Core Interface Specification for
   1432   more details and the GUID definition). If the
   1433   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
   1434   database, then, if possible, full authentication should be
   1435   skipped and the section contents simply returned in the
   1436   OutputBuffer. In this case, the
   1437   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
   1438   must be set on return. ExtractSection() is callable only from
   1439   TPL_NOTIFY and below. Behavior of ExtractSection() at any
   1440   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
   1441   defined in RaiseTPL() in the UEFI 2.0 specification.
   1442 
   1443 
   1444   @param This         Indicates the
   1445                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
   1446   @param InputSection Buffer containing the input GUIDed section
   1447                       to be processed. OutputBuffer OutputBuffer
   1448                       is allocated from boot services pool
   1449                       memory and contains the new section
   1450                       stream. The caller is responsible for
   1451                       freeing this buffer.
   1452   @param OutputBuffer *OutputBuffer is allocated from boot services
   1453                       pool memory and contains the new section stream.
   1454                       The caller is responsible for freeing this buffer.
   1455   @param OutputSize   A pointer to a caller-allocated UINTN in
   1456                       which the size of OutputBuffer allocation
   1457                       is stored. If the function returns
   1458                       anything other than EFI_SUCCESS, the value
   1459                       of OutputSize is undefined.
   1460 
   1461   @param AuthenticationStatus A pointer to a caller-allocated
   1462                               UINT32 that indicates the
   1463                               authentication status of the
   1464                               output buffer. If the input
   1465                               section's
   1466                               GuidedSectionHeader.Attributes
   1467                               field has the
   1468                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
   1469                               bit as clear, AuthenticationStatus
   1470                               must return zero. Both local bits
   1471                               (19:16) and aggregate bits (3:0)
   1472                               in AuthenticationStatus are
   1473                               returned by ExtractSection().
   1474                               These bits reflect the status of
   1475                               the extraction operation. The bit
   1476                               pattern in both regions must be
   1477                               the same, as the local and
   1478                               aggregate authentication statuses
   1479                               have equivalent meaning at this
   1480                               level. If the function returns
   1481                               anything other than EFI_SUCCESS,
   1482                               the value of AuthenticationStatus
   1483                               is undefined.
   1484 
   1485 
   1486   @retval EFI_SUCCESS          The InputSection was successfully
   1487                                processed and the section contents were
   1488                                returned.
   1489 
   1490   @retval EFI_OUT_OF_RESOURCES The system has insufficient
   1491                                resources to process the
   1492                                request.
   1493 
   1494   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
   1495                                 not match this instance of the
   1496                                 GUIDed Section Extraction
   1497                                 Protocol.
   1498 
   1499 **/
   1500 EFI_STATUS
   1501 EFIAPI
   1502 CustomGuidedSectionExtract (
   1503   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
   1504   IN CONST  VOID                                   *InputSection,
   1505   OUT       VOID                                   **OutputBuffer,
   1506   OUT       UINTN                                  *OutputSize,
   1507   OUT       UINT32                                 *AuthenticationStatus
   1508   )
   1509 {
   1510   EFI_STATUS      Status;
   1511   VOID            *ScratchBuffer;
   1512   VOID            *AllocatedOutputBuffer;
   1513   UINT32          OutputBufferSize;
   1514   UINT32          ScratchBufferSize;
   1515   UINT16          SectionAttribute;
   1516 
   1517   //
   1518   // Init local variable
   1519   //
   1520   ScratchBuffer         = NULL;
   1521   AllocatedOutputBuffer = NULL;
   1522 
   1523   //
   1524   // Call GetInfo to get the size and attribute of input guided section data.
   1525   //
   1526   Status = ExtractGuidedSectionGetInfo (
   1527              InputSection,
   1528              &OutputBufferSize,
   1529              &ScratchBufferSize,
   1530              &SectionAttribute
   1531              );
   1532 
   1533   if (EFI_ERROR (Status)) {
   1534     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
   1535     return Status;
   1536   }
   1537 
   1538   if (ScratchBufferSize > 0) {
   1539     //
   1540     // Allocate scratch buffer
   1541     //
   1542     ScratchBuffer = AllocatePool (ScratchBufferSize);
   1543     if (ScratchBuffer == NULL) {
   1544       return EFI_OUT_OF_RESOURCES;
   1545     }
   1546   }
   1547 
   1548   if (OutputBufferSize > 0) {
   1549     //
   1550     // Allocate output buffer
   1551     //
   1552     AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
   1553     if (AllocatedOutputBuffer == NULL) {
   1554       FreePool (ScratchBuffer);
   1555       return EFI_OUT_OF_RESOURCES;
   1556     }
   1557     *OutputBuffer = AllocatedOutputBuffer;
   1558   }
   1559 
   1560   //
   1561   // Call decode function to extract raw data from the guided section.
   1562   //
   1563   Status = ExtractGuidedSectionDecode (
   1564              InputSection,
   1565              OutputBuffer,
   1566              ScratchBuffer,
   1567              AuthenticationStatus
   1568              );
   1569   if (EFI_ERROR (Status)) {
   1570     //
   1571     // Decode failed
   1572     //
   1573     if (AllocatedOutputBuffer != NULL) {
   1574       CoreFreePool (AllocatedOutputBuffer);
   1575     }
   1576     if (ScratchBuffer != NULL) {
   1577       CoreFreePool (ScratchBuffer);
   1578     }
   1579     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
   1580     return Status;
   1581   }
   1582 
   1583   if (*OutputBuffer != AllocatedOutputBuffer) {
   1584     //
   1585     // OutputBuffer was returned as a different value,
   1586     // so copy section contents to the allocated memory buffer.
   1587     //
   1588     CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
   1589     *OutputBuffer = AllocatedOutputBuffer;
   1590   }
   1591 
   1592   //
   1593   // Set real size of output buffer.
   1594   //
   1595   *OutputSize = (UINTN) OutputBufferSize;
   1596 
   1597   //
   1598   // Free unused scratch buffer.
   1599   //
   1600   if (ScratchBuffer != NULL) {
   1601     CoreFreePool (ScratchBuffer);
   1602   }
   1603 
   1604   return EFI_SUCCESS;
   1605 }
   1606