REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1654 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1654 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Section Extraction Protocol implementation.
 | |
| 
 | |
|   Stream database is implemented as a linked list of section streams,
 | |
|   where each stream contains a linked list of children, which may be leaves or
 | |
|   encapsulations.
 | |
| 
 | |
|   Children that are encapsulations generate new stream entries
 | |
|   when they are created.  Streams can also be created by calls to
 | |
|   SEP->OpenSectionStream().
 | |
| 
 | |
|   The database is only created far enough to return the requested data from
 | |
|   any given stream, or to determine that the requested data is not found.
 | |
| 
 | |
|   If a GUIDed encapsulation is encountered, there are three possiblilites.
 | |
| 
 | |
|   1) A support protocol is found, in which the stream is simply processed with
 | |
|      the support protocol.
 | |
| 
 | |
|   2) A support protocol is not found, but the data is available to be read
 | |
|      without processing.  In this case, the database is built up through the
 | |
|      recursions to return the data, and a RPN event is set that will enable
 | |
|      the stream in question to be refreshed if and when the required section
 | |
|      extraction protocol is published.This insures the AuthenticationStatus
 | |
|      does not become stale in the cache.
 | |
| 
 | |
|   3) A support protocol is not found, and the data is not available to be read
 | |
|      without it.  This results in EFI_PROTOCOL_ERROR.
 | |
| 
 | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "DxeMain.h"
 | |
| 
 | |
| //
 | |
| // Local defines and typedefs
 | |
| //
 | |
| #define CORE_SECTION_CHILD_SIGNATURE  SIGNATURE_32('S','X','C','S')
 | |
| #define CHILD_SECTION_NODE_FROM_LINK(Node) \
 | |
|   CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
 | |
| 
 | |
| typedef struct {
 | |
|   UINT32        Signature;
 | |
|   LIST_ENTRY    Link;
 | |
|   UINT32        Type;
 | |
|   UINT32        Size;
 | |
|   //
 | |
|   // StreamBase + OffsetInStream == pointer to section header in stream.  The
 | |
|   // stream base is always known when walking the sections within.
 | |
|   //
 | |
|   UINT32        OffsetInStream;
 | |
|   //
 | |
|   // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
 | |
|   // encapsulating section.  Otherwise, it contains the stream handle
 | |
|   // of the encapsulated stream.  This handle is ALWAYS produced any time an
 | |
|   // encapsulating child is encountered, irrespective of whether the
 | |
|   // encapsulated stream is processed further.
 | |
|   //
 | |
|   UINTN         EncapsulatedStreamHandle;
 | |
|   EFI_GUID      *EncapsulationGuid;
 | |
|   //
 | |
|   // If the section REQUIRES an extraction protocol, register for RPN
 | |
|   // when the required GUIDed extraction protocol becomes available.
 | |
|   //
 | |
|   EFI_EVENT     Event;
 | |
| } CORE_SECTION_CHILD_NODE;
 | |
| 
 | |
| #define CORE_SECTION_STREAM_SIGNATURE  SIGNATURE_32('S','X','S','S')
 | |
| #define STREAM_NODE_FROM_LINK(Node) \
 | |
|   CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
 | |
| 
 | |
| typedef struct {
 | |
|   UINT32        Signature;
 | |
|   LIST_ENTRY    Link;
 | |
|   UINTN         StreamHandle;
 | |
|   UINT8         *StreamBuffer;
 | |
|   UINTN         StreamLength;
 | |
|   LIST_ENTRY    Children;
 | |
|   //
 | |
|   // Authentication status is from GUIDed encapsulations.
 | |
|   //
 | |
|   UINT32        AuthenticationStatus;
 | |
| } CORE_SECTION_STREAM_NODE;
 | |
| 
 | |
| #define NULL_STREAM_HANDLE  0
 | |
| 
 | |
| typedef struct {
 | |
|   CORE_SECTION_CHILD_NODE     *ChildNode;
 | |
|   CORE_SECTION_STREAM_NODE    *ParentStream;
 | |
|   VOID                        *Registration;
 | |
| } RPN_EVENT_CONTEXT;
 | |
| 
 | |
