mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-27 10:50:43 +00:00 
			
		
		
		
	 91c681977b
			
		
	
	
		91c681977b
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8669 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1320 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1320 lines
		
	
	
		
			48 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 - 2009, Intel Corporation. <BR>
 | |
| All rights reserved. This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <FrameworkDxe.h>
 | |
| 
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Protocol/Decompress.h>
 | |
| #include <Protocol/GuidedSectionExtraction.h>
 | |
| #include <Protocol/SectionExtraction.h>
 | |
| 
 | |
| //
 | |
| // Local defines and typedefs
 | |
| //
 | |
| #define FRAMEWORK_SECTION_CHILD_SIGNATURE  SIGNATURE_32('S','X','F','S')
 | |
| #define CHILD_SECTION_NODE_FROM_LINK(Node) \
 | |
|   CR (Node, FRAMEWORK_SECTION_CHILD_NODE, Link, FRAMEWORK_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;
 | |
| } FRAMEWORK_SECTION_CHILD_NODE;
 | |
| 
 | |
| #define FRAMEWORK_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
 | |
| #define STREAM_NODE_FROM_LINK(Node) \
 | |
|   CR (Node, FRAMEWORK_SECTION_STREAM_NODE, Link, FRAMEWORK_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;
 | |
| } FRAMEWORK_SECTION_STREAM_NODE;
 | |
| 
 | |
| #define NULL_STREAM_HANDLE    0
 | |
| 
 | |
| typedef struct {
 | |
|   FRAMEWORK_SECTION_CHILD_NODE     *ChildNode;
 | |
|   FRAMEWORK_SECTION_STREAM_NODE    *ParentStream;
 | |
|   VOID                             *Registration;
 | |
|   EFI_EVENT                        Event;
 | |
| } RPN_EVENT_CONTEXT;
 | |
| 
 | |
| /**
 | |
|   SEP member function.  This function creates and returns a new section stream
 | |
|   handle to represent the new section stream.
 | |
| 
 | |
|   @param This                 Indicates the calling context.
 | |
|   @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           Section wase opened 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     EFI_SECTION_EXTRACTION_PROTOCOL           *This,
 | |
|   IN     UINTN                                     SectionStreamLength,
 | |
|   IN     VOID                                      *SectionStream,
 | |
|      OUT UINTN                                     *SectionStreamHandle
 | |
|   )
 | |
| ;
 | |
| 
 | |
| /**
 | |
|   SEP member function.  Retrieves requested section from section stream.
 | |
| 
 | |
|   @param This                  Pointer to SEP instance.
 | |
|   @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 requried 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  Indicates the authentication status of the retrieved
 | |
|                                section.
 | |
| 
 | |
|  
 | |
|   @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 contents are section contents
 | |
|                                 are truncated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetSection (
 | |
|   IN EFI_SECTION_EXTRACTION_PROTOCOL                    *This,
 | |
|   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
 | |
|   )
 | |
| ;
 | |
| 
 | |
| /**
 | |
|   SEP member function.  Deletes an existing section stream
 | |
| 
 | |
|   @param This                   Indicates the calling context.
 | |
|   @param StreamHandleToClose    Indicates the stream to close
 | |
| 
 | |
|   @retval EFI_SUCCESS           Section stream was closed 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
 | |
| CloseSectionStream (
 | |
|   IN  EFI_SECTION_EXTRACTION_PROTOCOL           *This,
 | |
|   IN  UINTN                                     StreamHandleToClose
 | |
|   )
 | |
| ;
 | |
| 
 | |
| //
 | |
| // Module globals
 | |
| //
 | |
| LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
 | |
| 
 | |
| EFI_HANDLE mSectionExtractionHandle = NULL;
 | |
| 
 | |
| EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = { 
 | |
|   OpenSectionStream, 
 | |
|   GetSection, 
 | |
|   CloseSectionStream
 | |
| };
 | |
| 
 | |
| /**
 | |
|   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
 | |
| SectionExtractionEntryPoint (
 | |
|   IN EFI_HANDLE                   ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE             *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                         Status;
 | |
| 
 | |
|   //
 | |
|   // Install SEP to a new handle
 | |
|   //
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &mSectionExtractionHandle,
 | |
|                   &gEfiSectionExtractionProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &mSectionExtraction
 | |
|                   );
 | |
|   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) {
 | |
|     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.
 | |
|   @param AuthenticationStatus  Indicates the default authentication status for the
 | |
|                                new stream.
 | |
|   @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
 | |
|   )
 | |
| {
 | |
|   FRAMEWORK_SECTION_STREAM_NODE    *NewStream;
 | |
|   EFI_TPL                     OldTpl;
 | |
|   
 | |
|   //
 | |
|   // Allocate a new stream
 | |
|   //
 | |
|   NewStream = AllocatePool (sizeof (FRAMEWORK_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) {
 | |
|         FreePool (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 = FRAMEWORK_SECTION_STREAM_SIGNATURE;
 | |
|   NewStream->StreamHandle = (UINTN) NewStream;
 | |
|   NewStream->StreamLength = SectionStreamLength;
 | |
|   InitializeListHead (&NewStream->Children);
 | |
|   NewStream->AuthenticationStatus = AuthenticationStatus;
 | |
|   
 | |
|   //
 | |
|   // Add new stream to stream list
 | |
|   //
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   InsertTailList (&mStreamRoot, &NewStream->Link);
 | |
|   gBS->RestoreTPL (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 This                 Indicates the calling context.
 | |
|   @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           Section wase opened 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     EFI_SECTION_EXTRACTION_PROTOCOL           *This,
 | |
|   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,
 | |
|           TRUE,
 | |
|           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 FRAMEWORK_SECTION_STREAM_NODE *Stream,
 | |
|   IN FRAMEWORK_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) {
 | |
|     return TRUE;
 | |
|   }
 | |
|   GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
 | |
|   return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a protocol notification event and return it.
 | |
| 
 | |
|   @param ProtocolGuid    Protocol to register notification event on.
 | |
|   @param NotifyTpl       Maximum TPL to signal the NotifyFunction.
 | |
|   @param NotifyFunction  EFI notification routine.
 | |
|   @param NotifyContext   Context passed into Event when it is created.
 | |
|   @param Registration    Registration key returned from RegisterProtocolNotify().
 | |
|   @param SignalFlag      Boolean value to decide whether kick the event after register or not.
 | |
| 
 | |
|   @return The EFI_EVENT that has been registered to be signaled when a ProtocolGuid
 | |
|            is added to the system.
 | |
| 
 | |
| **/
 | |
