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 - 2007, Intel Corporation
31 All rights reserved. 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 EFI_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 EFI_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
;
106 IN CORE_SECTION_STREAM_NODE
*Stream
,
107 IN CORE_SECTION_CHILD_NODE
*Child
,
108 IN EFI_SECTION_TYPE SearchType
,
109 IN EFI_GUID
*SectionDefinitionGuid
116 NotifyGuidedExtraction (
125 CreateGuidedExtractionRpnEvent (
126 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
127 IN CORE_SECTION_CHILD_NODE
*ChildNode
134 IN UINTN SearchHandle
,
135 OUT CORE_SECTION_STREAM_NODE
**FoundStream
141 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
142 IN EFI_SECTION_TYPE SearchType
,
143 IN UINTN
*SectionInstance
,
144 IN EFI_GUID
*SectionDefinitionGuid
,
145 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
146 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
147 OUT UINT32
*AuthenticationStatus
153 IN CORE_SECTION_STREAM_NODE
*Stream
,
154 IN UINT32 ChildOffset
,
155 OUT CORE_SECTION_CHILD_NODE
**ChildNode
161 IN CORE_SECTION_CHILD_NODE
*ChildNode
166 OpenSectionStreamEx (
167 IN UINTN SectionStreamLength
,
168 IN VOID
*SectionStream
,
169 IN BOOLEAN AllocateBuffer
,
170 IN UINT32 AuthenticationStatus
,
171 OUT UINTN
*SectionStreamHandle
176 IsValidSectionStream (
177 IN VOID
*SectionStream
,
178 IN UINTN SectionStreamLength
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
193 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
195 EFI_HANDLE mSectionExtractionHandle
= NULL
;
197 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol
= {
198 CustomGuidedSectionExtract
203 InitializeSectionExtraction (
204 IN EFI_HANDLE ImageHandle
,
205 IN EFI_SYSTEM_TABLE
*SystemTable
210 Entry point of the section extraction code. Initializes an instance of the
211 section extraction interface and installs it on a new handle.
214 ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver
215 SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
218 EFI_SUCCESS: Driver initialized successfully
219 EFI_OUT_OF_RESOURCES: Could not allocate needed resources
224 EFI_GUID
*ExtractHandlerGuidTable
;
225 UINTN ExtractHandlerNumber
;
228 // Get custom extract guided section method guid list
230 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
232 Status
= EFI_SUCCESS
;
234 // Install custom guided extraction protocol
236 while (ExtractHandlerNumber
-- > 0) {
237 Status
= CoreInstallProtocolInterface (
238 &mSectionExtractionHandle
,
239 &ExtractHandlerGuidTable
[ExtractHandlerNumber
],
240 EFI_NATIVE_INTERFACE
,
241 &mCustomGuidedSectionExtractionProtocol
243 ASSERT_EFI_ERROR (Status
);
252 IN UINTN SectionStreamLength
,
253 IN VOID
*SectionStream
,
254 OUT UINTN
*SectionStreamHandle
259 SEP member function. This function creates and returns a new section stream
260 handle to represent the new section stream.
263 This - Indicates the calling context.
264 SectionStreamLength - Size in bytes of the section stream.
265 SectionStream - Buffer containing the new section stream.
266 SectionStreamHandle - A pointer to a caller allocated UINTN that on output
267 contains the new section stream handle.
271 EFI_OUT_OF_RESOURCES - memory allocation failed.
272 EFI_INVALID_PARAMETER - section stream does not end concident with end of
278 // Check to see section stream looks good...
280 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
281 return EFI_INVALID_PARAMETER
;
284 return OpenSectionStreamEx (
296 IN UINTN SectionStreamHandle
,
297 IN EFI_SECTION_TYPE
*SectionType
,
298 IN EFI_GUID
*SectionDefinitionGuid
,
299 IN UINTN SectionInstance
,
301 IN OUT UINTN
*BufferSize
,
302 OUT UINT32
*AuthenticationStatus
307 SEP member function. Retrieves requested section from section stream.
310 SectionStreamHandle: The section stream from which to extract the requested
312 SectionType: A pointer to the type of section to search for.
313 SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then
314 SectionDefinitionGuid indicates which of these types
315 of sections to search for.
316 SectionInstance: Indicates which instance of the requested section to
318 Buffer: Double indirection to buffer. If *Buffer is non-null on
319 input, then the buffer is caller allocated. If
320 *Buffer is NULL, then the buffer is callee allocated.
321 In either case, the requried buffer size is returned
323 BufferSize: On input, indicates the size of *Buffer if *Buffer is
324 non-null on input. On output, indicates the required
325 size (allocated size if callee allocated) of *Buffer.
326 AuthenticationStatus: Indicates the authentication status of the retrieved
330 EFI_SUCCESS: Section was retrieved successfully
331 EFI_PROTOCOL_ERROR: A GUID defined section was encountered in the section
332 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
333 bit set, but there was no corresponding GUIDed Section
334 Extraction Protocol in the handle database. *Buffer is
336 EFI_NOT_FOUND: An error was encountered when parsing the SectionStream.
337 This indicates the SectionStream is not correctly
339 EFI_NOT_FOUND: The requested section does not exist.
340 EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the
342 EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist.
343 EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is
344 insufficient to contain the requested section. The
345 input buffer is filled and contents are section contents
350 CORE_SECTION_STREAM_NODE
*StreamNode
;
353 CORE_SECTION_CHILD_NODE
*ChildNode
;
354 CORE_SECTION_STREAM_NODE
*ChildStreamNode
;
356 UINT32 ExtractedAuthenticationStatus
;
362 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
363 Instance
= SectionInstance
+ 1;
366 // Locate target stream
368 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
369 if (EFI_ERROR (Status
)) {
370 Status
= EFI_INVALID_PARAMETER
;
371 goto GetSection_Done
;
375 // Found the stream, now locate and return the appropriate section
377 if (SectionType
== NULL
) {
379 // SectionType == NULL means return the WHOLE section stream...
381 CopySize
= StreamNode
->StreamLength
;
382 CopyBuffer
= StreamNode
->StreamBuffer
;
383 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
386 // There's a requested section type, so go find it and return it...
388 Status
= FindChildNode (
392 SectionDefinitionGuid
,
395 &ExtractedAuthenticationStatus
397 if (EFI_ERROR (Status
)) {
398 goto GetSection_Done
;
400 CopySize
= ChildNode
->Size
- sizeof (EFI_COMMON_SECTION_HEADER
);
401 CopyBuffer
= ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
+ sizeof (EFI_COMMON_SECTION_HEADER
);
402 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
405 SectionSize
= CopySize
;
406 if (*Buffer
!= NULL
) {
408 // Caller allocated buffer. Fill to size and return required size...
410 if (*BufferSize
< CopySize
) {
411 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
412 CopySize
= *BufferSize
;
416 // Callee allocated buffer. Allocate buffer and return size.
418 *Buffer
= CoreAllocateBootServicesPool (CopySize
);
419 if (*Buffer
== NULL
) {
420 Status
= EFI_OUT_OF_RESOURCES
;
421 goto GetSection_Done
;
424 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
425 *BufferSize
= SectionSize
;
428 CoreRestoreTpl (OldTpl
);
436 IN UINTN StreamHandleToClose
441 SEP member function. Deletes an existing section stream
444 This - Indicates the calling context.
445 StreamHandleToClose - Indicates the stream to close
449 EFI_OUT_OF_RESOURCES - memory allocation failed.
450 EFI_INVALID_PARAMETER - section stream does not end concident with end of
455 CORE_SECTION_STREAM_NODE
*StreamNode
;
459 CORE_SECTION_CHILD_NODE
*ChildNode
;
461 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
464 // Locate target stream
466 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
467 if (!EFI_ERROR (Status
)) {
469 // Found the stream, so close it
471 RemoveEntryList (&StreamNode
->Link
);
472 while (!IsListEmpty (&StreamNode
->Children
)) {
473 Link
= GetFirstNode (&StreamNode
->Children
);
474 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
475 FreeChildNode (ChildNode
);
477 CoreFreePool (StreamNode
->StreamBuffer
);
478 CoreFreePool (StreamNode
);
479 Status
= EFI_SUCCESS
;
481 Status
= EFI_INVALID_PARAMETER
;
484 CoreRestoreTpl (OldTpl
);
492 IN CORE_SECTION_STREAM_NODE
*Stream
,
493 IN CORE_SECTION_CHILD_NODE
*Child
,
494 IN EFI_SECTION_TYPE SearchType
,
495 IN EFI_GUID
*SectionDefinitionGuid
500 Worker function. Determine if the input stream:child matches the input type.
503 Stream - Indicates the section stream associated with the child
504 Child - Indicates the child to check
505 SearchType - Indicates the type of section to check against for
506 SectionDefinitionGuid - Indicates the GUID to check against if the type is
507 EFI_SECTION_GUID_DEFINED
509 TRUE - The child matches
510 FALSE - The child doesn't match
514 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
516 if (SearchType
== EFI_SECTION_ALL
) {
519 if (Child
->Type
!= SearchType
) {
522 if (SearchType
!= EFI_SECTION_GUID_DEFINED
) {
525 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
526 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
533 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
534 IN EFI_SECTION_TYPE SearchType
,
535 IN OUT UINTN
*SectionInstance
,
536 IN EFI_GUID
*SectionDefinitionGuid
,
537 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
538 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
539 OUT UINT32
*AuthenticationStatus
544 Worker function Recursively searches / builds section stream database
545 looking for requested section.
548 SourceStream - Indicates the section stream in which to do the search.
549 SearchType - Indicates the type of section to search for.
550 SectionInstance - Indicates which instance of section to find. This is
551 an in/out parameter to deal with recursions.
552 SectionDefinitionGuid - Guid of section definition
553 FoundChild - Output indicating the child node that is found.
554 FoundStream - Output indicating which section stream the child was
555 found in. If this stream was generated as a result of
556 an encapsulation section, the streamhandle is visible
557 within the SEP driver only.
558 AuthenticationStatus- Indicates the authentication status of the found section.
561 EFI_SUCCESS - Child node was found and returned.
562 EFI_OUT_OF_RESOURCES- Memory allocation failed.
563 EFI_NOT_FOUND - Requested child node does not exist.
564 EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not
569 CORE_SECTION_CHILD_NODE
*CurrentChildNode
;
570 CORE_SECTION_CHILD_NODE
*RecursedChildNode
;
571 CORE_SECTION_STREAM_NODE
*RecursedFoundStream
;
572 UINT32 NextChildOffset
;
573 EFI_STATUS ErrorStatus
;
576 CurrentChildNode
= NULL
;
577 ErrorStatus
= EFI_NOT_FOUND
;
579 if (SourceStream
->StreamLength
== 0) {
580 return EFI_NOT_FOUND
;
583 if (IsListEmpty (&SourceStream
->Children
) &&
584 SourceStream
->StreamLength
>= sizeof (EFI_COMMON_SECTION_HEADER
)) {
586 // This occurs when a section stream exists, but no child sections
587 // have been parsed out yet. Therefore, extract the first child and add it
588 // to the list of children so we can get started.
589 // Section stream may contain an array of zero or more bytes.
590 // So, its size should be >= the size of commen section header.
592 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
593 if (EFI_ERROR (Status
)) {
599 // At least one child has been parsed out of the section stream. So, walk
600 // through the sections that have already been parsed out looking for the
601 // requested section, if necessary, continue parsing section stream and
602 // adding children until either the requested section is found, or we run
605 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
608 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
610 // The type matches, so check the instance count to see if it's the one we want
612 (*SectionInstance
)--;
613 if (*SectionInstance
== 0) {
617 *FoundChild
= CurrentChildNode
;
618 *FoundStream
= SourceStream
;
619 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
624 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
626 // If the current node is an encapsulating node, recurse into it...
628 Status
= FindChildNode (
629 (CORE_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
632 SectionDefinitionGuid
,
634 &RecursedFoundStream
,
638 // If the status is not EFI_SUCCESS, just save the error code and continue
639 // to find the request child node in the rest stream.
641 if (*SectionInstance
== 0) {
642 ASSERT_EFI_ERROR (Status
);
643 *FoundChild
= RecursedChildNode
;
644 *FoundStream
= RecursedFoundStream
;
647 ErrorStatus
= Status
;
651 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
653 // We haven't found the child node we're interested in yet, but there's
654 // still more nodes that have already been parsed so get the next one
655 // and continue searching..
657 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
660 // We've exhausted children that have already been parsed, so see if
661 // there's any more data and continue parsing out more children if there
664 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
666 // Round up to 4 byte boundary
668 NextChildOffset
+= 3;
669 NextChildOffset
&= ~(UINTN
)3;
670 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
672 // There's an unparsed child remaining in the stream, so create a new child node
674 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
675 if (EFI_ERROR (Status
)) {
679 ASSERT (EFI_ERROR (ErrorStatus
));
690 IN CORE_SECTION_STREAM_NODE
*Stream
,
691 IN UINT32 ChildOffset
,
692 OUT CORE_SECTION_CHILD_NODE
**ChildNode
697 Worker function. Constructor for new child nodes.
700 Stream - Indicates the section stream in which to add the child.
701 ChildOffset - Indicates the offset in Stream that is the beginning
702 of the child section.
703 ChildNode - Indicates the Callee allocated and initialized child.
706 EFI_SUCCESS - Child node was found and returned.
707 EFI_OUT_OF_RESOURCES- Memory allocation failed.
708 EFI_PROTOCOL_ERROR - Encapsulation sections produce new stream handles when
709 the child node is created. If the section type is GUID
710 defined, and the extraction GUID does not exist, and
711 producing the stream requires the GUID, then a protocol
712 error is generated and no child is produced.
713 Values returned by OpenSectionStreamEx.
718 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
719 EFI_COMPRESSION_SECTION
*CompressionHeader
;
720 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
721 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
722 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
723 VOID
*NewStreamBuffer
;
726 UINTN NewStreamBufferSize
;
727 UINT32 AuthenticationStatus
;
728 UINT32 SectionLength
;
730 CORE_SECTION_CHILD_NODE
*Node
;
732 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
735 // Allocate a new node
737 *ChildNode
= CoreAllocateBootServicesPool (sizeof (CORE_SECTION_CHILD_NODE
));
740 return EFI_OUT_OF_RESOURCES
;
746 Node
->Signature
= CORE_SECTION_CHILD_SIGNATURE
;
747 Node
->Type
= SectionHeader
->Type
;
748 Node
->Size
= SECTION_SIZE (SectionHeader
);
749 Node
->OffsetInStream
= ChildOffset
;
750 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
751 Node
->EncapsulationGuid
= NULL
;
754 // If it's an encapsulating section, then create the new section stream also
756 switch (Node
->Type
) {
757 case EFI_SECTION_COMPRESSION
:
759 // Get the CompressionSectionHeader
761 ASSERT (Node
->Size
>= sizeof (EFI_COMPRESSION_SECTION
));
763 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
766 // Allocate space for the new stream
768 if (CompressionHeader
->UncompressedLength
> 0) {
769 NewStreamBufferSize
= CompressionHeader
->UncompressedLength
;
770 NewStreamBuffer
= CoreAllocateBootServicesPool (NewStreamBufferSize
);
771 if (NewStreamBuffer
== NULL
) {
773 return EFI_OUT_OF_RESOURCES
;
776 if (CompressionHeader
->CompressionType
== EFI_NOT_COMPRESSED
) {
778 // stream is not actually compressed, just encapsulated. So just copy it.
780 CopyMem (NewStreamBuffer
, CompressionHeader
+ 1, NewStreamBufferSize
);
781 } else if (CompressionHeader
->CompressionType
== EFI_STANDARD_COMPRESSION
) {
783 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
787 // Decompress the stream
789 Status
= CoreLocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
791 ASSERT_EFI_ERROR (Status
);
793 Status
= Decompress
->GetInfo (
795 CompressionHeader
+ 1,
796 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
797 (UINT32
*)&NewStreamBufferSize
,
800 ASSERT_EFI_ERROR (Status
);
801 ASSERT (NewStreamBufferSize
== CompressionHeader
->UncompressedLength
);
803 ScratchBuffer
= CoreAllocateBootServicesPool (ScratchSize
);
804 if (ScratchBuffer
== NULL
) {
806 CoreFreePool (NewStreamBuffer
);
807 return EFI_OUT_OF_RESOURCES
;
810 Status
= Decompress
->Decompress (
812 CompressionHeader
+ 1,
813 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
815 (UINT32
)NewStreamBufferSize
,
819 ASSERT_EFI_ERROR (Status
);
820 CoreFreePool (ScratchBuffer
);
823 NewStreamBuffer
= NULL
;
824 NewStreamBufferSize
= 0;
827 Status
= OpenSectionStreamEx (
831 Stream
->AuthenticationStatus
,
832 &Node
->EncapsulatedStreamHandle
834 if (EFI_ERROR (Status
)) {
836 CoreFreePool (NewStreamBuffer
);
841 case EFI_SECTION_GUID_DEFINED
:
842 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
843 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
844 Status
= CoreLocateProtocol (Node
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
845 if (!EFI_ERROR (Status
)) {
847 // NewStreamBuffer is always allocated by ExtractSection... No caller
850 Status
= GuidedExtraction
->ExtractSection (
854 &NewStreamBufferSize
,
855 &AuthenticationStatus
857 if (EFI_ERROR (Status
)) {
858 CoreFreePool (*ChildNode
);
859 return EFI_PROTOCOL_ERROR
;
863 // Make sure we initialize the new stream with the correct
864 // authentication status for both aggregate and local status fields.
866 if (GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
868 // OR in the parent stream's aggregate status.
870 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
873 // since there's no authentication data contributed by the section,
874 // just inherit the full value from our immediate parent.
876 AuthenticationStatus
= Stream
->AuthenticationStatus
;
879 Status
= OpenSectionStreamEx (
883 AuthenticationStatus
,
884 &Node
->EncapsulatedStreamHandle
886 if (EFI_ERROR (Status
)) {
887 CoreFreePool (*ChildNode
);
888 CoreFreePool (NewStreamBuffer
);
893 // There's no GUIDed section extraction protocol available.
895 if (GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) {
897 // If the section REQUIRES an extraction protocol, then we're toast
899 CoreFreePool (*ChildNode
);
900 return EFI_PROTOCOL_ERROR
;
904 // Figure out the proper authentication status
906 AuthenticationStatus
= Stream
->AuthenticationStatus
;
908 SectionLength
= SECTION_SIZE (GuidedHeader
);
909 Status
= OpenSectionStreamEx (
910 SectionLength
- GuidedHeader
->DataOffset
,
911 (UINT8
*) GuidedHeader
+ GuidedHeader
->DataOffset
,
913 AuthenticationStatus
,
914 &Node
->EncapsulatedStreamHandle
916 if (EFI_ERROR (Status
)) {
927 // Nothing to do if it's a leaf
933 // Last, add the new child node to the stream
935 InsertTailList (&Stream
->Children
, &Node
->Link
);
944 CreateGuidedExtractionRpnEvent (
945 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
946 IN CORE_SECTION_CHILD_NODE
*ChildNode
951 Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
952 cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
955 ParentStream - Indicates the parent of the ecnapsulation section (child)
956 ChildNode - Indicates the child node that is the encapsulation section.
963 RPN_EVENT_CONTEXT
*Context
;
966 // Allocate new event structure and context
968 Context
= CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT
));
969 ASSERT (Context
!= NULL
);
971 Context
->ChildNode
= ChildNode
;
972 Context
->ParentStream
= ParentStream
;
974 Context
->Event
= CoreCreateProtocolNotifyEvent (
975 Context
->ChildNode
->EncapsulationGuid
,
977 NotifyGuidedExtraction
,
979 &Context
->Registration
,
990 NotifyGuidedExtraction (
997 RPN callback function. Removes a stale section stream and re-initializes it
998 with an updated AuthenticationStatus.
1001 Event - The event that fired
1002 RpnContext - A pointer to the context that allows us to identify
1003 the relevent encapsulation...
1011 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
1012 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
1013 VOID
*NewStreamBuffer
;
1014 UINTN NewStreamBufferSize
;
1015 UINT32 AuthenticationStatus
;
1016 RPN_EVENT_CONTEXT
*Context
;
1018 Context
= RpnContext
;
1020 Status
= CloseSectionStream (Context
->ChildNode
->EncapsulatedStreamHandle
);
1021 if (!EFI_ERROR (Status
)) {
1023 // The stream closed successfully, so re-open the stream with correct AuthenticationStatus
1026 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)
1027 (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
1028 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
1030 Status
= CoreLocateProtocol (Context
->ChildNode
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
1031 ASSERT_EFI_ERROR (Status
);
1034 Status
= GuidedExtraction
->ExtractSection (
1038 &NewStreamBufferSize
,
1039 &AuthenticationStatus
1041 ASSERT_EFI_ERROR (Status
);
1043 // OR in the parent stream's aggregagate status.
1045 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AUTH_STATUS_ALL
;
1046 Status
= OpenSectionStreamEx (
1047 NewStreamBufferSize
,
1050 AuthenticationStatus
,
1051 &Context
->ChildNode
->EncapsulatedStreamHandle
1053 ASSERT_EFI_ERROR (Status
);
1057 // If above, the stream did not close successfully, it indicates it's
1058 // alread been closed by someone, so just destroy the event and be done with
1062 CoreCloseEvent (Event
);
1063 CoreFreePool (Context
);
1071 IN CORE_SECTION_CHILD_NODE
*ChildNode
1075 Routine Description:
1076 Worker function. Destructor for child nodes.
1079 ChildNode - Indicates the node to destroy
1086 ASSERT (ChildNode
->Signature
== CORE_SECTION_CHILD_SIGNATURE
);
1088 // Remove the child from it's list
1090 RemoveEntryList (&ChildNode
->Link
);
1092 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1094 // If it's an encapsulating section, we close the resulting section stream.
1095 // CloseSectionStream will free all memory associated with the stream.
1097 CloseSectionStream (ChildNode
->EncapsulatedStreamHandle
);
1100 // Last, free the child node itself
1102 CoreFreePool (ChildNode
);
1108 OpenSectionStreamEx (
1109 IN UINTN SectionStreamLength
,
1110 IN VOID
*SectionStream
,
1111 IN BOOLEAN AllocateBuffer
,
1112 IN UINT32 AuthenticationStatus
,
1113 OUT UINTN
*SectionStreamHandle
1117 Routine Description:
1118 Worker function. Constructor for section streams.
1121 SectionStreamLength - Size in bytes of the section stream.
1122 SectionStream - Buffer containing the new section stream.
1123 AllocateBuffer - Indicates whether the stream buffer is to be copied
1124 or the input buffer is to be used in place.
1125 AuthenticationStatus- Indicates the default authentication status for the
1127 SectionStreamHandle - A pointer to a caller allocated section stream handle.
1130 EFI_SUCCESS - Stream was added to stream database.
1131 EFI_OUT_OF_RESOURCES - memory allocation failed.
1135 CORE_SECTION_STREAM_NODE
*NewStream
;
1139 // Allocate a new stream
1141 NewStream
= CoreAllocateBootServicesPool (sizeof (CORE_SECTION_STREAM_NODE
));
1142 if (NewStream
== NULL
) {
1143 return EFI_OUT_OF_RESOURCES
;
1146 if (AllocateBuffer
) {
1148 // if we're here, we're double buffering, allocate the buffer and copy the
1151 if (SectionStreamLength
> 0) {
1152 NewStream
->StreamBuffer
= CoreAllocateBootServicesPool (SectionStreamLength
);
1153 if (NewStream
->StreamBuffer
== NULL
) {
1154 CoreFreePool (NewStream
);
1155 return EFI_OUT_OF_RESOURCES
;
1158 // Copy in stream data
1160 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
1163 // It's possible to have a zero length section stream.
1165 NewStream
->StreamBuffer
= NULL
;
1169 // If were here, the caller has supplied the buffer (it's an internal call)
1170 // so just assign the buffer. This happens when we open section streams
1171 // as a result of expanding an encapsulating section.
1173 NewStream
->StreamBuffer
= SectionStream
;
1177 // Initialize the rest of the section stream
1179 NewStream
->Signature
= CORE_SECTION_STREAM_SIGNATURE
;
1180 NewStream
->StreamHandle
= (UINTN
) NewStream
;
1181 NewStream
->StreamLength
= SectionStreamLength
;
1182 InitializeListHead (&NewStream
->Children
);
1183 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
1186 // Add new stream to stream list
1188 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1189 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
1190 CoreRestoreTpl (OldTpl
);
1192 *SectionStreamHandle
= NewStream
->StreamHandle
;
1201 IN UINTN SearchHandle
,
1202 OUT CORE_SECTION_STREAM_NODE
**FoundStream
1206 Routine Description:
1207 Worker function. Search stream database for requested stream handle.
1210 SearchHandle - Indicates which stream to look for.
1211 FoundStream - Output pointer to the found stream.
1214 EFI_SUCCESS - StreamHandle was found and *FoundStream contains
1216 EFI_NOT_FOUND - SearchHandle was not found in the stream database.
1220 CORE_SECTION_STREAM_NODE
*StreamNode
;
1222 if (!IsListEmpty (&mStreamRoot
)) {
1223 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1225 if (StreamNode
->StreamHandle
== SearchHandle
) {
1226 *FoundStream
= StreamNode
;
1228 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1231 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1236 return EFI_NOT_FOUND
;
1242 IsValidSectionStream (
1243 IN VOID
*SectionStream
,
1244 IN UINTN SectionStreamLength
1248 Routine Description:
1249 Check if a stream is valid.
1252 SectionStream - The section stream to be checked
1253 SectionStreamLength - The length of section stream
1262 UINTN SectionLength
;
1263 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
1264 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
1267 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
1269 while (TotalLength
< SectionStreamLength
) {
1270 SectionLength
= SECTION_SIZE (SectionHeader
);
1271 TotalLength
+= SectionLength
;
1273 if (TotalLength
== SectionStreamLength
) {
1278 // Move to the next byte following the section...
1280 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINT8
*) SectionHeader
+ SectionLength
);
1283 // Figure out where the next section begins
1285 NextSectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINTN
) SectionHeader
+ 3);
1286 NextSectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINTN
) NextSectionHeader
& ~(UINTN
)3);
1287 TotalLength
+= (UINTN
) NextSectionHeader
- (UINTN
) SectionHeader
;
1288 SectionHeader
= NextSectionHeader
;
1296 The ExtractSection() function processes the input section and
1297 allocates a buffer from the pool in which it returns the section
1298 contents. If the section being extracted contains
1299 authentication information (the section's
1300 GuidedSectionHeader.Attributes field has the
1301 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1302 returned in AuthenticationStatus must reflect the results of
1303 the authentication operation. Depending on the algorithm and
1304 size of the encapsulated data, the time that is required to do
1305 a full authentication may be prohibitively long for some
1306 classes of systems. To indicate this, use
1307 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1308 the security policy driver (see the Platform Initialization
1309 Driver Execution Environment Core Interface Specification for
1310 more details and the GUID definition). If the
1311 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1312 database, then, if possible, full authentication should be
1313 skipped and the section contents simply returned in the
1314 OutputBuffer. In this case, the
1315 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1316 must be set on return. ExtractSection() is callable only from
1317 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1318 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1319 defined in RaiseTPL() in the UEFI 2.0 specification.
1322 @param This Indicates the
1323 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1325 @param InputSection Buffer containing the input GUIDed section
1326 to be processed. OutputBuffer OutputBuffer
1327 is allocated from boot services pool
1328 memory and contains the new section
1329 stream. The caller is responsible for
1330 freeing this buffer.
1332 @param OutputSize A pointer to a caller-allocated UINTN in
1333 which the size of OutputBuffer allocation
1334 is stored. If the function returns
1335 anything other than EFI_SUCCESS, the value
1336 of OutputSize is undefined.
1338 @param AuthenticationStatus A pointer to a caller-allocated
1339 UINT32 that indicates the
1340 authentication status of the
1341 output buffer. If the input
1343 GuidedSectionHeader.Attributes
1345 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1346 bit as clear, AuthenticationStatus
1347 must return zero. Both local bits
1348 (19:16) and aggregate bits (3:0)
1349 in AuthenticationStatus are
1350 returned by ExtractSection().
1351 These bits reflect the status of
1352 the extraction operation. The bit
1353 pattern in both regions must be
1354 the same, as the local and
1355 aggregate authentication statuses
1356 have equivalent meaning at this
1357 level. If the function returns
1358 anything other than EFI_SUCCESS,
1359 the value of AuthenticationStatus
1363 @retval EFI_SUCCESS The InputSection was successfully
1364 processed and the section contents were
1367 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1368 resources to process the
1371 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1372 not match this instance of the
1373 GUIDed Section Extraction
1379 CustomGuidedSectionExtract (
1380 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
1381 IN CONST VOID
*InputSection
,
1382 OUT VOID
**OutputBuffer
,
1383 OUT UINTN
*OutputSize
,
1384 OUT UINT32
*AuthenticationStatus
1388 VOID
*ScratchBuffer
;
1389 VOID
*AllocatedOutputBuffer
;
1390 UINT32 OutputBufferSize
;
1391 UINT32 ScratchBufferSize
;
1392 UINT16 SectionAttribute
;
1395 // Init local variable
1397 ScratchBuffer
= NULL
;
1398 AllocatedOutputBuffer
= NULL
;
1401 // Call GetInfo to get the size and attribute of input guided section data.
1403 Status
= ExtractGuidedSectionGetInfo (
1410 if (EFI_ERROR (Status
)) {
1411 DEBUG ((EFI_D_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
1415 if (ScratchBufferSize
!= 0) {
1417 // Allocate scratch buffer
1419 ScratchBuffer
= CoreAllocateBootServicesPool (ScratchBufferSize
);
1420 if (ScratchBuffer
== NULL
) {
1421 return EFI_OUT_OF_RESOURCES
;
1425 if (OutputBufferSize
> 0) {
1427 // Allocate output buffer
1429 AllocatedOutputBuffer
= CoreAllocateBootServicesPool (OutputBufferSize
);
1430 if (AllocatedOutputBuffer
== NULL
) {
1431 return EFI_OUT_OF_RESOURCES
;
1433 *OutputBuffer
= AllocatedOutputBuffer
;
1437 // Call decode function to extract raw data from the guided section.
1439 Status
= ExtractGuidedSectionDecode (
1443 AuthenticationStatus
1445 if (EFI_ERROR (Status
)) {
1449 if (AllocatedOutputBuffer
!= NULL
) {
1450 CoreFreePool (AllocatedOutputBuffer
);
1452 if (ScratchBuffer
!= NULL
) {
1453 CoreFreePool (ScratchBuffer
);
1455 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
1459 if (*OutputBuffer
!= AllocatedOutputBuffer
) {
1461 // OutputBuffer was returned as a different value,
1462 // so copy section contents to the allocated memory buffer.
1464 CopyMem (AllocatedOutputBuffer
, *OutputBuffer
, OutputBufferSize
);
1465 *OutputBuffer
= AllocatedOutputBuffer
;
1469 // Set real size of output buffer.
1471 *OutputSize
= (UINTN
) OutputBufferSize
;
1474 // Free unused scratch buffer.
1476 if (ScratchBuffer
!= NULL
) {
1477 CoreFreePool (ScratchBuffer
);