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
38 // Local defines and typedefs
40 #define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
41 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
42 CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
50 // StreamBase + OffsetInStream == pointer to section header in stream. The
51 // stream base is always known when walking the sections within.
53 UINT32 OffsetInStream
;
55 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
56 // encapsulating section. Otherwise, it contains the stream handle
57 // of the encapsulated stream. This handle is ALWAYS produced any time an
58 // encapsulating child is encountered, irrespective of whether the
59 // encapsulated stream is processed further.
61 UINTN EncapsulatedStreamHandle
;
62 EFI_GUID
*EncapsulationGuid
;
64 // If the section REQUIRES an extraction protocol, register for RPN
65 // when the required GUIDed extraction protocol becomes available.
68 } CORE_SECTION_CHILD_NODE
;
70 #define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
71 #define STREAM_NODE_FROM_LINK(Node) \
72 CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
82 // Authentication status is from GUIDed encapsulations.
84 UINT32 AuthenticationStatus
;
85 } CORE_SECTION_STREAM_NODE
;
87 #define NULL_STREAM_HANDLE 0
90 CORE_SECTION_CHILD_NODE
*ChildNode
;
91 CORE_SECTION_STREAM_NODE
*ParentStream
;
96 The ExtractSection() function processes the input section and
97 allocates a buffer from the pool in which it returns the section
98 contents. If the section being extracted contains
99 authentication information (the section's
100 GuidedSectionHeader.Attributes field has the
101 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
102 returned in AuthenticationStatus must reflect the results of
103 the authentication operation. Depending on the algorithm and
104 size of the encapsulated data, the time that is required to do
105 a full authentication may be prohibitively long for some
106 classes of systems. To indicate this, use
107 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
108 the security policy driver (see the Platform Initialization
109 Driver Execution Environment Core Interface Specification for
110 more details and the GUID definition). If the
111 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
112 database, then, if possible, full authentication should be
113 skipped and the section contents simply returned in the
114 OutputBuffer. In this case, the
115 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
116 must be set on return. ExtractSection() is callable only from
117 TPL_NOTIFY and below. Behavior of ExtractSection() at any
118 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
119 defined in RaiseTPL() in the UEFI 2.0 specification.
122 @param This Indicates the
123 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
124 @param InputSection Buffer containing the input GUIDed section
125 to be processed. OutputBuffer OutputBuffer
126 is allocated from boot services pool
127 memory and contains the new section
128 stream. The caller is responsible for
130 @param OutputBuffer *OutputBuffer is allocated from boot services
131 pool memory and contains the new section stream.
132 The caller is responsible for freeing this buffer.
133 @param OutputSize A pointer to a caller-allocated UINTN in
134 which the size of OutputBuffer allocation
135 is stored. If the function returns
136 anything other than EFI_SUCCESS, the value
137 of OutputSize is undefined.
139 @param AuthenticationStatus A pointer to a caller-allocated
140 UINT32 that indicates the
141 authentication status of the
142 output buffer. If the input
144 GuidedSectionHeader.Attributes
146 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
147 bit as clear, AuthenticationStatus
148 must return zero. Both local bits
149 (19:16) and aggregate bits (3:0)
150 in AuthenticationStatus are
151 returned by ExtractSection().
152 These bits reflect the status of
153 the extraction operation. The bit
154 pattern in both regions must be
155 the same, as the local and
156 aggregate authentication statuses
157 have equivalent meaning at this
158 level. If the function returns
159 anything other than EFI_SUCCESS,
160 the value of AuthenticationStatus
164 @retval EFI_SUCCESS The InputSection was successfully
165 processed and the section contents were
168 @retval EFI_OUT_OF_RESOURCES The system has insufficient
169 resources to process the
172 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
173 not match this instance of the
174 GUIDed Section Extraction
180 CustomGuidedSectionExtract (
181 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
182 IN CONST VOID
*InputSection
,
183 OUT VOID
**OutputBuffer
,
184 OUT UINTN
*OutputSize
,
185 OUT UINT32
*AuthenticationStatus
191 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
193 EFI_HANDLE mSectionExtractionHandle
= NULL
;
195 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol
= {
196 CustomGuidedSectionExtract
200 Entry point of the section extraction code. Initializes an instance of the
201 section extraction interface and installs it on a new handle.
203 @param ImageHandle A handle for the image that is initializing this driver
204 @param SystemTable A pointer to the EFI system table
206 @retval EFI_SUCCESS Driver initialized successfully
207 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
212 InitializeSectionExtraction (
213 IN EFI_HANDLE ImageHandle
,
214 IN EFI_SYSTEM_TABLE
*SystemTable
218 EFI_GUID
*ExtractHandlerGuidTable
;
219 UINTN ExtractHandlerNumber
;
222 // Get custom extract guided section method guid list
224 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
226 Status
= EFI_SUCCESS
;
228 // Install custom guided extraction protocol
230 while (ExtractHandlerNumber
-- > 0) {
231 Status
= CoreInstallProtocolInterface (
232 &mSectionExtractionHandle
,
233 &ExtractHandlerGuidTable
[ExtractHandlerNumber
],
234 EFI_NATIVE_INTERFACE
,
235 &mCustomGuidedSectionExtractionProtocol
237 ASSERT_EFI_ERROR (Status
);
244 Check if a stream is valid.
246 @param SectionStream The section stream to be checked
247 @param SectionStreamLength The length of section stream
249 @return A boolean value indicating the validness of the section stream.
253 IsValidSectionStream (
254 IN VOID
*SectionStream
,
255 IN UINTN SectionStreamLength
260 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
261 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
264 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
266 while (TotalLength
< SectionStreamLength
) {
267 if (IS_SECTION2 (SectionHeader
)) {
268 SectionLength
= SECTION2_SIZE (SectionHeader
);
270 SectionLength
= SECTION_SIZE (SectionHeader
);
273 TotalLength
+= SectionLength
;
275 if (TotalLength
== SectionStreamLength
) {
280 // Move to the next byte following the section...
282 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)((UINT8
*)SectionHeader
+ SectionLength
);
285 // Figure out where the next section begins
287 NextSectionHeader
= ALIGN_POINTER (SectionHeader
, 4);
288 TotalLength
+= (UINTN
)NextSectionHeader
- (UINTN
)SectionHeader
;
289 SectionHeader
= NextSectionHeader
;
297 Worker function. Constructor for section streams.
299 @param SectionStreamLength Size in bytes of the section stream.
300 @param SectionStream Buffer containing the new section stream.
301 @param AllocateBuffer Indicates whether the stream buffer is to be
302 copied or the input buffer is to be used in
303 place. AuthenticationStatus- Indicates the
304 default authentication status for the new
306 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
307 indicates the authentication status of the
308 output buffer. If the input section's
309 GuidedSectionHeader.Attributes field
310 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
311 bit as clear, AuthenticationStatus must return
312 zero. Both local bits (19:16) and aggregate
313 bits (3:0) in AuthenticationStatus are returned
314 by ExtractSection(). These bits reflect the
315 status of the extraction operation. The bit
316 pattern in both regions must be the same, as
317 the local and aggregate authentication statuses
318 have equivalent meaning at this level. If the
319 function returns anything other than
320 EFI_SUCCESS, the value of *AuthenticationStatus
322 @param SectionStreamHandle A pointer to a caller allocated section stream
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 CORE_SECTION_STREAM_NODE
*NewStream
;
342 // Allocate a new stream
344 NewStream
= AllocatePool (sizeof (CORE_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 CoreFreePool (NewStream
);
358 return EFI_OUT_OF_RESOURCES
;
362 // Copy in stream data
364 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
367 // It's possible to have a zero length section stream.
369 NewStream
->StreamBuffer
= NULL
;
373 // If were here, the caller has supplied the buffer (it's an internal call)
374 // so just assign the buffer. This happens when we open section streams
375 // as a result of expanding an encapsulating section.
377 NewStream
->StreamBuffer
= SectionStream
;
381 // Initialize the rest of the section stream
383 NewStream
->Signature
= CORE_SECTION_STREAM_SIGNATURE
;
384 NewStream
->StreamHandle
= (UINTN
)NewStream
;
385 NewStream
->StreamLength
= SectionStreamLength
;
386 InitializeListHead (&NewStream
->Children
);
387 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
390 // Add new stream to stream list
392 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
393 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
394 CoreRestoreTpl (OldTpl
);
396 *SectionStreamHandle
= NewStream
->StreamHandle
;
402 SEP member function. This function creates and returns a new section stream
403 handle to represent the new section stream.
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
408 output contains the new section stream handle.
410 @retval EFI_SUCCESS The section stream is created successfully.
411 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
412 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
419 IN UINTN SectionStreamLength
,
420 IN VOID
*SectionStream
,
421 OUT UINTN
*SectionStreamHandle
425 // Check to see section stream looks good...
427 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
428 return EFI_INVALID_PARAMETER
;
431 return OpenSectionStreamEx (
441 Worker function. Determine if the input stream:child matches the input type.
443 @param Stream Indicates the section stream associated with the
445 @param Child Indicates the child to check
446 @param SearchType Indicates the type of section to check against
448 @param SectionDefinitionGuid Indicates the GUID to check against if the type
449 is EFI_SECTION_GUID_DEFINED
451 @retval TRUE The child matches
452 @retval FALSE The child doesn't match
457 IN CORE_SECTION_STREAM_NODE
*Stream
,
458 IN CORE_SECTION_CHILD_NODE
*Child
,
459 IN EFI_SECTION_TYPE SearchType
,
460 IN EFI_GUID
*SectionDefinitionGuid
463 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
465 if (SearchType
== EFI_SECTION_ALL
) {
469 if (Child
->Type
!= SearchType
) {
473 if ((SearchType
!= EFI_SECTION_GUID_DEFINED
) || (SectionDefinitionGuid
== NULL
)) {
477 GuidedSection
= (EFI_GUID_DEFINED_SECTION
*)(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
478 if (IS_SECTION2 (GuidedSection
)) {
479 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2
*)GuidedSection
)->SectionDefinitionGuid
), SectionDefinitionGuid
);
481 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
486 Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
488 @param GuidedSectionGuid The Guided Section GUID.
489 @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
490 for the Guided Section.
492 @return TRUE The GuidedSectionGuid could be identified, and the pointer to
493 the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
494 @return FALSE The GuidedSectionGuid could not be identified, or
495 the Guided Section Extraction Protocol has not been installed yet.
499 VerifyGuidedSectionGuid (
500 IN EFI_GUID
*GuidedSectionGuid
,
501 OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
**GuidedSectionExtraction
504 EFI_GUID
*GuidRecorded
;
511 // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
513 Status
= EfiGetSystemConfigurationTable (GuidedSectionGuid
, (VOID
**)&GuidRecorded
);
514 if (Status
== EFI_SUCCESS
) {
515 if (CompareGuid (GuidRecorded
, GuidedSectionGuid
)) {
517 // Found the recorded GuidedSectionGuid.
519 Status
= CoreLocateProtocol (GuidedSectionGuid
, NULL
, (VOID
**)&Interface
);
520 if (!EFI_ERROR (Status
) && (Interface
!= NULL
)) {
522 // Found the supported Guided Section Extraction Porotocol for the Guided Section.
524 *GuidedSectionExtraction
= (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*)Interface
;
536 RPN callback function. Initializes the section stream
537 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
539 @param Event The event that fired
540 @param RpnContext A pointer to the context that allows us to identify
541 the relevent encapsulation.
545 NotifyGuidedExtraction (
551 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
552 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
553 VOID
*NewStreamBuffer
;
554 UINTN NewStreamBufferSize
;
555 UINT32 AuthenticationStatus
;
556 RPN_EVENT_CONTEXT
*Context
;
558 Context
= RpnContext
;
560 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)(Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
561 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
563 if (!VerifyGuidedSectionGuid (Context
->ChildNode
->EncapsulationGuid
, &GuidedExtraction
)) {
567 Status
= GuidedExtraction
->ExtractSection (
571 &NewStreamBufferSize
,
572 &AuthenticationStatus
574 ASSERT_EFI_ERROR (Status
);
577 // Make sure we initialize the new stream with the correct
578 // authentication status for both aggregate and local status fields.
580 if ((GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
582 // OR in the parent stream's aggregate status.
584 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
587 // since there's no authentication data contributed by the section,
588 // just inherit the full value from our immediate parent.
590 AuthenticationStatus
= Context
->ParentStream
->AuthenticationStatus
;
593 Status
= OpenSectionStreamEx (
597 AuthenticationStatus
,
598 &Context
->ChildNode
->EncapsulatedStreamHandle
600 ASSERT_EFI_ERROR (Status
);
603 // Close the event when done.
605 gBS
->CloseEvent (Event
);
606 Context
->ChildNode
->Event
= NULL
;
611 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
613 @param ParentStream Indicates the parent of the ecnapsulation section (child)
614 @param ChildNode Indicates the child node that is the encapsulation section.
618 CreateGuidedExtractionRpnEvent (
619 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
620 IN CORE_SECTION_CHILD_NODE
*ChildNode
623 RPN_EVENT_CONTEXT
*Context
;
626 // Allocate new event structure and context
628 Context
= AllocatePool (sizeof (RPN_EVENT_CONTEXT
));
629 ASSERT (Context
!= NULL
);
631 Context
->ChildNode
= ChildNode
;
632 Context
->ParentStream
= ParentStream
;
634 Context
->ChildNode
->Event
= EfiCreateProtocolNotifyEvent (
635 Context
->ChildNode
->EncapsulationGuid
,
637 NotifyGuidedExtraction
,
639 &Context
->Registration
644 Worker function. Constructor for new child nodes.
646 @param Stream Indicates the section stream in which to add the
648 @param ChildOffset Indicates the offset in Stream that is the
649 beginning of the child section.
650 @param ChildNode Indicates the Callee allocated and initialized
653 @retval EFI_SUCCESS Child node was found and returned.
654 EFI_OUT_OF_RESOURCES- Memory allocation failed.
655 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
656 handles when the child node is created. If the
657 section type is GUID defined, and the extraction
658 GUID does not exist, and producing the stream
659 requires the GUID, then a protocol error is
660 generated and no child is produced. Values
661 returned by OpenSectionStreamEx.
666 IN CORE_SECTION_STREAM_NODE
*Stream
,
667 IN UINT32 ChildOffset
,
668 OUT CORE_SECTION_CHILD_NODE
**ChildNode
672 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
673 EFI_COMPRESSION_SECTION
*CompressionHeader
;
674 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
675 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
676 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
677 VOID
*NewStreamBuffer
;
680 UINTN NewStreamBufferSize
;
681 UINT32 AuthenticationStatus
;
682 VOID
*CompressionSource
;
683 UINT32 CompressionSourceSize
;
684 UINT32 UncompressedLength
;
685 UINT8 CompressionType
;
686 UINT16 GuidedSectionAttributes
;
688 CORE_SECTION_CHILD_NODE
*Node
;
690 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)(Stream
->StreamBuffer
+ ChildOffset
);
693 // Allocate a new node
695 *ChildNode
= AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE
));
698 return EFI_OUT_OF_RESOURCES
;
704 Node
->Signature
= CORE_SECTION_CHILD_SIGNATURE
;
705 Node
->Type
= SectionHeader
->Type
;
706 if (IS_SECTION2 (SectionHeader
)) {
707 Node
->Size
= SECTION2_SIZE (SectionHeader
);
709 Node
->Size
= SECTION_SIZE (SectionHeader
);
712 Node
->OffsetInStream
= ChildOffset
;
713 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
714 Node
->EncapsulationGuid
= NULL
;
717 // If it's an encapsulating section, then create the new section stream also
719 switch (Node
->Type
) {
720 case EFI_SECTION_COMPRESSION
:
722 // Get the CompressionSectionHeader
724 if (Node
->Size
< sizeof (EFI_COMPRESSION_SECTION
)) {
726 return EFI_NOT_FOUND
;
729 CompressionHeader
= (EFI_COMPRESSION_SECTION
*)SectionHeader
;
731 if (IS_SECTION2 (CompressionHeader
)) {
732 CompressionSource
= (VOID
*)((UINT8
*)CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION2
));
733 CompressionSourceSize
= (UINT32
)(SECTION2_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION2
));
734 UncompressedLength
= ((EFI_COMPRESSION_SECTION2
*)CompressionHeader
)->UncompressedLength
;
735 CompressionType
= ((EFI_COMPRESSION_SECTION2
*)CompressionHeader
)->CompressionType
;
737 CompressionSource
= (VOID
*)((UINT8
*)CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION
));
738 CompressionSourceSize
= (UINT32
)(SECTION_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION
));
739 UncompressedLength
= CompressionHeader
->UncompressedLength
;
740 CompressionType
= CompressionHeader
->CompressionType
;
744 // Allocate space for the new stream
746 if (UncompressedLength
> 0) {
747 NewStreamBufferSize
= UncompressedLength
;
748 NewStreamBuffer
= AllocatePool (NewStreamBufferSize
);
749 if (NewStreamBuffer
== NULL
) {
751 return EFI_OUT_OF_RESOURCES
;
754 if (CompressionType
== EFI_NOT_COMPRESSED
) {
756 // stream is not actually compressed, just encapsulated. So just copy it.
758 CopyMem (NewStreamBuffer
, CompressionSource
, NewStreamBufferSize
);
759 } else if (CompressionType
== EFI_STANDARD_COMPRESSION
) {
761 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
765 // Decompress the stream
767 Status
= CoreLocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
768 ASSERT_EFI_ERROR (Status
);
769 ASSERT (Decompress
!= NULL
);
771 Status
= Decompress
->GetInfo (
774 CompressionSourceSize
,
775 (UINT32
*)&NewStreamBufferSize
,
778 if (EFI_ERROR (Status
) || (NewStreamBufferSize
!= UncompressedLength
)) {
780 CoreFreePool (NewStreamBuffer
);
781 if (!EFI_ERROR (Status
)) {
782 Status
= EFI_BAD_BUFFER_SIZE
;
788 ScratchBuffer
= AllocatePool (ScratchSize
);
789 if (ScratchBuffer
== NULL
) {
791 CoreFreePool (NewStreamBuffer
);
792 return EFI_OUT_OF_RESOURCES
;
795 Status
= Decompress
->Decompress (
798 CompressionSourceSize
,
800 (UINT32
)NewStreamBufferSize
,
804 CoreFreePool (ScratchBuffer
);
805 if (EFI_ERROR (Status
)) {
807 CoreFreePool (NewStreamBuffer
);
812 NewStreamBuffer
= NULL
;
813 NewStreamBufferSize
= 0;
816 Status
= OpenSectionStreamEx (
820 Stream
->AuthenticationStatus
,
821 &Node
->EncapsulatedStreamHandle
823 if (EFI_ERROR (Status
)) {
825 CoreFreePool (NewStreamBuffer
);
831 case EFI_SECTION_GUID_DEFINED
:
832 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)SectionHeader
;
833 if (IS_SECTION2 (GuidedHeader
)) {
834 Node
->EncapsulationGuid
= &(((EFI_GUID_DEFINED_SECTION2
*)GuidedHeader
)->SectionDefinitionGuid
);
835 GuidedSectionAttributes
= ((EFI_GUID_DEFINED_SECTION2
*)GuidedHeader
)->Attributes
;
837 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
838 GuidedSectionAttributes
= GuidedHeader
->Attributes
;
841 if (VerifyGuidedSectionGuid (Node
->EncapsulationGuid
, &GuidedExtraction
)) {
843 // NewStreamBuffer is always allocated by ExtractSection... No caller
846 Status
= GuidedExtraction
->ExtractSection (
850 &NewStreamBufferSize
,
851 &AuthenticationStatus
853 if (EFI_ERROR (Status
)) {
854 CoreFreePool (*ChildNode
);
855 return EFI_PROTOCOL_ERROR
;
859 // Make sure we initialize the new stream with the correct
860 // authentication status for both aggregate and local status fields.
862 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
864 // OR in the parent stream's aggregate status.
866 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
869 // since there's no authentication data contributed by the section,
870 // just inherit the full value from our immediate parent.
872 AuthenticationStatus
= Stream
->AuthenticationStatus
;
875 Status
= OpenSectionStreamEx (
879 AuthenticationStatus
,
880 &Node
->EncapsulatedStreamHandle
882 if (EFI_ERROR (Status
)) {
883 CoreFreePool (*ChildNode
);
884 CoreFreePool (NewStreamBuffer
);
889 // There's no GUIDed section extraction protocol available.
891 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) {
893 // If the section REQUIRES an extraction protocol, register for RPN
894 // when the required GUIDed extraction protocol becomes available.
896 CreateGuidedExtractionRpnEvent (Stream
, Node
);
899 // Figure out the proper authentication status
901 AuthenticationStatus
= Stream
->AuthenticationStatus
;
903 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
904 AuthenticationStatus
|= EFI_AUTH_STATUS_IMAGE_SIGNED
| EFI_AUTH_STATUS_NOT_TESTED
;
907 if (IS_SECTION2 (GuidedHeader
)) {
908 Status
= OpenSectionStreamEx (
909 SECTION2_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION2
*)GuidedHeader
)->DataOffset
,
910 (UINT8
*)GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION2
*)GuidedHeader
)->DataOffset
,
912 AuthenticationStatus
,
913 &Node
->EncapsulatedStreamHandle
916 Status
= OpenSectionStreamEx (
917 SECTION_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION
*)GuidedHeader
)->DataOffset
,
918 (UINT8
*)GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION
*)GuidedHeader
)->DataOffset
,
920 AuthenticationStatus
,
921 &Node
->EncapsulatedStreamHandle
925 if (EFI_ERROR (Status
)) {
937 // Nothing to do if it's a leaf
943 // Last, add the new child node to the stream
945 InsertTailList (&Stream
->Children
, &Node
->Link
);
951 Worker function Recursively searches / builds section stream database
952 looking for requested section.
954 @param SourceStream Indicates the section stream in which to do the
956 @param SearchType Indicates the type of section to search for.
957 @param SectionInstance Indicates which instance of section to find.
958 This is an in/out parameter and it is 1-based,
959 to deal with recursions.
960 @param SectionDefinitionGuid Guid of section definition
961 @param Depth Nesting depth of encapsulation sections.
962 Callers different from FindChildNode() are
963 responsible for passing in a zero Depth.
964 @param FoundChild Output indicating the child node that is found.
965 @param FoundStream Output indicating which section stream the child
966 was found in. If this stream was generated as a
967 result of an encapsulation section, the
968 streamhandle is visible within the SEP driver
970 @param AuthenticationStatus Indicates the authentication status of the found section.
972 @retval EFI_SUCCESS Child node was found and returned.
973 EFI_OUT_OF_RESOURCES- Memory allocation failed.
974 @retval EFI_NOT_FOUND Requested child node does not exist.
975 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
977 @retval EFI_ABORTED Recursion aborted because Depth has been
978 greater than or equal to
979 PcdFwVolDxeMaxEncapsulationDepth.
984 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
985 IN EFI_SECTION_TYPE SearchType
,
986 IN OUT UINTN
*SectionInstance
,
987 IN EFI_GUID
*SectionDefinitionGuid
,
989 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
990 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
991 OUT UINT32
*AuthenticationStatus
994 CORE_SECTION_CHILD_NODE
*CurrentChildNode
;
995 CORE_SECTION_CHILD_NODE
*RecursedChildNode
;
996 CORE_SECTION_STREAM_NODE
*RecursedFoundStream
;
997 UINT32 NextChildOffset
;
998 EFI_STATUS ErrorStatus
;
1001 ASSERT (*SectionInstance
> 0);
1003 if (Depth
>= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth
)) {
1007 CurrentChildNode
= NULL
;
1008 ErrorStatus
= EFI_NOT_FOUND
;
1010 if (SourceStream
->StreamLength
== 0) {
1011 return EFI_NOT_FOUND
;
1014 if (IsListEmpty (&SourceStream
->Children
) &&
1015 (SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)))
1018 // This occurs when a section stream exists, but no child sections
1019 // have been parsed out yet. Therefore, extract the first child and add it
1020 // to the list of children so we can get started.
1021 // Section stream may contain an array of zero or more bytes.
1022 // So, its size should be >= the size of commen section header.
1024 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
1025 if (EFI_ERROR (Status
)) {
1031 // At least one child has been parsed out of the section stream. So, walk
1032 // through the sections that have already been parsed out looking for the
1033 // requested section, if necessary, continue parsing section stream and
1034 // adding children until either the requested section is found, or we run
1037 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode (&SourceStream
->Children
));
1040 ASSERT (CurrentChildNode
!= NULL
);
1041 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
1043 // The type matches, so check the instance count to see if it's the one we want
1045 (*SectionInstance
)--;
1046 if (*SectionInstance
== 0) {
1050 *FoundChild
= CurrentChildNode
;
1051 *FoundStream
= SourceStream
;
1052 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
1058 // Type mismatch, or we haven't found the desired instance yet.
1060 ASSERT (*SectionInstance
> 0);
1062 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1064 // If the current node is an encapsulating node, recurse into it...
1066 Status
= FindChildNode (
1067 (CORE_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
1070 SectionDefinitionGuid
,
1073 &RecursedFoundStream
,
1074 AuthenticationStatus
1076 if (*SectionInstance
== 0) {
1078 // The recursive FindChildNode() call decreased (*SectionInstance) to
1081 ASSERT_EFI_ERROR (Status
);
1082 *FoundChild
= RecursedChildNode
;
1083 *FoundStream
= RecursedFoundStream
;
1086 if (Status
== EFI_ABORTED
) {
1088 // If the recursive call was aborted due to nesting depth, stop
1089 // looking for the requested child node. The skipped subtree could
1090 // throw off the instance counting.
1096 // Save the error code and continue to find the requested child node in
1097 // the rest of the stream.
1099 ErrorStatus
= Status
;
1101 } else if ((CurrentChildNode
->Type
== EFI_SECTION_GUID_DEFINED
) && (SearchType
!= EFI_SECTION_GUID_DEFINED
)) {
1103 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1104 // because a required GUIDED section extraction protocol does not exist.
1105 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1107 ErrorStatus
= EFI_PROTOCOL_ERROR
;
1110 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
1112 // We haven't found the child node we're interested in yet, but there's
1113 // still more nodes that have already been parsed so get the next one
1114 // and continue searching..
1116 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
1119 // We've exhausted children that have already been parsed, so see if
1120 // there's any more data and continue parsing out more children if there
1123 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
1125 // Round up to 4 byte boundary
1127 NextChildOffset
+= 3;
1128 NextChildOffset
&= ~(UINTN
)3;
1129 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
1131 // There's an unparsed child remaining in the stream, so create a new child node
1133 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
1134 if (EFI_ERROR (Status
)) {
1138 ASSERT (EFI_ERROR (ErrorStatus
));
1146 Worker function. Search stream database for requested stream handle.
1148 @param SearchHandle Indicates which stream to look for.
1149 @param FoundStream Output pointer to the found stream.
1151 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1153 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1159 IN UINTN SearchHandle
,
1160 OUT CORE_SECTION_STREAM_NODE
**FoundStream
1163 CORE_SECTION_STREAM_NODE
*StreamNode
;
1165 if (!IsListEmpty (&mStreamRoot
)) {
1166 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1168 if (StreamNode
->StreamHandle
== SearchHandle
) {
1169 *FoundStream
= StreamNode
;
1171 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1174 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1179 return EFI_NOT_FOUND
;
1183 SEP member function. Retrieves requested section from section stream.
1185 @param SectionStreamHandle The section stream from which to extract the
1187 @param SectionType A pointer to the type of section to search for.
1188 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1189 then SectionDefinitionGuid indicates which of
1190 these types of sections to search for.
1191 @param SectionInstance Indicates which instance of the requested
1193 @param Buffer Double indirection to buffer. If *Buffer is
1194 non-null on input, then the buffer is caller
1195 allocated. If Buffer is NULL, then the buffer
1196 is callee allocated. In either case, the
1197 required buffer size is returned in *BufferSize.
1198 @param BufferSize On input, indicates the size of *Buffer if
1199 *Buffer is non-null on input. On output,
1200 indicates the required size (allocated size if
1201 callee allocated) of *Buffer.
1202 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1203 indicates the authentication status of the
1204 output buffer. If the input section's
1205 GuidedSectionHeader.Attributes field
1206 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1207 bit as clear, AuthenticationStatus must return
1208 zero. Both local bits (19:16) and aggregate
1209 bits (3:0) in AuthenticationStatus are returned
1210 by ExtractSection(). These bits reflect the
1211 status of the extraction operation. The bit
1212 pattern in both regions must be the same, as
1213 the local and aggregate authentication statuses
1214 have equivalent meaning at this level. If the
1215 function returns anything other than
1216 EFI_SUCCESS, the value of *AuthenticationStatus
1218 @param IsFfs3Fv Indicates the FV format.
1220 @retval EFI_SUCCESS Section was retrieved successfully
1221 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1222 section stream with its
1223 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1224 but there was no corresponding GUIDed Section
1225 Extraction Protocol in the handle database.
1226 *Buffer is unmodified.
1227 @retval EFI_NOT_FOUND An error was encountered when parsing the
1228 SectionStream. This indicates the SectionStream
1229 is not correctly formatted.
1230 @retval EFI_NOT_FOUND The requested section does not exist.
1231 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1233 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1234 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1235 insufficient to contain the requested section.
1236 The input buffer is filled and section contents
1243 IN UINTN SectionStreamHandle
,
1244 IN EFI_SECTION_TYPE
*SectionType
,
1245 IN EFI_GUID
*SectionDefinitionGuid
,
1246 IN UINTN SectionInstance
,
1248 IN OUT UINTN
*BufferSize
,
1249 OUT UINT32
*AuthenticationStatus
,
1253 CORE_SECTION_STREAM_NODE
*StreamNode
;
1256 CORE_SECTION_CHILD_NODE
*ChildNode
;
1257 CORE_SECTION_STREAM_NODE
*ChildStreamNode
;
1259 UINT32 ExtractedAuthenticationStatus
;
1263 EFI_COMMON_SECTION_HEADER
*Section
;
1265 ChildStreamNode
= NULL
;
1266 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1267 Instance
= SectionInstance
+ 1;
1270 // Locate target stream
1272 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
1273 if (EFI_ERROR (Status
)) {
1274 Status
= EFI_INVALID_PARAMETER
;
1275 goto GetSection_Done
;
1279 // Found the stream, now locate and return the appropriate section
1281 if (SectionType
== NULL
) {
1283 // SectionType == NULL means return the WHOLE section stream...
1285 CopySize
= StreamNode
->StreamLength
;
1286 CopyBuffer
= StreamNode
->StreamBuffer
;
1287 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
1290 // There's a requested section type, so go find it and return it...
1292 Status
= FindChildNode (
1296 SectionDefinitionGuid
,
1297 0, // encapsulation depth
1300 &ExtractedAuthenticationStatus
1302 if (EFI_ERROR (Status
)) {
1303 if (Status
== EFI_ABORTED
) {
1306 "%a: recursion aborted due to nesting depth\n",
1310 // Map "aborted" to "not found".
1312 Status
= EFI_NOT_FOUND
;
1315 goto GetSection_Done
;
1318 Section
= (EFI_COMMON_SECTION_HEADER
*)(ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
);
1320 if (IS_SECTION2 (Section
)) {
1321 ASSERT (SECTION2_SIZE (Section
) > 0x00FFFFFF);
1323 DEBUG ((DEBUG_ERROR
, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
1324 Status
= EFI_NOT_FOUND
;
1325 goto GetSection_Done
;
1328 CopySize
= SECTION2_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER2
);
1329 CopyBuffer
= (UINT8
*)Section
+ sizeof (EFI_COMMON_SECTION_HEADER2
);
1331 CopySize
= SECTION_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER
);
1332 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
;
1358 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
1359 *BufferSize
= SectionSize
;
1362 CoreRestoreTpl (OldTpl
);
1368 Worker function. Destructor for child nodes.
1370 @param ChildNode Indicates the node to destroy
1375 IN CORE_SECTION_CHILD_NODE
*ChildNode
1378 ASSERT (ChildNode
->Signature
== CORE_SECTION_CHILD_SIGNATURE
);
1380 // Remove the child from it's list
1382 RemoveEntryList (&ChildNode
->Link
);
1384 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1386 // If it's an encapsulating section, we close the resulting section stream.
1387 // CloseSectionStream will free all memory associated with the stream.
1389 CloseSectionStream (ChildNode
->EncapsulatedStreamHandle
, TRUE
);
1392 if (ChildNode
->Event
!= NULL
) {
1393 gBS
->CloseEvent (ChildNode
->Event
);
1397 // Last, free the child node itself
1399 CoreFreePool (ChildNode
);
1403 SEP member function. Deletes an existing section stream
1405 @param StreamHandleToClose Indicates the stream to close
1406 @param FreeStreamBuffer TRUE - Need to free stream buffer;
1407 FALSE - No need to free stream buffer.
1409 @retval EFI_SUCCESS The section stream is closed sucessfully.
1410 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1411 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1417 CloseSectionStream (
1418 IN UINTN StreamHandleToClose
,
1419 IN BOOLEAN FreeStreamBuffer
1422 CORE_SECTION_STREAM_NODE
*StreamNode
;
1426 CORE_SECTION_CHILD_NODE
*ChildNode
;
1428 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1431 // Locate target stream
1433 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
1434 if (!EFI_ERROR (Status
)) {
1436 // Found the stream, so close it
1438 RemoveEntryList (&StreamNode
->Link
);
1439 while (!IsListEmpty (&StreamNode
->Children
)) {
1440 Link
= GetFirstNode (&StreamNode
->Children
);
1441 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
1442 FreeChildNode (ChildNode
);
1445 if (FreeStreamBuffer
) {
1446 CoreFreePool (StreamNode
->StreamBuffer
);
1449 CoreFreePool (StreamNode
);
1450 Status
= EFI_SUCCESS
;
1452 Status
= EFI_INVALID_PARAMETER
;
1455 CoreRestoreTpl (OldTpl
);
1460 The ExtractSection() function processes the input section and
1461 allocates a buffer from the pool in which it returns the section
1462 contents. If the section being extracted contains
1463 authentication information (the section's
1464 GuidedSectionHeader.Attributes field has the
1465 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1466 returned in AuthenticationStatus must reflect the results of
1467 the authentication operation. Depending on the algorithm and
1468 size of the encapsulated data, the time that is required to do
1469 a full authentication may be prohibitively long for some
1470 classes of systems. To indicate this, use
1471 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1472 the security policy driver (see the Platform Initialization
1473 Driver Execution Environment Core Interface Specification for
1474 more details and the GUID definition). If the
1475 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1476 database, then, if possible, full authentication should be
1477 skipped and the section contents simply returned in the
1478 OutputBuffer. In this case, the
1479 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1480 must be set on return. ExtractSection() is callable only from
1481 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1482 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1483 defined in RaiseTPL() in the UEFI 2.0 specification.
1486 @param This Indicates the
1487 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1488 @param InputSection Buffer containing the input GUIDed section
1489 to be processed. OutputBuffer OutputBuffer
1490 is allocated from boot services pool
1491 memory and contains the new section
1492 stream. The caller is responsible for
1493 freeing this buffer.
1494 @param OutputBuffer *OutputBuffer is allocated from boot services
1495 pool memory and contains the new section stream.
1496 The caller is responsible for freeing this buffer.
1497 @param OutputSize A pointer to a caller-allocated UINTN in
1498 which the size of OutputBuffer allocation
1499 is stored. If the function returns
1500 anything other than EFI_SUCCESS, the value
1501 of OutputSize is undefined.
1503 @param AuthenticationStatus A pointer to a caller-allocated
1504 UINT32 that indicates the
1505 authentication status of the
1506 output buffer. If the input
1508 GuidedSectionHeader.Attributes
1510 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1511 bit as clear, AuthenticationStatus
1512 must return zero. Both local bits
1513 (19:16) and aggregate bits (3:0)
1514 in AuthenticationStatus are
1515 returned by ExtractSection().
1516 These bits reflect the status of
1517 the extraction operation. The bit
1518 pattern in both regions must be
1519 the same, as the local and
1520 aggregate authentication statuses
1521 have equivalent meaning at this
1522 level. If the function returns
1523 anything other than EFI_SUCCESS,
1524 the value of AuthenticationStatus
1528 @retval EFI_SUCCESS The InputSection was successfully
1529 processed and the section contents were
1532 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1533 resources to process the
1536 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1537 not match this instance of the
1538 GUIDed Section Extraction
1544 CustomGuidedSectionExtract (
1545 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
1546 IN CONST VOID
*InputSection
,
1547 OUT VOID
**OutputBuffer
,
1548 OUT UINTN
*OutputSize
,
1549 OUT UINT32
*AuthenticationStatus
1553 VOID
*ScratchBuffer
;
1554 VOID
*AllocatedOutputBuffer
;
1555 UINT32 OutputBufferSize
;
1556 UINT32 ScratchBufferSize
;
1557 UINT16 SectionAttribute
;
1560 // Init local variable
1562 ScratchBuffer
= NULL
;
1563 AllocatedOutputBuffer
= NULL
;
1566 // Call GetInfo to get the size and attribute of input guided section data.
1568 Status
= ExtractGuidedSectionGetInfo (
1575 if (EFI_ERROR (Status
)) {
1576 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
1580 if (ScratchBufferSize
> 0) {
1582 // Allocate scratch buffer
1584 ScratchBuffer
= AllocatePool (ScratchBufferSize
);
1585 if (ScratchBuffer
== NULL
) {
1586 return EFI_OUT_OF_RESOURCES
;
1590 if (OutputBufferSize
> 0) {
1592 // Allocate output buffer
1594 AllocatedOutputBuffer
= AllocatePool (OutputBufferSize
);
1595 if (AllocatedOutputBuffer
== NULL
) {
1596 if (ScratchBuffer
!= NULL
) {
1597 FreePool (ScratchBuffer
);
1600 return EFI_OUT_OF_RESOURCES
;
1603 *OutputBuffer
= AllocatedOutputBuffer
;
1607 // Call decode function to extract raw data from the guided section.
1609 Status
= ExtractGuidedSectionDecode (
1613 AuthenticationStatus
1615 if (EFI_ERROR (Status
)) {
1619 if (AllocatedOutputBuffer
!= NULL
) {
1620 CoreFreePool (AllocatedOutputBuffer
);
1623 if (ScratchBuffer
!= NULL
) {
1624 CoreFreePool (ScratchBuffer
);
1627 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
1631 if (*OutputBuffer
!= AllocatedOutputBuffer
) {
1633 // OutputBuffer was returned as a different value,
1634 // so copy section contents to the allocated memory buffer.
1636 CopyMem (AllocatedOutputBuffer
, *OutputBuffer
, OutputBufferSize
);
1637 *OutputBuffer
= AllocatedOutputBuffer
;
1641 // Set real size of output buffer.
1643 *OutputSize
= (UINTN
)OutputBufferSize
;
1646 // Free unused scratch buffer.
1648 if (ScratchBuffer
!= NULL
) {
1649 CoreFreePool (ScratchBuffer
);