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 - 2016, Intel Corporation. All rights reserved.<BR>
31 This program and the accompanying materials
32 are licensed and made available under the terms and conditions of the BSD License
33 which accompanies this distribution. The full text of the license may be found at
34 http://opensource.org/licenses/bsd-license.php
36 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
37 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
41 #include <FrameworkDxe.h>
43 #include <Library/BaseLib.h>
44 #include <Library/DebugLib.h>
45 #include <Library/UefiBootServicesTableLib.h>
46 #include <Library/MemoryAllocationLib.h>
47 #include <Library/BaseMemoryLib.h>
48 #include <Library/UefiLib.h>
49 #include <Protocol/Decompress.h>
50 #include <Protocol/GuidedSectionExtraction.h>
51 #include <Protocol/SectionExtraction.h>
54 // Local defines and typedefs
56 #define FRAMEWORK_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','F','S')
57 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
58 CR (Node, FRAMEWORK_SECTION_CHILD_NODE, Link, FRAMEWORK_SECTION_CHILD_SIGNATURE)
66 // StreamBase + OffsetInStream == pointer to section header in stream. The
67 // stream base is always known when walking the sections within.
69 UINT32 OffsetInStream
;
71 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
72 // encapsulating section. Otherwise, it contains the stream handle
73 // of the encapsulated stream. This handle is ALWAYS produced any time an
74 // encapsulating child is encountered, irrespective of whether the
75 // encapsulated stream is processed further.
77 UINTN EncapsulatedStreamHandle
;
78 EFI_GUID
*EncapsulationGuid
;
80 // If the section REQUIRES an extraction protocol, register for RPN
81 // when the required GUIDed extraction protocol becomes available.
84 } FRAMEWORK_SECTION_CHILD_NODE
;
86 #define FRAMEWORK_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
87 #define STREAM_NODE_FROM_LINK(Node) \
88 CR (Node, FRAMEWORK_SECTION_STREAM_NODE, Link, FRAMEWORK_SECTION_STREAM_SIGNATURE)
98 // Authentication status is from GUIDed encapsulations.
100 UINT32 AuthenticationStatus
;
101 } FRAMEWORK_SECTION_STREAM_NODE
;
103 #define NULL_STREAM_HANDLE 0
106 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
107 FRAMEWORK_SECTION_STREAM_NODE
*ParentStream
;
112 SEP member function. This function creates and returns a new section stream
113 handle to represent the new section stream.
115 @param This Indicates the calling context.
116 @param SectionStreamLength Size in bytes of the section stream.
117 @param SectionStream Buffer containing the new section stream.
118 @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
119 contains the new section stream handle.
121 @retval EFI_SUCCESS Section wase opened successfully.
122 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
123 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
130 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
131 IN UINTN SectionStreamLength
,
132 IN VOID
*SectionStream
,
133 OUT UINTN
*SectionStreamHandle
138 SEP member function. Retrieves requested section from section stream.
140 @param This Pointer to SEP instance.
141 @param SectionStreamHandle The section stream from which to extract the requested
143 @param SectionType A pointer to the type of section to search for.
144 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
145 SectionDefinitionGuid indicates which of these types
146 of sections to search for.
147 @param SectionInstance Indicates which instance of the requested section to
149 @param Buffer Double indirection to buffer. If *Buffer is non-null on
150 input, then the buffer is caller allocated. If
151 *Buffer is NULL, then the buffer is callee allocated.
152 In either case, the required buffer size is returned
154 @param BufferSize On input, indicates the size of *Buffer if *Buffer is
155 non-null on input. On output, indicates the required
156 size (allocated size if callee allocated) of *Buffer.
157 @param AuthenticationStatus Indicates the authentication status of the retrieved
161 @retval EFI_SUCCESS Section was retrieved successfully
162 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
163 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
164 bit set, but there was no corresponding GUIDed Section
165 Extraction Protocol in the handle database. *Buffer is
167 @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
168 This indicates the SectionStream is not correctly
170 @retval EFI_NOT_FOUND The requested section does not exist.
171 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
173 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
174 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
175 insufficient to contain the requested section. The
176 input buffer is filled and contents are section contents
183 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
184 IN UINTN SectionStreamHandle
,
185 IN EFI_SECTION_TYPE
*SectionType
,
186 IN EFI_GUID
*SectionDefinitionGuid
,
187 IN UINTN SectionInstance
,
189 IN OUT UINTN
*BufferSize
,
190 OUT UINT32
*AuthenticationStatus
195 SEP member function. Deletes an existing section stream
197 @param This Indicates the calling context.
198 @param StreamHandleToClose Indicates the stream to close
200 @retval EFI_SUCCESS Section stream was closed successfully.
201 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
202 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
209 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
210 IN UINTN StreamHandleToClose
217 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
219 EFI_HANDLE mSectionExtractionHandle
= NULL
;
221 EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction
= {
228 Entry point of the section extraction code. Initializes an instance of the
229 section extraction interface and installs it on a new handle.
231 @param ImageHandle A handle for the image that is initializing this driver
232 @param SystemTable A pointer to the EFI system table
234 @retval EFI_SUCCESS Driver initialized successfully
235 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
240 SectionExtractionEntryPoint (
241 IN EFI_HANDLE ImageHandle
,
242 IN EFI_SYSTEM_TABLE
*SystemTable
248 // Install SEP to a new handle
250 Status
= gBS
->InstallProtocolInterface (
251 &mSectionExtractionHandle
,
252 &gEfiSectionExtractionProtocolGuid
,
253 EFI_NATIVE_INTERFACE
,
256 ASSERT_EFI_ERROR (Status
);
263 Check if a stream is valid.
265 @param SectionStream The section stream to be checked
266 @param SectionStreamLength The length of section stream
268 @return A boolean value indicating the validness of the section stream.
272 IsValidSectionStream (
273 IN VOID
*SectionStream
,
274 IN UINTN SectionStreamLength
279 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
280 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
283 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
285 while (TotalLength
< SectionStreamLength
) {
286 if (IS_SECTION2 (SectionHeader
)) {
287 SectionLength
= SECTION2_SIZE (SectionHeader
);
289 SectionLength
= SECTION_SIZE (SectionHeader
);
291 TotalLength
+= SectionLength
;
293 if (TotalLength
== SectionStreamLength
) {
298 // Move to the next byte following the section...
300 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINT8
*) SectionHeader
+ SectionLength
);
303 // Figure out where the next section begins
305 NextSectionHeader
= ALIGN_POINTER(SectionHeader
, 4);
306 TotalLength
+= (UINTN
) NextSectionHeader
- (UINTN
) SectionHeader
;
307 SectionHeader
= NextSectionHeader
;
315 Worker function. Constructor for section streams.
317 @param SectionStreamLength Size in bytes of the section stream.
318 @param SectionStream Buffer containing the new section stream.
319 @param AllocateBuffer Indicates whether the stream buffer is to be copied
320 or the input buffer is to be used in place.
321 @param AuthenticationStatus Indicates the default authentication status for the
323 @param SectionStreamHandle A pointer to a caller allocated section stream handle.
325 @retval EFI_SUCCESS Stream was added to stream database.
326 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
330 OpenSectionStreamEx (
331 IN UINTN SectionStreamLength
,
332 IN VOID
*SectionStream
,
333 IN BOOLEAN AllocateBuffer
,
334 IN UINT32 AuthenticationStatus
,
335 OUT UINTN
*SectionStreamHandle
338 FRAMEWORK_SECTION_STREAM_NODE
*NewStream
;
342 // Allocate a new stream
344 NewStream
= AllocatePool (sizeof (FRAMEWORK_SECTION_STREAM_NODE
));
345 if (NewStream
== NULL
) {
346 return EFI_OUT_OF_RESOURCES
;
349 if (AllocateBuffer
) {
351 // if we're here, we're double buffering, allocate the buffer and copy the
354 if (SectionStreamLength
> 0) {
355 NewStream
->StreamBuffer
= AllocatePool (SectionStreamLength
);
356 if (NewStream
->StreamBuffer
== NULL
) {
357 FreePool (NewStream
);
358 return EFI_OUT_OF_RESOURCES
;
361 // Copy in stream data
363 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
366 // It's possible to have a zero length section stream.
368 NewStream
->StreamBuffer
= NULL
;
372 // If were here, the caller has supplied the buffer (it's an internal call)
373 // so just assign the buffer. This happens when we open section streams
374 // as a result of expanding an encapsulating section.
376 NewStream
->StreamBuffer
= SectionStream
;
380 // Initialize the rest of the section stream
382 NewStream
->Signature
= FRAMEWORK_SECTION_STREAM_SIGNATURE
;
383 NewStream
->StreamHandle
= (UINTN
) NewStream
;
384 NewStream
->StreamLength
= SectionStreamLength
;
385 InitializeListHead (&NewStream
->Children
);
386 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
389 // Add new stream to stream list
391 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
392 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
393 gBS
->RestoreTPL (OldTpl
);
395 *SectionStreamHandle
= NewStream
->StreamHandle
;
401 SEP member function. This function creates and returns a new section stream
402 handle to represent the new section stream.
404 @param This Indicates the calling context.
405 @param SectionStreamLength Size in bytes of the section stream.
406 @param SectionStream Buffer containing the new section stream.
407 @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
408 contains the new section stream handle.
410 @retval EFI_SUCCESS Section wase opened successfully.
411 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
412 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
419 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
420 IN UINTN SectionStreamLength
,
421 IN VOID
*SectionStream
,
422 OUT UINTN
*SectionStreamHandle
426 // Check to see section stream looks good...
428 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
429 return EFI_INVALID_PARAMETER
;
432 return OpenSectionStreamEx (
442 Worker function. Determine if the input stream:child matches the input type.
444 @param Stream Indicates the section stream associated with the child
445 @param Child Indicates the child to check
446 @param SearchType Indicates the type of section to check against for
447 @param SectionDefinitionGuid Indicates the GUID to check against if the type is
448 EFI_SECTION_GUID_DEFINED
450 @retval TRUE The child matches
451 @retval FALSE The child doesn't match
456 IN FRAMEWORK_SECTION_STREAM_NODE
*Stream
,
457 IN FRAMEWORK_SECTION_CHILD_NODE
*Child
,
458 IN EFI_SECTION_TYPE SearchType
,
459 IN EFI_GUID
*SectionDefinitionGuid
462 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
464 if (SearchType
== EFI_SECTION_ALL
) {
467 if (Child
->Type
!= SearchType
) {
470 if ((SearchType
!= EFI_SECTION_GUID_DEFINED
) || (SectionDefinitionGuid
== NULL
)) {
473 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
474 if (IS_SECTION2 (GuidedSection
)) {
475 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2
*) GuidedSection
)->SectionDefinitionGuid
), SectionDefinitionGuid
);
477 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
482 Create a protocol notification event and return it.
484 @param ProtocolGuid Protocol to register notification event on.
485 @param NotifyTpl Maximum TPL to signal the NotifyFunction.
486 @param NotifyFunction EFI notification routine.
487 @param NotifyContext Context passed into Event when it is created.
488 @param Registration Registration key returned from RegisterProtocolNotify().
489 @param SignalFlag Boolean value to decide whether kick the event after register or not.
491 @return The EFI_EVENT that has been registered to be signaled when a ProtocolGuid
492 is added to the system.
496 CreateProtocolNotifyEvent (
497 IN EFI_GUID
*ProtocolGuid
,
498 IN EFI_TPL NotifyTpl
,
499 IN EFI_EVENT_NOTIFY NotifyFunction
,
500 IN VOID
*NotifyContext
,
501 OUT VOID
**Registration
,
502 IN BOOLEAN SignalFlag
512 Status
= gBS
->CreateEvent (
519 ASSERT_EFI_ERROR (Status
);
522 // Register for protocol notifactions on this event
525 Status
= gBS
->RegisterProtocolNotify (
530 ASSERT_EFI_ERROR (Status
);
534 // Kick the event so we will perform an initial pass of
535 // current installed drivers
537 gBS
->SignalEvent (Event
);
544 Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
546 @param GuidedSectionGuid The Guided Section GUID.
547 @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
548 for the Guided Section.
550 @return TRUE The GuidedSectionGuid could be identified, and the pointer to
551 the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
552 @return FALSE The GuidedSectionGuid could not be identified, or
553 the Guided Section Extraction Protocol has not been installed yet.
557 VerifyGuidedSectionGuid (
558 IN EFI_GUID
*GuidedSectionGuid
,
559 OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
**GuidedSectionExtraction
562 EFI_GUID
*GuidRecorded
;
567 // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
569 Status
= EfiGetSystemConfigurationTable (GuidedSectionGuid
, (VOID
**) &GuidRecorded
);
570 if (Status
== EFI_SUCCESS
) {
571 if (CompareGuid (GuidRecorded
, GuidedSectionGuid
)) {
573 // Found the recorded GuidedSectionGuid.
575 Status
= gBS
->LocateProtocol (GuidedSectionGuid
, NULL
, (VOID
**) &Interface
);
576 if (!EFI_ERROR (Status
) && Interface
!= NULL
) {
578 // Found the supported Guided Section Extraction Porotocol for the Guided Section.
580 *GuidedSectionExtraction
= (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*) Interface
;
591 RPN callback function.
592 1. Initialize the section stream when the GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
593 2. Removes a stale section stream and re-initializes it with an updated AuthenticationStatus.
595 @param Event The event that fired
596 @param RpnContext A pointer to the context that allows us to identify
597 the relevent encapsulation.
602 NotifyGuidedExtraction (
608 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
609 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
610 VOID
*NewStreamBuffer
;
611 UINTN NewStreamBufferSize
;
612 UINT32 AuthenticationStatus
;
613 RPN_EVENT_CONTEXT
*Context
;
615 Context
= RpnContext
;
616 Status
= EFI_SUCCESS
;
617 if (Context
->ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
618 Status
= CloseSectionStream (&mSectionExtraction
, Context
->ChildNode
->EncapsulatedStreamHandle
);
620 if (!EFI_ERROR (Status
)) {
622 // The stream is not initialized, open it.
623 // Or the stream closed successfully, so re-open the stream with correct AuthenticationStatus.
626 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)
627 (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
628 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
630 if (!VerifyGuidedSectionGuid (Context
->ChildNode
->EncapsulationGuid
, &GuidedExtraction
)) {
634 Status
= GuidedExtraction
->ExtractSection (
638 &NewStreamBufferSize
,
639 &AuthenticationStatus
641 ASSERT_EFI_ERROR (Status
);
643 // OR in the parent stream's aggregate status.
645 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
646 Status
= OpenSectionStreamEx (
650 AuthenticationStatus
,
651 &Context
->ChildNode
->EncapsulatedStreamHandle
653 ASSERT_EFI_ERROR (Status
);
657 // If above, the stream did not close successfully, it indicates it's
658 // already been closed by someone, so just destroy the event and be done with
662 gBS
->CloseEvent (Event
);
663 Context
->ChildNode
->Event
= NULL
;
668 Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
669 cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
671 @param ParentStream Indicates the parent of the ecnapsulation section (child)
672 @param ChildNode Indicates the child node that is the encapsulation section.
676 CreateGuidedExtractionRpnEvent (
677 IN FRAMEWORK_SECTION_STREAM_NODE
*ParentStream
,
678 IN FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
681 RPN_EVENT_CONTEXT
*Context
;
684 // Allocate new event structure and context
686 Context
= AllocatePool (sizeof (RPN_EVENT_CONTEXT
));
687 ASSERT (Context
!= NULL
);
689 Context
->ChildNode
= ChildNode
;
690 Context
->ParentStream
= ParentStream
;
692 Context
->ChildNode
->Event
= CreateProtocolNotifyEvent (
693 Context
->ChildNode
->EncapsulationGuid
,
695 NotifyGuidedExtraction
,
697 &Context
->Registration
,
703 Worker function. Constructor for new child nodes.
705 @param Stream Indicates the section stream in which to add the child.
706 @param ChildOffset Indicates the offset in Stream that is the beginning
707 of the child section.
708 @param ChildNode Indicates the Callee allocated and initialized child.
710 @retval EFI_SUCCESS Child node was found and returned.
711 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
712 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream handles when
713 the child node is created. If the section type is GUID
714 defined, and the extraction GUID does not exist, and
715 producing the stream requires the GUID, then a protocol
716 error is generated and no child is produced.
717 Values returned by OpenSectionStreamEx.
722 IN FRAMEWORK_SECTION_STREAM_NODE
*Stream
,
723 IN UINT32 ChildOffset
,
724 OUT FRAMEWORK_SECTION_CHILD_NODE
**ChildNode
728 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
729 EFI_COMPRESSION_SECTION
*CompressionHeader
;
730 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
731 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
732 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
733 VOID
*NewStreamBuffer
;
736 UINTN NewStreamBufferSize
;
737 UINT32 AuthenticationStatus
;
738 VOID
*CompressionSource
;
739 UINT32 CompressionSourceSize
;
740 UINT32 UncompressedLength
;
741 UINT8 CompressionType
;
742 UINT16 GuidedSectionAttributes
;
744 FRAMEWORK_SECTION_CHILD_NODE
*Node
;
746 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
749 // Allocate a new node
751 *ChildNode
= AllocateZeroPool (sizeof (FRAMEWORK_SECTION_CHILD_NODE
));
754 return EFI_OUT_OF_RESOURCES
;
760 Node
->Signature
= FRAMEWORK_SECTION_CHILD_SIGNATURE
;
761 Node
->Type
= SectionHeader
->Type
;
762 if (IS_SECTION2 (SectionHeader
)) {
763 Node
->Size
= SECTION2_SIZE (SectionHeader
);
765 Node
->Size
= SECTION_SIZE (SectionHeader
);
767 Node
->OffsetInStream
= ChildOffset
;
768 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
769 Node
->EncapsulationGuid
= NULL
;
772 // If it's an encapsulating section, then create the new section stream also
774 switch (Node
->Type
) {
775 case EFI_SECTION_COMPRESSION
:
777 // Get the CompressionSectionHeader
779 if (Node
->Size
< sizeof (EFI_COMPRESSION_SECTION
)) {
781 return EFI_NOT_FOUND
;
784 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
786 if (IS_SECTION2 (CompressionHeader
)) {
787 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION2
));
788 CompressionSourceSize
= (UINT32
) (SECTION2_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION2
));
789 UncompressedLength
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->UncompressedLength
;
790 CompressionType
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->CompressionType
;
792 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION
));
793 CompressionSourceSize
= (UINT32
) (SECTION_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION
));
794 UncompressedLength
= CompressionHeader
->UncompressedLength
;
795 CompressionType
= CompressionHeader
->CompressionType
;
799 // Allocate space for the new stream
801 if (UncompressedLength
> 0) {
802 NewStreamBufferSize
= UncompressedLength
;
803 NewStreamBuffer
= AllocatePool (NewStreamBufferSize
);
804 if (NewStreamBuffer
== NULL
) {
806 return EFI_OUT_OF_RESOURCES
;
809 if (CompressionType
== EFI_NOT_COMPRESSED
) {
811 // stream is not actually compressed, just encapsulated. So just copy it.
813 CopyMem (NewStreamBuffer
, CompressionSource
, NewStreamBufferSize
);
814 } else if (CompressionType
== EFI_STANDARD_COMPRESSION
) {
816 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
820 // Decompress the stream
822 Status
= gBS
->LocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
824 ASSERT_EFI_ERROR (Status
);
826 Status
= Decompress
->GetInfo (
829 CompressionSourceSize
,
830 (UINT32
*)&NewStreamBufferSize
,
833 if (EFI_ERROR (Status
) || (NewStreamBufferSize
!= UncompressedLength
)) {
835 FreePool (NewStreamBuffer
);
836 if (!EFI_ERROR (Status
)) {
837 Status
= EFI_BAD_BUFFER_SIZE
;
842 ScratchBuffer
= AllocatePool (ScratchSize
);
843 if (ScratchBuffer
== NULL
) {
845 FreePool (NewStreamBuffer
);
846 return EFI_OUT_OF_RESOURCES
;
849 Status
= Decompress
->Decompress (
852 CompressionSourceSize
,
854 (UINT32
)NewStreamBufferSize
,
858 FreePool (ScratchBuffer
);
859 if (EFI_ERROR (Status
)) {
861 FreePool (NewStreamBuffer
);
866 NewStreamBuffer
= NULL
;
867 NewStreamBufferSize
= 0;
870 Status
= OpenSectionStreamEx (
874 Stream
->AuthenticationStatus
,
875 &Node
->EncapsulatedStreamHandle
877 if (EFI_ERROR (Status
)) {
879 FreePool (NewStreamBuffer
);
884 case EFI_SECTION_GUID_DEFINED
:
885 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
886 if (IS_SECTION2 (GuidedHeader
)) {
887 Node
->EncapsulationGuid
= &(((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->SectionDefinitionGuid
);
888 GuidedSectionAttributes
= ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->Attributes
;
890 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
891 GuidedSectionAttributes
= GuidedHeader
->Attributes
;
893 if (VerifyGuidedSectionGuid (Node
->EncapsulationGuid
, &GuidedExtraction
)) {
895 // NewStreamBuffer is always allocated by ExtractSection... No caller
898 Status
= GuidedExtraction
->ExtractSection (
902 &NewStreamBufferSize
,
903 &AuthenticationStatus
905 if (EFI_ERROR (Status
)) {
906 FreePool (*ChildNode
);
907 return EFI_PROTOCOL_ERROR
;
911 // Make sure we initialize the new stream with the correct
912 // authentication status for both aggregate and local status fields.
914 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
916 // OR in the parent stream's aggregate status.
918 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
921 // since there's no authentication data contributed by the section,
922 // just inherit the full value from our immediate parent.
924 AuthenticationStatus
= Stream
->AuthenticationStatus
;
927 Status
= OpenSectionStreamEx (
931 AuthenticationStatus
,
932 &Node
->EncapsulatedStreamHandle
934 if (EFI_ERROR (Status
)) {
935 FreePool (*ChildNode
);
936 FreePool (NewStreamBuffer
);
941 // There's no GUIDed section extraction protocol available.
943 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) == EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) {
945 // If the section REQUIRES an extraction protocol, register for RPN
946 // when the required GUIDed extraction protocol becomes available.
948 AuthenticationStatus
= 0;
949 CreateGuidedExtractionRpnEvent (Stream
, Node
);
952 // Figure out the proper authentication status
954 AuthenticationStatus
= Stream
->AuthenticationStatus
;
955 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
957 // The local status of the new stream is contained in
958 // AuthenticaionStatus. This value needs to be ORed into the
959 // Aggregate bits also...
963 // Clear out and initialize the local status
965 AuthenticationStatus
&= ~EFI_LOCAL_AUTH_STATUS_ALL
;
966 AuthenticationStatus
|= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
;
968 // OR local status into aggregate status
970 AuthenticationStatus
|= AuthenticationStatus
>> 16;
973 if (IS_SECTION2 (GuidedHeader
)) {
974 Status
= OpenSectionStreamEx (
975 SECTION2_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
976 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
978 AuthenticationStatus
,
979 &Node
->EncapsulatedStreamHandle
982 Status
= OpenSectionStreamEx (
983 SECTION_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
984 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
986 AuthenticationStatus
,
987 &Node
->EncapsulatedStreamHandle
990 if (EFI_ERROR (Status
)) {
997 if ((AuthenticationStatus
& EFI_LOCAL_AUTH_STATUS_ALL
) ==
998 (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
)) {
1000 // Need to register for RPN for when the required GUIDed extraction
1001 // protocol becomes available. This will enable us to refresh the
1002 // AuthenticationStatus cached in the Stream if it's ever requested
1005 CreateGuidedExtractionRpnEvent (Stream
, Node
);
1013 // Nothing to do if it's a leaf
1019 // Last, add the new child node to the stream
1021 InsertTailList (&Stream
->Children
, &Node
->Link
);
1027 Worker function Recursively searches / builds section stream database
1028 looking for requested section.
1031 @param SourceStream Indicates the section stream in which to do the search.
1032 @param SearchType Indicates the type of section to search for.
1033 @param SectionInstance Indicates which instance of section to find. This is
1034 an in/out parameter to deal with recursions.
1035 @param SectionDefinitionGuid Guid of section definition
1036 @param FoundChild Output indicating the child node that is found.
1037 @param FoundStream Output indicating which section stream the child was
1038 found in. If this stream was generated as a result of
1039 an encapsulation section, the streamhandle is visible
1040 within the SEP driver only.
1041 @param AuthenticationStatus Indicates the authentication status of the found section.
1043 @retval EFI_SUCCESS Child node was found and returned.
1044 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1045 @retval EFI_NOT_FOUND Requested child node does not exist.
1046 @retval EFI_PROTOCOL_ERROR A required GUIDED section extraction protocol does not
1052 IN FRAMEWORK_SECTION_STREAM_NODE
*SourceStream
,
1053 IN EFI_SECTION_TYPE SearchType
,
1054 IN OUT UINTN
*SectionInstance
,
1055 IN EFI_GUID
*SectionDefinitionGuid
,
1056 OUT FRAMEWORK_SECTION_CHILD_NODE
**FoundChild
,
1057 OUT FRAMEWORK_SECTION_STREAM_NODE
**FoundStream
,
1058 OUT UINT32
*AuthenticationStatus
1061 FRAMEWORK_SECTION_CHILD_NODE
*CurrentChildNode
;
1062 FRAMEWORK_SECTION_CHILD_NODE
*RecursedChildNode
;
1063 FRAMEWORK_SECTION_STREAM_NODE
*RecursedFoundStream
;
1064 UINT32 NextChildOffset
;
1065 EFI_STATUS ErrorStatus
;
1068 CurrentChildNode
= NULL
;
1069 ErrorStatus
= EFI_NOT_FOUND
;
1071 if (SourceStream
->StreamLength
== 0) {
1072 return EFI_NOT_FOUND
;
1075 if (IsListEmpty (&SourceStream
->Children
) &&
1076 SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)) {
1078 // This occurs when a section stream exists, but no child sections
1079 // have been parsed out yet. Therefore, extract the first child and add it
1080 // to the list of children so we can get started.
1081 // Section stream may contain an array of zero or more bytes.
1082 // So, its size should be >= the size of commen section header.
1084 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
1085 if (EFI_ERROR (Status
)) {
1091 // At least one child has been parsed out of the section stream. So, walk
1092 // through the sections that have already been parsed out looking for the
1093 // requested section, if necessary, continue parsing section stream and
1094 // adding children until either the requested section is found, or we run
1097 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
1100 ASSERT (CurrentChildNode
!= NULL
);
1101 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
1103 // The type matches, so check the instance count to see if it's the one we want
1105 (*SectionInstance
)--;
1106 if (*SectionInstance
== 0) {
1110 *FoundChild
= CurrentChildNode
;
1111 *FoundStream
= SourceStream
;
1112 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
1117 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1119 // If the current node is an encapsulating node, recurse into it...
1121 Status
= FindChildNode (
1122 (FRAMEWORK_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
1125 SectionDefinitionGuid
,
1127 &RecursedFoundStream
,
1128 AuthenticationStatus
1131 // If the status is not EFI_SUCCESS, just save the error code and continue
1132 // to find the request child node in the rest stream.
1134 if (*SectionInstance
== 0) {
1135 ASSERT_EFI_ERROR (Status
);
1136 *FoundChild
= RecursedChildNode
;
1137 *FoundStream
= RecursedFoundStream
;
1140 ErrorStatus
= Status
;
1142 } else if ((CurrentChildNode
->Type
== EFI_SECTION_GUID_DEFINED
) && (SearchType
!= EFI_SECTION_GUID_DEFINED
)) {
1144 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1145 // because a required GUIDED section extraction protocol does not exist.
1146 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1148 ErrorStatus
= EFI_PROTOCOL_ERROR
;
1151 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
1153 // We haven't found the child node we're interested in yet, but there's
1154 // still more nodes that have already been parsed so get the next one
1155 // and continue searching..
1157 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
1160 // We've exhausted children that have already been parsed, so see if
1161 // there's any more data and continue parsing out more children if there
1164 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
1166 // Round up to 4 byte boundary
1168 NextChildOffset
+= 3;
1169 NextChildOffset
&= ~(UINTN
)3;
1170 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
1172 // There's an unparsed child remaining in the stream, so create a new child node
1174 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
1175 if (EFI_ERROR (Status
)) {
1179 ASSERT (EFI_ERROR (ErrorStatus
));
1187 Worker function. Search stream database for requested stream handle.
1189 @param SearchHandle Indicates which stream to look for.
1190 @param FoundStream Output pointer to the found stream.
1192 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1194 @retval EFI_NOT_FOUND SearchHandle was not found in the stream database.
1199 IN UINTN SearchHandle
,
1200 OUT FRAMEWORK_SECTION_STREAM_NODE
**FoundStream
1203 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1205 if (!IsListEmpty (&mStreamRoot
)) {
1206 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1208 if (StreamNode
->StreamHandle
== SearchHandle
) {
1209 *FoundStream
= StreamNode
;
1211 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1214 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1219 return EFI_NOT_FOUND
;
1223 SEP member function. Retrieves requested section from section stream.
1225 @param This Pointer to SEP instance.
1226 @param SectionStreamHandle The section stream from which to extract the requested
1228 @param SectionType A pointer to the type of section to search for.
1229 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
1230 SectionDefinitionGuid indicates which of these types
1231 of sections to search for.
1232 @param SectionInstance Indicates which instance of the requested section to
1234 @param Buffer Double indirection to buffer. If *Buffer is non-null on
1235 input, then the buffer is caller allocated. If
1236 *Buffer is NULL, then the buffer is callee allocated.
1237 In either case, the required buffer size is returned
1239 @param BufferSize On input, indicates the size of *Buffer if *Buffer is
1240 non-null on input. On output, indicates the required
1241 size (allocated size if callee allocated) of *Buffer.
1242 @param AuthenticationStatus Indicates the authentication status of the retrieved
1246 @retval EFI_SUCCESS Section was retrieved successfully
1247 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
1248 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
1249 bit set, but there was no corresponding GUIDed Section
1250 Extraction Protocol in the handle database. *Buffer is
1252 @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
1253 This indicates the SectionStream is not correctly
1255 @retval EFI_NOT_FOUND The requested section does not exist.
1256 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
1258 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1259 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1260 insufficient to contain the requested section. The
1261 input buffer is filled and contents are section contents
1268 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
1269 IN UINTN SectionStreamHandle
,
1270 IN EFI_SECTION_TYPE
*SectionType
,
1271 IN EFI_GUID
*SectionDefinitionGuid
,
1272 IN UINTN SectionInstance
,
1274 IN OUT UINTN
*BufferSize
,
1275 OUT UINT32
*AuthenticationStatus
1278 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1281 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
1282 FRAMEWORK_SECTION_STREAM_NODE
*ChildStreamNode
;
1284 UINT32 ExtractedAuthenticationStatus
;
1288 EFI_COMMON_SECTION_HEADER
*Section
;
1291 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1292 Instance
= SectionInstance
+ 1;
1293 ChildStreamNode
= NULL
;
1296 // Locate target stream
1298 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
1299 if (EFI_ERROR (Status
)) {
1300 Status
= EFI_INVALID_PARAMETER
;
1301 goto GetSection_Done
;
1305 // Found the stream, now locate and return the appropriate section
1307 if (SectionType
== NULL
) {
1309 // SectionType == NULL means return the WHOLE section stream...
1311 CopySize
= StreamNode
->StreamLength
;
1312 CopyBuffer
= StreamNode
->StreamBuffer
;
1313 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
1316 // There's a requested section type, so go find it and return it...
1318 Status
= FindChildNode (
1322 SectionDefinitionGuid
,
1325 &ExtractedAuthenticationStatus
1327 if (EFI_ERROR (Status
)) {
1328 goto GetSection_Done
;
1330 ASSERT (ChildNode
!= NULL
);
1331 ASSERT (ChildStreamNode
!= NULL
);
1332 Section
= (EFI_COMMON_SECTION_HEADER
*) (ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
);
1334 if (IS_SECTION2 (Section
)) {
1335 CopySize
= SECTION2_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER2
);
1336 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER2
);
1338 CopySize
= SECTION_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER
);
1339 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER
);
1341 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
1344 SectionSize
= CopySize
;
1345 if (*Buffer
!= NULL
) {
1347 // Caller allocated buffer. Fill to size and return required size...
1349 if (*BufferSize
< CopySize
) {
1350 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
1351 CopySize
= *BufferSize
;
1355 // Callee allocated buffer. Allocate buffer and return size.
1357 *Buffer
= AllocatePool (CopySize
);
1358 if (*Buffer
== NULL
) {
1359 Status
= EFI_OUT_OF_RESOURCES
;
1360 goto GetSection_Done
;
1363 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
1364 *BufferSize
= SectionSize
;
1367 gBS
->RestoreTPL (OldTpl
);
1372 Worker function. Destructor for child nodes.
1374 @param ChildNode Indicates the node to destroy
1379 IN FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
1382 ASSERT (ChildNode
->Signature
== FRAMEWORK_SECTION_CHILD_SIGNATURE
);
1384 // Remove the child from it's list
1386 RemoveEntryList (&ChildNode
->Link
);
1388 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1390 // If it's an encapsulating section, we close the resulting section stream.
1391 // CloseSectionStream will free all memory associated with the stream.
1393 CloseSectionStream (&mSectionExtraction
, ChildNode
->EncapsulatedStreamHandle
);
1396 if (ChildNode
->Event
!= NULL
) {
1397 gBS
->CloseEvent (ChildNode
->Event
);
1401 // Last, free the child node itself
1403 FreePool (ChildNode
);
1407 SEP member function. Deletes an existing section stream
1409 @param This Indicates the calling context.
1410 @param StreamHandleToClose Indicates the stream to close
1412 @retval EFI_SUCCESS Section stream was closed successfully.
1413 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1414 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
1420 CloseSectionStream (
1421 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
1422 IN UINTN StreamHandleToClose
1425 FRAMEWORK_SECTION_STREAM_NODE
*StreamNode
;
1429 FRAMEWORK_SECTION_CHILD_NODE
*ChildNode
;
1431 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1434 // Locate target stream
1436 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
1437 if (!EFI_ERROR (Status
)) {
1439 // Found the stream, so close it
1441 RemoveEntryList (&StreamNode
->Link
);
1442 while (!IsListEmpty (&StreamNode
->Children
)) {
1443 Link
= GetFirstNode (&StreamNode
->Children
);
1444 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
1445 FreeChildNode (ChildNode
);
1447 FreePool (StreamNode
->StreamBuffer
);
1448 FreePool (StreamNode
);
1449 Status
= EFI_SUCCESS
;
1451 Status
= EFI_INVALID_PARAMETER
;
1454 gBS
->RestoreTPL (OldTpl
);