| /**
 | |
|   The ExtractSection() function processes the input section and
 | |
|   allocates a buffer from the pool in which it returns the section
 | |
|   contents. If the section being extracted contains
 | |
|   authentication information (the section's
 | |
|   GuidedSectionHeader.Attributes field has the
 | |
|   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
 | |
|   returned in AuthenticationStatus must reflect the results of
 | |
|   the authentication operation. Depending on the algorithm and
 | |
|   size of the encapsulated data, the time that is required to do
 | |
|   a full authentication may be prohibitively long for some
 | |
|   classes of systems. To indicate this, use
 | |
|   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
 | |
|   the security policy driver (see the Platform Initialization
 | |
|   Driver Execution Environment Core Interface Specification for
 | |
|   more details and the GUID definition). If the
 | |
|   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
 | |
|   database, then, if possible, full authentication should be
 | |
|   skipped and the section contents simply returned in the
 | |
|   OutputBuffer. In this case, the
 | |
|   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
 | |
|   must be set on return. ExtractSection() is callable only from
 | |
|   TPL_NOTIFY and below. Behavior of ExtractSection() at any
 | |
|   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
 | |
|   defined in RaiseTPL() in the UEFI 2.0 specification.
 | |
| 
 | |
| 
 | |
|   @param This         Indicates the
 | |
|                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
 | |
|   @param InputSection Buffer containing the input GUIDed section
 | |
|                       to be processed. OutputBuffer OutputBuffer
 | |
|                       is allocated from boot services pool
 | |
|                       memory and contains the new section
 | |
|                       stream. The caller is responsible for
 | |
|                       freeing this buffer.
 | |
|   @param OutputBuffer *OutputBuffer is allocated from boot services
 | |
|                       pool memory and contains the new section stream.
 | |
|                       The caller is responsible for freeing this buffer.
 | |
|   @param OutputSize   A pointer to a caller-allocated UINTN in
 | |
|                       which the size of OutputBuffer allocation
 | |
|                       is stored. If the function returns
 | |
|                       anything other than EFI_SUCCESS, the value
 | |
|                       of OutputSize is undefined.
 | |
| 
 | |
|   @param AuthenticationStatus A pointer to a caller-allocated
 | |
|                               UINT32 that indicates the
 | |
|                               authentication status of the
 | |
|                               output buffer. If the input
 | |
|                               section's
 | |
|                               GuidedSectionHeader.Attributes
 | |
|                               field has the
 | |
|                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
 | |
|                               bit as clear, AuthenticationStatus
 | |
|                               must return zero. Both local bits
 | |
|                               (19:16) and aggregate bits (3:0)
 | |
|                               in AuthenticationStatus are
 | |
|                               returned by ExtractSection().
 | |
|                               These bits reflect the status of
 | |
|                               the extraction operation. The bit
 | |
|                               pattern in both regions must be
 | |
|                               the same, as the local and
 | |
|                               aggregate authentication statuses
 | |
|                               have equivalent meaning at this
 | |
|                               level. If the function returns
 | |
|                               anything other than EFI_SUCCESS,
 | |
|                               the value of AuthenticationStatus
 | |
|                               is undefined.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS          The InputSection was successfully
 | |
|                                processed and the section contents were
 | |
|                                returned.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES The system has insufficient
 | |
|                                resources to process the
 | |
|                                request.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
 | |
|                                 not match this instance of the
 | |
|                                 GUIDed Section Extraction
 | |
|                                 Protocol.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CustomGuidedSectionExtract (
 | |
|   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *This,
 | |
|   IN CONST  VOID                                    *InputSection,
 | |
|   OUT       VOID                                    **OutputBuffer,
 | |
|   OUT       UINTN                                   *OutputSize,
 | |
|   OUT       UINT32                                  *AuthenticationStatus
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Module globals
 | |
| //
 | |
| LIST_ENTRY  mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
 | |
| 
 | |
| EFI_HANDLE  mSectionExtractionHandle = NULL;
 | |
| 
 | |
| EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  mCustomGuidedSectionExtractionProtocol = {
 | |
|   CustomGuidedSectionExtract
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Entry point of the section extraction code. Initializes an instance of the
 | |
|   section extraction interface and installs it on a new handle.
 | |
| 
 | |
|   @param  ImageHandle   A handle for the image that is initializing this driver
 | |
|   @param  SystemTable   A pointer to the EFI system table
 | |
| 
 | |
|   @retval EFI_SUCCESS           Driver initialized successfully
 | |
|   @retval EFI_OUT_OF_RESOURCES  Could not allocate needed resources
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializeSectionExtraction (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_GUID    *ExtractHandlerGuidTable;
 | |
|   UINTN       ExtractHandlerNumber;
 | |
| 
 | |
|   //
 | |
|   // Get custom extract guided section method guid list
 | |
|   //
 | |
|   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   //
 | |
|   // Install custom guided extraction protocol
 | |
|   //
 | |
|   while (ExtractHandlerNumber-- > 0) {
 | |
|     Status = CoreInstallProtocolInterface (
 | |
|                &mSectionExtractionHandle,
 | |
|                &ExtractHandlerGuidTable[ExtractHandlerNumber],
 | |
|                EFI_NATIVE_INTERFACE,
 | |
|                &mCustomGuidedSectionExtractionProtocol
 | |
|                );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if a stream is valid.
 | |
| 
 | |
|   @param  SectionStream          The section stream to be checked
 | |
|   @param  SectionStreamLength    The length of section stream
 | |
| 
 | |
|   @return A boolean value indicating the validness of the section stream.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsValidSectionStream (
 | |
|   IN  VOID   *SectionStream,
 | |
|   IN  UINTN  SectionStreamLength
 | |
|   )
 | |
| {
 | |
|   UINTN                      TotalLength;
 | |
|   UINTN                      SectionLength;
 | |
|   EFI_COMMON_SECTION_HEADER  *SectionHeader;
 | |
|   EFI_COMMON_SECTION_HEADER  *NextSectionHeader;
 | |
| 
 | |
|   TotalLength   = 0;
 | |
|   SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
 | |
| 
 | |
|   while (TotalLength < SectionStreamLength) {
 | |
|     if (IS_SECTION2 (SectionHeader)) {
 | |
|       SectionLength = SECTION2_SIZE (SectionHeader);
 | |
|     } else {
 | |
|       SectionLength = SECTION_SIZE (SectionHeader);
 | |
|     }
 | |
| 
 | |
|     TotalLength += SectionLength;
 | |
| 
 | |
|     if (TotalLength == SectionStreamLength) {
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Move to the next byte following the section...
 | |
|     //
 | |
|     SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)SectionHeader + SectionLength);
 | |
| 
 | |
|     //
 | |
|     // Figure out where the next section begins
 | |
|     //
 | |
|     NextSectionHeader = ALIGN_POINTER (SectionHeader, 4);
 | |
|     TotalLength      += (UINTN)NextSectionHeader - (UINTN)SectionHeader;
 | |
|     SectionHeader     = NextSectionHeader;
 | |
|   }
 | |
| 
 | |
|   ASSERT (FALSE);
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Constructor for section streams.
 | |
| 
 | |
|   @param  SectionStreamLength    Size in bytes of the section stream.
 | |
|   @param  SectionStream          Buffer containing the new section stream.
 | |
|   @param  AllocateBuffer         Indicates whether the stream buffer is to be
 | |
|                                  copied or the input buffer is to be used in
 | |
|                                  place. AuthenticationStatus- Indicates the
 | |
|                                  default authentication status for the new
 | |
|                                  stream.
 | |
|   @param  AuthenticationStatus   A pointer to a caller-allocated UINT32 that
 | |
|                                  indicates the authentication status of the
 | |
|                                  output buffer. If the input section's
 | |
|                                  GuidedSectionHeader.Attributes field
 | |
|                                  has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
 | |
|                                  bit as clear, AuthenticationStatus must return
 | |
|                                  zero. Both local bits (19:16) and aggregate
 | |
|                                  bits (3:0) in AuthenticationStatus are returned
 | |
|                                  by ExtractSection(). These bits reflect the
 | |
|                                  status of the extraction operation. The bit
 | |
|                                  pattern in both regions must be the same, as
 | |
|                                  the local and aggregate authentication statuses
 | |
|                                  have equivalent meaning at this level. If the
 | |
|                                  function returns anything other than
 | |
|                                  EFI_SUCCESS, the value of *AuthenticationStatus
 | |
|                                  is undefined.
 | |
|   @param  SectionStreamHandle    A pointer to a caller allocated section stream
 | |
|                                  handle.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Stream was added to stream database.
 | |
|   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| OpenSectionStreamEx (
 | |
|   IN     UINTN    SectionStreamLength,
 | |
|   IN     VOID     *SectionStream,
 | |
|   IN     BOOLEAN  AllocateBuffer,
 | |
|   IN     UINT32   AuthenticationStatus,
 | |
|   OUT UINTN       *SectionStreamHandle
 | |
|   )
 | |
| {
 | |
|   CORE_SECTION_STREAM_NODE  *NewStream;
 | |
|   EFI_TPL                   OldTpl;
 | |
| 
 | |
|   //
 | |
|   // Allocate a new stream
 | |
|   //
 | |
|   NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
 | |
|   if (NewStream == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (AllocateBuffer) {
 | |
|     //
 | |
|     // if we're here, we're double buffering, allocate the buffer and copy the
 | |
|     // data in
 | |
|     //
 | |
|     if (SectionStreamLength > 0) {
 | |
|       NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
 | |
|       if (NewStream->StreamBuffer == NULL) {
 | |
|         CoreFreePool (NewStream);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Copy in stream data
 | |
|       //
 | |
|       CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
 | |
|     } else {
 | |
|       //
 | |
|       // It's possible to have a zero length section stream.
 | |
|       //
 | |
|       NewStream->StreamBuffer = NULL;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // If were here, the caller has supplied the buffer (it's an internal call)
 | |
|     // so just assign the buffer.  This happens when we open section streams
 | |
|     // as a result of expanding an encapsulating section.
 | |
|     //
 | |
|     NewStream->StreamBuffer = SectionStream;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize the rest of the section stream
 | |
|   //
 | |
|   NewStream->Signature    = CORE_SECTION_STREAM_SIGNATURE;
 | |
|   NewStream->StreamHandle = (UINTN)NewStream;
 | |
|   NewStream->StreamLength = SectionStreamLength;
 | |
|   InitializeListHead (&NewStream->Children);
 | |
|   NewStream->AuthenticationStatus = AuthenticationStatus;
 | |
| 
 | |
|   //
 | |
|   // Add new stream to stream list
 | |
|   //
 | |
|   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
 | |
|   InsertTailList (&mStreamRoot, &NewStream->Link);
 | |
|   CoreRestoreTpl (OldTpl);
 | |
| 
 | |
|   *SectionStreamHandle = NewStream->StreamHandle;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   SEP member function.  This function creates and returns a new section stream
 | |
|   handle to represent the new section stream.
 | |
| 
 | |
|   @param  SectionStreamLength    Size in bytes of the section stream.
 | |
|   @param  SectionStream          Buffer containing the new section stream.
 | |
|   @param  SectionStreamHandle    A pointer to a caller allocated UINTN that on
 | |
|                                  output contains the new section stream handle.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The section stream is created successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES   memory allocation failed.
 | |
|   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
 | |
|                                  of last section.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| OpenSectionStream (
 | |
|   IN     UINTN  SectionStreamLength,
 | |
|   IN     VOID   *SectionStream,
 | |
|   OUT UINTN     *SectionStreamHandle
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Check to see section stream looks good...
 | |
|   //
 | |
|   if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return OpenSectionStreamEx (
 | |
|            SectionStreamLength,
 | |
|            SectionStream,
 | |
|            FALSE,
 | |
|            0,
 | |
|            SectionStreamHandle
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Determine if the input stream:child matches the input type.
 | |
| 
 | |
|   @param  Stream                 Indicates the section stream associated with the
 | |
|                                  child
 | |
|   @param  Child                  Indicates the child to check
 | |
|   @param  SearchType             Indicates the type of section to check against
 | |
|                                  for
 | |
|   @param  SectionDefinitionGuid  Indicates the GUID to check against if the type
 | |
|                                  is EFI_SECTION_GUID_DEFINED
 | |
| 
 | |
|   @retval TRUE                   The child matches
 | |
|   @retval FALSE                  The child doesn't match
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ChildIsType (
 | |
|   IN CORE_SECTION_STREAM_NODE  *Stream,
 | |
|   IN CORE_SECTION_CHILD_NODE   *Child,
 | |
|   IN EFI_SECTION_TYPE          SearchType,
 | |
|   IN EFI_GUID                  *SectionDefinitionGuid
 | |
|   )
 | |
| {
 | |
|   EFI_GUID_DEFINED_SECTION  *GuidedSection;
 | |
| 
 | |
|   if (SearchType == EFI_SECTION_ALL) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if (Child->Type != SearchType) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   GuidedSection = (EFI_GUID_DEFINED_SECTION *)(Stream->StreamBuffer + Child->OffsetInStream);
 | |
|   if (IS_SECTION2 (GuidedSection)) {
 | |
|     return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *)GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
 | |
|   } else {
 | |
|     return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
 | |
| 
 | |
|   @param GuidedSectionGuid          The Guided Section GUID.
 | |
|   @param GuidedSectionExtraction    A pointer to the pointer to the supported Guided Section Extraction Protocol
 | |
|                                     for the Guided Section.
 | |
| 
 | |
|   @return TRUE      The GuidedSectionGuid could be identified, and the pointer to
 | |
|                     the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
 | |
|   @return FALSE     The GuidedSectionGuid could not be identified, or
 | |
|                     the Guided Section Extraction Protocol has not been installed yet.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| VerifyGuidedSectionGuid (
 | |
|   IN  EFI_GUID                                *GuidedSectionGuid,
 | |
|   OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  **GuidedSectionExtraction
 | |
|   )
 | |
| {
 | |
|   EFI_GUID    *GuidRecorded;
 | |
|   VOID        *Interface;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Interface = NULL;
 | |
| 
 | |
|   //
 | |
|   // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
 | |
|   //
 | |
|   Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **)&GuidRecorded);
 | |
|   if (Status == EFI_SUCCESS) {
 | |
|     if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
 | |
|       //
 | |
|       // Found the recorded GuidedSectionGuid.
 | |
|       //
 | |
|       Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **)&Interface);
 | |
|       if (!EFI_ERROR (Status) && (Interface != NULL)) {
 | |
|         //
 | |
|         // Found the supported Guided Section Extraction Porotocol for the Guided Section.
 | |
|         //
 | |
|         *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *)Interface;
 | |
|         return TRUE;
 | |
|       }
 | |
| 
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   RPN callback function. Initializes the section stream
 | |
|   when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
 | |
| 
 | |
|   @param Event               The event that fired
 | |
|   @param RpnContext          A pointer to the context that allows us to identify
 | |
|                              the relevent encapsulation.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| NotifyGuidedExtraction (
 | |
|   IN   EFI_EVENT  Event,
 | |
|   IN   VOID       *RpnContext
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_GUID_DEFINED_SECTION                *GuidedHeader;
 | |
|   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *GuidedExtraction;
 | |
|   VOID                                    *NewStreamBuffer;
 | |
|   UINTN                                   NewStreamBufferSize;
 | |
|   UINT32                                  AuthenticationStatus;
 | |
|   RPN_EVENT_CONTEXT                       *Context;
 | |
| 
 | |
|   Context = RpnContext;
 | |
| 
 | |
|   GuidedHeader = (EFI_GUID_DEFINED_SECTION *)(Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
 | |
|   ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
 | |
| 
 | |
|   if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Status = GuidedExtraction->ExtractSection (
 | |
|                                GuidedExtraction,
 | |
|                                GuidedHeader,
 | |
|                                &NewStreamBuffer,
 | |
|                                &NewStreamBufferSize,
 | |
|                                &AuthenticationStatus
 | |
|                                );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Make sure we initialize the new stream with the correct
 | |
|   // authentication status for both aggregate and local status fields.
 | |
|   //
 | |
|   if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
 | |
|     //
 | |
|     // OR in the parent stream's aggregate status.
 | |
|     //
 | |
|     AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
 | |
|   } else {
 | |
|     //
 | |
|     // since there's no authentication data contributed by the section,
 | |
|     // just inherit the full value from our immediate parent.
 | |
|     //
 | |
|     AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
 | |
|   }
 | |
| 
 | |
|   Status = OpenSectionStreamEx (
 | |
|              NewStreamBufferSize,
 | |
|              NewStreamBuffer,
 | |
|              FALSE,
 | |
|              AuthenticationStatus,
 | |
|              &Context->ChildNode->EncapsulatedStreamHandle
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   //  Close the event when done.
 | |
|   //
 | |
|   gBS->CloseEvent (Event);
 | |
|   Context->ChildNode->Event = NULL;
 | |
|   FreePool (Context);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
 | |
| 
 | |
|   @param ParentStream        Indicates the parent of the ecnapsulation section (child)
 | |
|   @param ChildNode           Indicates the child node that is the encapsulation section.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CreateGuidedExtractionRpnEvent (
 | |
|   IN CORE_SECTION_STREAM_NODE  *ParentStream,
 | |
|   IN CORE_SECTION_CHILD_NODE   *ChildNode
 | |
|   )
 | |
| {
 | |
|   RPN_EVENT_CONTEXT  *Context;
 | |
| 
 | |
|   //
 | |
|   // Allocate new event structure and context
 | |
|   //
 | |
|   Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
 | |
|   ASSERT (Context != NULL);
 | |
| 
 | |
|   Context->ChildNode    = ChildNode;
 | |
|   Context->ParentStream = ParentStream;
 | |
| 
 | |
|   Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
 | |
|                                 Context->ChildNode->EncapsulationGuid,
 | |
|                                 TPL_NOTIFY,
 | |
|                                 NotifyGuidedExtraction,
 | |
|                                 Context,
 | |
|                                 &Context->Registration
 | |
|                                 );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Constructor for new child nodes.
 | |
| 
 | |
|   @param  Stream                 Indicates the section stream in which to add the
 | |
|                                  child.
 | |
|   @param  ChildOffset            Indicates the offset in Stream that is the
 | |
|                                  beginning of the child section.
 | |
|   @param  ChildNode              Indicates the Callee allocated and initialized
 | |
|                                  child.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Child node was found and returned.
 | |
|                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
 | |
|   @retval EFI_PROTOCOL_ERROR     Encapsulation sections produce new stream
 | |
|                                  handles when the child node is created.  If the
 | |
|                                  section type is GUID defined, and the extraction
 | |
|                                  GUID does not exist, and producing the stream
 | |
|                                  requires the GUID, then a protocol error is
 | |
|                                  generated and no child is produced. Values
 | |
|                                  returned by OpenSectionStreamEx.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CreateChildNode (
 | |
|   IN     CORE_SECTION_STREAM_NODE  *Stream,
 | |
|   IN     UINT32                    ChildOffset,
 | |
|   OUT    CORE_SECTION_CHILD_NODE   **ChildNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_COMMON_SECTION_HEADER               *SectionHeader;
 | |
|   EFI_COMPRESSION_SECTION                 *CompressionHeader;
 | |
|   EFI_GUID_DEFINED_SECTION                *GuidedHeader;
 | |
|   EFI_DECOMPRESS_PROTOCOL                 *Decompress;
 | |
|   EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *GuidedExtraction;
 | |
|   VOID                                    *NewStreamBuffer;
 | |
|   VOID                                    *ScratchBuffer;
 | |
|   UINT32                                  ScratchSize;
 | |
|   UINTN                                   NewStreamBufferSize;
 | |
|   UINT32                                  AuthenticationStatus;
 | |
|   VOID                                    *CompressionSource;
 | |
|   UINT32                                  CompressionSourceSize;
 | |
|   UINT32                                  UncompressedLength;
 | |
|   UINT8                                   CompressionType;
 | |
|   UINT16                                  GuidedSectionAttributes;
 | |
| 
 | |
|   CORE_SECTION_CHILD_NODE  *Node;
 | |
| 
 | |
|   SectionHeader = (EFI_COMMON_SECTION_HEADER *)(Stream->StreamBuffer + ChildOffset);
 | |
| 
 | |
|   //
 | |
|   // Allocate a new node
 | |
|   //
 | |
|   *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
 | |
|   Node       = *ChildNode;
 | |
|   if (Node == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Now initialize it
 | |
|   //
 | |
|   Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
 | |
|   Node->Type      = SectionHeader->Type;
 | |
|   if (IS_SECTION2 (SectionHeader)) {
 | |
|     Node->Size = SECTION2_SIZE (SectionHeader);
 | |
|   } else {
 | |
|     Node->Size = SECTION_SIZE (SectionHeader);
 | |
|   }
 | |
| 
 | |
|   Node->OffsetInStream           = ChildOffset;
 | |
|   Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
 | |
|   Node->EncapsulationGuid        = NULL;
 | |
| 
 | |
|   //
 | |
|   // If it's an encapsulating section, then create the new section stream also
 | |
|   //
 | |
|   switch (Node->Type) {
 | |
|     case EFI_SECTION_COMPRESSION:
 | |
|       //
 | |
|       // Get the CompressionSectionHeader
 | |
|       //
 | |
|       if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
 | |
|         CoreFreePool (Node);
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       CompressionHeader = (EFI_COMPRESSION_SECTION *)SectionHeader;
 | |
| 
 | |
|       if (IS_SECTION2 (CompressionHeader)) {
 | |
|         CompressionSource     = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
 | |
|         CompressionSourceSize = (UINT32)(SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
 | |
|         UncompressedLength    = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->UncompressedLength;
 | |
|         CompressionType       = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->CompressionType;
 | |
|       } else {
 | |
|         CompressionSource     = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
 | |
|         CompressionSourceSize = (UINT32)(SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
 | |
|         UncompressedLength    = CompressionHeader->UncompressedLength;
 | |
|         CompressionType       = CompressionHeader->CompressionType;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Allocate space for the new stream
 | |
|       //
 | |
|       if (UncompressedLength > 0) {
 | |
|         NewStreamBufferSize = UncompressedLength;
 | |
|         NewStreamBuffer     = AllocatePool (NewStreamBufferSize);
 | |
|         if (NewStreamBuffer == NULL) {
 | |
|           CoreFreePool (Node);
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         }
 | |
| 
 | |
|         if (CompressionType == EFI_NOT_COMPRESSED) {
 | |
|           //
 | |
|           // stream is not actually compressed, just encapsulated.  So just copy it.
 | |
|           //
 | |
|           CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
 | |
|         } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
 | |
|           //
 | |
|           // Only support the EFI_SATNDARD_COMPRESSION algorithm.
 | |
|           //
 | |
| 
 | |
|           //
 | |
|           // Decompress the stream
 | |
|           //
 | |
|           Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
 | |
|           ASSERT_EFI_ERROR (Status);
 | |
|           ASSERT (Decompress != NULL);
 | |
| 
 | |
|           Status = Decompress->GetInfo (
 | |
|                                  Decompress,
 | |
|                                  CompressionSource,
 | |
|                                  CompressionSourceSize,
 | |
|                                  (UINT32 *)&NewStreamBufferSize,
 | |
|                                  &ScratchSize
 | |
|                                  );
 | |
|           if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
 | |
|             CoreFreePool (Node);
 | |
|             CoreFreePool (NewStreamBuffer);
 | |
|             if (!EFI_ERROR (Status)) {
 | |
|               Status = EFI_BAD_BUFFER_SIZE;
 | |
|             }
 | |
| 
 | |
|             return Status;
 | |
|           }
 | |
| 
 | |
|           ScratchBuffer = AllocatePool (ScratchSize);
 | |
|           if (ScratchBuffer == NULL) {
 | |
|             CoreFreePool (Node);
 | |
|             CoreFreePool (NewStreamBuffer);
 | |
|             return EFI_OUT_OF_RESOURCES;
 | |
|           }
 | |
| 
 | |
|           Status = Decompress->Decompress (
 | |
|                                  Decompress,
 | |
|                                  CompressionSource,
 | |
|                                  CompressionSourceSize,
 | |
|                                  NewStreamBuffer,
 | |
|                                  (UINT32)NewStreamBufferSize,
 | |
|                                  ScratchBuffer,
 | |
|                                  ScratchSize
 | |
|                                  );
 | |
|           CoreFreePool (ScratchBuffer);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             CoreFreePool (Node);
 | |
|             CoreFreePool (NewStreamBuffer);
 | |
|             return Status;
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         NewStreamBuffer     = NULL;
 | |
|         NewStreamBufferSize = 0;
 | |
|       }
 | |
| 
 | |
|       Status = OpenSectionStreamEx (
 | |
|                  NewStreamBufferSize,
 | |
|                  NewStreamBuffer,
 | |
|                  FALSE,
 | |
|                  Stream->AuthenticationStatus,
 | |
|                  &Node->EncapsulatedStreamHandle
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         CoreFreePool (Node);
 | |
|         CoreFreePool (NewStreamBuffer);
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case EFI_SECTION_GUID_DEFINED:
 | |
|       GuidedHeader = (EFI_GUID_DEFINED_SECTION *)SectionHeader;
 | |
|       if (IS_SECTION2 (GuidedHeader)) {
 | |
|         Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->SectionDefinitionGuid);
 | |
|         GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->Attributes;
 | |
|       } else {
 | |
|         Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
 | |
|         GuidedSectionAttributes = GuidedHeader->Attributes;
 | |
|       }
 | |
| 
 | |
|       if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
 | |
|         //
 | |
|         // NewStreamBuffer is always allocated by ExtractSection... No caller
 | |
|         // allocation here.
 | |
|         //
 | |
|         Status = GuidedExtraction->ExtractSection (
 | |
|                                      GuidedExtraction,
 | |
|                                      GuidedHeader,
 | |
|                                      &NewStreamBuffer,
 | |
|                                      &NewStreamBufferSize,
 | |
|                                      &AuthenticationStatus
 | |
|                                      );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           CoreFreePool (*ChildNode);
 | |
|           return EFI_PROTOCOL_ERROR;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Make sure we initialize the new stream with the correct
 | |
|         // authentication status for both aggregate and local status fields.
 | |
|         //
 | |
|         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
 | |
|           //
 | |
|           // OR in the parent stream's aggregate status.
 | |
|           //
 | |
|           AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
 | |
|         } else {
 | |
|           //
 | |
|           // since there's no authentication data contributed by the section,
 | |
|           // just inherit the full value from our immediate parent.
 | |
|           //
 | |
|           AuthenticationStatus = Stream->AuthenticationStatus;
 | |
|         }
 | |
| 
 | |
|         Status = OpenSectionStreamEx (
 | |
|                    NewStreamBufferSize,
 | |
|                    NewStreamBuffer,
 | |
|                    FALSE,
 | |
|                    AuthenticationStatus,
 | |
|                    &Node->EncapsulatedStreamHandle
 | |
|                    );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           CoreFreePool (*ChildNode);
 | |
|           CoreFreePool (NewStreamBuffer);
 | |
|           return Status;
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // There's no GUIDed section extraction protocol available.
 | |
|         //
 | |
|         if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
 | |
|           //
 | |
|           // If the section REQUIRES an extraction protocol, register for RPN
 | |
|           // when the required GUIDed extraction protocol becomes available.
 | |
|           //
 | |
|           CreateGuidedExtractionRpnEvent (Stream, Node);
 | |
|         } else {
 | |
|           //
 | |
|           // Figure out the proper authentication status
 | |
|           //
 | |
|           AuthenticationStatus = Stream->AuthenticationStatus;
 | |
| 
 | |
|           if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
 | |
|             AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
 | |
|           }
 | |
| 
 | |
|           if (IS_SECTION2 (GuidedHeader)) {
 | |
|             Status = OpenSectionStreamEx (
 | |
|                        SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
 | |
|                        (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
 | |
|                        TRUE,
 | |
|                        AuthenticationStatus,
 | |
|                        &Node->EncapsulatedStreamHandle
 | |
|                        );
 | |
|           } else {
 | |
|             Status = OpenSectionStreamEx (
 | |
|                        SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
 | |
|                        (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
 | |
|                        TRUE,
 | |
|                        AuthenticationStatus,
 | |
|                        &Node->EncapsulatedStreamHandle
 | |
|                        );
 | |
|           }
 | |
| 
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             CoreFreePool (Node);
 | |
|             return Status;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
| 
 | |
|       //
 | |
|       // Nothing to do if it's a leaf
 | |
|       //
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Last, add the new child node to the stream
 | |
|   //
 | |
|   InsertTailList (&Stream->Children, &Node->Link);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function  Recursively searches / builds section stream database
 | |
|   looking for requested section.
 | |
| 
 | |
|   @param  SourceStream           Indicates the section stream in which to do the
 | |
|                                  search.
 | |
|   @param  SearchType             Indicates the type of section to search for.
 | |
|   @param  SectionInstance        Indicates which instance of section to find.
 | |
|                                  This is an in/out parameter and it is 1-based,
 | |
|                                  to deal with recursions.
 | |
|   @param  SectionDefinitionGuid  Guid of section definition
 | |
|   @param  Depth                  Nesting depth of encapsulation sections.
 | |
|                                  Callers different from FindChildNode() are
 | |
|                                  responsible for passing in a zero Depth.
 | |
|   @param  FoundChild             Output indicating the child node that is found.
 | |
|   @param  FoundStream            Output indicating which section stream the child
 | |
|                                  was found in.  If this stream was generated as a
 | |
|                                  result of an encapsulation section, the
 | |
|                                  streamhandle is visible within the SEP driver
 | |
|                                  only.
 | |
|   @param  AuthenticationStatus   Indicates the authentication status of the found section.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Child node was found and returned.
 | |
|                                  EFI_OUT_OF_RESOURCES- Memory allocation failed.
 | |
|   @retval EFI_NOT_FOUND          Requested child node does not exist.
 | |
|   @retval EFI_PROTOCOL_ERROR     a required GUIDED section extraction protocol
 | |
|                                  does not exist
 | |
|   @retval EFI_ABORTED            Recursion aborted because Depth has been
 | |
|                                  greater than or equal to
 | |
|                                  PcdFwVolDxeMaxEncapsulationDepth.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindChildNode (
 | |
|   IN     CORE_SECTION_STREAM_NODE  *SourceStream,
 | |
|   IN     EFI_SECTION_TYPE          SearchType,
 | |
|   IN OUT UINTN                     *SectionInstance,
 | |
|   IN     EFI_GUID                  *SectionDefinitionGuid,
 | |
|   IN     UINT32                    Depth,
 | |
|   OUT    CORE_SECTION_CHILD_NODE   **FoundChild,
 | |
|   OUT    CORE_SECTION_STREAM_NODE  **FoundStream,
 | |
|   OUT    UINT32                    *AuthenticationStatus
 | |
|   )
 | |
| {
 | |
|   CORE_SECTION_CHILD_NODE   *CurrentChildNode;
 | |
|   CORE_SECTION_CHILD_NODE   *RecursedChildNode;
 | |
|   CORE_SECTION_STREAM_NODE  *RecursedFoundStream;
 | |
|   UINT32                    NextChildOffset;
 | |
|   EFI_STATUS                ErrorStatus;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   ASSERT (*SectionInstance > 0);
 | |
| 
 | |
|   if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   CurrentChildNode = NULL;
 | |
|   ErrorStatus      = EFI_NOT_FOUND;
 | |
| 
 | |
|   if (SourceStream->StreamLength == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (IsListEmpty (&SourceStream->Children) &&
 | |
|       (SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)))
 | |
|   {
 | |
|     //
 | |
|     // This occurs when a section stream exists, but no child sections
 | |
|     // have been parsed out yet.  Therefore, extract the first child and add it
 | |
|     // to the list of children so we can get started.
 | |
|     // Section stream may contain an array of zero or more bytes.
 | |
|     // So, its size should be >= the size of commen section header.
 | |
|     //
 | |
|     Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // At least one child has been parsed out of the section stream.  So, walk
 | |
|   // through the sections that have already been parsed out looking for the
 | |
|   // requested section, if necessary, continue parsing section stream and
 | |
|   // adding children until either the requested section is found, or we run
 | |
|   // out of data
 | |
|   //
 | |
|   CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode (&SourceStream->Children));
 | |
| 
 | |
|   for ( ; ;) {
 | |
|     ASSERT (CurrentChildNode != NULL);
 | |
|     if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
 | |
|       //
 | |
|       // The type matches, so check the instance count to see if it's the one we want
 | |
|       //
 | |
|       (*SectionInstance)--;
 | |
|       if (*SectionInstance == 0) {
 | |
|         //
 | |
|         // Got it!
 | |
|         //
 | |
|         *FoundChild           = CurrentChildNode;
 | |
|         *FoundStream          = SourceStream;
 | |
|         *AuthenticationStatus = SourceStream->AuthenticationStatus;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Type mismatch, or we haven't found the desired instance yet.
 | |
|     //
 | |
|     ASSERT (*SectionInstance > 0);
 | |
| 
 | |
|     if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
 | |
|       //
 | |
|       // If the current node is an encapsulating node, recurse into it...
 | |
|       //
 | |
|       Status = FindChildNode (
 | |
|                  (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
 | |
|                  SearchType,
 | |
|                  SectionInstance,
 | |
|                  SectionDefinitionGuid,
 | |
|                  Depth + 1,
 | |
|                  &RecursedChildNode,
 | |
|                  &RecursedFoundStream,
 | |
|                  AuthenticationStatus
 | |
|                  );
 | |
|       if (*SectionInstance == 0) {
 | |
|         //
 | |
|         // The recursive FindChildNode() call decreased (*SectionInstance) to
 | |
|         // zero.
 | |
|         //
 | |
|         ASSERT_EFI_ERROR (Status);
 | |
|         *FoundChild  = RecursedChildNode;
 | |
|         *FoundStream = RecursedFoundStream;
 | |
|         return EFI_SUCCESS;
 | |
|       } else {
 | |
|         if (Status == EFI_ABORTED) {
 | |
|           //
 | |
|           // If the recursive call was aborted due to nesting depth, stop
 | |
|           // looking for the requested child node. The skipped subtree could
 | |
|           // throw off the instance counting.
 | |
|           //
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Save the error code and continue to find the requested child node in
 | |
|         // the rest of the stream.
 | |
|         //
 | |
|         ErrorStatus = Status;
 | |
|       }
 | |
|     } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
 | |
|       //
 | |
|       // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
 | |
|       // because a required GUIDED section extraction protocol does not exist.
 | |
|       // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
 | |
|       //
 | |
|       ErrorStatus = EFI_PROTOCOL_ERROR;
 | |
|     }
 | |
| 
 | |
|     if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
 | |
|       //
 | |
|       // We haven't found the child node we're interested in yet, but there's
 | |
|       // still more nodes that have already been parsed so get the next one
 | |
|       // and continue searching..
 | |
|       //
 | |
|       CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
 | |
|     } else {
 | |
|       //
 | |
|       // We've exhausted children that have already been parsed, so see if
 | |
|       // there's any more data and continue parsing out more children if there
 | |
|       // is.
 | |
|       //
 | |
|       NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
 | |
|       //
 | |
|       // Round up to 4 byte boundary
 | |
|       //
 | |
|       NextChildOffset += 3;
 | |
|       NextChildOffset &= ~(UINTN)3;
 | |
|       if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
 | |
|         //
 | |
|         // There's an unparsed child remaining in the stream, so create a new child node
 | |
|         //
 | |
|         Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           return Status;
 | |
|         }
 | |
|       } else {
 | |
|         ASSERT (EFI_ERROR (ErrorStatus));
 | |
|         return ErrorStatus;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Search stream database for requested stream handle.
 | |
| 
 | |
|   @param  SearchHandle           Indicates which stream to look for.
 | |
|   @param  FoundStream            Output pointer to the found stream.
 | |
| 
 | |
|   @retval EFI_SUCCESS            StreamHandle was found and *FoundStream contains
 | |
|                                  the stream node.
 | |
|   @retval EFI_NOT_FOUND          SearchHandle was not found in the stream
 | |
|                                  database.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindStreamNode (
 | |
|   IN  UINTN                     SearchHandle,
 | |
|   OUT CORE_SECTION_STREAM_NODE  **FoundStream
 | |
|   )
 | |
| {
 | |
|   CORE_SECTION_STREAM_NODE  *StreamNode;
 | |
| 
 | |
|   if (!IsListEmpty (&mStreamRoot)) {
 | |
|     StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
 | |
|     for ( ; ;) {
 | |
|       if (StreamNode->StreamHandle == SearchHandle) {
 | |
|         *FoundStream = StreamNode;
 | |
|         return EFI_SUCCESS;
 | |
|       } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
 | |
|         break;
 | |
|       } else {
 | |
|         StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   SEP member function.  Retrieves requested section from section stream.
 | |
| 
 | |
|   @param  SectionStreamHandle   The section stream from which to extract the
 | |
|                                 requested section.
 | |
|   @param  SectionType           A pointer to the type of section to search for.
 | |
|   @param  SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
 | |
|                                 then SectionDefinitionGuid indicates which of
 | |
|                                 these types of sections to search for.
 | |
|   @param  SectionInstance       Indicates which instance of the requested
 | |
|                                 section to return.
 | |
|   @param  Buffer                Double indirection to buffer.  If *Buffer is
 | |
|                                 non-null on input, then the buffer is caller
 | |
|                                 allocated.  If Buffer is NULL, then the buffer
 | |
|                                 is callee allocated.  In either case, the
 | |
|                                 required buffer size is returned in *BufferSize.
 | |
|   @param  BufferSize            On input, indicates the size of *Buffer if
 | |
|                                 *Buffer is non-null on input.  On output,
 | |
|                                 indicates the required size (allocated size if
 | |
|                                 callee allocated) of *Buffer.
 | |
|   @param  AuthenticationStatus  A pointer to a caller-allocated UINT32 that
 | |
|                                 indicates the authentication status of the
 | |
|                                 output buffer. If the input section's
 | |
|                                 GuidedSectionHeader.Attributes field
 | |
|                                 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
 | |
|                                 bit as clear, AuthenticationStatus must return
 | |
|                                 zero. Both local bits (19:16) and aggregate
 | |
|                                 bits (3:0) in AuthenticationStatus are returned
 | |
|                                 by ExtractSection(). These bits reflect the
 | |
|                                 status of the extraction operation. The bit
 | |
|                                 pattern in both regions must be the same, as
 | |
|                                 the local and aggregate authentication statuses
 | |
|                                 have equivalent meaning at this level. If the
 | |
|                                 function returns anything other than
 | |
|                                 EFI_SUCCESS, the value of *AuthenticationStatus
 | |
|                                 is undefined.
 | |
|   @param  IsFfs3Fv              Indicates the FV format.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Section was retrieved successfully
 | |
|   @retval EFI_PROTOCOL_ERROR    A GUID defined section was encountered in the
 | |
|                                 section stream with its
 | |
|                                 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
 | |
|                                 but there was no corresponding GUIDed Section
 | |
|                                 Extraction Protocol in the handle database.
 | |
|                                 *Buffer is unmodified.
 | |
|   @retval EFI_NOT_FOUND         An error was encountered when parsing the
 | |
|                                 SectionStream.  This indicates the SectionStream
 | |
|                                 is not correctly formatted.
 | |
|   @retval EFI_NOT_FOUND         The requested section does not exist.
 | |
|   @retval EFI_OUT_OF_RESOURCES  The system has insufficient resources to process
 | |
|                                 the request.
 | |
|   @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
 | |
|   @retval EFI_WARN_TOO_SMALL    The size of the caller allocated input buffer is
 | |
|                                 insufficient to contain the requested section.
 | |
|                                 The input buffer is filled and section contents
 | |
|                                 are truncated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetSection (
 | |
|   IN UINTN             SectionStreamHandle,
 | |
|   IN EFI_SECTION_TYPE  *SectionType,
 | |
|   IN EFI_GUID          *SectionDefinitionGuid,
 | |
|   IN UINTN             SectionInstance,
 | |
|   IN VOID              **Buffer,
 | |
|   IN OUT UINTN         *BufferSize,
 | |
|   OUT UINT32           *AuthenticationStatus,
 | |
|   IN BOOLEAN           IsFfs3Fv
 | |
|   )
 | |
| {
 | |
|   CORE_SECTION_STREAM_NODE   *StreamNode;
 | |
|   EFI_TPL                    OldTpl;
 | |
|   EFI_STATUS                 Status;
 | |
|   CORE_SECTION_CHILD_NODE    *ChildNode;
 | |
|   CORE_SECTION_STREAM_NODE   *ChildStreamNode;
 | |
|   UINTN                      CopySize;
 | |
|   UINT32                     ExtractedAuthenticationStatus;
 | |
|   UINTN                      Instance;
 | |
|   UINT8                      *CopyBuffer;
 | |
|   UINTN                      SectionSize;
 | |
|   EFI_COMMON_SECTION_HEADER  *Section;
 | |
| 
 | |
|   ChildStreamNode = NULL;
 | |
|   OldTpl          = CoreRaiseTpl (TPL_NOTIFY);
 | |
|   Instance        = SectionInstance + 1;
 | |
| 
 | |
|   //
 | |
|   // Locate target stream
 | |
|   //
 | |
|   Status = FindStreamNode (SectionStreamHandle, &StreamNode);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto GetSection_Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Found the stream, now locate and return the appropriate section
 | |
|   //
 | |
|   if (SectionType == NULL) {
 | |
|     //
 | |
|     // SectionType == NULL means return the WHOLE section stream...
 | |
|     //
 | |
|     CopySize              = StreamNode->StreamLength;
 | |
|     CopyBuffer            = StreamNode->StreamBuffer;
 | |
|     *AuthenticationStatus = StreamNode->AuthenticationStatus;
 | |
|   } else {
 | |
|     //
 | |
|     // There's a requested section type, so go find it and return it...
 | |
|     //
 | |
|     Status = FindChildNode (
 | |
|                StreamNode,
 | |
|                *SectionType,
 | |
|                &Instance,
 | |
|                SectionDefinitionGuid,
 | |
|                0,                             // encapsulation depth
 | |
|                &ChildNode,
 | |
|                &ChildStreamNode,
 | |
|                &ExtractedAuthenticationStatus
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (Status == EFI_ABORTED) {
 | |
|         DEBUG ((
 | |
|           DEBUG_ERROR,
 | |
|           "%a: recursion aborted due to nesting depth\n",
 | |
|           __FUNCTION__
 | |
|           ));
 | |
|         //
 | |
|         // Map "aborted" to "not found".
 | |
|         //
 | |
|         Status = EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       goto GetSection_Done;
 | |
|     }
 | |
| 
 | |
|     Section = (EFI_COMMON_SECTION_HEADER *)(ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
 | |
| 
 | |
|     if (IS_SECTION2 (Section)) {
 | |
|       ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
 | |
|       if (!IsFfs3Fv) {
 | |
|         DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
 | |
|         Status = EFI_NOT_FOUND;
 | |
|         goto GetSection_Done;
 | |
|       }
 | |
| 
 | |
|       CopySize   = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
 | |
|       CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2);
 | |
|     } else {
 | |
|       CopySize   = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
 | |
|       CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER);
 | |
|     }
 | |
| 
 | |
|     *AuthenticationStatus = ExtractedAuthenticationStatus;
 | |
|   }
 | |
| 
 | |
|   SectionSize = CopySize;
 | |
|   if (*Buffer != NULL) {
 | |
|     //
 | |
|     // Caller allocated buffer.  Fill to size and return required size...
 | |
|     //
 | |
|     if (*BufferSize < CopySize) {
 | |
|       Status   = EFI_WARN_BUFFER_TOO_SMALL;
 | |
|       CopySize = *BufferSize;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Callee allocated buffer.  Allocate buffer and return size.
 | |
|     //
 | |
|     *Buffer = AllocatePool (CopySize);
 | |
|     if (*Buffer == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto GetSection_Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   CopyMem (*Buffer, CopyBuffer, CopySize);
 | |
|   *BufferSize = SectionSize;
 | |
| 
 | |
| GetSection_Done:
 | |
|   CoreRestoreTpl (OldTpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Destructor for child nodes.
 | |
| 
 | |
|   @param  ChildNode              Indicates the node to destroy
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FreeChildNode (
 | |
|   IN  CORE_SECTION_CHILD_NODE  *ChildNode
 | |
|   )
 | |
| {
 | |
|   ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
 | |
|   //
 | |
|   // Remove the child from it's list
 | |
|   //
 | |
|   RemoveEntryList (&ChildNode->Link);
 | |
| 
 | |
|   if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
 | |
|     //
 | |
|     // If it's an encapsulating section, we close the resulting section stream.
 | |
|     // CloseSectionStream will free all memory associated with the stream.
 | |
|     //
 | |
|     CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
 | |
|   }
 | |
| 
 | |
|   if (ChildNode->Event != NULL) {
 | |
|     gBS->CloseEvent (ChildNode->Event);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Last, free the child node itself
 | |
|   //
 | |
|   CoreFreePool (ChildNode);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   SEP member function.  Deletes an existing section stream
 | |
| 
 | |
|   @param  StreamHandleToClose    Indicates the stream to close
 | |
|   @param  FreeStreamBuffer       TRUE - Need to free stream buffer;
 | |
|                                  FALSE - No need to free stream buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The section stream is closed sucessfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
 | |
|   @retval EFI_INVALID_PARAMETER  Section stream does not end concident with end
 | |
|                                  of last section.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CloseSectionStream (
 | |
|   IN  UINTN    StreamHandleToClose,
 | |
|   IN  BOOLEAN  FreeStreamBuffer
 | |
|   )
 | |
| {
 | |
|   CORE_SECTION_STREAM_NODE  *StreamNode;
 | |
|   EFI_TPL                   OldTpl;
 | |
|   EFI_STATUS                Status;
 | |
|   LIST_ENTRY                *Link;
 | |
|   CORE_SECTION_CHILD_NODE   *ChildNode;
 | |
| 
 | |
|   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
 | |
| 
 | |
|   //
 | |
|   // Locate target stream
 | |
|   //
 | |
|   Status = FindStreamNode (StreamHandleToClose, &StreamNode);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Found the stream, so close it
 | |
|     //
 | |
|     RemoveEntryList (&StreamNode->Link);
 | |
|     while (!IsListEmpty (&StreamNode->Children)) {
 | |
|       Link      = GetFirstNode (&StreamNode->Children);
 | |
|       ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
 | |
|       FreeChildNode (ChildNode);
 | |
|     }
 | |
| 
 | |
|     if (FreeStreamBuffer) {
 | |
|       CoreFreePool (StreamNode->StreamBuffer);
 | |
|     }
 | |
| 
 | |
|     CoreFreePool (StreamNode);
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   CoreRestoreTpl (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The ExtractSection() function processes the input section and
 | |
|   allocates a buffer from the pool in which it returns the section
 | |
|   contents. If the section being extracted contains
 | |
|   authentication information (the section's
 | |
|   GuidedSectionHeader.Attributes field has the
 | |
|   EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
 | |
|   returned in AuthenticationStatus must reflect the results of
 | |
|   the authentication operation. Depending on the algorithm and
 | |
|   size of the encapsulated data, the time that is required to do
 | |
|   a full authentication may be prohibitively long for some
 | |
|   classes of systems. To indicate this, use
 | |
|   EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
 | |
|   the security policy driver (see the Platform Initialization
 | |
|   Driver Execution Environment Core Interface Specification for
 | |
|   more details and the GUID definition). If the
 | |
|   EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
 | |
|   database, then, if possible, full authentication should be
 | |
|   skipped and the section contents simply returned in the
 | |
|   OutputBuffer. In this case, the
 | |
|   EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
 | |
|   must be set on return. ExtractSection() is callable only from
 | |
|   TPL_NOTIFY and below. Behavior of ExtractSection() at any
 | |
|   EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
 | |
|   defined in RaiseTPL() in the UEFI 2.0 specification.
 | |
| 
 | |
| 
 | |
|   @param This         Indicates the
 | |
|                       EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
 | |
|   @param InputSection Buffer containing the input GUIDed section
 | |
|                       to be processed. OutputBuffer OutputBuffer
 | |
|                       is allocated from boot services pool
 | |
|                       memory and contains the new section
 | |
|                       stream. The caller is responsible for
 | |
|                       freeing this buffer.
 | |
|   @param OutputBuffer *OutputBuffer is allocated from boot services
 | |
|                       pool memory and contains the new section stream.
 | |
|                       The caller is responsible for freeing this buffer.
 | |
|   @param OutputSize   A pointer to a caller-allocated UINTN in
 | |
|                       which the size of OutputBuffer allocation
 | |
|                       is stored. If the function returns
 | |
|                       anything other than EFI_SUCCESS, the value
 | |
|                       of OutputSize is undefined.
 | |
| 
 | |
|   @param AuthenticationStatus A pointer to a caller-allocated
 | |
|                               UINT32 that indicates the
 | |
|                               authentication status of the
 | |
|                               output buffer. If the input
 | |
|                               section's
 | |
|                               GuidedSectionHeader.Attributes
 | |
|                               field has the
 | |
|                               EFI_GUIDED_SECTION_AUTH_STATUS_VAL
 | |
|                               bit as clear, AuthenticationStatus
 | |
|                               must return zero. Both local bits
 | |
|                               (19:16) and aggregate bits (3:0)
 | |
|                               in AuthenticationStatus are
 | |
|                               returned by ExtractSection().
 | |
|                               These bits reflect the status of
 | |
|                               the extraction operation. The bit
 | |
|                               pattern in both regions must be
 | |
|                               the same, as the local and
 | |
|                               aggregate authentication statuses
 | |
|                               have equivalent meaning at this
 | |
|                               level. If the function returns
 | |
|                               anything other than EFI_SUCCESS,
 | |
|                               the value of AuthenticationStatus
 | |
|                               is undefined.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS          The InputSection was successfully
 | |
|                                processed and the section contents were
 | |
|                                returned.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES The system has insufficient
 | |
|                                resources to process the
 | |
|                                request.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
 | |
|                                 not match this instance of the
 | |
|                                 GUIDed Section Extraction
 | |
|                                 Protocol.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CustomGuidedSectionExtract (
 | |
|   IN CONST  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL  *This,
 | |
|   IN CONST  VOID                                    *InputSection,
 | |
|   OUT       VOID                                    **OutputBuffer,
 | |
|   OUT       UINTN                                   *OutputSize,
 | |
|   OUT       UINT32                                  *AuthenticationStatus
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   VOID        *ScratchBuffer;
 | |
|   VOID        *AllocatedOutputBuffer;
 | |
|   UINT32      OutputBufferSize;
 | |
|   UINT32      ScratchBufferSize;
 | |
|   UINT16      SectionAttribute;
 | |
| 
 | |
|   //
 | |
|   // Init local variable
 | |
|   //
 | |
|   ScratchBuffer         = NULL;
 | |
|   AllocatedOutputBuffer = NULL;
 | |
| 
 | |
|   //
 | |
|   // Call GetInfo to get the size and attribute of input guided section data.
 | |
|   //
 | |
|   Status = ExtractGuidedSectionGetInfo (
 | |
|              InputSection,
 | |
|              &OutputBufferSize,
 | |
|              &ScratchBufferSize,
 | |
|              &SectionAttribute
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (ScratchBufferSize > 0) {
 | |
|     //
 | |
|     // Allocate scratch buffer
 | |
|     //
 | |
|     ScratchBuffer = AllocatePool (ScratchBufferSize);
 | |
|     if (ScratchBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (OutputBufferSize > 0) {
 | |
|     //
 | |
|     // Allocate output buffer
 | |
|     //
 | |
|     AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
 | |
|     if (AllocatedOutputBuffer == NULL) {
 | |
|       if (ScratchBuffer != NULL) {
 | |
|         FreePool (ScratchBuffer);
 | |
|       }
 | |
| 
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     *OutputBuffer = AllocatedOutputBuffer;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Call decode function to extract raw data from the guided section.
 | |
|   //
 | |
|   Status = ExtractGuidedSectionDecode (
 | |
|              InputSection,
 | |
|              OutputBuffer,
 | |
|              ScratchBuffer,
 | |
|              AuthenticationStatus
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Decode failed
 | |
|     //
 | |
|     if (AllocatedOutputBuffer != NULL) {
 | |
|       CoreFreePool (AllocatedOutputBuffer);
 | |
|     }
 | |
| 
 | |
|     if (ScratchBuffer != NULL) {
 | |
|       CoreFreePool (ScratchBuffer);
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (*OutputBuffer != AllocatedOutputBuffer) {
 | |
|     //
 | |
|     // OutputBuffer was returned as a different value,
 | |
|     // so copy section contents to the allocated memory buffer.
 | |
|     //
 | |
|     CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
 | |
|     *OutputBuffer = AllocatedOutputBuffer;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set real size of output buffer.
 | |
|   //
 | |
|   *OutputSize = (UINTN)OutputBufferSize;
 | |
| 
 | |
|   //
 | |
|   // Free unused scratch buffer.
 | |
|   //
 | |
|   if (ScratchBuffer != NULL) {
 | |
|     CoreFreePool (ScratchBuffer);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |