summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/Dxe/SectionExtraction
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Core/Dxe/SectionExtraction')
-rw-r--r--MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c3306
1 files changed, 1653 insertions, 1653 deletions
diff --git a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
index 2152833ff6..ce1a3835ba 100644
--- a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
+++ b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
@@ -1,1653 +1,1653 @@
-/** @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",
- __func__
- ));
- //
- // 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;
-}
+/** @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",
+ __func__
+ ));
+ //
+ // 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;
+}