+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-Module Name:\r
-\r
- CoreSectionExtraction.c\r
- \r
-Abstract:\r
-\r
- Section Extraction Protocol implementation.\r
- \r
- Stream database is implemented as a linked list of section streams,\r
- where each stream contains a linked list of children, which may be leaves or\r
- encapsulations. \r
- \r
- Children that are encapsulations generate new stream entries\r
- when they are created. Streams can also be created by calls to \r
- SEP->OpenSectionStream().\r
- \r
- The database is only created far enough to return the requested data from\r
- any given stream, or to determine that the requested data is not found.\r
- \r
- If a GUIDed encapsulation is encountered, there are three possiblilites.\r
- \r
- 1) A support protocol is found, in which the stream is simply processed with\r
- the support protocol.\r
- \r
- 2) A support protocol is not found, but the data is available to be read\r
- without processing. In this case, the database is built up through the\r
- recursions to return the data, and a RPN event is set that will enable\r
- the stream in question to be refreshed if and when the required section\r
- extraction protocol is published.This insures the AuthenticationStatus \r
- does not become stale in the cache.\r
- \r
- 3) A support protocol is not found, and the data is not available to be read\r
- without it. This results in EFI_PROTOCOL_ERROR.\r
- \r
---*/\r
-\r
-#include <DxeMain.h>\r
-\r
-//\r
-// Local defines and typedefs\r
-//\r
-#define CORE_SECTION_CHILD_SIGNATURE EFI_SIGNATURE_32('S','X','C','S')\r
-#define CHILD_SECTION_NODE_FROM_LINK(Node) \\r
- CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)\r
-\r
-typedef struct {\r
- UINT32 Signature;\r
- LIST_ENTRY Link;\r
- UINT32 Type;\r
- UINT32 Size;\r
- //\r
- // StreamBase + OffsetInStream == pointer to section header in stream. The\r
- // stream base is always known when walking the sections within.\r
- //\r
- UINT32 OffsetInStream;\r
- //\r
- // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an\r
- // encapsulating section. Otherwise, it contains the stream handle\r
- // of the encapsulated stream. This handle is ALWAYS produced any time an\r
- // encapsulating child is encountered, irrespective of whether the\r
- // encapsulated stream is processed further.\r
- //\r
- UINTN EncapsulatedStreamHandle;\r
- EFI_GUID *EncapsulationGuid;\r
-} CORE_SECTION_CHILD_NODE;\r
-\r
-#define CORE_SECTION_STREAM_SIGNATURE EFI_SIGNATURE_32('S','X','S','S')\r
-#define STREAM_NODE_FROM_LINK(Node) \\r
- CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)\r
-\r
-typedef struct {\r
- UINT32 Signature;\r
- LIST_ENTRY Link;\r
- UINTN StreamHandle;\r
- UINT8 *StreamBuffer;\r
- UINTN StreamLength;\r
- LIST_ENTRY Children;\r
- //\r
- // Authentication status is from GUIDed encapsulations.\r
- //\r
- UINT32 AuthenticationStatus;\r
-} CORE_SECTION_STREAM_NODE;\r
-\r
-#define NULL_STREAM_HANDLE 0\r
-\r
-typedef struct {\r
- CORE_SECTION_CHILD_NODE *ChildNode;\r
- CORE_SECTION_STREAM_NODE *ParentStream;\r
- VOID *Registration;\r
- EFI_EVENT Event;\r
-} RPN_EVENT_CONTEXT;\r
- \r
- \r
-\r
-//\r
-// Local prototypes\r
-//\r
-\r
-STATIC\r
-BOOLEAN\r
-ChildIsType (\r
- IN CORE_SECTION_STREAM_NODE *Stream,\r
- IN CORE_SECTION_CHILD_NODE *Child,\r
- IN EFI_SECTION_TYPE SearchType,\r
- IN EFI_GUID *SectionDefinitionGuid\r
- );\r
-\r
-STATIC\r
-VOID\r
-EFIAPI\r
-NotifyGuidedExtraction (\r
- IN EFI_EVENT Event,\r
- IN VOID *RpnContext\r
- );\r
-\r
-STATIC\r
-VOID\r
-CreateGuidedExtractionRpnEvent (\r
- IN CORE_SECTION_STREAM_NODE *ParentStream,\r
- IN CORE_SECTION_CHILD_NODE *ChildNode\r
- );\r
-\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-OpenSectionStream (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN SectionStreamLength,\r
- IN VOID *SectionStream,\r
- OUT UINTN *SectionStreamHandle\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-GetSection (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN SectionStreamHandle,\r
- IN EFI_SECTION_TYPE *SectionType,\r
- IN EFI_GUID *SectionDefinitionGuid,\r
- IN UINTN SectionInstance,\r
- IN VOID **Buffer,\r
- IN OUT UINTN *BufferSize,\r
- OUT UINT32 *AuthenticationStatus\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-CloseSectionStream (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN StreamHandleToClose\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-FindStreamNode (\r
- IN UINTN SearchHandle,\r
- OUT CORE_SECTION_STREAM_NODE **FoundStream\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-FindChildNode (\r
- IN CORE_SECTION_STREAM_NODE *SourceStream,\r
- IN EFI_SECTION_TYPE SearchType,\r
- IN UINTN *SectionInstance,\r
- IN EFI_GUID *SectionDefinitionGuid,\r
- OUT CORE_SECTION_CHILD_NODE **FoundChild,\r
- OUT CORE_SECTION_STREAM_NODE **FoundStream,\r
- OUT UINT32 *AuthenticationStatus\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-CreateChildNode (\r
- IN CORE_SECTION_STREAM_NODE *Stream,\r
- IN UINT32 ChildOffset,\r
- OUT CORE_SECTION_CHILD_NODE **ChildNode\r
- );\r
- \r
-STATIC\r
-VOID\r
-FreeChildNode (\r
- IN CORE_SECTION_CHILD_NODE *ChildNode\r
- );\r
- \r
-STATIC\r
-EFI_STATUS\r
-OpenSectionStreamEx (\r
- IN UINTN SectionStreamLength,\r
- IN VOID *SectionStream,\r
- IN BOOLEAN AllocateBuffer,\r
- IN UINT32 AuthenticationStatus, \r
- OUT UINTN *SectionStreamHandle\r
- );\r
- \r
-STATIC\r
-BOOLEAN\r
-IsValidSectionStream (\r
- IN VOID *SectionStream,\r
- IN UINTN SectionStreamLength\r
- );\r
- \r
-//\r
-// Module globals\r
-//\r
-LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);\r
-\r
-EFI_HANDLE mSectionExtractionHandle = NULL;\r
-\r
-EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = { \r
- OpenSectionStream, \r
- GetSection, \r
- CloseSectionStream\r
-};\r
-\r
- \r
-EFI_STATUS\r
-EFIAPI\r
-InitializeSectionExtraction (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description: \r
- Entry point of the section extraction code. Initializes an instance of the \r
- section extraction interface and installs it on a new handle.\r
-\r
-Arguments: \r
- ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver\r
- SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table \r
-\r
-Returns: \r
- EFI_SUCCESS: Driver initialized successfully\r
- EFI_OUT_OF_RESOURCES: Could not allocate needed resources\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Install SEP to a new handle\r
- //\r
- Status = CoreInstallProtocolInterface (\r
- &mSectionExtractionHandle,\r
- &gEfiSectionExtractionProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &mSectionExtraction\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-OpenSectionStream (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN SectionStreamLength,\r
- IN VOID *SectionStream,\r
- OUT UINTN *SectionStreamHandle\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- SEP member function. This function creates and returns a new section stream\r
- handle to represent the new section stream.\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- SectionStreamLength - Size in bytes of the section stream.\r
- SectionStream - Buffer containing the new section stream.\r
- SectionStreamHandle - A pointer to a caller allocated UINTN that on output\r
- contains the new section stream handle.\r
-\r
-Returns:\r
- EFI_SUCCESS\r
- EFI_OUT_OF_RESOURCES - memory allocation failed.\r
- EFI_INVALID_PARAMETER - section stream does not end concident with end of\r
- last section.\r
-\r
---*/\r
-{\r
- //\r
- // Check to see section stream looks good...\r
- //\r
- if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- \r
- return OpenSectionStreamEx ( \r
- SectionStreamLength, \r
- SectionStream,\r
- TRUE,\r
- 0,\r
- SectionStreamHandle\r
- );\r
-}\r
- \r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-GetSection (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN SectionStreamHandle,\r
- IN EFI_SECTION_TYPE *SectionType,\r
- IN EFI_GUID *SectionDefinitionGuid,\r
- IN UINTN SectionInstance,\r
- IN VOID **Buffer,\r
- IN OUT UINTN *BufferSize,\r
- OUT UINT32 *AuthenticationStatus\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- SEP member function. Retrieves requested section from section stream.\r
-\r
-Arguments: \r
- This: Pointer to SEP instance.\r
- SectionStreamHandle: The section stream from which to extract the requested\r
- section.\r
- SectionType: A pointer to the type of section to search for.\r
- SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then\r
- SectionDefinitionGuid indicates which of these types\r
- of sections to search for.\r
- SectionInstance: Indicates which instance of the requested section to\r
- return.\r
- Buffer: Double indirection to buffer. If *Buffer is non-null on\r
- input, then the buffer is caller allocated. If\r
- *Buffer is NULL, then the buffer is callee allocated.\r
- In either case, the requried buffer size is returned\r
- in *BufferSize.\r
- BufferSize: On input, indicates the size of *Buffer if *Buffer is\r
- non-null on input. On output, indicates the required\r
- size (allocated size if callee allocated) of *Buffer.\r
- AuthenticationStatus: Indicates the authentication status of the retrieved\r
- section.\r
-\r
-Returns: \r
- EFI_SUCCESS: Section was retrieved successfully\r
- EFI_PROTOCOL_ERROR: A GUID defined section was encountered in the section \r
- stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED\r
- bit set, but there was no corresponding GUIDed Section \r
- Extraction Protocol in the handle database. *Buffer is \r
- unmodified.\r
- EFI_NOT_FOUND: An error was encountered when parsing the SectionStream.\r
- This indicates the SectionStream is not correctly \r
- formatted.\r
- EFI_NOT_FOUND: The requested section does not exist.\r
- EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the \r
- request.\r
- EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist.\r
- EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is \r
- insufficient to contain the requested section. The \r
- input buffer is filled and contents are section contents\r
- are truncated.\r
-\r
---*/\r
-{\r
- CORE_SECTION_STREAM_NODE *StreamNode;\r
- EFI_TPL OldTpl;\r
- EFI_STATUS Status;\r
- CORE_SECTION_CHILD_NODE *ChildNode;\r
- CORE_SECTION_STREAM_NODE *ChildStreamNode;\r
- UINTN CopySize;\r
- UINT32 ExtractedAuthenticationStatus;\r
- UINTN Instance;\r
- UINT8 *CopyBuffer;\r
- UINTN SectionSize;\r
- \r
-\r
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
- Instance = SectionInstance + 1;\r
- \r
- //\r
- // Locate target stream\r
- //\r
- Status = FindStreamNode (SectionStreamHandle, &StreamNode);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto GetSection_Done;\r
- }\r
- \r
- //\r
- // Found the stream, now locate and return the appropriate section\r
- //\r
- if (SectionType == NULL) {\r
- //\r
- // SectionType == NULL means return the WHOLE section stream...\r
- //\r
- CopySize = StreamNode->StreamLength;\r
- CopyBuffer = StreamNode->StreamBuffer;\r
- *AuthenticationStatus = StreamNode->AuthenticationStatus;\r
- } else {\r
- //\r
- // There's a requested section type, so go find it and return it...\r
- //\r
- Status = FindChildNode (\r
- StreamNode, \r
- *SectionType, \r
- &Instance, \r
- SectionDefinitionGuid,\r
- &ChildNode,\r
- &ChildStreamNode, \r
- &ExtractedAuthenticationStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto GetSection_Done;\r
- }\r
- CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER);\r
- CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER);\r
- *AuthenticationStatus = ExtractedAuthenticationStatus;\r
- } \r
- \r
- SectionSize = CopySize; \r
- if (*Buffer != NULL) {\r
- //\r
- // Caller allocated buffer. Fill to size and return required size...\r
- //\r
- if (*BufferSize < CopySize) {\r
- Status = EFI_WARN_BUFFER_TOO_SMALL;\r
- CopySize = *BufferSize;\r
- }\r
- } else {\r
- //\r
- // Callee allocated buffer. Allocate buffer and return size.\r
- //\r
- *Buffer = CoreAllocateBootServicesPool (CopySize);\r
- if (*Buffer == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto GetSection_Done;\r
- }\r
- }\r
- CopyMem (*Buffer, CopyBuffer, CopySize);\r
- *BufferSize = SectionSize;\r
- \r
-GetSection_Done:\r
- CoreRestoreTpl (OldTpl);\r
- return Status;\r
-}\r
-\r
-\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-CloseSectionStream (\r
- IN EFI_SECTION_EXTRACTION_PROTOCOL *This,\r
- IN UINTN StreamHandleToClose\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- SEP member function. Deletes an existing section stream\r
-\r
-Arguments:\r
- This - Indicates the calling context.\r
- StreamHandleToClose - Indicates the stream to close\r
-\r
-Returns:\r
- EFI_SUCCESS\r
- EFI_OUT_OF_RESOURCES - memory allocation failed.\r
- EFI_INVALID_PARAMETER - section stream does not end concident with end of\r
- last section.\r
-\r
---*/\r
-{\r
- CORE_SECTION_STREAM_NODE *StreamNode;\r
- EFI_TPL OldTpl;\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Link;\r
- CORE_SECTION_CHILD_NODE *ChildNode;\r
- \r
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
- \r
- //\r
- // Locate target stream\r
- //\r
- Status = FindStreamNode (StreamHandleToClose, &StreamNode);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Found the stream, so close it\r
- //\r
- RemoveEntryList (&StreamNode->Link);\r
- while (!IsListEmpty (&StreamNode->Children)) {\r
- Link = GetFirstNode (&StreamNode->Children);\r
- ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);\r
- FreeChildNode (ChildNode);\r
- }\r
- CoreFreePool (StreamNode->StreamBuffer);\r
- CoreFreePool (StreamNode);\r
- Status = EFI_SUCCESS;\r
- } else {\r
- Status = EFI_INVALID_PARAMETER;\r
- }\r
- \r
- CoreRestoreTpl (OldTpl);\r
- return Status;\r
-}\r
-\r
-\r
-STATIC\r
-BOOLEAN\r
-ChildIsType (\r
- IN CORE_SECTION_STREAM_NODE *Stream,\r
- IN CORE_SECTION_CHILD_NODE *Child,\r
- IN EFI_SECTION_TYPE SearchType,\r
- IN EFI_GUID *SectionDefinitionGuid\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Worker function. Determine if the input stream:child matches the input type.\r
-\r
-Arguments:\r
- Stream - Indicates the section stream associated with the child\r
- Child - Indicates the child to check\r
- SearchType - Indicates the type of section to check against for\r
- SectionDefinitionGuid - Indicates the GUID to check against if the type is\r
- EFI_SECTION_GUID_DEFINED\r
-Returns:\r
- TRUE - The child matches\r
- FALSE - The child doesn't match\r
-\r
---*/\r
-{\r
- EFI_GUID_DEFINED_SECTION *GuidedSection;\r
- \r
- if (SearchType == EFI_SECTION_ALL) {\r
- return TRUE;\r
- }\r
- if (Child->Type != SearchType) {\r
- return FALSE;\r
- }\r
- if (SearchType != EFI_SECTION_GUID_DEFINED) {\r
- return TRUE;\r
- }\r
- GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);\r
- return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);\r
-}\r
-\r
-\r
-STATIC\r
-EFI_STATUS\r
-FindChildNode (\r
- IN CORE_SECTION_STREAM_NODE *SourceStream,\r
- IN EFI_SECTION_TYPE SearchType,\r
- IN OUT UINTN *SectionInstance,\r
- IN EFI_GUID *SectionDefinitionGuid,\r
- OUT CORE_SECTION_CHILD_NODE **FoundChild,\r
- OUT CORE_SECTION_STREAM_NODE **FoundStream,\r
- OUT UINT32 *AuthenticationStatus\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Worker function Recursively searches / builds section stream database\r
- looking for requested section.\r
-\r
-Arguments:\r
- SourceStream - Indicates the section stream in which to do the search.\r
- SearchType - Indicates the type of section to search for.\r
- SectionInstance - Indicates which instance of section to find. This is\r
- an in/out parameter to deal with recursions.\r
- SectionDefinitionGuid - Guid of section definition\r
- FoundChild - Output indicating the child node that is found.\r
- FoundStream - Output indicating which section stream the child was\r
- found in. If this stream was generated as a result of\r
- an encapsulation section, the streamhandle is visible\r
- within the SEP driver only.\r
- AuthenticationStatus- Indicates the authentication status of the found section.\r
-\r
-Returns:\r
- EFI_SUCCESS - Child node was found and returned.\r
- EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
- EFI_NOT_FOUND - Requested child node does not exist.\r
- EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not\r
- exist\r
-\r
---*/\r
-{\r
- CORE_SECTION_CHILD_NODE *CurrentChildNode;\r
- CORE_SECTION_CHILD_NODE *RecursedChildNode;\r
- CORE_SECTION_STREAM_NODE *RecursedFoundStream;\r
- UINT32 NextChildOffset;\r
- EFI_STATUS ErrorStatus;\r
- EFI_STATUS Status;\r
- \r
- CurrentChildNode = NULL;\r
- ErrorStatus = EFI_NOT_FOUND;\r
- \r
- if (SourceStream->StreamLength == 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
- \r
- if (IsListEmpty (&SourceStream->Children) && \r
- SourceStream->StreamLength > sizeof (EFI_COMMON_SECTION_HEADER)) {\r
- //\r
- // This occurs when a section stream exists, but no child sections\r
- // have been parsed out yet. Therefore, extract the first child and add it\r
- // to the list of children so we can get started.\r
- //\r
- Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
- \r
- //\r
- // At least one child has been parsed out of the section stream. So, walk\r
- // through the sections that have already been parsed out looking for the\r
- // requested section, if necessary, continue parsing section stream and\r
- // adding children until either the requested section is found, or we run\r
- // out of data\r
- //\r
- CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));\r
-\r
- for (;;) {\r
- if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {\r
- //\r
- // The type matches, so check the instance count to see if it's the one we want\r
- //\r
- (*SectionInstance)--;\r
- if (*SectionInstance == 0) {\r
- //\r
- // Got it!\r
- //\r
- *FoundChild = CurrentChildNode;\r
- *FoundStream = SourceStream;\r
- *AuthenticationStatus = SourceStream->AuthenticationStatus;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- \r
- if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
- //\r
- // If the current node is an encapsulating node, recurse into it...\r
- //\r
- Status = FindChildNode (\r
- (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,\r
- SearchType,\r
- SectionInstance,\r
- SectionDefinitionGuid,\r
- &RecursedChildNode,\r
- &RecursedFoundStream,\r
- AuthenticationStatus\r
- );\r
- //\r
- // If the status is not EFI_SUCCESS, just save the error code and continue\r
- // to find the request child node in the rest stream.\r
- //\r
- if (*SectionInstance == 0) {\r
- ASSERT_EFI_ERROR (Status);\r
- *FoundChild = RecursedChildNode;\r
- *FoundStream = RecursedFoundStream;\r
- return EFI_SUCCESS;\r
- } else {\r
- ErrorStatus = Status;\r
- }\r
- }\r
- \r
- if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {\r
- //\r
- // We haven't found the child node we're interested in yet, but there's\r
- // still more nodes that have already been parsed so get the next one\r
- // and continue searching..\r
- //\r
- CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));\r
- } else {\r
- //\r
- // We've exhausted children that have already been parsed, so see if\r
- // there's any more data and continue parsing out more children if there\r
- // is.\r
- //\r
- NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;\r
- //\r
- // Round up to 4 byte boundary\r
- //\r
- NextChildOffset += 3;\r
- NextChildOffset &= ~(UINTN)3;\r
- if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {\r
- //\r
- // There's an unparsed child remaining in the stream, so create a new child node\r
- //\r
- Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
- ASSERT (EFI_ERROR (ErrorStatus));\r
- return ErrorStatus;\r
- }\r
- }\r
- }\r
-}\r
-\r
-\r
-STATIC\r
-EFI_STATUS\r
-CreateChildNode (\r
- IN CORE_SECTION_STREAM_NODE *Stream,\r
- IN UINT32 ChildOffset,\r
- OUT CORE_SECTION_CHILD_NODE **ChildNode\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Worker function. Constructor for new child nodes.\r
-\r
-Arguments:\r
- Stream - Indicates the section stream in which to add the child.\r
- ChildOffset - Indicates the offset in Stream that is the beginning\r
- of the child section.\r
- ChildNode - Indicates the Callee allocated and initialized child.\r
-\r
-Returns:\r
- EFI_SUCCESS - Child node was found and returned.\r
- EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
- EFI_PROTOCOL_ERROR - Encapsulation sections produce new stream handles when\r
- the child node is created. If the section type is GUID\r
- defined, and the extraction GUID does not exist, and\r
- producing the stream requires the GUID, then a protocol\r
- error is generated and no child is produced.\r
- Values returned by OpenSectionStreamEx.\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_COMMON_SECTION_HEADER *SectionHeader;\r
- EFI_COMPRESSION_SECTION *CompressionHeader;\r
- EFI_GUID_DEFINED_SECTION *GuidedHeader;\r
- EFI_TIANO_DECOMPRESS_PROTOCOL *Decompress;\r
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;\r
- VOID *NewStreamBuffer;\r
- VOID *ScratchBuffer;\r
- UINT32 ScratchSize;\r
- UINTN NewStreamBufferSize;\r
- UINT32 AuthenticationStatus;\r
- UINT32 SectionLength;\r
- \r
- CORE_SECTION_CHILD_NODE *Node;\r
-\r
- SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);\r
-\r
- //\r
- // Allocate a new node\r
- //\r
- *ChildNode = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_CHILD_NODE));\r
- Node = *ChildNode;\r
- if (Node == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- \r
- //\r
- // Now initialize it\r
- //\r
- Node->Signature = CORE_SECTION_CHILD_SIGNATURE;\r
- Node->Type = SectionHeader->Type;\r
- Node->Size = SECTION_SIZE (SectionHeader);\r
- Node->OffsetInStream = ChildOffset;\r
- Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;\r
- Node->EncapsulationGuid = NULL;\r
- \r
- //\r
- // If it's an encapsulating section, then create the new section stream also\r
- //\r
- switch (Node->Type) {\r
- case EFI_SECTION_COMPRESSION:\r
- //\r
- // Get the CompressionSectionHeader\r
- //\r
- ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));\r
- \r
- CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;\r
- \r
- //\r
- // Allocate space for the new stream\r
- //\r
- if (CompressionHeader->UncompressedLength > 0) {\r
- NewStreamBufferSize = CompressionHeader->UncompressedLength;\r
- NewStreamBuffer = CoreAllocateBootServicesPool (NewStreamBufferSize);\r
- if (NewStreamBuffer == NULL) {\r
- CoreFreePool (Node);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- \r
- if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) {\r
- //\r
- // stream is not actually compressed, just encapsulated. So just copy it.\r
- //\r
- CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize);\r
- } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION ||\r
- CompressionHeader->CompressionType == EFI_CUSTOMIZED_COMPRESSION) {\r
- //\r
- // Decompress the stream\r
- //\r
- if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) {\r
- Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);\r
- } else {\r
- Status = CoreLocateProtocol (&gEfiCustomizedDecompressProtocolGuid, NULL, (VOID **)&Decompress);\r
- }\r
- \r
- ASSERT_EFI_ERROR (Status);\r
- \r
- Status = Decompress->GetInfo (\r
- Decompress,\r
- CompressionHeader + 1,\r
- Node->Size - sizeof (EFI_COMPRESSION_SECTION),\r
- (UINT32 *)&NewStreamBufferSize,\r
- &ScratchSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength);\r
-\r
- ScratchBuffer = CoreAllocateBootServicesPool (ScratchSize);\r
- if (ScratchBuffer == NULL) {\r
- CoreFreePool (Node);\r
- CoreFreePool (NewStreamBuffer);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Status = Decompress->Decompress (\r
- Decompress,\r
- CompressionHeader + 1,\r
- Node->Size - sizeof (EFI_COMPRESSION_SECTION),\r
- NewStreamBuffer,\r
- (UINT32)NewStreamBufferSize,\r
- ScratchBuffer,\r
- ScratchSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- CoreFreePool (ScratchBuffer); \r
- }\r
- } else {\r
- NewStreamBuffer = NULL;\r
- NewStreamBufferSize = 0;\r
- }\r
- \r
- Status = OpenSectionStreamEx (\r
- NewStreamBufferSize,\r
- NewStreamBuffer,\r
- FALSE,\r
- Stream->AuthenticationStatus,\r
- &Node->EncapsulatedStreamHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- CoreFreePool (Node);\r
- CoreFreePool (NewStreamBuffer);\r
- return Status;\r
- }\r
- break;\r
-\r
- case EFI_SECTION_GUID_DEFINED:\r
- GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;\r
- Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;\r
- Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // NewStreamBuffer is always allocated by ExtractSection... No caller\r
- // allocation here.\r
- //\r
- Status = GuidedExtraction->ExtractSection (\r
- GuidedExtraction,\r
- GuidedHeader,\r
- &NewStreamBuffer,\r
- &NewStreamBufferSize,\r
- &AuthenticationStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- CoreFreePool (*ChildNode);\r
- return EFI_PROTOCOL_ERROR;\r
- }\r
- \r
- //\r
- // Make sure we initialize the new stream with the correct \r
- // authentication status for both aggregate and local status fields.\r
- //\r
- if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {\r
- //\r
- // OR in the parent stream's aggregate status.\r
- //\r
- AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;\r
- } else {\r
- //\r
- // since there's no authentication data contributed by the section,\r
- // just inherit the full value from our immediate parent.\r
- //\r
- AuthenticationStatus = Stream->AuthenticationStatus;\r
- }\r
- \r
- Status = OpenSectionStreamEx (\r
- NewStreamBufferSize,\r
- NewStreamBuffer,\r
- FALSE,\r
- AuthenticationStatus,\r
- &Node->EncapsulatedStreamHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- CoreFreePool (*ChildNode);\r
- CoreFreePool (NewStreamBuffer);\r
- return Status;\r
- }\r
- } else {\r
- //\r
- // There's no GUIDed section extraction protocol available.\r
- //\r
- if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {\r
- //\r
- // If the section REQUIRES an extraction protocol, then we're toast\r
- //\r
- CoreFreePool (*ChildNode);\r
- return EFI_PROTOCOL_ERROR;\r
- }\r
- \r
- //\r
- // Figure out the proper authentication status\r
- //\r
- AuthenticationStatus = Stream->AuthenticationStatus;\r
- if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {\r
- //\r
- // The local status of the new stream is contained in \r
- // AuthenticaionStatus. This value needs to be ORed into the\r
- // Aggregate bits also...\r
- //\r
- \r
- //\r
- // Clear out and initialize the local status\r
- //\r
- AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL;\r
- AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED;\r
- //\r
- // OR local status into aggregate status\r
- //\r
- AuthenticationStatus |= AuthenticationStatus >> 16;\r
- }\r
- \r
- SectionLength = SECTION_SIZE (GuidedHeader);\r
- Status = OpenSectionStreamEx (\r
- SectionLength - GuidedHeader->DataOffset,\r
- (UINT8 *) GuidedHeader + GuidedHeader->DataOffset,\r
- TRUE,\r
- AuthenticationStatus,\r
- &Node->EncapsulatedStreamHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- CoreFreePool (Node);\r
- return Status;\r
- }\r
- }\r
- \r
- if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) == \r
- (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) {\r
- //\r
- // Need to register for RPN for when the required GUIDed extraction\r
- // protocol becomes available. This will enable us to refresh the\r
- // AuthenticationStatus cached in the Stream if it's ever requested\r
- // again.\r
- //\r
- CreateGuidedExtractionRpnEvent (Stream, Node);\r
- }\r
- \r
- break;\r
-\r
- default:\r
- \r
- //\r
- // Nothing to do if it's a leaf\r
- //\r
- break;\r
- }\r
- \r
- //\r
- // Last, add the new child node to the stream\r
- //\r
- InsertTailList (&Stream->Children, &Node->Link);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-STATIC\r
-VOID\r
-CreateGuidedExtractionRpnEvent (\r
- IN CORE_SECTION_STREAM_NODE *ParentStream,\r
- IN CORE_SECTION_CHILD_NODE *ChildNode\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Worker function. Constructor for RPN event if needed to keep AuthenticationStatus\r
- cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...\r
-\r
-Arguments:\r
- ParentStream - Indicates the parent of the ecnapsulation section (child)\r
- ChildNode - Indicates the child node that is the encapsulation section.\r
-\r
-Returns:\r
- None\r
-\r
---*/\r
-{\r
- RPN_EVENT_CONTEXT *Context;\r
- \r
- //\r
- // Allocate new event structure and context\r
- //\r
- Context = CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT));\r
- ASSERT (Context != NULL);\r
- \r
- Context->ChildNode = ChildNode;\r
- Context->ParentStream = ParentStream;\r
- \r
- Context->Event = CoreCreateProtocolNotifyEvent (\r
- Context->ChildNode->EncapsulationGuid,\r
- TPL_NOTIFY,\r
- NotifyGuidedExtraction,\r
- Context,\r
- &Context->Registration,\r
- FALSE\r
- );\r
-}\r
- \r
- \r
-STATIC\r
-VOID\r
-EFIAPI\r
-NotifyGuidedExtraction (\r
- IN EFI_EVENT Event,\r
- IN VOID *RpnContext\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- RPN callback function. Removes a stale section stream and re-initializes it\r
- with an updated AuthenticationStatus.\r
-\r
-Arguments:\r
- Event - The event that fired\r
- RpnContext - A pointer to the context that allows us to identify\r
- the relevent encapsulation...\r
-\r
-Returns:\r
- None\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_GUID_DEFINED_SECTION *GuidedHeader;\r
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;\r
- VOID *NewStreamBuffer;\r
- UINTN NewStreamBufferSize;\r
- UINT32 AuthenticationStatus;\r
- RPN_EVENT_CONTEXT *Context;\r
- \r
- Context = RpnContext;\r
- \r
- Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // The stream closed successfully, so re-open the stream with correct AuthenticationStatus\r
- //\r
- \r
- GuidedHeader = (EFI_GUID_DEFINED_SECTION *) \r
- (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);\r
- ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);\r
- \r
- Status = CoreLocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- \r
- Status = GuidedExtraction->ExtractSection (\r
- GuidedExtraction,\r
- GuidedHeader,\r
- &NewStreamBuffer,\r
- &NewStreamBufferSize,\r
- &AuthenticationStatus\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- //\r
- // OR in the parent stream's aggregagate status.\r
- //\r
- AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;\r
- Status = OpenSectionStreamEx (\r
- NewStreamBufferSize,\r
- NewStreamBuffer,\r
- FALSE,\r
- AuthenticationStatus,\r
- &Context->ChildNode->EncapsulatedStreamHandle\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- //\r
- // If above, the stream did not close successfully, it indicates it's\r
- // alread been closed by someone, so just destroy the event and be done with\r
- // it.\r
- //\r
- \r
- CoreCloseEvent (Event);\r
- CoreFreePool (Context);\r
-} \r
- \r
-\r
-STATIC\r
-VOID\r
-FreeChildNode (\r
- IN CORE_SECTION_CHILD_NODE *ChildNode\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Worker function. Destructor for child nodes.\r
-\r
-Arguments:\r
- ChildNode - Indicates the node to destroy\r
-\r
-Returns:\r
- none\r
-\r
---*/\r
-{\r
- ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);\r
- //\r
- // Remove the child from it's list\r
- //\r
- RemoveEntryList (&ChildNode->Link);\r
- \r
- if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
- //\r
- // If it's an encapsulating section, we close the resulting section stream.\r
- // CloseSectionStream will free all memory associated with the stream.\r
- //\r
- CloseSectionStream (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle);\r
- }\r
- //\r
- // Last, free the child node itself\r
- //\r
- CoreFreePool (ChildNode);\r
-} \r
-\r
-\r
-STATIC\r
-EFI_STATUS\r
-OpenSectionStreamEx (\r
- IN UINTN SectionStreamLength,\r
- IN VOID *SectionStream,\r
- IN BOOLEAN AllocateBuffer,\r
- IN UINT32 AuthenticationStatus, \r
- OUT UINTN *SectionStreamHandle\r
- )\r
-/*++\r
-\r
- Routine Description:\r
- Worker function. Constructor for section streams.\r
-\r
- Arguments:\r
- SectionStreamLength - Size in bytes of the section stream.\r
- SectionStream - Buffer containing the new section stream.\r
- AllocateBuffer - Indicates whether the stream buffer is to be copied\r
- or the input buffer is to be used in place.\r
- AuthenticationStatus- Indicates the default authentication status for the\r
- new stream.\r
- SectionStreamHandle - A pointer to a caller allocated section stream handle.\r
-\r
- Returns:\r
- EFI_SUCCESS - Stream was added to stream database.\r
- EFI_OUT_OF_RESOURCES - memory allocation failed.\r
-\r
---*/\r
-{\r
- CORE_SECTION_STREAM_NODE *NewStream;\r
- EFI_TPL OldTpl;\r
- \r
- //\r
- // Allocate a new stream\r
- //\r
- NewStream = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_STREAM_NODE));\r
- if (NewStream == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- \r
- if (AllocateBuffer) { \r
- //\r
- // if we're here, we're double buffering, allocate the buffer and copy the\r
- // data in\r
- //\r
- if (SectionStreamLength > 0) {\r
- NewStream->StreamBuffer = CoreAllocateBootServicesPool (SectionStreamLength); \r
- if (NewStream->StreamBuffer == NULL) {\r
- CoreFreePool (NewStream);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Copy in stream data\r
- //\r
- CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);\r
- } else {\r
- //\r
- // It's possible to have a zero length section stream.\r
- //\r
- NewStream->StreamBuffer = NULL;\r
- }\r
- } else {\r
- //\r
- // If were here, the caller has supplied the buffer (it's an internal call)\r
- // so just assign the buffer. This happens when we open section streams\r
- // as a result of expanding an encapsulating section.\r
- //\r
- NewStream->StreamBuffer = SectionStream;\r
- }\r
- \r
- //\r
- // Initialize the rest of the section stream\r
- //\r
- NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;\r
- NewStream->StreamHandle = (UINTN) NewStream;\r
- NewStream->StreamLength = SectionStreamLength;\r
- InitializeListHead (&NewStream->Children);\r
- NewStream->AuthenticationStatus = AuthenticationStatus;\r
- \r
- //\r
- // Add new stream to stream list\r
- //\r
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
- InsertTailList (&mStreamRoot, &NewStream->Link);\r
- CoreRestoreTpl (OldTpl);\r
-\r
- *SectionStreamHandle = NewStream->StreamHandle;\r
- \r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-STATIC\r
-EFI_STATUS\r
-FindStreamNode (\r
- IN UINTN SearchHandle,\r
- OUT CORE_SECTION_STREAM_NODE **FoundStream\r
- )\r
-/*++\r
-\r
- Routine Description:\r
- Worker function. Search stream database for requested stream handle.\r
-\r
- Arguments:\r
- SearchHandle - Indicates which stream to look for.\r
- FoundStream - Output pointer to the found stream.\r
-\r
- Returns:\r
- EFI_SUCCESS - StreamHandle was found and *FoundStream contains\r
- the stream node.\r
- EFI_NOT_FOUND - SearchHandle was not found in the stream database.\r
-\r
---*/\r
-{ \r
- CORE_SECTION_STREAM_NODE *StreamNode;\r
- \r
- if (!IsListEmpty (&mStreamRoot)) {\r
- StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));\r
- for (;;) {\r
- if (StreamNode->StreamHandle == SearchHandle) {\r
- *FoundStream = StreamNode;\r
- return EFI_SUCCESS;\r
- } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {\r
- break;\r
- } else {\r
- StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));\r
- }\r
- }\r
- }\r
- \r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-\r
-STATIC\r
-BOOLEAN\r
-IsValidSectionStream (\r
- IN VOID *SectionStream,\r
- IN UINTN SectionStreamLength\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Check if a stream is valid.\r
-\r
-Arguments:\r
- SectionStream - The section stream to be checked\r
- SectionStreamLength - The length of section stream\r
-\r
-Returns:\r
- TRUE\r
- FALSE\r
-\r
---*/\r
-{\r
- UINTN TotalLength;\r
- UINTN SectionLength;\r
- EFI_COMMON_SECTION_HEADER *SectionHeader;\r
- EFI_COMMON_SECTION_HEADER *NextSectionHeader;\r
-\r
- TotalLength = 0;\r
- SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;\r
- \r
- while (TotalLength < SectionStreamLength) {\r
- SectionLength = SECTION_SIZE (SectionHeader);\r
- TotalLength += SectionLength;\r
-\r
- if (TotalLength == SectionStreamLength) {\r
- return TRUE; \r
- }\r
-\r
- //\r
- // Move to the next byte following the section...\r
- //\r
- SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);\r
- \r
- //\r
- // Figure out where the next section begins\r
- //\r
- NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) SectionHeader + 3);\r
- NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader & ~(UINTN)3);\r
- TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;\r
- SectionHeader = NextSectionHeader;\r
- }\r
-\r
- ASSERT (FALSE);\r
- return FALSE;\r
-}\r