| EFI_EVENT
 | |
| CreateProtocolNotifyEvent (
 | |
|   IN EFI_GUID             *ProtocolGuid,
 | |
|   IN EFI_TPL              NotifyTpl,
 | |
|   IN EFI_EVENT_NOTIFY     NotifyFunction,
 | |
|   IN VOID                 *NotifyContext,
 | |
|   OUT VOID                **Registration,
 | |
|   IN  BOOLEAN             SignalFlag
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_EVENT               Event;
 | |
| 
 | |
|   //
 | |
|   // Create the event
 | |
|   //
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|             EVT_NOTIFY_SIGNAL,
 | |
|             NotifyTpl,
 | |
|             NotifyFunction,
 | |
|             NotifyContext,
 | |
|            &Event
 | |
|             );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Register for protocol notifactions on this event
 | |
|   //
 | |
| 
 | |
|   Status = gBS->RegisterProtocolNotify (
 | |
|             ProtocolGuid,
 | |
|             Event,
 | |
|             Registration
 | |
|             );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   if (SignalFlag) {
 | |
|     //
 | |
|     // Kick the event so we will perform an initial pass of
 | |
|     // current installed drivers
 | |
|     //
 | |
|     gBS->SignalEvent (Event);
 | |
|   }
 | |
| 
 | |
|   return Event;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   RPN callback function.  Removes a stale section stream and re-initializes it
 | |
|   with an updated AuthenticationStatus.
 | |
| 
 | |
|   @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;
 | |
|   
 | |
|   Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // The stream closed successfully, so re-open the stream with correct AuthenticationStatus
 | |
|     //
 | |
|   
 | |
|     GuidedHeader = (EFI_GUID_DEFINED_SECTION *) 
 | |
|       (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
 | |
|     ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
 | |
|     
 | |
|     Status = gBS->LocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     
 | |
|     Status = GuidedExtraction->ExtractSection (
 | |
|                                  GuidedExtraction,
 | |
|                                  GuidedHeader,
 | |
|                                  &NewStreamBuffer,
 | |
|                                  &NewStreamBufferSize,
 | |
|                                  &AuthenticationStatus
 | |
|                                  );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|     //
 | |
|     // OR in the parent stream's aggregagate status.
 | |
|     //
 | |
|     AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;
 | |
|     Status = OpenSectionStreamEx (
 | |
|                NewStreamBufferSize,
 | |
|                NewStreamBuffer,
 | |
|                FALSE,
 | |
|                AuthenticationStatus,
 | |
|                &Context->ChildNode->EncapsulatedStreamHandle
 | |
|                );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   //  If above, the stream  did not close successfully, it indicates it's
 | |
|   //  alread been closed by someone, so just destroy the event and be done with
 | |
|   //  it.
 | |
|   //
 | |
|   
 | |
|   gBS->CloseEvent (Event);
 | |
|   FreePool (Context);
 | |
| }  
 | |
