diff --git a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c index a7a4509bb1..c8484d45d4 100644 --- a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c +++ b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c @@ -95,191 +95,6 @@ typedef struct { } RPN_EVENT_CONTEXT; - -// -// Local prototypes -// -/** - 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 - ); - - -/** - 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 - ); - - -/** - Worker function Recursively searches / builds section stream database - looking for requested section. - - @param SourceStream Indicates the section stream in which to do the - search. - @param SearchType Indicates the type of section to search for. - @param SectionInstance Indicates which instance of section to find. - This is an in/out parameter to deal with - recursions. - @param SectionDefinitionGuid Guid of section definition - @param FoundChild Output indicating the child node that is found. - @param FoundStream Output indicating which section stream the child - was found in. If this stream was generated as a - result of an encapsulation section, the - streamhandle is visible within the SEP driver - only. - @param AuthenticationStatus Indicates the authentication status of the found section. - - @retval EFI_SUCCESS Child node was found and returned. - EFI_OUT_OF_RESOURCES- Memory allocation failed. - @retval EFI_NOT_FOUND Requested child node does not exist. - @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol - does not exist - -**/ -EFI_STATUS -FindChildNode ( - IN CORE_SECTION_STREAM_NODE *SourceStream, - IN EFI_SECTION_TYPE SearchType, - IN OUT UINTN *SectionInstance, - IN EFI_GUID *SectionDefinitionGuid, - OUT CORE_SECTION_CHILD_NODE **FoundChild, - OUT CORE_SECTION_STREAM_NODE **FoundStream, - OUT UINT32 *AuthenticationStatus - ); - - -/** - 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 - ); - - -/** - Worker function. Destructor for child nodes. - - @param ChildNode Indicates the node to destroy - -**/ -VOID -FreeChildNode ( - IN CORE_SECTION_CHILD_NODE *ChildNode - ); - - -/** - 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 - ); - - -/** - 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 - ); - - /** The ExtractSection() function processes the input section and allocates a buffer from the pool in which it returns the section @@ -430,6 +245,160 @@ InitializeSectionExtraction ( } +/** + Check if a stream is valid. + + @param SectionStream The section stream to be checked + @param SectionStreamLength The length of section stream + + @return A boolean value indicating the validness of the section stream. + +**/ +BOOLEAN +IsValidSectionStream ( + IN VOID *SectionStream, + IN UINTN SectionStreamLength + ) +{ + UINTN TotalLength; + UINTN SectionLength; + EFI_COMMON_SECTION_HEADER *SectionHeader; + EFI_COMMON_SECTION_HEADER *NextSectionHeader; + + TotalLength = 0; + SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream; + + while (TotalLength < SectionStreamLength) { + SectionLength = SECTION_SIZE (SectionHeader); + TotalLength += SectionLength; + + if (TotalLength == SectionStreamLength) { + return TRUE; + } + + // + // Move to the next byte following the section... + // + SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength); + + // + // Figure out where the next section begins + // + NextSectionHeader = ALIGN_POINTER(SectionHeader, 4); + TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; + SectionHeader = NextSectionHeader; + } + + ASSERT (FALSE); + return FALSE; +} + + +/** + Worker function. Constructor for section streams. + + @param SectionStreamLength Size in bytes of the section stream. + @param SectionStream Buffer containing the new section stream. + @param AllocateBuffer Indicates whether the stream buffer is to be + copied or the input buffer is to be used in + place. 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. @@ -470,211 +439,6 @@ OpenSectionStream ( } -/** - 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 - requried buffer size is returned in *BufferSize. - @param BufferSize On input, indicates the size of *Buffer if - *Buffer is non-null on input. On output, - indicates the required size (allocated size if - callee allocated) of *Buffer. - @param AuthenticationStatus 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. - - @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 - ) -{ - 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; - - - 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, - &ChildNode, - &ChildStreamNode, - &ExtractedAuthenticationStatus - ); - if (EFI_ERROR (Status)) { - goto GetSection_Done; - } - CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER); - CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER); - *AuthenticationStatus = ExtractedAuthenticationStatus; - } - - SectionSize = CopySize; - if (*Buffer != NULL) { - // - // Caller allocated buffer. Fill to size and return required size... - // - if (*BufferSize < CopySize) { - Status = EFI_WARN_BUFFER_TOO_SMALL; - CopySize = *BufferSize; - } - } else { - // - // Callee allocated buffer. Allocate buffer and return size. - // - *Buffer = AllocatePool (CopySize); - if (*Buffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto GetSection_Done; - } - } - CopyMem (*Buffer, CopyBuffer, CopySize); - *BufferSize = SectionSize; - -GetSection_Done: - CoreRestoreTpl (OldTpl); - - return Status; -} - - - -/** - SEP member function. Deletes an existing section stream - - @param StreamHandleToClose Indicates the stream to close - - @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 - ) -{ - 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); - } - CoreFreePool (StreamNode->StreamBuffer); - CoreFreePool (StreamNode); - Status = EFI_SUCCESS; - } else { - Status = EFI_INVALID_PARAMETER; - } - - CoreRestoreTpl (OldTpl); - return Status; -} - - /** Worker function. Determine if the input stream:child matches the input type. @@ -715,161 +479,6 @@ ChildIsType ( } -/** - Worker function Recursively searches / builds section stream database - looking for requested section. - - @param SourceStream Indicates the section stream in which to do the - search. - @param SearchType Indicates the type of section to search for. - @param SectionInstance Indicates which instance of section to find. - This is an in/out parameter to deal with - recursions. - @param SectionDefinitionGuid Guid of section definition - @param FoundChild Output indicating the child node that is found. - @param FoundStream Output indicating which section stream the child - was found in. If this stream was generated as a - result of an encapsulation section, the - streamhandle is visible within the SEP driver - only. - @param AuthenticationStatus Indicates the authentication status of the found section. - - @retval EFI_SUCCESS Child node was found and returned. - EFI_OUT_OF_RESOURCES- Memory allocation failed. - @retval EFI_NOT_FOUND Requested child node does not exist. - @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol - does not exist - -**/ -EFI_STATUS -FindChildNode ( - IN CORE_SECTION_STREAM_NODE *SourceStream, - IN EFI_SECTION_TYPE SearchType, - IN OUT UINTN *SectionInstance, - IN EFI_GUID *SectionDefinitionGuid, - 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; - - CurrentChildNode = NULL; - ErrorStatus = EFI_NOT_FOUND; - - if (SourceStream->StreamLength == 0) { - return EFI_NOT_FOUND; - } - - if (IsListEmpty (&SourceStream->Children) && - SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) { - // - // This occurs when a section stream exists, but no child sections - // have been parsed out yet. Therefore, extract the first child and add it - // to the list of children so we can get started. - // Section stream may contain an array of zero or more bytes. - // So, its size should be >= the size of commen section header. - // - Status = CreateChildNode (SourceStream, 0, &CurrentChildNode); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // At least one child has been parsed out of the section stream. So, walk - // through the sections that have already been parsed out looking for the - // requested section, if necessary, continue parsing section stream and - // adding children until either the requested section is found, or we run - // out of data - // - CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children)); - - for (;;) { - if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) { - // - // The type matches, so check the instance count to see if it's the one we want - // - (*SectionInstance)--; - if (*SectionInstance == 0) { - // - // Got it! - // - *FoundChild = CurrentChildNode; - *FoundStream = SourceStream; - *AuthenticationStatus = SourceStream->AuthenticationStatus; - return EFI_SUCCESS; - } - } - - if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) { - // - // If the current node is an encapsulating node, recurse into it... - // - Status = FindChildNode ( - (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle, - SearchType, - SectionInstance, - SectionDefinitionGuid, - &RecursedChildNode, - &RecursedFoundStream, - AuthenticationStatus - ); - // - // If the status is not EFI_SUCCESS, just save the error code and continue - // to find the request child node in the rest stream. - // - if (*SectionInstance == 0) { - ASSERT_EFI_ERROR (Status); - *FoundChild = RecursedChildNode; - *FoundStream = RecursedFoundStream; - return EFI_SUCCESS; - } else { - ErrorStatus = Status; - } - } - - if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) { - // - // We haven't found the child node we're interested in yet, but there's - // still more nodes that have already been parsed so get the next one - // and continue searching.. - // - CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link)); - } else { - // - // We've exhausted children that have already been parsed, so see if - // there's any more data and continue parsing out more children if there - // is. - // - NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size; - // - // Round up to 4 byte boundary - // - NextChildOffset += 3; - NextChildOffset &= ~(UINTN) 3; - if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) { - // - // There's an unparsed child remaining in the stream, so create a new child node - // - Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode); - if (EFI_ERROR (Status)) { - return Status; - } - } else { - ASSERT (EFI_ERROR (ErrorStatus)); - return ErrorStatus; - } - } - } -} - - /** Worker function. Constructor for new child nodes. @@ -1123,143 +732,160 @@ CreateChildNode ( /** - Worker function. Destructor for child nodes. + Worker function Recursively searches / builds section stream database + looking for requested section. - @param ChildNode Indicates the node to destroy + @param SourceStream Indicates the section stream in which to do the + search. + @param SearchType Indicates the type of section to search for. + @param SectionInstance Indicates which instance of section to find. + This is an in/out parameter to deal with + recursions. + @param SectionDefinitionGuid Guid of section definition + @param FoundChild Output indicating the child node that is found. + @param FoundStream Output indicating which section stream the child + was found in. If this stream was generated as a + result of an encapsulation section, the + streamhandle is visible within the SEP driver + only. + @param AuthenticationStatus Indicates the authentication status of the found section. -**/ -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); - } - // - // Last, free the child node itself - // - CoreFreePool (ChildNode); -} - - - -/** - 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. + @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 **/ EFI_STATUS -OpenSectionStreamEx ( - IN UINTN SectionStreamLength, - IN VOID *SectionStream, - IN BOOLEAN AllocateBuffer, - IN UINT32 AuthenticationStatus, - OUT UINTN *SectionStreamHandle +FindChildNode ( + IN CORE_SECTION_STREAM_NODE *SourceStream, + IN EFI_SECTION_TYPE SearchType, + IN OUT UINTN *SectionInstance, + IN EFI_GUID *SectionDefinitionGuid, + OUT CORE_SECTION_CHILD_NODE **FoundChild, + OUT CORE_SECTION_STREAM_NODE **FoundStream, + OUT UINT32 *AuthenticationStatus ) { - CORE_SECTION_STREAM_NODE *NewStream; - EFI_TPL OldTpl; + CORE_SECTION_CHILD_NODE *CurrentChildNode; + CORE_SECTION_CHILD_NODE *RecursedChildNode; + CORE_SECTION_STREAM_NODE *RecursedFoundStream; + UINT32 NextChildOffset; + EFI_STATUS ErrorStatus; + EFI_STATUS Status; - // - // Allocate a new stream - // - NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE)); - if (NewStream == NULL) { - return EFI_OUT_OF_RESOURCES; + CurrentChildNode = NULL; + ErrorStatus = EFI_NOT_FOUND; + + if (SourceStream->StreamLength == 0) { + return EFI_NOT_FOUND; } - if (AllocateBuffer) { + if (IsListEmpty (&SourceStream->Children) && + SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) { // - // if we're here, we're double buffering, allocate the buffer and copy the - // data in + // 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. // - if (SectionStreamLength > 0) { - NewStream->StreamBuffer = AllocatePool (SectionStreamLength); - if (NewStream->StreamBuffer == NULL) { - CoreFreePool (NewStream); - return EFI_OUT_OF_RESOURCES; + Status = CreateChildNode (SourceStream, 0, &CurrentChildNode); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // At least one child has been parsed out of the section stream. So, walk + // through the sections that have already been parsed out looking for the + // requested section, if necessary, continue parsing section stream and + // adding children until either the requested section is found, or we run + // out of data + // + CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children)); + + for (;;) { + if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) { + // + // The type matches, so check the instance count to see if it's the one we want + // + (*SectionInstance)--; + if (*SectionInstance == 0) { + // + // Got it! + // + *FoundChild = CurrentChildNode; + *FoundStream = SourceStream; + *AuthenticationStatus = SourceStream->AuthenticationStatus; + return EFI_SUCCESS; } + } + + if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) { // - // Copy in stream data + // If the current node is an encapsulating node, recurse into it... // - CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength); + Status = FindChildNode ( + (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle, + SearchType, + SectionInstance, + SectionDefinitionGuid, + &RecursedChildNode, + &RecursedFoundStream, + AuthenticationStatus + ); + // + // If the status is not EFI_SUCCESS, just save the error code and continue + // to find the request child node in the rest stream. + // + if (*SectionInstance == 0) { + ASSERT_EFI_ERROR (Status); + *FoundChild = RecursedChildNode; + *FoundStream = RecursedFoundStream; + return EFI_SUCCESS; + } else { + ErrorStatus = Status; + } + } + + if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) { + // + // We haven't found the child node we're interested in yet, but there's + // still more nodes that have already been parsed so get the next one + // and continue searching.. + // + CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link)); } else { // - // It's possible to have a zero length section stream. + // 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. // - NewStream->StreamBuffer = NULL; + 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; + } } - } 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; } - /** Worker function. Search stream database for requested stream handle. @@ -1299,52 +925,237 @@ FindStreamNode ( /** - Check if a stream is valid. + SEP member function. Retrieves requested section from section stream. - @param SectionStream The section stream to be checked - @param SectionStreamLength The length of 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 + requried buffer size is returned in *BufferSize. + @param BufferSize On input, indicates the size of *Buffer if + *Buffer is non-null on input. On output, + indicates the required size (allocated size if + callee allocated) of *Buffer. + @param AuthenticationStatus 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. - @return A boolean value indicating the validness of the section stream. + @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. **/ -BOOLEAN -IsValidSectionStream ( - IN VOID *SectionStream, - IN UINTN SectionStreamLength +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 ) { - UINTN TotalLength; - UINTN SectionLength; - EFI_COMMON_SECTION_HEADER *SectionHeader; - EFI_COMMON_SECTION_HEADER *NextSectionHeader; + 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; - TotalLength = 0; - SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream; - while (TotalLength < SectionStreamLength) { - SectionLength = SECTION_SIZE (SectionHeader); - TotalLength += SectionLength; + OldTpl = CoreRaiseTpl (TPL_NOTIFY); + Instance = SectionInstance + 1; - 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 = (EFI_COMMON_SECTION_HEADER *) ((UINTN) SectionHeader + 3); - NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader & ~(UINTN)3); - TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; - SectionHeader = NextSectionHeader; + // + // Locate target stream + // + Status = FindStreamNode (SectionStreamHandle, &StreamNode); + if (EFI_ERROR (Status)) { + Status = EFI_INVALID_PARAMETER; + goto GetSection_Done; } - ASSERT (FALSE); - return FALSE; + // + // Found the stream, now locate and return the appropriate section + // + if (SectionType == NULL) { + // + // SectionType == NULL means return the WHOLE section stream... + // + CopySize = StreamNode->StreamLength; + CopyBuffer = StreamNode->StreamBuffer; + *AuthenticationStatus = StreamNode->AuthenticationStatus; + } else { + // + // There's a requested section type, so go find it and return it... + // + Status = FindChildNode ( + StreamNode, + *SectionType, + &Instance, + SectionDefinitionGuid, + &ChildNode, + &ChildStreamNode, + &ExtractedAuthenticationStatus + ); + if (EFI_ERROR (Status)) { + goto GetSection_Done; + } + CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER); + CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER); + *AuthenticationStatus = ExtractedAuthenticationStatus; + } + + SectionSize = CopySize; + if (*Buffer != NULL) { + // + // Caller allocated buffer. Fill to size and return required size... + // + if (*BufferSize < CopySize) { + Status = EFI_WARN_BUFFER_TOO_SMALL; + CopySize = *BufferSize; + } + } else { + // + // Callee allocated buffer. Allocate buffer and return size. + // + *Buffer = AllocatePool (CopySize); + if (*Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto GetSection_Done; + } + } + CopyMem (*Buffer, CopyBuffer, CopySize); + *BufferSize = SectionSize; + +GetSection_Done: + 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); + } + // + // Last, free the child node itself + // + CoreFreePool (ChildNode); +} + + +/** + SEP member function. Deletes an existing section stream + + @param StreamHandleToClose Indicates the stream to close + + @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 + ) +{ + 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); + } + CoreFreePool (StreamNode->StreamBuffer); + CoreFreePool (StreamNode); + Status = EFI_SUCCESS; + } else { + Status = EFI_INVALID_PARAMETER; + } + + CoreRestoreTpl (OldTpl); + return Status; } @@ -1469,7 +1280,7 @@ CustomGuidedSectionExtract ( return Status; } - if (ScratchBufferSize != 0) { + if (ScratchBufferSize > 0) { // // Allocate scratch buffer // @@ -1485,6 +1296,7 @@ CustomGuidedSectionExtract ( // AllocatedOutputBuffer = AllocatePool (OutputBufferSize); if (AllocatedOutputBuffer == NULL) { + FreePool (ScratchBuffer); return EFI_OUT_OF_RESOURCES; } *OutputBuffer = AllocatedOutputBuffer;