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