| 
 | |
| /**
 | |
|   Worker function.  Constructor for RPN event if needed to keep AuthenticationStatus
 | |
|   cache correct 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 FRAMEWORK_SECTION_STREAM_NODE       *ParentStream,
 | |
|   IN FRAMEWORK_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->Event = CreateProtocolNotifyEvent (
 | |
|                     Context->ChildNode->EncapsulationGuid,
 | |
|                     TPL_NOTIFY,
 | |
|                     NotifyGuidedExtraction,
 | |
|                     Context,
 | |
|                     &Context->Registration,
 | |
|                     FALSE
 | |
|                     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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.
 | |
|   @retval 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     FRAMEWORK_SECTION_STREAM_NODE              *Stream,
 | |
|   IN     UINT32                                ChildOffset,
 | |
|      OUT FRAMEWORK_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;
 | |
|   UINT32                                       SectionLength;
 | |
|     
 | |
|   FRAMEWORK_SECTION_CHILD_NODE                      *Node;
 | |
| 
 | |
|   SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
 | |
| 
 | |
|   //
 | |
|   // Allocate a new node
 | |
|   //
 | |
|   *ChildNode = AllocatePool (sizeof (FRAMEWORK_SECTION_CHILD_NODE));
 | |
|   Node = *ChildNode;
 | |
|   if (Node == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Now initialize it
 | |
|   //
 | |
|   Node->Signature = FRAMEWORK_SECTION_CHILD_SIGNATURE;
 | |
|   Node->Type = SectionHeader->Type;
 | |
|   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
 | |
|       //
 | |
|       ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));
 | |
|       
 | |
|       CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
 | |
|       
 | |
|       //
 | |
|       // Allocate space for the new stream
 | |
|       //
 | |
|       if (CompressionHeader->UncompressedLength > 0) {
 | |
|         NewStreamBufferSize = CompressionHeader->UncompressedLength;
 | |
|         NewStreamBuffer = AllocatePool (NewStreamBufferSize);
 | |
|         if (NewStreamBuffer == NULL) {
 | |
|           FreePool (Node);
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         }
 | |
|         
 | |
|         if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) {
 | |
|           //
 | |
|           // stream is not actually compressed, just encapsulated.  So just copy it.
 | |
|           //
 | |
|           CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize);
 | |
|         } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) {
 | |
|           //
 | |
|           // Only support the EFI_SATNDARD_COMPRESSION algorithm.
 | |
|           // 
 | |
| 
 | |
|           //
 | |
|           // Decompress the stream
 | |
|           //
 | |
|           Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
 | |
|           
 | |
|           ASSERT_EFI_ERROR (Status);
 | |
|           
 | |
|           Status = Decompress->GetInfo (
 | |
|                                  Decompress,
 | |
|                                  CompressionHeader + 1,
 | |
|                                  Node->Size - sizeof (EFI_COMPRESSION_SECTION),
 | |
|                                  (UINT32 *)&NewStreamBufferSize,
 | |
|                                  &ScratchSize
 | |
|                                  );
 | |
|           ASSERT_EFI_ERROR (Status);
 | |
|           ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength);
 | |
| 
 | |
|           ScratchBuffer = AllocatePool (ScratchSize);
 | |
|           if (ScratchBuffer == NULL) {
 | |
|             FreePool (Node);
 | |
|             FreePool (NewStreamBuffer);
 | |
|             return EFI_OUT_OF_RESOURCES;
 | |
|           }
 | |
| 
 | |
|           Status = Decompress->Decompress (
 | |
|                                  Decompress,
 | |
|                                  CompressionHeader + 1,
 | |
|                                  Node->Size - sizeof (EFI_COMPRESSION_SECTION),
 | |
|                                  NewStreamBuffer,
 | |
|                                  (UINT32)NewStreamBufferSize,
 | |
|                                  ScratchBuffer,
 | |
|                                  ScratchSize
 | |
|                                  );
 | |
|           ASSERT_EFI_ERROR (Status);
 | |
|           FreePool (ScratchBuffer);                                           
 | |
|         }
 | |
|       } else {
 | |
|         NewStreamBuffer = NULL;
 | |
|         NewStreamBufferSize = 0;
 | |
|       }
 | |
|       
 | |
|       Status = OpenSectionStreamEx (
 | |
|                  NewStreamBufferSize,
 | |
|                  NewStreamBuffer,
 | |
|                  FALSE,
 | |
|                  Stream->AuthenticationStatus,
 | |
|                  &Node->EncapsulatedStreamHandle
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         FreePool (Node);
 | |
|         FreePool (NewStreamBuffer);
 | |
|         return Status;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_SECTION_GUID_DEFINED:
 | |
|       GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
 | |
|       Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
 | |
|       Status = gBS->LocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         //
 | |
|         // NewStreamBuffer is always allocated by ExtractSection... No caller
 | |
|         // allocation here.
 | |
|         //
 | |
|         Status = GuidedExtraction->ExtractSection (
 | |
|                                      GuidedExtraction,
 | |
|                                      GuidedHeader,
 | |
|                                      &NewStreamBuffer,
 | |
|                                      &NewStreamBufferSize,
 | |
|                                      &AuthenticationStatus
 | |
|                                      );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (*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 ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
 | |
|           //
 | |
|           // OR in the parent stream's aggregate status.
 | |
|           //
 | |
|           AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_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)) {
 | |
|           FreePool (*ChildNode);
 | |
|           FreePool (NewStreamBuffer);
 | |
|           return Status;
 | |
|         }
 | |
|       } else {
 | |
|         //
 | |
|         // There's no GUIDed section extraction protocol available.
 | |
|         //
 | |
|         if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {
 | |
|           //
 | |
|           // If the section REQUIRES an extraction protocol, then we're toast
 | |
|           //
 | |
|           FreePool (*ChildNode);
 | |
|           return EFI_PROTOCOL_ERROR;
 | |
|         }
 | |
|         
 | |
|         //
 | |
|         // Figure out the proper authentication status
 | |
|         //
 | |
|         AuthenticationStatus = Stream->AuthenticationStatus;
 | |
|         if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
 | |
|           //
 | |
|           //  The local status of the new stream is contained in 
 | |
|           //  AuthenticaionStatus.  This value needs to be ORed into the
 | |
|           //  Aggregate bits also...
 | |
|           //
 | |
|           
 | |
|           //
 | |
|           // Clear out and initialize the local status
 | |
|           //
 | |
|           AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL;
 | |
|           AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED;
 | |
|           //
 | |
|           // OR local status into aggregate status
 | |
|           //
 | |
|           AuthenticationStatus |= AuthenticationStatus >> 16;
 | |
|         }
 | |
|         
 | |
|         SectionLength = SECTION_SIZE (GuidedHeader);
 | |
|         Status = OpenSectionStreamEx (
 | |
|                    SectionLength - GuidedHeader->DataOffset,
 | |
|                    (UINT8 *) GuidedHeader + GuidedHeader->DataOffset,
 | |
|                    TRUE,
 | |
|                    AuthenticationStatus,
 | |
|                    &Node->EncapsulatedStreamHandle
 | |
|                    );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           FreePool (Node);
 | |
|           return Status;
 | |
|         }
 | |
|       }
 | |
|       
 | |
|       if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) == 
 | |
|             (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) {
 | |
|         //
 | |
|         // Need to register for RPN for when the required GUIDed extraction
 | |
|         // protocol becomes available.  This will enable us to refresh the
 | |
|         // AuthenticationStatus cached in the Stream if it's ever requested
 | |
|         // again.
 | |
|         //
 | |
|         CreateGuidedExtractionRpnEvent (Stream, Node);
 | |
|       }
 | |
|       
 | |
|       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 to deal with recursions.
 | |
|   @param SectionDefinitionGuid Guid of section definition
 | |
|   @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.
 | |
|   @retval 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
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindChildNode (
 | |
|   IN     FRAMEWORK_SECTION_STREAM_NODE                   *SourceStream,
 | |
|   IN     EFI_SECTION_TYPE                           SearchType,
 | |
|   IN OUT UINTN                                      *SectionInstance,
 | |
|   IN     EFI_GUID                                   *SectionDefinitionGuid,
 | |
|   OUT    FRAMEWORK_SECTION_CHILD_NODE                    **FoundChild,
 | |
|   OUT    FRAMEWORK_SECTION_STREAM_NODE                   **FoundStream,
 | |
|   OUT    UINT32                                     *AuthenticationStatus
 | |
|   )
 | |
| {
 | |
|   FRAMEWORK_SECTION_CHILD_NODE                       *CurrentChildNode;
 | |
|   FRAMEWORK_SECTION_CHILD_NODE                       *RecursedChildNode;
 | |
|   FRAMEWORK_SECTION_STREAM_NODE                      *RecursedFoundStream;
 | |
|   UINT32                                        NextChildOffset;
 | |
|   EFI_STATUS                                    ErrorStatus;
 | |
|   EFI_STATUS                                    Status;
 | |
|   
 | |
|   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 (;;) {
 | |
|     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;
 | |
|       }
 | |
|     }
 | |
|     
 | |
|     if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
 | |
|       //
 | |
|       // If the current node is an encapsulating node, recurse into it...
 | |
|       //
 | |
|       Status = FindChildNode (
 | |
|                 (FRAMEWORK_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
 | |
|                 SearchType,
 | |
|                 SectionInstance,
 | |
|                 SectionDefinitionGuid,
 | |
|                 &RecursedChildNode,
 | |
|                 &RecursedFoundStream,
 | |
|                 AuthenticationStatus
 | |
|                 );
 | |
|       //
 | |
|       // If the status is not EFI_SUCCESS, just save the error code and continue
 | |
|       // to find the request child node in the rest stream.
 | |
|       //
 | |
|       if (*SectionInstance == 0) {
 | |
|         ASSERT_EFI_ERROR (Status);
 | |
|         *FoundChild = RecursedChildNode;
 | |
|         *FoundStream = RecursedFoundStream;
 | |
|         return EFI_SUCCESS;
 | |
|       } else {
 | |
|         ErrorStatus = Status;
 | |
|       }
 | |
|     }
 | |
|     
 | |
|     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 FRAMEWORK_SECTION_STREAM_NODE                  **FoundStream
 | |
|   )
 | |
| {  
 | |
|   FRAMEWORK_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 This                  Pointer to SEP instance.
 | |
|   @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 requried 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  Indicates the authentication status of the retrieved
 | |
|                                section.
 | |
| 
 | |
|  
 | |
|   @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 contents are section contents
 | |
|                                 are truncated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetSection (
 | |
|   IN EFI_SECTION_EXTRACTION_PROTOCOL                    *This,
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   FRAMEWORK_SECTION_STREAM_NODE                              *StreamNode;
 | |
|   EFI_TPL                                               OldTpl;
 | |
|   EFI_STATUS                                            Status;
 | |
|   FRAMEWORK_SECTION_CHILD_NODE                               *ChildNode;
 | |
|   FRAMEWORK_SECTION_STREAM_NODE                              *ChildStreamNode;
 | |
|   UINTN                                                 CopySize;
 | |
|   UINT32                                                ExtractedAuthenticationStatus;
 | |
|   UINTN                                                 Instance;
 | |
|   UINT8                                                 *CopyBuffer;
 | |
|   UINTN                                                 SectionSize;
 | |
|   
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (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,
 | |
|                       &ChildNode,
 | |
|                       &ChildStreamNode, 
 | |
|                       &ExtractedAuthenticationStatus
 | |
|                       );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto GetSection_Done;
 | |
|     }
 | |
|     CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER);
 | |
|     CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + 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:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Worker function.  Destructor for child nodes.
 | |
| 
 | |
|   @param ChildNode           Indicates the node to destroy
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FreeChildNode (
 | |
|   IN  FRAMEWORK_SECTION_CHILD_NODE                   *ChildNode
 | |
|   )
 | |
| {
 | |
|   ASSERT (ChildNode->Signature == FRAMEWORK_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 (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle);
 | |
|   }
 | |
|   //
 | |
|   // Last, free the child node itself
 | |
|   //
 | |
|   FreePool (ChildNode);
 | |
| }  
 | |
| 
 | |
| /**
 | |
|   SEP member function.  Deletes an existing section stream
 | |
| 
 | |
|   @param This                   Indicates the calling context.
 | |
|   @param StreamHandleToClose    Indicates the stream to close
 | |
| 
 | |
|   @retval EFI_SUCCESS           Section stream was closed 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
 | |
| CloseSectionStream (
 | |
|   IN  EFI_SECTION_EXTRACTION_PROTOCOL           *This,
 | |
|   IN  UINTN                                     StreamHandleToClose
 | |
|   )
 | |
| {
 | |
|   FRAMEWORK_SECTION_STREAM_NODE                      *StreamNode;
 | |
|   EFI_TPL                                       OldTpl;
 | |
|   EFI_STATUS                                    Status;
 | |
|   LIST_ENTRY                                    *Link;
 | |
|   FRAMEWORK_SECTION_CHILD_NODE                       *ChildNode;
 | |
|   
 | |
|   OldTpl = gBS->RaiseTPL (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);
 | |
|     }
 | |
|     FreePool (StreamNode->StreamBuffer);
 | |
|     FreePool (StreamNode);
 | |
|     Status = EFI_SUCCESS;
 | |
|   } else {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 |