+/**\r
+ Worker function Recursively searches / builds section stream database\r
+ looking for requested section.\r
+\r
+ @param SourceStream Indicates the section stream in which to do the\r
+ search.\r
+ @param SearchType Indicates the type of section to search for.\r
+ @param SectionInstance Indicates which instance of section to find.\r
+ This is an in/out parameter to deal with\r
+ recursions.\r
+ @param SectionDefinitionGuid Guid of section definition\r
+ @param FoundChild Output indicating the child node that is found.\r
+ @param FoundStream Output indicating which section stream the child\r
+ was found in. If this stream was generated as a\r
+ result of an encapsulation section, the\r
+ streamhandle is visible within the SEP driver\r
+ only.\r
+ @param AuthenticationStatus Indicates the authentication status of the found section.\r
+\r
+ @retval EFI_SUCCESS Child node was found and returned.\r
+ EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
+ @retval EFI_NOT_FOUND Requested child node does not exist.\r
+ @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol\r
+ does not exist\r
+\r
+**/\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
+ 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
+ // Section stream may contain an array of zero or more bytes.\r
+ // So, its size should be >= the size of commen section header.\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
+ ASSERT (CurrentChildNode != NULL);\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
+/**\r
+ Worker function. Search stream database for requested stream handle.\r
+\r
+ @param SearchHandle Indicates which stream to look for.\r
+ @param FoundStream Output pointer to the found stream.\r
+\r
+ @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains\r
+ the stream node.\r
+ @retval EFI_NOT_FOUND SearchHandle was not found in the stream\r
+ database.\r
+\r
+**/\r
+EFI_STATUS\r
+FindStreamNode (\r
+ IN UINTN SearchHandle,\r
+ OUT CORE_SECTION_STREAM_NODE **FoundStream\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
+/**\r
+ SEP member function. Retrieves requested section from section stream.\r
+\r
+ @param SectionStreamHandle The section stream from which to extract the\r
+ requested section.\r
+ @param SectionType A pointer to the type of section to search for.\r
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,\r
+ then SectionDefinitionGuid indicates which of\r
+ these types of sections to search for.\r
+ @param SectionInstance Indicates which instance of the requested\r
+ section to return.\r
+ @param Buffer Double indirection to buffer. If *Buffer is\r
+ non-null on input, then the buffer is caller\r
+ allocated. If Buffer is NULL, then the buffer\r
+ is callee allocated. In either case, the\r
+ requried buffer size is returned in *BufferSize.\r
+ @param BufferSize On input, indicates the size of *Buffer if\r
+ *Buffer is non-null on input. On output,\r
+ indicates the required size (allocated size if\r
+ callee allocated) of *Buffer.\r
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that\r
+ indicates the authentication status of the\r
+ output buffer. If the input section's\r
+ GuidedSectionHeader.Attributes field\r
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID\r
+ bit as clear, AuthenticationStatus must return\r
+ zero. Both local bits (19:16) and aggregate\r
+ bits (3:0) in AuthenticationStatus are returned\r
+ by ExtractSection(). These bits reflect the\r
+ status of the extraction operation. The bit\r
+ pattern in both regions must be the same, as\r
+ the local and aggregate authentication statuses\r
+ have equivalent meaning at this level. If the\r
+ function returns anything other than\r
+ EFI_SUCCESS, the value of *AuthenticationStatus\r
+ is undefined.\r
+\r
+ @retval EFI_SUCCESS Section was retrieved successfully\r
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the\r
+ section stream with its\r
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,\r
+ but there was no corresponding GUIDed Section\r
+ Extraction Protocol in the handle database.\r
+ *Buffer is unmodified.\r
+ @retval EFI_NOT_FOUND An error was encountered when parsing the\r
+ SectionStream. This indicates the SectionStream\r
+ is not correctly formatted.\r
+ @retval EFI_NOT_FOUND The requested section does not exist.\r
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process\r
+ the request.\r
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.\r
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is\r
+ insufficient to contain the requested section.\r
+ The input buffer is filled and section contents\r
+ are truncated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSection (\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