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 - 2010, 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 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
;
298 Worker function. Constructor for section streams.
300 @param SectionStreamLength Size in bytes of the section stream.
301 @param SectionStream Buffer containing the new section stream.
302 @param AllocateBuffer Indicates whether the stream buffer is to be
303 copied or the input buffer is to be used in
304 place. AuthenticationStatus- Indicates the
305 default authentication status for the new
307 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
308 indicates the authentication status of the
309 output buffer. If the input section's
310 GuidedSectionHeader.Attributes field
311 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
312 bit as clear, AuthenticationStatus must return
313 zero. Both local bits (19:16) and aggregate
314 bits (3:0) in AuthenticationStatus are returned
315 by ExtractSection(). These bits reflect the
316 status of the extraction operation. The bit
317 pattern in both regions must be the same, as
318 the local and aggregate authentication statuses
319 have equivalent meaning at this level. If the
320 function returns anything other than
321 EFI_SUCCESS, the value of *AuthenticationStatus
323 @param SectionStreamHandle A pointer to a caller allocated section stream
326 @retval EFI_SUCCESS Stream was added to stream database.
327 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
331 OpenSectionStreamEx (
332 IN UINTN SectionStreamLength
,
333 IN VOID
*SectionStream
,
334 IN BOOLEAN AllocateBuffer
,
335 IN UINT32 AuthenticationStatus
,
336 OUT UINTN
*SectionStreamHandle
339 CORE_SECTION_STREAM_NODE
*NewStream
;
343 // Allocate a new stream
345 NewStream
= AllocatePool (sizeof (CORE_SECTION_STREAM_NODE
));
346 if (NewStream
== NULL
) {
347 return EFI_OUT_OF_RESOURCES
;
350 if (AllocateBuffer
) {
352 // if we're here, we're double buffering, allocate the buffer and copy the
355 if (SectionStreamLength
> 0) {
356 NewStream
->StreamBuffer
= AllocatePool (SectionStreamLength
);
357 if (NewStream
->StreamBuffer
== NULL
) {
358 CoreFreePool (NewStream
);
359 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
;
403 SEP member function. This function creates and returns a new section stream
404 handle to represent the new section stream.
406 @param SectionStreamLength Size in bytes of the section stream.
407 @param SectionStream Buffer containing the new section stream.
408 @param SectionStreamHandle A pointer to a caller allocated UINTN that on
409 output contains the new section stream handle.
411 @retval EFI_SUCCESS The section stream is created successfully.
412 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
413 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
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 (
444 Worker function. Determine if the input stream:child matches the input type.
446 @param Stream Indicates the section stream associated with the
448 @param Child Indicates the child to check
449 @param SearchType Indicates the type of section to check against
451 @param SectionDefinitionGuid Indicates the GUID to check against if the type
452 is EFI_SECTION_GUID_DEFINED
454 @retval TRUE The child matches
455 @retval FALSE The child doesn't match
460 IN CORE_SECTION_STREAM_NODE
*Stream
,
461 IN CORE_SECTION_CHILD_NODE
*Child
,
462 IN EFI_SECTION_TYPE SearchType
,
463 IN EFI_GUID
*SectionDefinitionGuid
466 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
468 if (SearchType
== EFI_SECTION_ALL
) {
471 if (Child
->Type
!= SearchType
) {
474 if ((SearchType
!= EFI_SECTION_GUID_DEFINED
) || (SectionDefinitionGuid
== NULL
)) {
477 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
478 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
482 RPN callback function. Initializes the section stream
483 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
485 @param Event The event that fired
486 @param RpnContext A pointer to the context that allows us to identify
487 the relevent encapsulation.
491 NotifyGuidedExtraction (
497 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
498 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
499 VOID
*NewStreamBuffer
;
500 UINTN NewStreamBufferSize
;
501 UINT32 AuthenticationStatus
;
502 RPN_EVENT_CONTEXT
*Context
;
504 Context
= RpnContext
;
506 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
507 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
509 Status
= gBS
->LocateProtocol (Context
->ChildNode
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
510 if (EFI_ERROR (Status
)) {
514 Status
= GuidedExtraction
->ExtractSection (
518 &NewStreamBufferSize
,
519 &AuthenticationStatus
521 ASSERT_EFI_ERROR (Status
);
524 // Make sure we initialize the new stream with the correct
525 // authentication status for both aggregate and local status fields.
527 if ((GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
529 // OR in the parent stream's aggregate status.
531 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
534 // since there's no authentication data contributed by the section,
535 // just inherit the full value from our immediate parent.
537 AuthenticationStatus
= Context
->ParentStream
->AuthenticationStatus
;
540 Status
= OpenSectionStreamEx (
544 AuthenticationStatus
,
545 &Context
->ChildNode
->EncapsulatedStreamHandle
547 ASSERT_EFI_ERROR (Status
);
550 // Close the event when done.
552 gBS
->CloseEvent (Event
);
557 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
559 @param ParentStream Indicates the parent of the ecnapsulation section (child)
560 @param ChildNode Indicates the child node that is the encapsulation section.
564 CreateGuidedExtractionRpnEvent (
565 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
566 IN CORE_SECTION_CHILD_NODE
*ChildNode
569 RPN_EVENT_CONTEXT
*Context
;
572 // Allocate new event structure and context
574 Context
= AllocatePool (sizeof (RPN_EVENT_CONTEXT
));
575 ASSERT (Context
!= NULL
);
577 Context
->ChildNode
= ChildNode
;
578 Context
->ParentStream
= ParentStream
;
580 Context
->Event
= EfiCreateProtocolNotifyEvent (
581 Context
->ChildNode
->EncapsulationGuid
,
583 NotifyGuidedExtraction
,
585 &Context
->Registration
590 Worker function. Constructor for new child nodes.
592 @param Stream Indicates the section stream in which to add the
594 @param ChildOffset Indicates the offset in Stream that is the
595 beginning of the child section.
596 @param ChildNode Indicates the Callee allocated and initialized
599 @retval EFI_SUCCESS Child node was found and returned.
600 EFI_OUT_OF_RESOURCES- Memory allocation failed.
601 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
602 handles when the child node is created. If the
603 section type is GUID defined, and the extraction
604 GUID does not exist, and producing the stream
605 requires the GUID, then a protocol error is
606 generated and no child is produced. Values
607 returned by OpenSectionStreamEx.
612 IN CORE_SECTION_STREAM_NODE
*Stream
,
613 IN UINT32 ChildOffset
,
614 OUT CORE_SECTION_CHILD_NODE
**ChildNode
618 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
619 EFI_COMPRESSION_SECTION
*CompressionHeader
;
620 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
621 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
622 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
623 VOID
*NewStreamBuffer
;
626 UINTN NewStreamBufferSize
;
627 UINT32 AuthenticationStatus
;
628 UINT32 SectionLength
;
630 CORE_SECTION_CHILD_NODE
*Node
;
632 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
635 // Allocate a new node
637 *ChildNode
= AllocatePool (sizeof (CORE_SECTION_CHILD_NODE
));
640 return EFI_OUT_OF_RESOURCES
;
646 Node
->Signature
= CORE_SECTION_CHILD_SIGNATURE
;
647 Node
->Type
= SectionHeader
->Type
;
648 Node
->Size
= SECTION_SIZE (SectionHeader
);
649 Node
->OffsetInStream
= ChildOffset
;
650 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
651 Node
->EncapsulationGuid
= NULL
;
654 // If it's an encapsulating section, then create the new section stream also
656 switch (Node
->Type
) {
657 case EFI_SECTION_COMPRESSION
:
659 // Get the CompressionSectionHeader
661 ASSERT (Node
->Size
>= sizeof (EFI_COMPRESSION_SECTION
));
663 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
666 // Allocate space for the new stream
668 if (CompressionHeader
->UncompressedLength
> 0) {
669 NewStreamBufferSize
= CompressionHeader
->UncompressedLength
;
670 NewStreamBuffer
= AllocatePool (NewStreamBufferSize
);
671 if (NewStreamBuffer
== NULL
) {
673 return EFI_OUT_OF_RESOURCES
;
676 if (CompressionHeader
->CompressionType
== EFI_NOT_COMPRESSED
) {
678 // stream is not actually compressed, just encapsulated. So just copy it.
680 CopyMem (NewStreamBuffer
, CompressionHeader
+ 1, NewStreamBufferSize
);
681 } else if (CompressionHeader
->CompressionType
== EFI_STANDARD_COMPRESSION
) {
683 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
687 // Decompress the stream
689 Status
= CoreLocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
690 ASSERT_EFI_ERROR (Status
);
691 ASSERT (Decompress
!= NULL
);
693 Status
= Decompress
->GetInfo (
695 CompressionHeader
+ 1,
696 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
697 (UINT32
*)&NewStreamBufferSize
,
700 ASSERT_EFI_ERROR (Status
);
701 ASSERT (NewStreamBufferSize
== CompressionHeader
->UncompressedLength
);
703 ScratchBuffer
= AllocatePool (ScratchSize
);
704 if (ScratchBuffer
== NULL
) {
706 CoreFreePool (NewStreamBuffer
);
707 return EFI_OUT_OF_RESOURCES
;
710 Status
= Decompress
->Decompress (
712 CompressionHeader
+ 1,
713 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
715 (UINT32
)NewStreamBufferSize
,
719 ASSERT_EFI_ERROR (Status
);
720 CoreFreePool (ScratchBuffer
);
723 NewStreamBuffer
= NULL
;
724 NewStreamBufferSize
= 0;
727 Status
= OpenSectionStreamEx (
731 Stream
->AuthenticationStatus
,
732 &Node
->EncapsulatedStreamHandle
734 if (EFI_ERROR (Status
)) {
736 CoreFreePool (NewStreamBuffer
);
741 case EFI_SECTION_GUID_DEFINED
:
742 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
743 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
744 Status
= CoreLocateProtocol (Node
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
745 if (!EFI_ERROR (Status
) && GuidedExtraction
!= NULL
) {
747 // NewStreamBuffer is always allocated by ExtractSection... No caller
750 Status
= GuidedExtraction
->ExtractSection (
754 &NewStreamBufferSize
,
755 &AuthenticationStatus
757 if (EFI_ERROR (Status
)) {
758 CoreFreePool (*ChildNode
);
759 return EFI_PROTOCOL_ERROR
;
763 // Make sure we initialize the new stream with the correct
764 // authentication status for both aggregate and local status fields.
766 if ((GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) != 0) {
768 // OR in the parent stream's aggregate status.
770 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
773 // since there's no authentication data contributed by the section,
774 // just inherit the full value from our immediate parent.
776 AuthenticationStatus
= Stream
->AuthenticationStatus
;
779 Status
= OpenSectionStreamEx (
783 AuthenticationStatus
,
784 &Node
->EncapsulatedStreamHandle
786 if (EFI_ERROR (Status
)) {
787 CoreFreePool (*ChildNode
);
788 CoreFreePool (NewStreamBuffer
);
793 // There's no GUIDed section extraction protocol available.
795 if ((GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) {
797 // If the section REQUIRES an extraction protocol, register for RPN
798 // when the required GUIDed extraction protocol becomes available.
800 CreateGuidedExtractionRpnEvent (Stream
, Node
);
803 // Figure out the proper authentication status
805 AuthenticationStatus
= Stream
->AuthenticationStatus
;
807 SectionLength
= SECTION_SIZE (GuidedHeader
);
808 Status
= OpenSectionStreamEx (
809 SectionLength
- GuidedHeader
->DataOffset
,
810 (UINT8
*) GuidedHeader
+ GuidedHeader
->DataOffset
,
812 AuthenticationStatus
,
813 &Node
->EncapsulatedStreamHandle
815 if (EFI_ERROR (Status
)) {
827 // Nothing to do if it's a leaf
833 // Last, add the new child node to the stream
835 InsertTailList (&Stream
->Children
, &Node
->Link
);
842 Worker function Recursively searches / builds section stream database
843 looking for requested section.
845 @param SourceStream Indicates the section stream in which to do the
847 @param SearchType Indicates the type of section to search for.
848 @param SectionInstance Indicates which instance of section to find.
849 This is an in/out parameter to deal with
851 @param SectionDefinitionGuid Guid of section definition
852 @param FoundChild Output indicating the child node that is found.
853 @param FoundStream Output indicating which section stream the child
854 was found in. If this stream was generated as a
855 result of an encapsulation section, the
856 streamhandle is visible within the SEP driver
858 @param AuthenticationStatus Indicates the authentication status of the found section.
860 @retval EFI_SUCCESS Child node was found and returned.
861 EFI_OUT_OF_RESOURCES- Memory allocation failed.
862 @retval EFI_NOT_FOUND Requested child node does not exist.
863 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
869 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
870 IN EFI_SECTION_TYPE SearchType
,
871 IN OUT UINTN
*SectionInstance
,
872 IN EFI_GUID
*SectionDefinitionGuid
,
873 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
874 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
875 OUT UINT32
*AuthenticationStatus
878 CORE_SECTION_CHILD_NODE
*CurrentChildNode
;
879 CORE_SECTION_CHILD_NODE
*RecursedChildNode
;
880 CORE_SECTION_STREAM_NODE
*RecursedFoundStream
;
881 UINT32 NextChildOffset
;
882 EFI_STATUS ErrorStatus
;
885 CurrentChildNode
= NULL
;
886 ErrorStatus
= EFI_NOT_FOUND
;
888 if (SourceStream
->StreamLength
== 0) {
889 return EFI_NOT_FOUND
;
892 if (IsListEmpty (&SourceStream
->Children
) &&
893 SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)) {
895 // This occurs when a section stream exists, but no child sections
896 // have been parsed out yet. Therefore, extract the first child and add it
897 // to the list of children so we can get started.
898 // Section stream may contain an array of zero or more bytes.
899 // So, its size should be >= the size of commen section header.
901 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
902 if (EFI_ERROR (Status
)) {
908 // At least one child has been parsed out of the section stream. So, walk
909 // through the sections that have already been parsed out looking for the
910 // requested section, if necessary, continue parsing section stream and
911 // adding children until either the requested section is found, or we run
914 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
917 ASSERT (CurrentChildNode
!= NULL
);
918 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
920 // The type matches, so check the instance count to see if it's the one we want
922 (*SectionInstance
)--;
923 if (*SectionInstance
== 0) {
927 *FoundChild
= CurrentChildNode
;
928 *FoundStream
= SourceStream
;
929 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
934 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
936 // If the current node is an encapsulating node, recurse into it...
938 Status
= FindChildNode (
939 (CORE_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
942 SectionDefinitionGuid
,
944 &RecursedFoundStream
,
948 // If the status is not EFI_SUCCESS, just save the error code and continue
949 // to find the request child node in the rest stream.
951 if (*SectionInstance
== 0) {
952 ASSERT_EFI_ERROR (Status
);
953 *FoundChild
= RecursedChildNode
;
954 *FoundStream
= RecursedFoundStream
;
957 ErrorStatus
= Status
;
959 } else if ((CurrentChildNode
->Type
== EFI_SECTION_GUID_DEFINED
) && (SearchType
!= EFI_SECTION_GUID_DEFINED
)) {
961 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
962 // because a required GUIDED section extraction protocol does not exist.
963 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
965 ErrorStatus
= EFI_PROTOCOL_ERROR
;
968 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
970 // We haven't found the child node we're interested in yet, but there's
971 // still more nodes that have already been parsed so get the next one
972 // and continue searching..
974 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
977 // We've exhausted children that have already been parsed, so see if
978 // there's any more data and continue parsing out more children if there
981 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
983 // Round up to 4 byte boundary
985 NextChildOffset
+= 3;
986 NextChildOffset
&= ~(UINTN
) 3;
987 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
989 // There's an unparsed child remaining in the stream, so create a new child node
991 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
992 if (EFI_ERROR (Status
)) {
996 ASSERT (EFI_ERROR (ErrorStatus
));
1005 Worker function. Search stream database for requested stream handle.
1007 @param SearchHandle Indicates which stream to look for.
1008 @param FoundStream Output pointer to the found stream.
1010 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1012 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1018 IN UINTN SearchHandle
,
1019 OUT CORE_SECTION_STREAM_NODE
**FoundStream
1022 CORE_SECTION_STREAM_NODE
*StreamNode
;
1024 if (!IsListEmpty (&mStreamRoot
)) {
1025 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1027 if (StreamNode
->StreamHandle
== SearchHandle
) {
1028 *FoundStream
= StreamNode
;
1030 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1033 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1038 return EFI_NOT_FOUND
;
1043 SEP member function. Retrieves requested section from section stream.
1045 @param SectionStreamHandle The section stream from which to extract the
1047 @param SectionType A pointer to the type of section to search for.
1048 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1049 then SectionDefinitionGuid indicates which of
1050 these types of sections to search for.
1051 @param SectionInstance Indicates which instance of the requested
1053 @param Buffer Double indirection to buffer. If *Buffer is
1054 non-null on input, then the buffer is caller
1055 allocated. If Buffer is NULL, then the buffer
1056 is callee allocated. In either case, the
1057 requried buffer size is returned in *BufferSize.
1058 @param BufferSize On input, indicates the size of *Buffer if
1059 *Buffer is non-null on input. On output,
1060 indicates the required size (allocated size if
1061 callee allocated) of *Buffer.
1062 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1063 indicates the authentication status of the
1064 output buffer. If the input section's
1065 GuidedSectionHeader.Attributes field
1066 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1067 bit as clear, AuthenticationStatus must return
1068 zero. Both local bits (19:16) and aggregate
1069 bits (3:0) in AuthenticationStatus are returned
1070 by ExtractSection(). These bits reflect the
1071 status of the extraction operation. The bit
1072 pattern in both regions must be the same, as
1073 the local and aggregate authentication statuses
1074 have equivalent meaning at this level. If the
1075 function returns anything other than
1076 EFI_SUCCESS, the value of *AuthenticationStatus
1079 @retval EFI_SUCCESS Section was retrieved successfully
1080 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1081 section stream with its
1082 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1083 but there was no corresponding GUIDed Section
1084 Extraction Protocol in the handle database.
1085 *Buffer is unmodified.
1086 @retval EFI_NOT_FOUND An error was encountered when parsing the
1087 SectionStream. This indicates the SectionStream
1088 is not correctly formatted.
1089 @retval EFI_NOT_FOUND The requested section does not exist.
1090 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1092 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1093 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1094 insufficient to contain the requested section.
1095 The input buffer is filled and section contents
1102 IN UINTN SectionStreamHandle
,
1103 IN EFI_SECTION_TYPE
*SectionType
,
1104 IN EFI_GUID
*SectionDefinitionGuid
,
1105 IN UINTN SectionInstance
,
1107 IN OUT UINTN
*BufferSize
,
1108 OUT UINT32
*AuthenticationStatus
1111 CORE_SECTION_STREAM_NODE
*StreamNode
;
1114 CORE_SECTION_CHILD_NODE
*ChildNode
;
1115 CORE_SECTION_STREAM_NODE
*ChildStreamNode
;
1117 UINT32 ExtractedAuthenticationStatus
;
1123 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1124 Instance
= SectionInstance
+ 1;
1127 // Locate target stream
1129 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
1130 if (EFI_ERROR (Status
)) {
1131 Status
= EFI_INVALID_PARAMETER
;
1132 goto GetSection_Done
;
1136 // Found the stream, now locate and return the appropriate section
1138 if (SectionType
== NULL
) {
1140 // SectionType == NULL means return the WHOLE section stream...
1142 CopySize
= StreamNode
->StreamLength
;
1143 CopyBuffer
= StreamNode
->StreamBuffer
;
1144 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
1147 // There's a requested section type, so go find it and return it...
1149 Status
= FindChildNode (
1153 SectionDefinitionGuid
,
1156 &ExtractedAuthenticationStatus
1158 if (EFI_ERROR (Status
)) {
1159 goto GetSection_Done
;
1161 CopySize
= ChildNode
->Size
- sizeof (EFI_COMMON_SECTION_HEADER
);
1162 CopyBuffer
= ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
+ sizeof (EFI_COMMON_SECTION_HEADER
);
1163 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
1166 SectionSize
= CopySize
;
1167 if (*Buffer
!= NULL
) {
1169 // Caller allocated buffer. Fill to size and return required size...
1171 if (*BufferSize
< CopySize
) {
1172 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
1173 CopySize
= *BufferSize
;
1177 // Callee allocated buffer. Allocate buffer and return size.
1179 *Buffer
= AllocatePool (CopySize
);
1180 if (*Buffer
== NULL
) {
1181 Status
= EFI_OUT_OF_RESOURCES
;
1182 goto GetSection_Done
;
1185 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
1186 *BufferSize
= SectionSize
;
1189 CoreRestoreTpl (OldTpl
);
1196 Worker function. Destructor for child nodes.
1198 @param ChildNode Indicates the node to destroy
1203 IN CORE_SECTION_CHILD_NODE
*ChildNode
1206 ASSERT (ChildNode
->Signature
== CORE_SECTION_CHILD_SIGNATURE
);
1208 // Remove the child from it's list
1210 RemoveEntryList (&ChildNode
->Link
);
1212 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1214 // If it's an encapsulating section, we close the resulting section stream.
1215 // CloseSectionStream will free all memory associated with the stream.
1217 CloseSectionStream (ChildNode
->EncapsulatedStreamHandle
);
1220 // Last, free the child node itself
1222 CoreFreePool (ChildNode
);
1227 SEP member function. Deletes an existing section stream
1229 @param StreamHandleToClose Indicates the stream to close
1231 @retval EFI_SUCCESS The section stream is closed sucessfully.
1232 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1233 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1239 CloseSectionStream (
1240 IN UINTN StreamHandleToClose
1243 CORE_SECTION_STREAM_NODE
*StreamNode
;
1247 CORE_SECTION_CHILD_NODE
*ChildNode
;
1249 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1252 // Locate target stream
1254 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
1255 if (!EFI_ERROR (Status
)) {
1257 // Found the stream, so close it
1259 RemoveEntryList (&StreamNode
->Link
);
1260 while (!IsListEmpty (&StreamNode
->Children
)) {
1261 Link
= GetFirstNode (&StreamNode
->Children
);
1262 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
1263 FreeChildNode (ChildNode
);
1265 CoreFreePool (StreamNode
->StreamBuffer
);
1266 CoreFreePool (StreamNode
);
1267 Status
= EFI_SUCCESS
;
1269 Status
= EFI_INVALID_PARAMETER
;
1272 CoreRestoreTpl (OldTpl
);
1278 The ExtractSection() function processes the input section and
1279 allocates a buffer from the pool in which it returns the section
1280 contents. If the section being extracted contains
1281 authentication information (the section's
1282 GuidedSectionHeader.Attributes field has the
1283 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1284 returned in AuthenticationStatus must reflect the results of
1285 the authentication operation. Depending on the algorithm and
1286 size of the encapsulated data, the time that is required to do
1287 a full authentication may be prohibitively long for some
1288 classes of systems. To indicate this, use
1289 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1290 the security policy driver (see the Platform Initialization
1291 Driver Execution Environment Core Interface Specification for
1292 more details and the GUID definition). If the
1293 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1294 database, then, if possible, full authentication should be
1295 skipped and the section contents simply returned in the
1296 OutputBuffer. In this case, the
1297 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1298 must be set on return. ExtractSection() is callable only from
1299 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1300 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1301 defined in RaiseTPL() in the UEFI 2.0 specification.
1304 @param This Indicates the
1305 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1306 @param InputSection Buffer containing the input GUIDed section
1307 to be processed. OutputBuffer OutputBuffer
1308 is allocated from boot services pool
1309 memory and contains the new section
1310 stream. The caller is responsible for
1311 freeing this buffer.
1312 @param OutputBuffer *OutputBuffer is allocated from boot services
1313 pool memory and contains the new section stream.
1314 The caller is responsible for freeing this buffer.
1315 @param OutputSize A pointer to a caller-allocated UINTN in
1316 which the size of OutputBuffer allocation
1317 is stored. If the function returns
1318 anything other than EFI_SUCCESS, the value
1319 of OutputSize is undefined.
1321 @param AuthenticationStatus A pointer to a caller-allocated
1322 UINT32 that indicates the
1323 authentication status of the
1324 output buffer. If the input
1326 GuidedSectionHeader.Attributes
1328 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1329 bit as clear, AuthenticationStatus
1330 must return zero. Both local bits
1331 (19:16) and aggregate bits (3:0)
1332 in AuthenticationStatus are
1333 returned by ExtractSection().
1334 These bits reflect the status of
1335 the extraction operation. The bit
1336 pattern in both regions must be
1337 the same, as the local and
1338 aggregate authentication statuses
1339 have equivalent meaning at this
1340 level. If the function returns
1341 anything other than EFI_SUCCESS,
1342 the value of AuthenticationStatus
1346 @retval EFI_SUCCESS The InputSection was successfully
1347 processed and the section contents were
1350 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1351 resources to process the
1354 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1355 not match this instance of the
1356 GUIDed Section Extraction
1362 CustomGuidedSectionExtract (
1363 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
1364 IN CONST VOID
*InputSection
,
1365 OUT VOID
**OutputBuffer
,
1366 OUT UINTN
*OutputSize
,
1367 OUT UINT32
*AuthenticationStatus
1371 VOID
*ScratchBuffer
;
1372 VOID
*AllocatedOutputBuffer
;
1373 UINT32 OutputBufferSize
;
1374 UINT32 ScratchBufferSize
;
1375 UINT16 SectionAttribute
;
1378 // Init local variable
1380 ScratchBuffer
= NULL
;
1381 AllocatedOutputBuffer
= NULL
;
1384 // Call GetInfo to get the size and attribute of input guided section data.
1386 Status
= ExtractGuidedSectionGetInfo (
1393 if (EFI_ERROR (Status
)) {
1394 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
1398 if (ScratchBufferSize
> 0) {
1400 // Allocate scratch buffer
1402 ScratchBuffer
= AllocatePool (ScratchBufferSize
);
1403 if (ScratchBuffer
== NULL
) {
1404 return EFI_OUT_OF_RESOURCES
;
1408 if (OutputBufferSize
> 0) {
1410 // Allocate output buffer
1412 AllocatedOutputBuffer
= AllocatePool (OutputBufferSize
);
1413 if (AllocatedOutputBuffer
== NULL
) {
1414 FreePool (ScratchBuffer
);
1415 return EFI_OUT_OF_RESOURCES
;
1417 *OutputBuffer
= AllocatedOutputBuffer
;
1421 // Call decode function to extract raw data from the guided section.
1423 Status
= ExtractGuidedSectionDecode (
1427 AuthenticationStatus
1429 if (EFI_ERROR (Status
)) {
1433 if (AllocatedOutputBuffer
!= NULL
) {
1434 CoreFreePool (AllocatedOutputBuffer
);
1436 if (ScratchBuffer
!= NULL
) {
1437 CoreFreePool (ScratchBuffer
);
1439 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
1443 if (*OutputBuffer
!= AllocatedOutputBuffer
) {
1445 // OutputBuffer was returned as a different value,
1446 // so copy section contents to the allocated memory buffer.
1448 CopyMem (AllocatedOutputBuffer
, *OutputBuffer
, OutputBufferSize
);
1449 *OutputBuffer
= AllocatedOutputBuffer
;
1453 // Set real size of output buffer.
1455 *OutputSize
= (UINTN
) OutputBufferSize
;
1458 // Free unused scratch buffer.
1460 if (ScratchBuffer
!= NULL
) {
1461 CoreFreePool (ScratchBuffer
);