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 - 2011, 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.
44 // Local defines and typedefs
46 #define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
47 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
48 CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
56 // StreamBase + OffsetInStream == pointer to section header in stream. The
57 // stream base is always known when walking the sections within.
59 UINT32 OffsetInStream
;
61 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
62 // encapsulating section. Otherwise, it contains the stream handle
63 // of the encapsulated stream. This handle is ALWAYS produced any time an
64 // encapsulating child is encountered, irrespective of whether the
65 // encapsulated stream is processed further.
67 UINTN EncapsulatedStreamHandle
;
68 EFI_GUID
*EncapsulationGuid
;
69 } CORE_SECTION_CHILD_NODE
;
71 #define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
72 #define STREAM_NODE_FROM_LINK(Node) \
73 CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
83 // Authentication status is from GUIDed encapsulations.
85 UINT32 AuthenticationStatus
;
86 } CORE_SECTION_STREAM_NODE
;
88 #define NULL_STREAM_HANDLE 0
91 CORE_SECTION_CHILD_NODE
*ChildNode
;
92 CORE_SECTION_STREAM_NODE
*ParentStream
;
99 The ExtractSection() function processes the input section and
100 allocates a buffer from the pool in which it returns the section
101 contents. If the section being extracted contains
102 authentication information (the section's
103 GuidedSectionHeader.Attributes field has the
104 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
105 returned in AuthenticationStatus must reflect the results of
106 the authentication operation. Depending on the algorithm and
107 size of the encapsulated data, the time that is required to do
108 a full authentication may be prohibitively long for some
109 classes of systems. To indicate this, use
110 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
111 the security policy driver (see the Platform Initialization
112 Driver Execution Environment Core Interface Specification for
113 more details and the GUID definition). If the
114 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
115 database, then, if possible, full authentication should be
116 skipped and the section contents simply returned in the
117 OutputBuffer. In this case, the
118 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
119 must be set on return. ExtractSection() is callable only from
120 TPL_NOTIFY and below. Behavior of ExtractSection() at any
121 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
122 defined in RaiseTPL() in the UEFI 2.0 specification.
125 @param This Indicates the
126 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
127 @param InputSection Buffer containing the input GUIDed section
128 to be processed. OutputBuffer OutputBuffer
129 is allocated from boot services pool
130 memory and contains the new section
131 stream. The caller is responsible for
133 @param OutputBuffer *OutputBuffer is allocated from boot services
134 pool memory and contains the new section stream.
135 The caller is responsible for freeing this buffer.
136 @param OutputSize A pointer to a caller-allocated UINTN in
137 which the size of OutputBuffer allocation
138 is stored. If the function returns
139 anything other than EFI_SUCCESS, the value
140 of OutputSize is undefined.
142 @param AuthenticationStatus A pointer to a caller-allocated
143 UINT32 that indicates the
144 authentication status of the
145 output buffer. If the input
147 GuidedSectionHeader.Attributes
149 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
150 bit as clear, AuthenticationStatus
151 must return zero. Both local bits
152 (19:16) and aggregate bits (3:0)
153 in AuthenticationStatus are
154 returned by ExtractSection().
155 These bits reflect the status of
156 the extraction operation. The bit
157 pattern in both regions must be
158 the same, as the local and
159 aggregate authentication statuses
160 have equivalent meaning at this
161 level. If the function returns
162 anything other than EFI_SUCCESS,
163 the value of AuthenticationStatus
167 @retval EFI_SUCCESS The InputSection was successfully
168 processed and the section contents were
171 @retval EFI_OUT_OF_RESOURCES The system has insufficient
172 resources to process the
175 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
176 not match this instance of the
177 GUIDed Section Extraction
183 CustomGuidedSectionExtract (
184 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
185 IN CONST VOID
*InputSection
,
186 OUT VOID
**OutputBuffer
,
187 OUT UINTN
*OutputSize
,
188 OUT UINT32
*AuthenticationStatus
194 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
196 EFI_HANDLE mSectionExtractionHandle
= NULL
;
198 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol
= {
199 CustomGuidedSectionExtract
204 Entry point of the section extraction code. Initializes an instance of the
205 section extraction interface and installs it on a new handle.
207 @param ImageHandle A handle for the image that is initializing this driver
208 @param SystemTable A pointer to the EFI system table
210 @retval EFI_SUCCESS Driver initialized successfully
211 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
216 InitializeSectionExtraction (
217 IN EFI_HANDLE ImageHandle
,
218 IN EFI_SYSTEM_TABLE
*SystemTable
222 EFI_GUID
*ExtractHandlerGuidTable
;
223 UINTN ExtractHandlerNumber
;
226 // Get custom extract guided section method guid list
228 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
230 Status
= EFI_SUCCESS
;
232 // Install custom guided extraction protocol
234 while (ExtractHandlerNumber
-- > 0) {
235 Status
= CoreInstallProtocolInterface (
236 &mSectionExtractionHandle
,
237 &ExtractHandlerGuidTable
[ExtractHandlerNumber
],
238 EFI_NATIVE_INTERFACE
,
239 &mCustomGuidedSectionExtractionProtocol
241 ASSERT_EFI_ERROR (Status
);
249 Check if a stream is valid.
251 @param SectionStream The section stream to be checked
252 @param SectionStreamLength The length of section stream
254 @return A boolean value indicating the validness of the section stream.
258 IsValidSectionStream (
259 IN VOID
*SectionStream
,
260 IN UINTN SectionStreamLength
265 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
266 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
269 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
271 while (TotalLength
< SectionStreamLength
) {
272 if (IS_SECTION2 (SectionHeader
)) {
273 SectionLength
= SECTION2_SIZE (SectionHeader
);
275 SectionLength
= SECTION_SIZE (SectionHeader
);
277 TotalLength
+= SectionLength
;
279 if (TotalLength
== SectionStreamLength
) {
284 // Move to the next byte following the section...
286 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINT8
*) SectionHeader
+ SectionLength
);
289 // Figure out where the next section begins
291 NextSectionHeader
= ALIGN_POINTER(SectionHeader
, 4);
292 TotalLength
+= (UINTN
) NextSectionHeader
- (UINTN
) SectionHeader
;
293 SectionHeader
= NextSectionHeader
;
302 Worker function. Constructor for section streams.
304 @param SectionStreamLength Size in bytes of the section stream.
305 @param SectionStream Buffer containing the new section stream.
306 @param AllocateBuffer Indicates whether the stream buffer is to be
307 copied or the input buffer is to be used in
308 place. AuthenticationStatus- Indicates the
309 default authentication status for the new
311 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
312 indicates the authentication status of the
313 output buffer. If the input section's
314 GuidedSectionHeader.Attributes field
315 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
316 bit as clear, AuthenticationStatus must return
317 zero. Both local bits (19:16) and aggregate
318 bits (3:0) in AuthenticationStatus are returned
319 by ExtractSection(). These bits reflect the
320 status of the extraction operation. The bit
321 pattern in both regions must be the same, as
322 the local and aggregate authentication statuses
323 have equivalent meaning at this level. If the
324 function returns anything other than
325 EFI_SUCCESS, the value of *AuthenticationStatus
327 @param SectionStreamHandle A pointer to a caller allocated section stream
330 @retval EFI_SUCCESS Stream was added to stream database.
331 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
335 OpenSectionStreamEx (
336 IN UINTN SectionStreamLength
,
337 IN VOID
*SectionStream
,
338 IN BOOLEAN AllocateBuffer
,
339 IN UINT32 AuthenticationStatus
,
340 OUT UINTN
*SectionStreamHandle
343 CORE_SECTION_STREAM_NODE
*NewStream
;
347 // Allocate a new stream
349 NewStream
= AllocatePool (sizeof (CORE_SECTION_STREAM_NODE
));
350 if (NewStream
== NULL
) {
351 return EFI_OUT_OF_RESOURCES
;
354 if (AllocateBuffer
) {
356 // if we're here, we're double buffering, allocate the buffer and copy the
359 if (SectionStreamLength
> 0) {
360 NewStream
->StreamBuffer
= AllocatePool (SectionStreamLength
);
361 if (NewStream
->StreamBuffer
== NULL
) {
362 CoreFreePool (NewStream
);
363 return EFI_OUT_OF_RESOURCES
;
366 // Copy in stream data
368 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
371 // It's possible to have a zero length section stream.
373 NewStream
->StreamBuffer
= NULL
;
377 // If were here, the caller has supplied the buffer (it's an internal call)
378 // so just assign the buffer. This happens when we open section streams
379 // as a result of expanding an encapsulating section.
381 NewStream
->StreamBuffer
= SectionStream
;
385 // Initialize the rest of the section stream
387 NewStream
->Signature
= CORE_SECTION_STREAM_SIGNATURE
;
388 NewStream
->StreamHandle
= (UINTN
) NewStream
;
389 NewStream
->StreamLength
= SectionStreamLength
;
390 InitializeListHead (&NewStream
->Children
);
391 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
394 // Add new stream to stream list
396 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
397 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
398 CoreRestoreTpl (OldTpl
);
400 *SectionStreamHandle
= NewStream
->StreamHandle
;
407 SEP member function. This function creates and returns a new section stream
408 handle to represent the new section stream.
410 @param SectionStreamLength Size in bytes of the section stream.
411 @param SectionStream Buffer containing the new section stream.
412 @param SectionStreamHandle A pointer to a caller allocated UINTN that on
413 output contains the new section stream handle.
415 @retval EFI_SUCCESS The section stream is created successfully.
416 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
417 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
424 IN UINTN SectionStreamLength
,
425 IN VOID
*SectionStream
,
426 OUT UINTN
*SectionStreamHandle
430 // Check to see section stream looks good...
432 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
433 return EFI_INVALID_PARAMETER
;
436 return OpenSectionStreamEx (
448 Worker function. Determine if the input stream:child matches the input type.
450 @param Stream Indicates the section stream associated with the
452 @param Child Indicates the child to check
453 @param SearchType Indicates the type of section to check against
455 @param SectionDefinitionGuid Indicates the GUID to check against if the type
456 is EFI_SECTION_GUID_DEFINED
458 @retval TRUE The child matches
459 @retval FALSE The child doesn't match
464 IN CORE_SECTION_STREAM_NODE
*Stream
,
465 IN CORE_SECTION_CHILD_NODE
*Child
,
466 IN EFI_SECTION_TYPE SearchType
,
467 IN EFI_GUID
*SectionDefinitionGuid
470 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
472 if (SearchType
== EFI_SECTION_ALL
) {
475 if (Child
->Type
!= SearchType
) {
478 if ((SearchType
!= EFI_SECTION_GUID_DEFINED
) || (SectionDefinitionGuid
== NULL
)) {
481 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
482 if (IS_SECTION2 (GuidedSection
)) {
483 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2
*) GuidedSection
)->SectionDefinitionGuid
), SectionDefinitionGuid
);
485 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
490 RPN callback function. Initializes the section stream
491 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
493 @param Event The event that fired
494 @param RpnContext A pointer to the context that allows us to identify
495 the relevent encapsulation.
499 NotifyGuidedExtraction (
505 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
506 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
507 VOID
*NewStreamBuffer
;
508 UINTN NewStreamBufferSize
;
509 UINT32 AuthenticationStatus
;
510 RPN_EVENT_CONTEXT
*Context
;
512 Context
= RpnContext
;
514 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
515 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
517 Status
= gBS
->LocateProtocol (Context
->ChildNode
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
518 if (EFI_ERROR (Status
)) {
522 Status
= GuidedExtraction
->ExtractSection (
526 &NewStreamBufferSize
,
527 &AuthenticationStatus
529 ASSERT_EFI_ERROR (Status
);
532 // Make sure we initialize the new stream with the correct
533 // authentication status for both aggregate and local status fields.
535 if ((GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
537 // OR in the parent stream's aggregate status.
539 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
542 // since there's no authentication data contributed by the section,
543 // just inherit the full value from our immediate parent.
545 AuthenticationStatus
= Context
->ParentStream
->AuthenticationStatus
;
548 Status
= OpenSectionStreamEx (
552 AuthenticationStatus
,
553 &Context
->ChildNode
->EncapsulatedStreamHandle
555 ASSERT_EFI_ERROR (Status
);
558 // Close the event when done.
560 gBS
->CloseEvent (Event
);
565 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
567 @param ParentStream Indicates the parent of the ecnapsulation section (child)
568 @param ChildNode Indicates the child node that is the encapsulation section.
572 CreateGuidedExtractionRpnEvent (
573 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
574 IN CORE_SECTION_CHILD_NODE
*ChildNode
577 RPN_EVENT_CONTEXT
*Context
;
580 // Allocate new event structure and context
582 Context
= AllocatePool (sizeof (RPN_EVENT_CONTEXT
));
583 ASSERT (Context
!= NULL
);
585 Context
->ChildNode
= ChildNode
;
586 Context
->ParentStream
= ParentStream
;
588 Context
->Event
= EfiCreateProtocolNotifyEvent (
589 Context
->ChildNode
->EncapsulationGuid
,
591 NotifyGuidedExtraction
,
593 &Context
->Registration
598 Worker function. Constructor for new child nodes.
600 @param Stream Indicates the section stream in which to add the
602 @param ChildOffset Indicates the offset in Stream that is the
603 beginning of the child section.
604 @param ChildNode Indicates the Callee allocated and initialized
607 @retval EFI_SUCCESS Child node was found and returned.
608 EFI_OUT_OF_RESOURCES- Memory allocation failed.
609 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
610 handles when the child node is created. If the
611 section type is GUID defined, and the extraction
612 GUID does not exist, and producing the stream
613 requires the GUID, then a protocol error is
614 generated and no child is produced. Values
615 returned by OpenSectionStreamEx.
620 IN CORE_SECTION_STREAM_NODE
*Stream
,
621 IN UINT32 ChildOffset
,
622 OUT CORE_SECTION_CHILD_NODE
**ChildNode
626 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
627 EFI_COMPRESSION_SECTION
*CompressionHeader
;
628 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
629 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
630 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
631 VOID
*NewStreamBuffer
;
634 UINTN NewStreamBufferSize
;
635 UINT32 AuthenticationStatus
;
636 VOID
*CompressionSource
;
637 UINT32 CompressionSourceSize
;
638 UINT32 UncompressedLength
;
639 UINT8 CompressionType
;
640 UINT16 GuidedSectionAttributes
;
642 CORE_SECTION_CHILD_NODE
*Node
;
644 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
647 // Allocate a new node
649 *ChildNode
= AllocatePool (sizeof (CORE_SECTION_CHILD_NODE
));
652 return EFI_OUT_OF_RESOURCES
;
658 Node
->Signature
= CORE_SECTION_CHILD_SIGNATURE
;
659 Node
->Type
= SectionHeader
->Type
;
660 if (IS_SECTION2 (SectionHeader
)) {
661 Node
->Size
= SECTION2_SIZE (SectionHeader
);
663 Node
->Size
= SECTION_SIZE (SectionHeader
);
665 Node
->OffsetInStream
= ChildOffset
;
666 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
667 Node
->EncapsulationGuid
= NULL
;
670 // If it's an encapsulating section, then create the new section stream also
672 switch (Node
->Type
) {
673 case EFI_SECTION_COMPRESSION
:
675 // Get the CompressionSectionHeader
677 ASSERT (Node
->Size
>= sizeof (EFI_COMPRESSION_SECTION
));
679 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
681 if (IS_SECTION2 (CompressionHeader
)) {
682 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION2
));
683 CompressionSourceSize
= (UINT32
) (SECTION2_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION2
));
684 UncompressedLength
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->UncompressedLength
;
685 CompressionType
= ((EFI_COMPRESSION_SECTION2
*) CompressionHeader
)->CompressionType
;
687 CompressionSource
= (VOID
*) ((UINT8
*) CompressionHeader
+ sizeof (EFI_COMPRESSION_SECTION
));
688 CompressionSourceSize
= (UINT32
) (SECTION_SIZE (CompressionHeader
) - sizeof (EFI_COMPRESSION_SECTION
));
689 UncompressedLength
= CompressionHeader
->UncompressedLength
;
690 CompressionType
= CompressionHeader
->CompressionType
;
694 // Allocate space for the new stream
696 if (UncompressedLength
> 0) {
697 NewStreamBufferSize
= UncompressedLength
;
698 NewStreamBuffer
= AllocatePool (NewStreamBufferSize
);
699 if (NewStreamBuffer
== NULL
) {
701 return EFI_OUT_OF_RESOURCES
;
704 if (CompressionType
== EFI_NOT_COMPRESSED
) {
706 // stream is not actually compressed, just encapsulated. So just copy it.
708 CopyMem (NewStreamBuffer
, CompressionSource
, NewStreamBufferSize
);
709 } else if (CompressionType
== EFI_STANDARD_COMPRESSION
) {
711 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
715 // Decompress the stream
717 Status
= CoreLocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
718 ASSERT_EFI_ERROR (Status
);
719 ASSERT (Decompress
!= NULL
);
721 Status
= Decompress
->GetInfo (
724 CompressionSourceSize
,
725 (UINT32
*)&NewStreamBufferSize
,
728 ASSERT_EFI_ERROR (Status
);
729 ASSERT (NewStreamBufferSize
== UncompressedLength
);
731 ScratchBuffer
= AllocatePool (ScratchSize
);
732 if (ScratchBuffer
== NULL
) {
734 CoreFreePool (NewStreamBuffer
);
735 return EFI_OUT_OF_RESOURCES
;
738 Status
= Decompress
->Decompress (
741 CompressionSourceSize
,
743 (UINT32
)NewStreamBufferSize
,
747 ASSERT_EFI_ERROR (Status
);
748 CoreFreePool (ScratchBuffer
);
751 NewStreamBuffer
= NULL
;
752 NewStreamBufferSize
= 0;
755 Status
= OpenSectionStreamEx (
759 Stream
->AuthenticationStatus
,
760 &Node
->EncapsulatedStreamHandle
762 if (EFI_ERROR (Status
)) {
764 CoreFreePool (NewStreamBuffer
);
769 case EFI_SECTION_GUID_DEFINED
:
770 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
771 if (IS_SECTION2 (GuidedHeader
)) {
772 Node
->EncapsulationGuid
= &(((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->SectionDefinitionGuid
);
773 GuidedSectionAttributes
= ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->Attributes
;
775 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
776 GuidedSectionAttributes
= GuidedHeader
->Attributes
;
778 Status
= CoreLocateProtocol (Node
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
779 if (!EFI_ERROR (Status
) && GuidedExtraction
!= NULL
) {
781 // NewStreamBuffer is always allocated by ExtractSection... No caller
784 Status
= GuidedExtraction
->ExtractSection (
788 &NewStreamBufferSize
,
789 &AuthenticationStatus
791 if (EFI_ERROR (Status
)) {
792 CoreFreePool (*ChildNode
);
793 return EFI_PROTOCOL_ERROR
;
797 // Make sure we initialize the new stream with the correct
798 // authentication status for both aggregate and local status fields.
800 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
802 // OR in the parent stream's aggregate status.
804 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
807 // since there's no authentication data contributed by the section,
808 // just inherit the full value from our immediate parent.
810 AuthenticationStatus
= Stream
->AuthenticationStatus
;
813 Status
= OpenSectionStreamEx (
817 AuthenticationStatus
,
818 &Node
->EncapsulatedStreamHandle
820 if (EFI_ERROR (Status
)) {
821 CoreFreePool (*ChildNode
);
822 CoreFreePool (NewStreamBuffer
);
827 // There's no GUIDed section extraction protocol available.
829 if ((GuidedSectionAttributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) {
831 // If the section REQUIRES an extraction protocol, register for RPN
832 // when the required GUIDed extraction protocol becomes available.
834 CreateGuidedExtractionRpnEvent (Stream
, Node
);
837 // Figure out the proper authentication status
839 AuthenticationStatus
= Stream
->AuthenticationStatus
;
841 if (IS_SECTION2 (GuidedHeader
)) {
842 Status
= OpenSectionStreamEx (
843 SECTION2_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
844 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION2
*) GuidedHeader
)->DataOffset
,
846 AuthenticationStatus
,
847 &Node
->EncapsulatedStreamHandle
850 Status
= OpenSectionStreamEx (
851 SECTION_SIZE (GuidedHeader
) - ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
852 (UINT8
*) GuidedHeader
+ ((EFI_GUID_DEFINED_SECTION
*) GuidedHeader
)->DataOffset
,
854 AuthenticationStatus
,
855 &Node
->EncapsulatedStreamHandle
858 if (EFI_ERROR (Status
)) {
870 // Nothing to do if it's a leaf
876 // Last, add the new child node to the stream
878 InsertTailList (&Stream
->Children
, &Node
->Link
);
885 Worker function Recursively searches / builds section stream database
886 looking for requested section.
888 @param SourceStream Indicates the section stream in which to do the
890 @param SearchType Indicates the type of section to search for.
891 @param SectionInstance Indicates which instance of section to find.
892 This is an in/out parameter to deal with
894 @param SectionDefinitionGuid Guid of section definition
895 @param FoundChild Output indicating the child node that is found.
896 @param FoundStream Output indicating which section stream the child
897 was found in. If this stream was generated as a
898 result of an encapsulation section, the
899 streamhandle is visible within the SEP driver
901 @param AuthenticationStatus Indicates the authentication status of the found section.
903 @retval EFI_SUCCESS Child node was found and returned.
904 EFI_OUT_OF_RESOURCES- Memory allocation failed.
905 @retval EFI_NOT_FOUND Requested child node does not exist.
906 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
912 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
913 IN EFI_SECTION_TYPE SearchType
,
914 IN OUT UINTN
*SectionInstance
,
915 IN EFI_GUID
*SectionDefinitionGuid
,
916 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
917 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
918 OUT UINT32
*AuthenticationStatus
921 CORE_SECTION_CHILD_NODE
*CurrentChildNode
;
922 CORE_SECTION_CHILD_NODE
*RecursedChildNode
;
923 CORE_SECTION_STREAM_NODE
*RecursedFoundStream
;
924 UINT32 NextChildOffset
;
925 EFI_STATUS ErrorStatus
;
928 CurrentChildNode
= NULL
;
929 ErrorStatus
= EFI_NOT_FOUND
;
931 if (SourceStream
->StreamLength
== 0) {
932 return EFI_NOT_FOUND
;
935 if (IsListEmpty (&SourceStream
->Children
) &&
936 SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)) {
938 // This occurs when a section stream exists, but no child sections
939 // have been parsed out yet. Therefore, extract the first child and add it
940 // to the list of children so we can get started.
941 // Section stream may contain an array of zero or more bytes.
942 // So, its size should be >= the size of commen section header.
944 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
945 if (EFI_ERROR (Status
)) {
951 // At least one child has been parsed out of the section stream. So, walk
952 // through the sections that have already been parsed out looking for the
953 // requested section, if necessary, continue parsing section stream and
954 // adding children until either the requested section is found, or we run
957 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
960 ASSERT (CurrentChildNode
!= NULL
);
961 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
963 // The type matches, so check the instance count to see if it's the one we want
965 (*SectionInstance
)--;
966 if (*SectionInstance
== 0) {
970 *FoundChild
= CurrentChildNode
;
971 *FoundStream
= SourceStream
;
972 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
977 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
979 // If the current node is an encapsulating node, recurse into it...
981 Status
= FindChildNode (
982 (CORE_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
985 SectionDefinitionGuid
,
987 &RecursedFoundStream
,
991 // If the status is not EFI_SUCCESS, just save the error code and continue
992 // to find the request child node in the rest stream.
994 if (*SectionInstance
== 0) {
995 ASSERT_EFI_ERROR (Status
);
996 *FoundChild
= RecursedChildNode
;
997 *FoundStream
= RecursedFoundStream
;
1000 ErrorStatus
= Status
;
1002 } else if ((CurrentChildNode
->Type
== EFI_SECTION_GUID_DEFINED
) && (SearchType
!= EFI_SECTION_GUID_DEFINED
)) {
1004 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1005 // because a required GUIDED section extraction protocol does not exist.
1006 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1008 ErrorStatus
= EFI_PROTOCOL_ERROR
;
1011 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
1013 // We haven't found the child node we're interested in yet, but there's
1014 // still more nodes that have already been parsed so get the next one
1015 // and continue searching..
1017 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
1020 // We've exhausted children that have already been parsed, so see if
1021 // there's any more data and continue parsing out more children if there
1024 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
1026 // Round up to 4 byte boundary
1028 NextChildOffset
+= 3;
1029 NextChildOffset
&= ~(UINTN
) 3;
1030 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
1032 // There's an unparsed child remaining in the stream, so create a new child node
1034 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
1035 if (EFI_ERROR (Status
)) {
1039 ASSERT (EFI_ERROR (ErrorStatus
));
1048 Worker function. Search stream database for requested stream handle.
1050 @param SearchHandle Indicates which stream to look for.
1051 @param FoundStream Output pointer to the found stream.
1053 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1055 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1061 IN UINTN SearchHandle
,
1062 OUT CORE_SECTION_STREAM_NODE
**FoundStream
1065 CORE_SECTION_STREAM_NODE
*StreamNode
;
1067 if (!IsListEmpty (&mStreamRoot
)) {
1068 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1070 if (StreamNode
->StreamHandle
== SearchHandle
) {
1071 *FoundStream
= StreamNode
;
1073 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1076 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1081 return EFI_NOT_FOUND
;
1086 SEP member function. Retrieves requested section from section stream.
1088 @param SectionStreamHandle The section stream from which to extract the
1090 @param SectionType A pointer to the type of section to search for.
1091 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1092 then SectionDefinitionGuid indicates which of
1093 these types of sections to search for.
1094 @param SectionInstance Indicates which instance of the requested
1096 @param Buffer Double indirection to buffer. If *Buffer is
1097 non-null on input, then the buffer is caller
1098 allocated. If Buffer is NULL, then the buffer
1099 is callee allocated. In either case, the
1100 requried buffer size is returned in *BufferSize.
1101 @param BufferSize On input, indicates the size of *Buffer if
1102 *Buffer is non-null on input. On output,
1103 indicates the required size (allocated size if
1104 callee allocated) of *Buffer.
1105 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1106 indicates the authentication status of the
1107 output buffer. If the input section's
1108 GuidedSectionHeader.Attributes field
1109 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1110 bit as clear, AuthenticationStatus must return
1111 zero. Both local bits (19:16) and aggregate
1112 bits (3:0) in AuthenticationStatus are returned
1113 by ExtractSection(). These bits reflect the
1114 status of the extraction operation. The bit
1115 pattern in both regions must be the same, as
1116 the local and aggregate authentication statuses
1117 have equivalent meaning at this level. If the
1118 function returns anything other than
1119 EFI_SUCCESS, the value of *AuthenticationStatus
1121 @param IsFfs3Fv Indicates the FV format.
1123 @retval EFI_SUCCESS Section was retrieved successfully
1124 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1125 section stream with its
1126 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1127 but there was no corresponding GUIDed Section
1128 Extraction Protocol in the handle database.
1129 *Buffer is unmodified.
1130 @retval EFI_NOT_FOUND An error was encountered when parsing the
1131 SectionStream. This indicates the SectionStream
1132 is not correctly formatted.
1133 @retval EFI_NOT_FOUND The requested section does not exist.
1134 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1136 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1137 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1138 insufficient to contain the requested section.
1139 The input buffer is filled and section contents
1146 IN UINTN SectionStreamHandle
,
1147 IN EFI_SECTION_TYPE
*SectionType
,
1148 IN EFI_GUID
*SectionDefinitionGuid
,
1149 IN UINTN SectionInstance
,
1151 IN OUT UINTN
*BufferSize
,
1152 OUT UINT32
*AuthenticationStatus
,
1156 CORE_SECTION_STREAM_NODE
*StreamNode
;
1159 CORE_SECTION_CHILD_NODE
*ChildNode
;
1160 CORE_SECTION_STREAM_NODE
*ChildStreamNode
;
1162 UINT32 ExtractedAuthenticationStatus
;
1166 EFI_COMMON_SECTION_HEADER
*Section
;
1169 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1170 Instance
= SectionInstance
+ 1;
1173 // Locate target stream
1175 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
1176 if (EFI_ERROR (Status
)) {
1177 Status
= EFI_INVALID_PARAMETER
;
1178 goto GetSection_Done
;
1182 // Found the stream, now locate and return the appropriate section
1184 if (SectionType
== NULL
) {
1186 // SectionType == NULL means return the WHOLE section stream...
1188 CopySize
= StreamNode
->StreamLength
;
1189 CopyBuffer
= StreamNode
->StreamBuffer
;
1190 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
1193 // There's a requested section type, so go find it and return it...
1195 Status
= FindChildNode (
1199 SectionDefinitionGuid
,
1202 &ExtractedAuthenticationStatus
1204 if (EFI_ERROR (Status
)) {
1205 goto GetSection_Done
;
1208 Section
= (EFI_COMMON_SECTION_HEADER
*) (ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
);
1210 if (IS_SECTION2 (Section
)) {
1211 ASSERT (SECTION2_SIZE (Section
) > 0x00FFFFFF);
1213 DEBUG ((DEBUG_ERROR
, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
1214 Status
= EFI_NOT_FOUND
;
1215 goto GetSection_Done
;
1217 CopySize
= SECTION2_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER2
);
1218 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER2
);
1220 CopySize
= SECTION_SIZE (Section
) - sizeof (EFI_COMMON_SECTION_HEADER
);
1221 CopyBuffer
= (UINT8
*) Section
+ sizeof (EFI_COMMON_SECTION_HEADER
);
1223 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
1226 SectionSize
= CopySize
;
1227 if (*Buffer
!= NULL
) {
1229 // Caller allocated buffer. Fill to size and return required size...
1231 if (*BufferSize
< CopySize
) {
1232 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
1233 CopySize
= *BufferSize
;
1237 // Callee allocated buffer. Allocate buffer and return size.
1239 *Buffer
= AllocatePool (CopySize
);
1240 if (*Buffer
== NULL
) {
1241 Status
= EFI_OUT_OF_RESOURCES
;
1242 goto GetSection_Done
;
1245 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
1246 *BufferSize
= SectionSize
;
1249 CoreRestoreTpl (OldTpl
);
1256 Worker function. Destructor for child nodes.
1258 @param ChildNode Indicates the node to destroy
1263 IN CORE_SECTION_CHILD_NODE
*ChildNode
1266 ASSERT (ChildNode
->Signature
== CORE_SECTION_CHILD_SIGNATURE
);
1268 // Remove the child from it's list
1270 RemoveEntryList (&ChildNode
->Link
);
1272 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1274 // If it's an encapsulating section, we close the resulting section stream.
1275 // CloseSectionStream will free all memory associated with the stream.
1277 CloseSectionStream (ChildNode
->EncapsulatedStreamHandle
);
1280 // Last, free the child node itself
1282 CoreFreePool (ChildNode
);
1287 SEP member function. Deletes an existing section stream
1289 @param StreamHandleToClose Indicates the stream to close
1291 @retval EFI_SUCCESS The section stream is closed sucessfully.
1292 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1293 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1299 CloseSectionStream (
1300 IN UINTN StreamHandleToClose
1303 CORE_SECTION_STREAM_NODE
*StreamNode
;
1307 CORE_SECTION_CHILD_NODE
*ChildNode
;
1309 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1312 // Locate target stream
1314 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
1315 if (!EFI_ERROR (Status
)) {
1317 // Found the stream, so close it
1319 RemoveEntryList (&StreamNode
->Link
);
1320 while (!IsListEmpty (&StreamNode
->Children
)) {
1321 Link
= GetFirstNode (&StreamNode
->Children
);
1322 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
1323 FreeChildNode (ChildNode
);
1325 CoreFreePool (StreamNode
->StreamBuffer
);
1326 CoreFreePool (StreamNode
);
1327 Status
= EFI_SUCCESS
;
1329 Status
= EFI_INVALID_PARAMETER
;
1332 CoreRestoreTpl (OldTpl
);
1338 The ExtractSection() function processes the input section and
1339 allocates a buffer from the pool in which it returns the section
1340 contents. If the section being extracted contains
1341 authentication information (the section's
1342 GuidedSectionHeader.Attributes field has the
1343 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1344 returned in AuthenticationStatus must reflect the results of
1345 the authentication operation. Depending on the algorithm and
1346 size of the encapsulated data, the time that is required to do
1347 a full authentication may be prohibitively long for some
1348 classes of systems. To indicate this, use
1349 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1350 the security policy driver (see the Platform Initialization
1351 Driver Execution Environment Core Interface Specification for
1352 more details and the GUID definition). If the
1353 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1354 database, then, if possible, full authentication should be
1355 skipped and the section contents simply returned in the
1356 OutputBuffer. In this case, the
1357 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1358 must be set on return. ExtractSection() is callable only from
1359 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1360 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1361 defined in RaiseTPL() in the UEFI 2.0 specification.
1364 @param This Indicates the
1365 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1366 @param InputSection Buffer containing the input GUIDed section
1367 to be processed. OutputBuffer OutputBuffer
1368 is allocated from boot services pool
1369 memory and contains the new section
1370 stream. The caller is responsible for
1371 freeing this buffer.
1372 @param OutputBuffer *OutputBuffer is allocated from boot services
1373 pool memory and contains the new section stream.
1374 The caller is responsible for freeing this buffer.
1375 @param OutputSize A pointer to a caller-allocated UINTN in
1376 which the size of OutputBuffer allocation
1377 is stored. If the function returns
1378 anything other than EFI_SUCCESS, the value
1379 of OutputSize is undefined.
1381 @param AuthenticationStatus A pointer to a caller-allocated
1382 UINT32 that indicates the
1383 authentication status of the
1384 output buffer. If the input
1386 GuidedSectionHeader.Attributes
1388 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1389 bit as clear, AuthenticationStatus
1390 must return zero. Both local bits
1391 (19:16) and aggregate bits (3:0)
1392 in AuthenticationStatus are
1393 returned by ExtractSection().
1394 These bits reflect the status of
1395 the extraction operation. The bit
1396 pattern in both regions must be
1397 the same, as the local and
1398 aggregate authentication statuses
1399 have equivalent meaning at this
1400 level. If the function returns
1401 anything other than EFI_SUCCESS,
1402 the value of AuthenticationStatus
1406 @retval EFI_SUCCESS The InputSection was successfully
1407 processed and the section contents were
1410 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1411 resources to process the
1414 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1415 not match this instance of the
1416 GUIDed Section Extraction
1422 CustomGuidedSectionExtract (
1423 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
1424 IN CONST VOID
*InputSection
,
1425 OUT VOID
**OutputBuffer
,
1426 OUT UINTN
*OutputSize
,
1427 OUT UINT32
*AuthenticationStatus
1431 VOID
*ScratchBuffer
;
1432 VOID
*AllocatedOutputBuffer
;
1433 UINT32 OutputBufferSize
;
1434 UINT32 ScratchBufferSize
;
1435 UINT16 SectionAttribute
;
1438 // Init local variable
1440 ScratchBuffer
= NULL
;
1441 AllocatedOutputBuffer
= NULL
;
1444 // Call GetInfo to get the size and attribute of input guided section data.
1446 Status
= ExtractGuidedSectionGetInfo (
1453 if (EFI_ERROR (Status
)) {
1454 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
1458 if (ScratchBufferSize
> 0) {
1460 // Allocate scratch buffer
1462 ScratchBuffer
= AllocatePool (ScratchBufferSize
);
1463 if (ScratchBuffer
== NULL
) {
1464 return EFI_OUT_OF_RESOURCES
;
1468 if (OutputBufferSize
> 0) {
1470 // Allocate output buffer
1472 AllocatedOutputBuffer
= AllocatePool (OutputBufferSize
);
1473 if (AllocatedOutputBuffer
== NULL
) {
1474 FreePool (ScratchBuffer
);
1475 return EFI_OUT_OF_RESOURCES
;
1477 *OutputBuffer
= AllocatedOutputBuffer
;
1481 // Call decode function to extract raw data from the guided section.
1483 Status
= ExtractGuidedSectionDecode (
1487 AuthenticationStatus
1489 if (EFI_ERROR (Status
)) {
1493 if (AllocatedOutputBuffer
!= NULL
) {
1494 CoreFreePool (AllocatedOutputBuffer
);
1496 if (ScratchBuffer
!= NULL
) {
1497 CoreFreePool (ScratchBuffer
);
1499 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
1503 if (*OutputBuffer
!= AllocatedOutputBuffer
) {
1505 // OutputBuffer was returned as a different value,
1506 // so copy section contents to the allocated memory buffer.
1508 CopyMem (AllocatedOutputBuffer
, *OutputBuffer
, OutputBufferSize
);
1509 *OutputBuffer
= AllocatedOutputBuffer
;
1513 // Set real size of output buffer.
1515 *OutputSize
= (UINTN
) OutputBufferSize
;
1518 // Free unused scratch buffer.
1520 if (ScratchBuffer
!= NULL
) {
1521 CoreFreePool (ScratchBuffer
);