2 Section Extraction Protocol implementation.
4 Stream database is implemented as a linked list of section streams,
5 where each stream contains a linked list of children, which may be leaves or
8 Children that are encapsulations generate new stream entries
9 when they are created. Streams can also be created by calls to
10 SEP->OpenSectionStream().
12 The database is only created far enough to return the requested data from
13 any given stream, or to determine that the requested data is not found.
15 If a GUIDed encapsulation is encountered, there are three possiblilites.
17 1) A support protocol is found, in which the stream is simply processed with
20 2) A support protocol is not found, but the data is available to be read
21 without processing. In this case, the database is built up through the
22 recursions to return the data, and a RPN event is set that will enable
23 the stream in question to be refreshed if and when the required section
24 extraction protocol is published.This insures the AuthenticationStatus
25 does not become stale in the cache.
27 3) A support protocol is not found, and the data is not available to be read
28 without it. This results in EFI_PROTOCOL_ERROR.
30 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
31 SPDX-License-Identifier: BSD-2-Clause-Patent
35 #include <FrameworkDxe.h>
37 #include <Library/BaseLib.h>
38 #include <Library/DebugLib.h>
39 #include <Library/UefiBootServicesTableLib.h>
40 #include <Library/MemoryAllocationLib.h>
41 #include <Library/BaseMemoryLib.h>
42 #include <Library/UefiLib.h>
43 #include <Protocol/Decompress.h>
44 #include <Protocol/GuidedSectionExtraction.h>
45 #include <Protocol/SectionExtraction.h>
48 // Local defines and typedefs
50 #define FRAMEWORK_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','F','S')
51 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
52 CR (Node, FRAMEWORK_SECTION_CHILD_NODE, Link, FRAMEWORK_SECTION_CHILD_SIGNATURE)
60 // StreamBase + OffsetInStream == pointer to section header in stream. The
61 // stream base is always known when walking the sections within.
63 UINT32 OffsetInStream
;
65 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
66 // encapsulating section. Otherwise, it contains the stream handle
67 // of the encapsulated stream. This handle is ALWAYS produced any time an
68 // encapsulating child is encountered, irrespective of whether the
69 // encapsulated stream is processed further.
71 UINTN EncapsulatedStreamHandle
;
72 EFI_GUID
*EncapsulationGuid
;
74 // If the section REQUIRES an extraction protocol, register for RPN
75 // when the required GUIDed extraction protocol becomes available.
78 } FRAMEWORK_SECTION_CHILD_NODE
;
80 #define FRAMEWORK_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
81 #define STREAM_NODE_FROM_LINK(Node) \
82 CR (Node, FRAMEWORK_SECTION_STREAM_NODE, Link, FRAMEWORK_SECTION_STREAM_SIGNATURE)
92 // Authentication status is from GUIDed encapsulations.
94 UINT32 AuthenticationStatus
;
95 } FRAMEWORK_SECTION_STREAM_NODE
;
97 #define NULL_STREAM_HANDLE 0
100 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
101 FRAMEWORK_SECTION_STREAM_NODE
*ParentStream
;
106 SEP member function. This function creates and returns a new section stream
107 handle to represent the new section stream.
109 @param This Indicates the calling context.
110 @param SectionStreamLength Size in bytes of the section stream.
111 @param SectionStream Buffer containing the new section stream.
112 @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
113 contains the new section stream handle.
115 @retval EFI_SUCCESS Section wase opened successfully.
116 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
117 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
124 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
125 IN UINTN SectionStreamLength
,
126 IN VOID
*SectionStream
,
127 OUT UINTN
*SectionStreamHandle
132 SEP member function. Retrieves requested section from section stream.
134 @param This Pointer to SEP instance.
135 @param SectionStreamHandle The section stream from which to extract the requested
137 @param SectionType A pointer to the type of section to search for.
138 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
139 SectionDefinitionGuid indicates which of these types
140 of sections to search for.
141 @param SectionInstance Indicates which instance of the requested section to
143 @param Buffer Double indirection to buffer. If *Buffer is non-null on
144 input, then the buffer is caller allocated. If
145 *Buffer is NULL, then the buffer is callee allocated.
146 In either case, the required buffer size is returned
148 @param BufferSize On input, indicates the size of *Buffer if *Buffer is
149 non-null on input. On output, indicates the required
150 size (allocated size if callee allocated) of *Buffer.
151 @param AuthenticationStatus Indicates the authentication status of the retrieved
155 @retval EFI_SUCCESS Section was retrieved successfully
156 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
157 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
158 bit set, but there was no corresponding GUIDed Section
159 Extraction Protocol in the handle database. *Buffer is
161 @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
162 This indicates the SectionStream is not correctly
164 @retval EFI_NOT_FOUND The requested section does not exist.
165 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
167 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
168 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
169 insufficient to contain the requested section. The
170 input buffer is filled and contents are section contents
177 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
178 IN UINTN SectionStreamHandle
,
179 IN EFI_SECTION_TYPE
*SectionType
,
180 IN EFI_GUID
*SectionDefinitionGuid
,
181 IN UINTN SectionInstance
,
183 IN OUT UINTN
*BufferSize
,
184 OUT UINT32
*AuthenticationStatus
189 SEP member function. Deletes an existing section stream
191 @param This Indicates the calling context.
192 @param StreamHandleToClose Indicates the stream to close
194 @retval EFI_SUCCESS Section stream was closed successfully.
195 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
196 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
203 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
204 IN UINTN StreamHandleToClose
211 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
213 EFI_HANDLE mSectionExtractionHandle
= NULL
;
215 EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction
= {
222 Entry point of the section extraction code. Initializes an instance of the
223 section extraction interface and installs it on a new handle.
225 @param ImageHandle A handle for the image that is initializing this driver
226 @param SystemTable A pointer to the EFI system table
228 @retval EFI_SUCCESS Driver initialized successfully
229 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
234 SectionExtractionEntryPoint (
235 IN EFI_HANDLE ImageHandle
,
236 IN EFI_SYSTEM_TABLE
*SystemTable
242 // Install SEP to a new handle
244 Status
= gBS
->InstallProtocolInterface (
245 &mSectionExtractionHandle
,
246 &gEfiSectionExtractionProtocolGuid
,
247 EFI_NATIVE_INTERFACE
,
250 ASSERT_EFI_ERROR (Status
);
257 Check if a stream is valid.
259 @param SectionStream The section stream to be checked
260 @param SectionStreamLength The length of section stream
262 @return A boolean value indicating the validness of the section stream.
266 IsValidSectionStream (
267 IN VOID
*SectionStream
,
268 IN UINTN SectionStreamLength
273 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
274 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
277 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
279 while (TotalLength
< SectionStreamLength
) {
280 if (IS_SECTION2 (SectionHeader
)) {
281 SectionLength
= SECTION2_SIZE (SectionHeader
);
283 SectionLength
= SECTION_SIZE (SectionHeader
);
285 TotalLength
+= SectionLength
;
287 if (TotalLength
== SectionStreamLength
) {
292 // Move to the next byte following the section...
294 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINT8
*) SectionHeader
+ SectionLength
);
297 // Figure out where the next section begins
299 NextSectionHeader
= ALIGN_POINTER(SectionHeader
, 4);
300 TotalLength
+= (UINTN
) NextSectionHeader
- (UINTN
) SectionHeader
;
301 SectionHeader
= NextSectionHeader
;
309 Worker function. Constructor for section streams.
311 @param SectionStreamLength Size in bytes of the section stream.
312 @param SectionStream Buffer containing the new section stream.
313 @param AllocateBuffer Indicates whether the stream buffer is to be copied
314 or the input buffer is to be used in place.
315 @param AuthenticationStatus Indicates the default authentication status for the
317 @param SectionStreamHandle A pointer to a caller allocated section stream handle.
319 @retval EFI_SUCCESS Stream was added to stream database.
320 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
324 OpenSectionStreamEx (
325 IN UINTN SectionStreamLength
,
326 IN VOID
*SectionStream
,
327 IN BOOLEAN AllocateBuffer
,
328 IN UINT32 AuthenticationStatus
,
329 OUT UINTN
*SectionStreamHandle
332 FRAMEWORK_SECTION_STREAM_NODE
*NewStream
;
336 // Allocate a new stream
338 NewStream
= AllocatePool (sizeof (FRAMEWORK_SECTION_STREAM_NODE
));
339 if (NewStream
== NULL
) {
340 return EFI_OUT_OF_RESOURCES
;
343 if (AllocateBuffer
) {
345 // if we're here, we're double buffering, allocate the buffer and copy the
348 if (SectionStreamLength
> 0) {
349 NewStream
->StreamBuffer
= AllocatePool (SectionStreamLength
);
350 if (NewStream
->StreamBuffer
== NULL
) {
351 FreePool (NewStream
);
352 return EFI_OUT_OF_RESOURCES
;
355 // Copy in stream data
357 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
360 // It's possible to have a zero length section stream.
362 NewStream
->StreamBuffer
= NULL
;
366 // If were here, the caller has supplied the buffer (it's an internal call)
367 // so just assign the buffer. This happens when we open section streams
368 // as a result of expanding an encapsulating section.
370 NewStream
->StreamBuffer
= SectionStream
;
374 // Initialize the rest of the section stream
376 NewStream
->Signature
= FRAMEWORK_SECTION_STREAM_SIGNATURE
;
377 NewStream
->StreamHandle
= (UINTN
) NewStream
;
378 NewStream
->StreamLength
= SectionStreamLength
;
379 InitializeListHead (&NewStream
->Children
);
380 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
383 // Add new stream to stream list
385 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
386 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
387 gBS
->RestoreTPL (OldTpl
);
389 *SectionStreamHandle
= NewStream
->StreamHandle
;
395 SEP member function. This function creates and returns a new section stream
396 handle to represent the new section stream.
398 @param This Indicates the calling context.
399 @param SectionStreamLength Size in bytes of the section stream.
400 @param SectionStream Buffer containing the new section stream.
401 @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
402 contains the new section stream handle.
404 @retval EFI_SUCCESS Section wase opened successfully.
405 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
406 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
413 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
414 IN UINTN SectionStreamLength
,
415 IN VOID
*SectionStream
,
416 OUT UINTN
*SectionStreamHandle
420 // Check to see section stream looks good...
422 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
423 return EFI_INVALID_PARAMETER
;
426 return OpenSectionStreamEx (
436 Worker function. Determine if the input stream:child matches the input type.
438 @param Stream Indicates the section stream associated with the child
439 @param Child Indicates the child to check
440 @param SearchType Indicates the type of section to check against for
441 @param SectionDefinitionGuid Indicates the GUID to check against if the type is
442 EFI_SECTION_GUID_DEFINED
444 @retval TRUE The child matches
445 @retval FALSE The child doesn't match
450 IN FRAMEWORK_SECTION_STREAM_NODE
*Stream
,
451 IN FRAMEWORK_SECTION_CHILD_NODE
*Child
,
452 IN EFI_SECTION_TYPE SearchType
,
453 IN EFI_GUID
*SectionDefinitionGuid
456 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
458 if (SearchType
== EFI_SECTION_ALL
) {
461 if (Child
->Type
!= SearchType
) {
464 if ((SearchType
!= EFI_SECTION_GUID_DEFINED
) || (SectionDefinitionGuid
== NULL
)) {
467 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
468 if (IS_SECTION2 (GuidedSection
)) {
469 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2
*) GuidedSection
)->SectionDefinitionGuid
), SectionDefinitionGuid
);
471 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
476 Create a protocol notification event and return it.
478 @param ProtocolGuid Protocol to register notification event on.
479 @param NotifyTpl Maximum TPL to signal the NotifyFunction.
480 @param NotifyFunction EFI notification routine.
481 @param NotifyContext Context passed into Event when it is created.
482 @param Registration Registration key returned from RegisterProtocolNotify().
483 @param SignalFlag Boolean value to decide whether kick the event after register or not.
485 @return The EFI_EVENT that has been registered to be signaled when a ProtocolGuid
486 is added to the system.
490 CreateProtocolNotifyEvent (
491 IN EFI_GUID
*ProtocolGuid
,
492 IN EFI_TPL NotifyTpl
,
493 IN EFI_EVENT_NOTIFY NotifyFunction
,
494 IN VOID
*NotifyContext
,
495 OUT VOID
**Registration
,
496 IN BOOLEAN SignalFlag
506 Status
= gBS
->CreateEvent (
513 ASSERT_EFI_ERROR (Status
);
516 // Register for protocol notifactions on this event
519 Status
= gBS
->RegisterProtocolNotify (
524 ASSERT_EFI_ERROR (Status
);
528 // Kick the event so we will perform an initial pass of
529 // current installed drivers
531 gBS
->SignalEvent (Event
);
538 Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
540 @param GuidedSectionGuid The Guided Section GUID.
541 @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
542 for the Guided Section.
544 @return TRUE The GuidedSectionGuid could be identified, and the pointer to
545 the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
546 @return FALSE The GuidedSectionGuid could not be identified, or
547 the Guided Section Extraction Protocol has not been installed yet.
551 VerifyGuidedSectionGuid (
552 IN EFI_GUID
*GuidedSectionGuid
,
553 OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
**GuidedSectionExtraction
556 EFI_GUID
*GuidRecorded
;
561 // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
563 Status
= EfiGetSystemConfigurationTable (GuidedSectionGuid
, (VOID
**) &GuidRecorded
);
564 if (Status
== EFI_SUCCESS
) {
565 if (CompareGuid (GuidRecorded
, GuidedSectionGuid
)) {
567 // Found the recorded GuidedSectionGuid.
569 Status
= gBS
->LocateProtocol (GuidedSectionGuid
, NULL
, (VOID
**) &Interface
);
570 if (!EFI_ERROR (Status
) && Interface
!= NULL
) {
572 // Found the supported Guided Section Extraction Porotocol for the Guided Section.
574 *GuidedSectionExtraction
= (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*) Interface
;
585 RPN callback function.
586 1. Initialize the section stream when the GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
587 2. Removes a stale section stream and re-initializes it with an updated AuthenticationStatus.
589 @param Event The event that fired
590 @param RpnContext A pointer to the context that allows us to identify
591 the relevent encapsulation.
596 NotifyGuidedExtraction (
602 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
603 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
604 VOID
*NewStreamBuffer
;
605 UINTN NewStreamBufferSize
;
606 UINT32 AuthenticationStatus
;
607 RPN_EVENT_CONTEXT
*Context
;
609 Context
= RpnContext
;
610 Status
= EFI_SUCCESS
;
611 if (Context
->ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
612 Status
= CloseSectionStream (&mSectionExtraction
, Context
->ChildNode
->EncapsulatedStreamHandle
);
614 if (!EFI_ERROR (Status
)) {
616 // The stream is not initialized, open it.
617 // Or the stream closed successfully, so re-open the stream with correct AuthenticationStatus.
620 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)
621 (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
622 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
624 if (!VerifyGuidedSectionGuid (Context
->ChildNode
->EncapsulationGuid
, &GuidedExtraction
)) {
628 Status
= GuidedExtraction
->ExtractSection (
632 &NewStreamBufferSize
,
633 &AuthenticationStatus
635 ASSERT_EFI_ERROR (Status
);
637 // OR in the parent stream's aggregate status.
639 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
640 Status
= OpenSectionStreamEx (
644 AuthenticationStatus
,
645 &Context
->ChildNode
->EncapsulatedStreamHandle
647 ASSERT_EFI_ERROR (Status
);
651 // If above, the stream did not close successfully, it indicates it's
652 // already been closed by someone, so just destroy the event and be done with
656 gBS
->CloseEvent (Event
);
657 Context
->ChildNode
->Event
= NULL
;
662 Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
663 cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
665 @param ParentStream Indicates the parent of the ecnapsulation section (child)
666 @param ChildNode Indicates the child node that is the encapsulation section.
670 CreateGuidedExtractionRpnEvent (
671 IN FRAMEWORK_SECTION_STREAM_NODE
*ParentStream
,
672 IN FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
675 RPN_EVENT_CONTEXT
*Context
;
678 // Allocate new event structure and context
680 Context
= AllocatePool (sizeof (RPN_EVENT_CONTEXT
));
681 ASSERT (Context
!= NULL
);
683 Context
->ChildNode
= ChildNode
;
684 Context
->ParentStream
= ParentStream
;
686 Context
->ChildNode
->Event
= CreateProtocolNotifyEvent (
687 Context
->ChildNode
->EncapsulationGuid
,
689 NotifyGuidedExtraction
,
691 &Context
->Registration
,
697 Worker function. Constructor for new child nodes.
699 @param Stream Indicates the section stream in which to add the child.
700 @param ChildOffset Indicates the offset in Stream that is the beginning
701 of the child section.
702 @param ChildNode Indicates the Callee allocated and initialized child.
704 @retval EFI_SUCCESS Child node was found and returned.
705 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
706 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream handles when
707 the child node is created. If the section type is GUID
708 defined, and the extraction GUID does not exist, and
709 producing the stream requires the GUID, then a protocol
710 error is generated and no child is produced.
711 Values returned by OpenSectionStreamEx.
716 IN FRAMEWORK_SECTION_STREAM_NODE
*Stream
,
717 IN UINT32 ChildOffset
,
718 OUT FRAMEWORK_SECTION_CHILD_NODE
**ChildNode
722 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
723 EFI_COMPRESSION_SECTION
*CompressionHeader
;
724 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
725 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
726 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
727 VOID
*NewStreamBuffer
;
730 UINTN NewStreamBufferSize
;
731 UINT32 AuthenticationStatus
;
732 VOID
*CompressionSource
;
733 UINT32 CompressionSourceSize
;
734 UINT32 UncompressedLength
;
735 UINT8 CompressionType
;
736 UINT16 GuidedSectionAttributes
;
738 FRAMEWORK_SECTION_CHILD_NODE
*Node
;
740 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
743 // Allocate a new node
745 *ChildNode
= AllocateZeroPool (sizeof (FRAMEWORK_SECTION_CHILD_NODE
));
748 return EFI_OUT_OF_RESOURCES
;
754 Node
->Signature
= FRAMEWORK_SECTION_CHILD_SIGNATURE
;
755 Node
->Type
= SectionHeader
->Type
;
756 if (IS_SECTION2 (SectionHeader
)) {
757 Node
->Size
= SECTION2_SIZE (SectionHeader
);
759 Node
->Size
= SECTION_SIZE (SectionHeader
);
761 Node
->OffsetInStream
= ChildOffset
;
762 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
763 Node
->EncapsulationGuid
= NULL
;
766 // If it's an encapsulating section, then create the new section stream also
768 switch (Node
->Type
) {
769 case EFI_SECTION_COMPRESSION
:
771 // Get the CompressionSectionHeader
773 if (Node
->Size
< sizeof (EFI_COMPRESSION_SECTION
)) {
775 return EFI_NOT_FOUND
;
778 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
780 if (IS_SECTION2 (CompressionHeader
)) {
781 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION2
));
782 CompressionSourceSize
= (UINT32
) (SECTION2_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION2
));
783 UncompressedLength
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->UncompressedLength
;
784 CompressionType
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->CompressionType
;
786 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION
));
787 CompressionSourceSize
= (UINT32
) (SECTION_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION
));
788 UncompressedLength
= CompressionHeader
->UncompressedLength
;
789 CompressionType
= CompressionHeader
->CompressionType
;
793 // Allocate space for the new stream
795 if (UncompressedLength
> 0) {
796 NewStreamBufferSize
= UncompressedLength
;
797 NewStreamBuffer
= AllocatePool (NewStreamBufferSize
);
798 if (NewStreamBuffer
== NULL
) {
800 return EFI_OUT_OF_RESOURCES
;
803 if (CompressionType
== EFI_NOT_COMPRESSED
) {
805 // stream is not actually compressed, just encapsulated. So just copy it.
807 CopyMem (NewStreamBuffer
, CompressionSource
, NewStreamBufferSize
);
808 } else if (CompressionType
== EFI_STANDARD_COMPRESSION
) {
810 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
814 // Decompress the stream
816 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
818 ASSERT_EFI_ERROR (Status
);
820 Status
= Decompress
->GetInfo (
823 CompressionSourceSize
,
824 (UINT32
*)&NewStreamBufferSize
,
827 if (EFI_ERROR (Status
) || (NewStreamBufferSize
!= UncompressedLength
)) {
829 FreePool (NewStreamBuffer
);
830 if (!EFI_ERROR (Status
)) {
831 Status
= EFI_BAD_BUFFER_SIZE
;
836 ScratchBuffer
= AllocatePool (ScratchSize
);
837 if (ScratchBuffer
== NULL
) {
839 FreePool (NewStreamBuffer
);
840 return EFI_OUT_OF_RESOURCES
;
843 Status
= Decompress
->Decompress (
846 CompressionSourceSize
,
848 (UINT32
)NewStreamBufferSize
,
852 FreePool (ScratchBuffer
);
853 if (EFI_ERROR (Status
)) {
855 FreePool (NewStreamBuffer
);
860 NewStreamBuffer
= NULL
;
861 NewStreamBufferSize
= 0;
864 Status
= OpenSectionStreamEx (
868 Stream
->AuthenticationStatus
,
869 &Node
->EncapsulatedStreamHandle
871 if (EFI_ERROR (Status
)) {
873 FreePool (NewStreamBuffer
);
878 case EFI_SECTION_GUID_DEFINED
:
879 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
880 if (IS_SECTION2 (GuidedHeader
)) {
881 Node
->EncapsulationGuid
= &(((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->SectionDefinitionGuid
);
882 GuidedSectionAttributes
= ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->Attributes
;
884 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
885 GuidedSectionAttributes
= GuidedHeader
->Attributes
;
887 if (VerifyGuidedSectionGuid (Node
->EncapsulationGuid
, &GuidedExtraction
)) {
889 // NewStreamBuffer is always allocated by ExtractSection... No caller
892 Status
= GuidedExtraction
->ExtractSection (
896 &NewStreamBufferSize
,
897 &AuthenticationStatus
899 if (EFI_ERROR (Status
)) {
900 FreePool (*ChildNode
);
901 return EFI_PROTOCOL_ERROR
;
905 // Make sure we initialize the new stream with the correct
906 // authentication status for both aggregate and local status fields.
908 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
910 // OR in the parent stream's aggregate status.
912 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
915 // since there's no authentication data contributed by the section,
916 // just inherit the full value from our immediate parent.
918 AuthenticationStatus
= Stream
->AuthenticationStatus
;
921 Status
= OpenSectionStreamEx (
925 AuthenticationStatus
,
926 &Node
->EncapsulatedStreamHandle
928 if (EFI_ERROR (Status
)) {
929 FreePool (*ChildNode
);
930 FreePool (NewStreamBuffer
);
935 // There's no GUIDed section extraction protocol available.
937 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) == EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) {
939 // If the section REQUIRES an extraction protocol, register for RPN
940 // when the required GUIDed extraction protocol becomes available.
942 AuthenticationStatus
= 0;
943 CreateGuidedExtractionRpnEvent (Stream
, Node
);
946 // Figure out the proper authentication status
948 AuthenticationStatus
= Stream
->AuthenticationStatus
;
949 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
951 // The local status of the new stream is contained in
952 // AuthenticaionStatus. This value needs to be ORed into the
953 // Aggregate bits also...
957 // Clear out and initialize the local status
959 AuthenticationStatus
&= ~EFI_LOCAL_AUTH_STATUS_ALL
;
960 AuthenticationStatus
|= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
;
962 // OR local status into aggregate status
964 AuthenticationStatus
|= AuthenticationStatus
>> 16;
967 if (IS_SECTION2 (GuidedHeader
)) {
968 Status
= OpenSectionStreamEx (
969 SECTION2_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
970 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
972 AuthenticationStatus
,
973 &Node
->EncapsulatedStreamHandle
976 Status
= OpenSectionStreamEx (
977 SECTION_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
978 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
980 AuthenticationStatus
,
981 &Node
->EncapsulatedStreamHandle
984 if (EFI_ERROR (Status
)) {
991 if ((AuthenticationStatus
& EFI_LOCAL_AUTH_STATUS_ALL
) ==
992 (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
)) {
994 // Need to register for RPN for when the required GUIDed extraction
995 // protocol becomes available. This will enable us to refresh the
996 // AuthenticationStatus cached in the Stream if it's ever requested
999 CreateGuidedExtractionRpnEvent (Stream
, Node
);
1007 // Nothing to do if it's a leaf
1013 // Last, add the new child node to the stream
1015 InsertTailList (&Stream
->Children
, &Node
->Link
);
1021 Worker function Recursively searches / builds section stream database
1022 looking for requested section.
1025 @param SourceStream Indicates the section stream in which to do the search.
1026 @param SearchType Indicates the type of section to search for.
1027 @param SectionInstance Indicates which instance of section to find. This is
1028 an in/out parameter to deal with recursions.
1029 @param SectionDefinitionGuid Guid of section definition
1030 @param FoundChild Output indicating the child node that is found.
1031 @param FoundStream Output indicating which section stream the child was
1032 found in. If this stream was generated as a result of
1033 an encapsulation section, the streamhandle is visible
1034 within the SEP driver only.
1035 @param AuthenticationStatus Indicates the authentication status of the found section.
1037 @retval EFI_SUCCESS Child node was found and returned.
1038 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1039 @retval EFI_NOT_FOUND Requested child node does not exist.
1040 @retval EFI_PROTOCOL_ERROR A required GUIDED section extraction protocol does not
1046 IN FRAMEWORK_SECTION_STREAM_NODE
*SourceStream
,
1047 IN EFI_SECTION_TYPE SearchType
,
1048 IN OUT UINTN
*SectionInstance
,
1049 IN EFI_GUID
*SectionDefinitionGuid
,
1050 OUT FRAMEWORK_SECTION_CHILD_NODE
**FoundChild
,
1051 OUT FRAMEWORK_SECTION_STREAM_NODE
**FoundStream
,
1052 OUT UINT32
*AuthenticationStatus
1055 FRAMEWORK_SECTION_CHILD_NODE
*CurrentChildNode
;
1056 FRAMEWORK_SECTION_CHILD_NODE
*RecursedChildNode
;
1057 FRAMEWORK_SECTION_STREAM_NODE
*RecursedFoundStream
;
1058 UINT32 NextChildOffset
;
1059 EFI_STATUS ErrorStatus
;
1062 CurrentChildNode
= NULL
;
1063 ErrorStatus
= EFI_NOT_FOUND
;
1065 if (SourceStream
->StreamLength
== 0) {
1066 return EFI_NOT_FOUND
;
1069 if (IsListEmpty (&SourceStream
->Children
) &&
1070 SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)) {
1072 // This occurs when a section stream exists, but no child sections
1073 // have been parsed out yet. Therefore, extract the first child and add it
1074 // to the list of children so we can get started.
1075 // Section stream may contain an array of zero or more bytes.
1076 // So, its size should be >= the size of commen section header.
1078 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
1079 if (EFI_ERROR (Status
)) {
1085 // At least one child has been parsed out of the section stream. So, walk
1086 // through the sections that have already been parsed out looking for the
1087 // requested section, if necessary, continue parsing section stream and
1088 // adding children until either the requested section is found, or we run
1091 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
1094 ASSERT (CurrentChildNode
!= NULL
);
1095 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
1097 // The type matches, so check the instance count to see if it's the one we want
1099 (*SectionInstance
)--;
1100 if (*SectionInstance
== 0) {
1104 *FoundChild
= CurrentChildNode
;
1105 *FoundStream
= SourceStream
;
1106 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
1111 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1113 // If the current node is an encapsulating node, recurse into it...
1115 Status
= FindChildNode (
1116 (FRAMEWORK_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
1119 SectionDefinitionGuid
,
1121 &RecursedFoundStream
,
1122 AuthenticationStatus
1125 // If the status is not EFI_SUCCESS, just save the error code and continue
1126 // to find the request child node in the rest stream.
1128 if (*SectionInstance
== 0) {
1129 ASSERT_EFI_ERROR (Status
);
1130 *FoundChild
= RecursedChildNode
;
1131 *FoundStream
= RecursedFoundStream
;
1134 ErrorStatus
= Status
;
1136 } else if ((CurrentChildNode
->Type
== EFI_SECTION_GUID_DEFINED
) && (SearchType
!= EFI_SECTION_GUID_DEFINED
)) {
1138 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1139 // because a required GUIDED section extraction protocol does not exist.
1140 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1142 ErrorStatus
= EFI_PROTOCOL_ERROR
;
1145 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
1147 // We haven't found the child node we're interested in yet, but there's
1148 // still more nodes that have already been parsed so get the next one
1149 // and continue searching..
1151 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
1154 // We've exhausted children that have already been parsed, so see if
1155 // there's any more data and continue parsing out more children if there
1158 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
1160 // Round up to 4 byte boundary
1162 NextChildOffset
+= 3;
1163 NextChildOffset
&= ~(UINTN
)3;
1164 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
1166 // There's an unparsed child remaining in the stream, so create a new child node
1168 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
1169 if (EFI_ERROR (Status
)) {
1173 ASSERT (EFI_ERROR (ErrorStatus
));
1181 Worker function. Search stream database for requested stream handle.
1183 @param SearchHandle Indicates which stream to look for.
1184 @param FoundStream Output pointer to the found stream.
1186 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1188 @retval EFI_NOT_FOUND SearchHandle was not found in the stream database.
1193 IN UINTN SearchHandle
,
1194 OUT FRAMEWORK_SECTION_STREAM_NODE
**FoundStream
1197 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1199 if (!IsListEmpty (&mStreamRoot
)) {
1200 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1202 if (StreamNode
->StreamHandle
== SearchHandle
) {
1203 *FoundStream
= StreamNode
;
1205 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1208 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1213 return EFI_NOT_FOUND
;
1217 SEP member function. Retrieves requested section from section stream.
1219 @param This Pointer to SEP instance.
1220 @param SectionStreamHandle The section stream from which to extract the requested
1222 @param SectionType A pointer to the type of section to search for.
1223 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
1224 SectionDefinitionGuid indicates which of these types
1225 of sections to search for.
1226 @param SectionInstance Indicates which instance of the requested section to
1228 @param Buffer Double indirection to buffer. If *Buffer is non-null on
1229 input, then the buffer is caller allocated. If
1230 *Buffer is NULL, then the buffer is callee allocated.
1231 In either case, the required buffer size is returned
1233 @param BufferSize On input, indicates the size of *Buffer if *Buffer is
1234 non-null on input. On output, indicates the required
1235 size (allocated size if callee allocated) of *Buffer.
1236 @param AuthenticationStatus Indicates the authentication status of the retrieved
1240 @retval EFI_SUCCESS Section was retrieved successfully
1241 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
1242 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
1243 bit set, but there was no corresponding GUIDed Section
1244 Extraction Protocol in the handle database. *Buffer is
1246 @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
1247 This indicates the SectionStream is not correctly
1249 @retval EFI_NOT_FOUND The requested section does not exist.
1250 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
1252 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1253 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1254 insufficient to contain the requested section. The
1255 input buffer is filled and contents are section contents
1262 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
1263 IN UINTN SectionStreamHandle
,
1264 IN EFI_SECTION_TYPE
*SectionType
,
1265 IN EFI_GUID
*SectionDefinitionGuid
,
1266 IN UINTN SectionInstance
,
1268 IN OUT UINTN
*BufferSize
,
1269 OUT UINT32
*AuthenticationStatus
1272 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1275 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
1276 FRAMEWORK_SECTION_STREAM_NODE
*ChildStreamNode
;
1278 UINT32 ExtractedAuthenticationStatus
;
1282 EFI_COMMON_SECTION_HEADER
*Section
;
1285 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1286 Instance
= SectionInstance
+ 1;
1287 ChildStreamNode
= NULL
;
1290 // Locate target stream
1292 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
1293 if (EFI_ERROR (Status
)) {
1294 Status
= EFI_INVALID_PARAMETER
;
1295 goto GetSection_Done
;
1299 // Found the stream, now locate and return the appropriate section
1301 if (SectionType
== NULL
) {
1303 // SectionType == NULL means return the WHOLE section stream...
1305 CopySize
= StreamNode
->StreamLength
;
1306 CopyBuffer
= StreamNode
->StreamBuffer
;
1307 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
1310 // There's a requested section type, so go find it and return it...
1312 Status
= FindChildNode (
1316 SectionDefinitionGuid
,
1319 &ExtractedAuthenticationStatus
1321 if (EFI_ERROR (Status
)) {
1322 goto GetSection_Done
;
1324 ASSERT (ChildNode
!= NULL
);
1325 ASSERT (ChildStreamNode
!= NULL
);
1326 Section
= (EFI_COMMON_SECTION_HEADER
*) (ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
);
1328 if (IS_SECTION2 (Section
)) {
1329 CopySize
= SECTION2_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER2
);
1330 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER2
);
1332 CopySize
= SECTION_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER
);
1333 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER
);
1335 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
1338 SectionSize
= CopySize
;
1339 if (*Buffer
!= NULL
) {
1341 // Caller allocated buffer. Fill to size and return required size...
1343 if (*BufferSize
< CopySize
) {
1344 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
1345 CopySize
= *BufferSize
;
1349 // Callee allocated buffer. Allocate buffer and return size.
1351 *Buffer
= AllocatePool (CopySize
);
1352 if (*Buffer
== NULL
) {
1353 Status
= EFI_OUT_OF_RESOURCES
;
1354 goto GetSection_Done
;
1357 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
1358 *BufferSize
= SectionSize
;
1361 gBS
->RestoreTPL (OldTpl
);
1366 Worker function. Destructor for child nodes.
1368 @param ChildNode Indicates the node to destroy
1373 IN FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
1376 ASSERT (ChildNode
->Signature
== FRAMEWORK_SECTION_CHILD_SIGNATURE
);
1378 // Remove the child from it's list
1380 RemoveEntryList (&ChildNode
->Link
);
1382 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1384 // If it's an encapsulating section, we close the resulting section stream.
1385 // CloseSectionStream will free all memory associated with the stream.
1387 CloseSectionStream (&mSectionExtraction
, ChildNode
->EncapsulatedStreamHandle
);
1390 if (ChildNode
->Event
!= NULL
) {
1391 gBS
->CloseEvent (ChildNode
->Event
);
1395 // Last, free the child node itself
1397 FreePool (ChildNode
);
1401 SEP member function. Deletes an existing section stream
1403 @param This Indicates the calling context.
1404 @param StreamHandleToClose Indicates the stream to close
1406 @retval EFI_SUCCESS Section stream was closed successfully.
1407 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1408 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
1414 CloseSectionStream (
1415 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
1416 IN UINTN StreamHandleToClose
1419 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1423 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
1425 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1428 // Locate target stream
1430 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
1431 if (!EFI_ERROR (Status
)) {
1433 // Found the stream, so close it
1435 RemoveEntryList (&StreamNode
->Link
);
1436 while (!IsListEmpty (&StreamNode
->Children
)) {
1437 Link
= GetFirstNode (&StreamNode
->Children
);
1438 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
1439 FreeChildNode (ChildNode
);
1441 FreePool (StreamNode
->StreamBuffer
);
1442 FreePool (StreamNode
);
1443 Status
= EFI_SUCCESS
;
1445 Status
= EFI_INVALID_PARAMETER
;
1448 gBS
->RestoreTPL (OldTpl
);