3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 CoreSectionExtraction.c
18 Section Extraction Protocol implementation.
20 Stream database is implemented as a linked list of section streams,
21 where each stream contains a linked list of children, which may be leaves or
24 Children that are encapsulations generate new stream entries
25 when they are created. Streams can also be created by calls to
26 SEP->OpenSectionStream().
28 The database is only created far enough to return the requested data from
29 any given stream, or to determine that the requested data is not found.
31 If a GUIDed encapsulation is encountered, there are three possiblilites.
33 1) A support protocol is found, in which the stream is simply processed with
36 2) A support protocol is not found, but the data is available to be read
37 without processing. In this case, the database is built up through the
38 recursions to return the data, and a RPN event is set that will enable
39 the stream in question to be refreshed if and when the required section
40 extraction protocol is published.This insures the AuthenticationStatus
41 does not become stale in the cache.
43 3) A support protocol is not found, and the data is not available to be read
44 without it. This results in EFI_PROTOCOL_ERROR.
51 // Local defines and typedefs
53 #define CORE_SECTION_CHILD_SIGNATURE EFI_SIGNATURE_32('S','X','C','S')
54 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
55 CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
63 // StreamBase + OffsetInStream == pointer to section header in stream. The
64 // stream base is always known when walking the sections within.
66 UINT32 OffsetInStream
;
68 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
69 // encapsulating section. Otherwise, it contains the stream handle
70 // of the encapsulated stream. This handle is ALWAYS produced any time an
71 // encapsulating child is encountered, irrespective of whether the
72 // encapsulated stream is processed further.
74 UINTN EncapsulatedStreamHandle
;
75 EFI_GUID
*EncapsulationGuid
;
76 } CORE_SECTION_CHILD_NODE
;
78 #define CORE_SECTION_STREAM_SIGNATURE EFI_SIGNATURE_32('S','X','S','S')
79 #define STREAM_NODE_FROM_LINK(Node) \
80 CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
90 // Authentication status is from GUIDed encapsulations.
92 UINT32 AuthenticationStatus
;
93 } CORE_SECTION_STREAM_NODE
;
95 #define NULL_STREAM_HANDLE 0
98 CORE_SECTION_CHILD_NODE
*ChildNode
;
99 CORE_SECTION_STREAM_NODE
*ParentStream
;
113 IN CORE_SECTION_STREAM_NODE
*Stream
,
114 IN CORE_SECTION_CHILD_NODE
*Child
,
115 IN EFI_SECTION_TYPE SearchType
,
116 IN EFI_GUID
*SectionDefinitionGuid
122 NotifyGuidedExtraction (
129 CreateGuidedExtractionRpnEvent (
130 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
131 IN CORE_SECTION_CHILD_NODE
*ChildNode
138 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
139 IN UINTN SectionStreamLength
,
140 IN VOID
*SectionStream
,
141 OUT UINTN
*SectionStreamHandle
148 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
149 IN UINTN SectionStreamHandle
,
150 IN EFI_SECTION_TYPE
*SectionType
,
151 IN EFI_GUID
*SectionDefinitionGuid
,
152 IN UINTN SectionInstance
,
154 IN OUT UINTN
*BufferSize
,
155 OUT UINT32
*AuthenticationStatus
162 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
163 IN UINTN StreamHandleToClose
169 IN UINTN SearchHandle
,
170 OUT CORE_SECTION_STREAM_NODE
**FoundStream
176 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
177 IN EFI_SECTION_TYPE SearchType
,
178 IN UINTN
*SectionInstance
,
179 IN EFI_GUID
*SectionDefinitionGuid
,
180 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
181 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
182 OUT UINT32
*AuthenticationStatus
188 IN CORE_SECTION_STREAM_NODE
*Stream
,
189 IN UINT32 ChildOffset
,
190 OUT CORE_SECTION_CHILD_NODE
**ChildNode
196 IN CORE_SECTION_CHILD_NODE
*ChildNode
201 OpenSectionStreamEx (
202 IN UINTN SectionStreamLength
,
203 IN VOID
*SectionStream
,
204 IN BOOLEAN AllocateBuffer
,
205 IN UINT32 AuthenticationStatus
,
206 OUT UINTN
*SectionStreamHandle
211 IsValidSectionStream (
212 IN VOID
*SectionStream
,
213 IN UINTN SectionStreamLength
217 CustomDecompressExtractSection (
218 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
219 IN CONST VOID
*InputSection
,
220 OUT VOID
**OutputBuffer
,
221 OUT UINTN
*OutputSize
,
222 OUT UINT32
*AuthenticationStatus
227 LIST_ENTRY mStreamRoot
= INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot
);
229 EFI_HANDLE mSectionExtractionHandle
= NULL
;
231 EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction
= {
237 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomDecompressExtraction
= {
238 CustomDecompressExtractSection
243 InitializeSectionExtraction (
244 IN EFI_HANDLE ImageHandle
,
245 IN EFI_SYSTEM_TABLE
*SystemTable
250 Entry point of the section extraction code. Initializes an instance of the
251 section extraction interface and installs it on a new handle.
254 ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver
255 SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
258 EFI_SUCCESS: Driver initialized successfully
259 EFI_OUT_OF_RESOURCES: Could not allocate needed resources
264 EFI_GUID
**DecompressGuidList
;
265 UINT32 DecompressMethodNumber
;
268 // Install SEP to a new handle
270 Status
= CoreInstallProtocolInterface (
271 &mSectionExtractionHandle
,
272 &gEfiSectionExtractionProtocolGuid
,
273 EFI_NATIVE_INTERFACE
,
276 ASSERT_EFI_ERROR (Status
);
279 // Get custom decompress method guid list
281 DecompressGuidList
= NULL
;
282 DecompressMethodNumber
= 0;
283 Status
= CustomDecompressGetAlgorithms (DecompressGuidList
, &DecompressMethodNumber
);
284 if (Status
== EFI_OUT_OF_RESOURCES
) {
285 DecompressGuidList
= (EFI_GUID
**) CoreAllocateBootServicesPool (DecompressMethodNumber
* sizeof (EFI_GUID
*));
286 ASSERT (DecompressGuidList
!= NULL
);
287 Status
= CustomDecompressGetAlgorithms (DecompressGuidList
, &DecompressMethodNumber
);
289 ASSERT_EFI_ERROR(Status
);
292 // Install custom decompress guided extraction protocol
294 while (DecompressMethodNumber
-- > 0) {
295 Status
= CoreInstallProtocolInterface (
296 &mSectionExtractionHandle
,
297 DecompressGuidList
[DecompressMethodNumber
],
298 EFI_NATIVE_INTERFACE
,
299 &mCustomDecompressExtraction
301 ASSERT_EFI_ERROR (Status
);
304 CoreFreePool (DecompressGuidList
);
313 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
314 IN UINTN SectionStreamLength
,
315 IN VOID
*SectionStream
,
316 OUT UINTN
*SectionStreamHandle
321 SEP member function. This function creates and returns a new section stream
322 handle to represent the new section stream.
325 This - Indicates the calling context.
326 SectionStreamLength - Size in bytes of the section stream.
327 SectionStream - Buffer containing the new section stream.
328 SectionStreamHandle - A pointer to a caller allocated UINTN that on output
329 contains the new section stream handle.
333 EFI_OUT_OF_RESOURCES - memory allocation failed.
334 EFI_INVALID_PARAMETER - section stream does not end concident with end of
340 // Check to see section stream looks good...
342 if (!IsValidSectionStream (SectionStream
, SectionStreamLength
)) {
343 return EFI_INVALID_PARAMETER
;
346 return OpenSectionStreamEx (
359 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
360 IN UINTN SectionStreamHandle
,
361 IN EFI_SECTION_TYPE
*SectionType
,
362 IN EFI_GUID
*SectionDefinitionGuid
,
363 IN UINTN SectionInstance
,
365 IN OUT UINTN
*BufferSize
,
366 OUT UINT32
*AuthenticationStatus
371 SEP member function. Retrieves requested section from section stream.
374 This: Pointer to SEP instance.
375 SectionStreamHandle: The section stream from which to extract the requested
377 SectionType: A pointer to the type of section to search for.
378 SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then
379 SectionDefinitionGuid indicates which of these types
380 of sections to search for.
381 SectionInstance: Indicates which instance of the requested section to
383 Buffer: Double indirection to buffer. If *Buffer is non-null on
384 input, then the buffer is caller allocated. If
385 *Buffer is NULL, then the buffer is callee allocated.
386 In either case, the requried buffer size is returned
388 BufferSize: On input, indicates the size of *Buffer if *Buffer is
389 non-null on input. On output, indicates the required
390 size (allocated size if callee allocated) of *Buffer.
391 AuthenticationStatus: Indicates the authentication status of the retrieved
395 EFI_SUCCESS: Section was retrieved successfully
396 EFI_PROTOCOL_ERROR: A GUID defined section was encountered in the section
397 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
398 bit set, but there was no corresponding GUIDed Section
399 Extraction Protocol in the handle database. *Buffer is
401 EFI_NOT_FOUND: An error was encountered when parsing the SectionStream.
402 This indicates the SectionStream is not correctly
404 EFI_NOT_FOUND: The requested section does not exist.
405 EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the
407 EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist.
408 EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is
409 insufficient to contain the requested section. The
410 input buffer is filled and contents are section contents
415 CORE_SECTION_STREAM_NODE
*StreamNode
;
418 CORE_SECTION_CHILD_NODE
*ChildNode
;
419 CORE_SECTION_STREAM_NODE
*ChildStreamNode
;
421 UINT32 ExtractedAuthenticationStatus
;
427 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
428 Instance
= SectionInstance
+ 1;
431 // Locate target stream
433 Status
= FindStreamNode (SectionStreamHandle
, &StreamNode
);
434 if (EFI_ERROR (Status
)) {
435 Status
= EFI_INVALID_PARAMETER
;
436 goto GetSection_Done
;
440 // Found the stream, now locate and return the appropriate section
442 if (SectionType
== NULL
) {
444 // SectionType == NULL means return the WHOLE section stream...
446 CopySize
= StreamNode
->StreamLength
;
447 CopyBuffer
= StreamNode
->StreamBuffer
;
448 *AuthenticationStatus
= StreamNode
->AuthenticationStatus
;
451 // There's a requested section type, so go find it and return it...
453 Status
= FindChildNode (
457 SectionDefinitionGuid
,
460 &ExtractedAuthenticationStatus
462 if (EFI_ERROR (Status
)) {
463 goto GetSection_Done
;
465 CopySize
= ChildNode
->Size
- sizeof (EFI_COMMON_SECTION_HEADER
);
466 CopyBuffer
= ChildStreamNode
->StreamBuffer
+ ChildNode
->OffsetInStream
+ sizeof (EFI_COMMON_SECTION_HEADER
);
467 *AuthenticationStatus
= ExtractedAuthenticationStatus
;
470 SectionSize
= CopySize
;
471 if (*Buffer
!= NULL
) {
473 // Caller allocated buffer. Fill to size and return required size...
475 if (*BufferSize
< CopySize
) {
476 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
477 CopySize
= *BufferSize
;
481 // Callee allocated buffer. Allocate buffer and return size.
483 *Buffer
= CoreAllocateBootServicesPool (CopySize
);
484 if (*Buffer
== NULL
) {
485 Status
= EFI_OUT_OF_RESOURCES
;
486 goto GetSection_Done
;
489 CopyMem (*Buffer
, CopyBuffer
, CopySize
);
490 *BufferSize
= SectionSize
;
493 CoreRestoreTpl (OldTpl
);
502 IN EFI_SECTION_EXTRACTION_PROTOCOL
*This
,
503 IN UINTN StreamHandleToClose
508 SEP member function. Deletes an existing section stream
511 This - Indicates the calling context.
512 StreamHandleToClose - Indicates the stream to close
516 EFI_OUT_OF_RESOURCES - memory allocation failed.
517 EFI_INVALID_PARAMETER - section stream does not end concident with end of
522 CORE_SECTION_STREAM_NODE
*StreamNode
;
526 CORE_SECTION_CHILD_NODE
*ChildNode
;
528 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
531 // Locate target stream
533 Status
= FindStreamNode (StreamHandleToClose
, &StreamNode
);
534 if (!EFI_ERROR (Status
)) {
536 // Found the stream, so close it
538 RemoveEntryList (&StreamNode
->Link
);
539 while (!IsListEmpty (&StreamNode
->Children
)) {
540 Link
= GetFirstNode (&StreamNode
->Children
);
541 ChildNode
= CHILD_SECTION_NODE_FROM_LINK (Link
);
542 FreeChildNode (ChildNode
);
544 CoreFreePool (StreamNode
->StreamBuffer
);
545 CoreFreePool (StreamNode
);
546 Status
= EFI_SUCCESS
;
548 Status
= EFI_INVALID_PARAMETER
;
551 CoreRestoreTpl (OldTpl
);
559 IN CORE_SECTION_STREAM_NODE
*Stream
,
560 IN CORE_SECTION_CHILD_NODE
*Child
,
561 IN EFI_SECTION_TYPE SearchType
,
562 IN EFI_GUID
*SectionDefinitionGuid
567 Worker function. Determine if the input stream:child matches the input type.
570 Stream - Indicates the section stream associated with the child
571 Child - Indicates the child to check
572 SearchType - Indicates the type of section to check against for
573 SectionDefinitionGuid - Indicates the GUID to check against if the type is
574 EFI_SECTION_GUID_DEFINED
576 TRUE - The child matches
577 FALSE - The child doesn't match
581 EFI_GUID_DEFINED_SECTION
*GuidedSection
;
583 if (SearchType
== EFI_SECTION_ALL
) {
586 if (Child
->Type
!= SearchType
) {
589 if (SearchType
!= EFI_SECTION_GUID_DEFINED
) {
592 GuidedSection
= (EFI_GUID_DEFINED_SECTION
* )(Stream
->StreamBuffer
+ Child
->OffsetInStream
);
593 return CompareGuid (&GuidedSection
->SectionDefinitionGuid
, SectionDefinitionGuid
);
600 IN CORE_SECTION_STREAM_NODE
*SourceStream
,
601 IN EFI_SECTION_TYPE SearchType
,
602 IN OUT UINTN
*SectionInstance
,
603 IN EFI_GUID
*SectionDefinitionGuid
,
604 OUT CORE_SECTION_CHILD_NODE
**FoundChild
,
605 OUT CORE_SECTION_STREAM_NODE
**FoundStream
,
606 OUT UINT32
*AuthenticationStatus
611 Worker function Recursively searches / builds section stream database
612 looking for requested section.
615 SourceStream - Indicates the section stream in which to do the search.
616 SearchType - Indicates the type of section to search for.
617 SectionInstance - Indicates which instance of section to find. This is
618 an in/out parameter to deal with recursions.
619 SectionDefinitionGuid - Guid of section definition
620 FoundChild - Output indicating the child node that is found.
621 FoundStream - Output indicating which section stream the child was
622 found in. If this stream was generated as a result of
623 an encapsulation section, the streamhandle is visible
624 within the SEP driver only.
625 AuthenticationStatus- Indicates the authentication status of the found section.
628 EFI_SUCCESS - Child node was found and returned.
629 EFI_OUT_OF_RESOURCES- Memory allocation failed.
630 EFI_NOT_FOUND - Requested child node does not exist.
631 EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not
636 CORE_SECTION_CHILD_NODE
*CurrentChildNode
;
637 CORE_SECTION_CHILD_NODE
*RecursedChildNode
;
638 CORE_SECTION_STREAM_NODE
*RecursedFoundStream
;
639 UINT32 NextChildOffset
;
640 EFI_STATUS ErrorStatus
;
643 CurrentChildNode
= NULL
;
644 ErrorStatus
= EFI_NOT_FOUND
;
646 if (SourceStream
->StreamLength
== 0) {
647 return EFI_NOT_FOUND
;
650 if (IsListEmpty (&SourceStream
->Children
) &&
651 SourceStream
->StreamLength
> sizeof (EFI_COMMON_SECTION_HEADER
)) {
653 // This occurs when a section stream exists, but no child sections
654 // have been parsed out yet. Therefore, extract the first child and add it
655 // to the list of children so we can get started.
657 Status
= CreateChildNode (SourceStream
, 0, &CurrentChildNode
);
658 if (EFI_ERROR (Status
)) {
664 // At least one child has been parsed out of the section stream. So, walk
665 // through the sections that have already been parsed out looking for the
666 // requested section, if necessary, continue parsing section stream and
667 // adding children until either the requested section is found, or we run
670 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream
->Children
));
673 if (ChildIsType (SourceStream
, CurrentChildNode
, SearchType
, SectionDefinitionGuid
)) {
675 // The type matches, so check the instance count to see if it's the one we want
677 (*SectionInstance
)--;
678 if (*SectionInstance
== 0) {
682 *FoundChild
= CurrentChildNode
;
683 *FoundStream
= SourceStream
;
684 *AuthenticationStatus
= SourceStream
->AuthenticationStatus
;
689 if (CurrentChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
691 // If the current node is an encapsulating node, recurse into it...
693 Status
= FindChildNode (
694 (CORE_SECTION_STREAM_NODE
*)CurrentChildNode
->EncapsulatedStreamHandle
,
697 SectionDefinitionGuid
,
699 &RecursedFoundStream
,
703 // If the status is not EFI_SUCCESS, just save the error code and continue
704 // to find the request child node in the rest stream.
706 if (*SectionInstance
== 0) {
707 ASSERT_EFI_ERROR (Status
);
708 *FoundChild
= RecursedChildNode
;
709 *FoundStream
= RecursedFoundStream
;
712 ErrorStatus
= Status
;
716 if (!IsNodeAtEnd (&SourceStream
->Children
, &CurrentChildNode
->Link
)) {
718 // We haven't found the child node we're interested in yet, but there's
719 // still more nodes that have already been parsed so get the next one
720 // and continue searching..
722 CurrentChildNode
= CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream
->Children
, &CurrentChildNode
->Link
));
725 // We've exhausted children that have already been parsed, so see if
726 // there's any more data and continue parsing out more children if there
729 NextChildOffset
= CurrentChildNode
->OffsetInStream
+ CurrentChildNode
->Size
;
731 // Round up to 4 byte boundary
733 NextChildOffset
+= 3;
734 NextChildOffset
&= ~(UINTN
)3;
735 if (NextChildOffset
<= SourceStream
->StreamLength
- sizeof (EFI_COMMON_SECTION_HEADER
)) {
737 // There's an unparsed child remaining in the stream, so create a new child node
739 Status
= CreateChildNode (SourceStream
, NextChildOffset
, &CurrentChildNode
);
740 if (EFI_ERROR (Status
)) {
744 ASSERT (EFI_ERROR (ErrorStatus
));
755 IN CORE_SECTION_STREAM_NODE
*Stream
,
756 IN UINT32 ChildOffset
,
757 OUT CORE_SECTION_CHILD_NODE
**ChildNode
762 Worker function. Constructor for new child nodes.
765 Stream - Indicates the section stream in which to add the child.
766 ChildOffset - Indicates the offset in Stream that is the beginning
767 of the child section.
768 ChildNode - Indicates the Callee allocated and initialized child.
771 EFI_SUCCESS - Child node was found and returned.
772 EFI_OUT_OF_RESOURCES- Memory allocation failed.
773 EFI_PROTOCOL_ERROR - Encapsulation sections produce new stream handles when
774 the child node is created. If the section type is GUID
775 defined, and the extraction GUID does not exist, and
776 producing the stream requires the GUID, then a protocol
777 error is generated and no child is produced.
778 Values returned by OpenSectionStreamEx.
783 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
784 EFI_COMPRESSION_SECTION
*CompressionHeader
;
785 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
786 EFI_DECOMPRESS_PROTOCOL
*Decompress
;
787 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
788 VOID
*NewStreamBuffer
;
791 UINTN NewStreamBufferSize
;
792 UINT32 AuthenticationStatus
;
793 UINT32 SectionLength
;
795 CORE_SECTION_CHILD_NODE
*Node
;
797 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) (Stream
->StreamBuffer
+ ChildOffset
);
800 // Allocate a new node
802 *ChildNode
= CoreAllocateBootServicesPool (sizeof (CORE_SECTION_CHILD_NODE
));
805 return EFI_OUT_OF_RESOURCES
;
811 Node
->Signature
= CORE_SECTION_CHILD_SIGNATURE
;
812 Node
->Type
= SectionHeader
->Type
;
813 Node
->Size
= SECTION_SIZE (SectionHeader
);
814 Node
->OffsetInStream
= ChildOffset
;
815 Node
->EncapsulatedStreamHandle
= NULL_STREAM_HANDLE
;
816 Node
->EncapsulationGuid
= NULL
;
819 // If it's an encapsulating section, then create the new section stream also
821 switch (Node
->Type
) {
822 case EFI_SECTION_COMPRESSION
:
824 // Get the CompressionSectionHeader
826 ASSERT (Node
->Size
>= sizeof (EFI_COMPRESSION_SECTION
));
828 CompressionHeader
= (EFI_COMPRESSION_SECTION
*) SectionHeader
;
831 // Allocate space for the new stream
833 if (CompressionHeader
->UncompressedLength
> 0) {
834 NewStreamBufferSize
= CompressionHeader
->UncompressedLength
;
835 NewStreamBuffer
= CoreAllocateBootServicesPool (NewStreamBufferSize
);
836 if (NewStreamBuffer
== NULL
) {
838 return EFI_OUT_OF_RESOURCES
;
841 if (CompressionHeader
->CompressionType
== EFI_NOT_COMPRESSED
) {
843 // stream is not actually compressed, just encapsulated. So just copy it.
845 CopyMem (NewStreamBuffer
, CompressionHeader
+ 1, NewStreamBufferSize
);
846 } else if (CompressionHeader
->CompressionType
== EFI_STANDARD_COMPRESSION
) {
848 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
852 // Decompress the stream
854 Status
= CoreLocateProtocol (&gEfiDecompressProtocolGuid
, NULL
, (VOID
**)&Decompress
);
856 ASSERT_EFI_ERROR (Status
);
858 Status
= Decompress
->GetInfo (
860 CompressionHeader
+ 1,
861 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
862 (UINT32
*)&NewStreamBufferSize
,
865 ASSERT_EFI_ERROR (Status
);
866 ASSERT (NewStreamBufferSize
== CompressionHeader
->UncompressedLength
);
868 ScratchBuffer
= CoreAllocateBootServicesPool (ScratchSize
);
869 if (ScratchBuffer
== NULL
) {
871 CoreFreePool (NewStreamBuffer
);
872 return EFI_OUT_OF_RESOURCES
;
875 Status
= Decompress
->Decompress (
877 CompressionHeader
+ 1,
878 Node
->Size
- sizeof (EFI_COMPRESSION_SECTION
),
880 (UINT32
)NewStreamBufferSize
,
884 ASSERT_EFI_ERROR (Status
);
885 CoreFreePool (ScratchBuffer
);
888 NewStreamBuffer
= NULL
;
889 NewStreamBufferSize
= 0;
892 Status
= OpenSectionStreamEx (
896 Stream
->AuthenticationStatus
,
897 &Node
->EncapsulatedStreamHandle
899 if (EFI_ERROR (Status
)) {
901 CoreFreePool (NewStreamBuffer
);
906 case EFI_SECTION_GUID_DEFINED
:
907 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*) SectionHeader
;
908 Node
->EncapsulationGuid
= &GuidedHeader
->SectionDefinitionGuid
;
909 Status
= CoreLocateProtocol (Node
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
910 if (!EFI_ERROR (Status
)) {
912 // NewStreamBuffer is always allocated by ExtractSection... No caller
915 Status
= GuidedExtraction
->ExtractSection (
919 &NewStreamBufferSize
,
920 &AuthenticationStatus
922 if (EFI_ERROR (Status
)) {
923 CoreFreePool (*ChildNode
);
924 return EFI_PROTOCOL_ERROR
;
928 // Make sure we initialize the new stream with the correct
929 // authentication status for both aggregate and local status fields.
931 if (GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
933 // OR in the parent stream's aggregate status.
935 AuthenticationStatus
|= Stream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
938 // since there's no authentication data contributed by the section,
939 // just inherit the full value from our immediate parent.
941 AuthenticationStatus
= Stream
->AuthenticationStatus
;
944 Status
= OpenSectionStreamEx (
948 AuthenticationStatus
,
949 &Node
->EncapsulatedStreamHandle
951 if (EFI_ERROR (Status
)) {
952 CoreFreePool (*ChildNode
);
953 CoreFreePool (NewStreamBuffer
);
958 // There's no GUIDed section extraction protocol available.
960 if (GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) {
962 // If the section REQUIRES an extraction protocol, then we're toast
964 CoreFreePool (*ChildNode
);
965 return EFI_PROTOCOL_ERROR
;
969 // Figure out the proper authentication status
971 AuthenticationStatus
= Stream
->AuthenticationStatus
;
972 if (GuidedHeader
->Attributes
& EFI_GUIDED_SECTION_AUTH_STATUS_VALID
) {
974 // The local status of the new stream is contained in
975 // AuthenticaionStatus. This value needs to be ORed into the
976 // Aggregate bits also...
980 // Clear out and initialize the local status
982 AuthenticationStatus
&= ~EFI_LOCAL_AUTH_STATUS_ALL
;
983 AuthenticationStatus
|= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
;
985 // OR local status into aggregate status
987 AuthenticationStatus
|= AuthenticationStatus
>> 16;
990 SectionLength
= SECTION_SIZE (GuidedHeader
);
991 Status
= OpenSectionStreamEx (
992 SectionLength
- GuidedHeader
->DataOffset
,
993 (UINT8
*) GuidedHeader
+ GuidedHeader
->DataOffset
,
995 AuthenticationStatus
,
996 &Node
->EncapsulatedStreamHandle
998 if (EFI_ERROR (Status
)) {
1004 if ((AuthenticationStatus
& EFI_LOCAL_AUTH_STATUS_ALL
) ==
1005 (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED
| EFI_LOCAL_AUTH_STATUS_NOT_TESTED
)) {
1007 // Need to register for RPN for when the required GUIDed extraction
1008 // protocol becomes available. This will enable us to refresh the
1009 // AuthenticationStatus cached in the Stream if it's ever requested
1012 CreateGuidedExtractionRpnEvent (Stream
, Node
);
1020 // Nothing to do if it's a leaf
1026 // Last, add the new child node to the stream
1028 InsertTailList (&Stream
->Children
, &Node
->Link
);
1036 CreateGuidedExtractionRpnEvent (
1037 IN CORE_SECTION_STREAM_NODE
*ParentStream
,
1038 IN CORE_SECTION_CHILD_NODE
*ChildNode
1042 Routine Description:
1043 Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
1044 cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
1047 ParentStream - Indicates the parent of the ecnapsulation section (child)
1048 ChildNode - Indicates the child node that is the encapsulation section.
1055 RPN_EVENT_CONTEXT
*Context
;
1058 // Allocate new event structure and context
1060 Context
= CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT
));
1061 ASSERT (Context
!= NULL
);
1063 Context
->ChildNode
= ChildNode
;
1064 Context
->ParentStream
= ParentStream
;
1066 Context
->Event
= CoreCreateProtocolNotifyEvent (
1067 Context
->ChildNode
->EncapsulationGuid
,
1069 NotifyGuidedExtraction
,
1071 &Context
->Registration
,
1080 NotifyGuidedExtraction (
1086 Routine Description:
1087 RPN callback function. Removes a stale section stream and re-initializes it
1088 with an updated AuthenticationStatus.
1091 Event - The event that fired
1092 RpnContext - A pointer to the context that allows us to identify
1093 the relevent encapsulation...
1101 EFI_GUID_DEFINED_SECTION
*GuidedHeader
;
1102 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*GuidedExtraction
;
1103 VOID
*NewStreamBuffer
;
1104 UINTN NewStreamBufferSize
;
1105 UINT32 AuthenticationStatus
;
1106 RPN_EVENT_CONTEXT
*Context
;
1108 Context
= RpnContext
;
1110 Status
= CloseSectionStream (&mSectionExtraction
, Context
->ChildNode
->EncapsulatedStreamHandle
);
1111 if (!EFI_ERROR (Status
)) {
1113 // The stream closed successfully, so re-open the stream with correct AuthenticationStatus
1116 GuidedHeader
= (EFI_GUID_DEFINED_SECTION
*)
1117 (Context
->ParentStream
->StreamBuffer
+ Context
->ChildNode
->OffsetInStream
);
1118 ASSERT (GuidedHeader
->CommonHeader
.Type
== EFI_SECTION_GUID_DEFINED
);
1120 Status
= CoreLocateProtocol (Context
->ChildNode
->EncapsulationGuid
, NULL
, (VOID
**)&GuidedExtraction
);
1121 ASSERT_EFI_ERROR (Status
);
1124 Status
= GuidedExtraction
->ExtractSection (
1128 &NewStreamBufferSize
,
1129 &AuthenticationStatus
1131 ASSERT_EFI_ERROR (Status
);
1133 // OR in the parent stream's aggregagate status.
1135 AuthenticationStatus
|= Context
->ParentStream
->AuthenticationStatus
& EFI_AGGREGATE_AUTH_STATUS_ALL
;
1136 Status
= OpenSectionStreamEx (
1137 NewStreamBufferSize
,
1140 AuthenticationStatus
,
1141 &Context
->ChildNode
->EncapsulatedStreamHandle
1143 ASSERT_EFI_ERROR (Status
);
1147 // If above, the stream did not close successfully, it indicates it's
1148 // alread been closed by someone, so just destroy the event and be done with
1152 CoreCloseEvent (Event
);
1153 CoreFreePool (Context
);
1160 IN CORE_SECTION_CHILD_NODE
*ChildNode
1164 Routine Description:
1165 Worker function. Destructor for child nodes.
1168 ChildNode - Indicates the node to destroy
1175 ASSERT (ChildNode
->Signature
== CORE_SECTION_CHILD_SIGNATURE
);
1177 // Remove the child from it's list
1179 RemoveEntryList (&ChildNode
->Link
);
1181 if (ChildNode
->EncapsulatedStreamHandle
!= NULL_STREAM_HANDLE
) {
1183 // If it's an encapsulating section, we close the resulting section stream.
1184 // CloseSectionStream will free all memory associated with the stream.
1186 CloseSectionStream (&mSectionExtraction
, ChildNode
->EncapsulatedStreamHandle
);
1189 // Last, free the child node itself
1191 CoreFreePool (ChildNode
);
1197 OpenSectionStreamEx (
1198 IN UINTN SectionStreamLength
,
1199 IN VOID
*SectionStream
,
1200 IN BOOLEAN AllocateBuffer
,
1201 IN UINT32 AuthenticationStatus
,
1202 OUT UINTN
*SectionStreamHandle
1206 Routine Description:
1207 Worker function. Constructor for section streams.
1210 SectionStreamLength - Size in bytes of the section stream.
1211 SectionStream - Buffer containing the new section stream.
1212 AllocateBuffer - Indicates whether the stream buffer is to be copied
1213 or the input buffer is to be used in place.
1214 AuthenticationStatus- Indicates the default authentication status for the
1216 SectionStreamHandle - A pointer to a caller allocated section stream handle.
1219 EFI_SUCCESS - Stream was added to stream database.
1220 EFI_OUT_OF_RESOURCES - memory allocation failed.
1224 CORE_SECTION_STREAM_NODE
*NewStream
;
1228 // Allocate a new stream
1230 NewStream
= CoreAllocateBootServicesPool (sizeof (CORE_SECTION_STREAM_NODE
));
1231 if (NewStream
== NULL
) {
1232 return EFI_OUT_OF_RESOURCES
;
1235 if (AllocateBuffer
) {
1237 // if we're here, we're double buffering, allocate the buffer and copy the
1240 if (SectionStreamLength
> 0) {
1241 NewStream
->StreamBuffer
= CoreAllocateBootServicesPool (SectionStreamLength
);
1242 if (NewStream
->StreamBuffer
== NULL
) {
1243 CoreFreePool (NewStream
);
1244 return EFI_OUT_OF_RESOURCES
;
1247 // Copy in stream data
1249 CopyMem (NewStream
->StreamBuffer
, SectionStream
, SectionStreamLength
);
1252 // It's possible to have a zero length section stream.
1254 NewStream
->StreamBuffer
= NULL
;
1258 // If were here, the caller has supplied the buffer (it's an internal call)
1259 // so just assign the buffer. This happens when we open section streams
1260 // as a result of expanding an encapsulating section.
1262 NewStream
->StreamBuffer
= SectionStream
;
1266 // Initialize the rest of the section stream
1268 NewStream
->Signature
= CORE_SECTION_STREAM_SIGNATURE
;
1269 NewStream
->StreamHandle
= (UINTN
) NewStream
;
1270 NewStream
->StreamLength
= SectionStreamLength
;
1271 InitializeListHead (&NewStream
->Children
);
1272 NewStream
->AuthenticationStatus
= AuthenticationStatus
;
1275 // Add new stream to stream list
1277 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1278 InsertTailList (&mStreamRoot
, &NewStream
->Link
);
1279 CoreRestoreTpl (OldTpl
);
1281 *SectionStreamHandle
= NewStream
->StreamHandle
;
1290 IN UINTN SearchHandle
,
1291 OUT CORE_SECTION_STREAM_NODE
**FoundStream
1295 Routine Description:
1296 Worker function. Search stream database for requested stream handle.
1299 SearchHandle - Indicates which stream to look for.
1300 FoundStream - Output pointer to the found stream.
1303 EFI_SUCCESS - StreamHandle was found and *FoundStream contains
1305 EFI_NOT_FOUND - SearchHandle was not found in the stream database.
1309 CORE_SECTION_STREAM_NODE
*StreamNode
;
1311 if (!IsListEmpty (&mStreamRoot
)) {
1312 StreamNode
= STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot
));
1314 if (StreamNode
->StreamHandle
== SearchHandle
) {
1315 *FoundStream
= StreamNode
;
1317 } else if (IsNodeAtEnd (&mStreamRoot
, &StreamNode
->Link
)) {
1320 StreamNode
= STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot
, &StreamNode
->Link
));
1325 return EFI_NOT_FOUND
;
1331 IsValidSectionStream (
1332 IN VOID
*SectionStream
,
1333 IN UINTN SectionStreamLength
1337 Routine Description:
1338 Check if a stream is valid.
1341 SectionStream - The section stream to be checked
1342 SectionStreamLength - The length of section stream
1351 UINTN SectionLength
;
1352 EFI_COMMON_SECTION_HEADER
*SectionHeader
;
1353 EFI_COMMON_SECTION_HEADER
*NextSectionHeader
;
1356 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*)SectionStream
;
1358 while (TotalLength
< SectionStreamLength
) {
1359 SectionLength
= SECTION_SIZE (SectionHeader
);
1360 TotalLength
+= SectionLength
;
1362 if (TotalLength
== SectionStreamLength
) {
1367 // Move to the next byte following the section...
1369 SectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINT8
*) SectionHeader
+ SectionLength
);
1372 // Figure out where the next section begins
1374 NextSectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINTN
) SectionHeader
+ 3);
1375 NextSectionHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINTN
) NextSectionHeader
& ~(UINTN
)3);
1376 TotalLength
+= (UINTN
) NextSectionHeader
- (UINTN
) SectionHeader
;
1377 SectionHeader
= NextSectionHeader
;
1385 The ExtractSection() function processes the input section and
1386 allocates a buffer from the pool in which it returns the section
1387 contents. If the section being extracted contains
1388 authentication information (the section's
1389 GuidedSectionHeader.Attributes field has the
1390 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1391 returned in AuthenticationStatus must reflect the results of
1392 the authentication operation. Depending on the algorithm and
1393 size of the encapsulated data, the time that is required to do
1394 a full authentication may be prohibitively long for some
1395 classes of systems. To indicate this, use
1396 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1397 the security policy driver (see the Platform Initialization
1398 Driver Execution Environment Core Interface Specification for
1399 more details and the GUID definition). If the
1400 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1401 database, then, if possible, full authentication should be
1402 skipped and the section contents simply returned in the
1403 OutputBuffer. In this case, the
1404 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1405 must be set on return. ExtractSection() is callable only from
1406 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1407 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1408 defined in RaiseTPL() in the UEFI 2.0 specification.
1411 @param This Indicates the
1412 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1414 @param InputSection Buffer containing the input GUIDed section
1415 to be processed. OutputBuffer OutputBuffer
1416 is allocated from boot services pool
1417 memory and contains the new section
1418 stream. The caller is responsible for
1419 freeing this buffer.
1421 @param OutputSize A pointer to a caller-allocated UINTN in
1422 which the size of OutputBuffer allocation
1423 is stored. If the function returns
1424 anything other than EFI_SUCCESS, the value
1425 of OutputSize is undefined.
1427 @param AuthenticationStatus A pointer to a caller-allocated
1428 UINT32 that indicates the
1429 authentication status of the
1430 output buffer. If the input
1432 GuidedSectionHeader.Attributes
1434 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1435 bit as clear, AuthenticationStatus
1436 must return zero. Both local bits
1437 (19:16) and aggregate bits (3:0)
1438 in AuthenticationStatus are
1439 returned by ExtractSection().
1440 These bits reflect the status of
1441 the extraction operation. The bit
1442 pattern in both regions must be
1443 the same, as the local and
1444 aggregate authentication statuses
1445 have equivalent meaning at this
1446 level. If the function returns
1447 anything other than EFI_SUCCESS,
1448 the value of AuthenticationStatus
1452 @retval EFI_SUCCESS The InputSection was successfully
1453 processed and the section contents were
1456 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1457 resources to process the
1460 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1461 not match this instance of the
1462 GUIDed Section Extraction
1467 CustomDecompressExtractSection (
1468 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL
*This
,
1469 IN CONST VOID
*InputSection
,
1470 OUT VOID
**OutputBuffer
,
1471 OUT UINTN
*OutputSize
,
1472 OUT UINT32
*AuthenticationStatus
1476 UINT8
*ScratchBuffer
;
1478 UINT32 SectionLength
;
1481 // Set authentic value to zero.
1483 *AuthenticationStatus
= 0;
1485 // Calculate Section data Size
1487 SectionLength
= *(UINT32
*) (((EFI_COMMON_SECTION_HEADER
*) InputSection
)->Size
) & 0x00ffffff;
1489 // Get compressed data information
1491 Status
= CustomDecompressGetInfo (
1492 (GUID
*) ((UINT8
*) InputSection
+ sizeof (EFI_COMMON_SECTION_HEADER
)),
1493 (UINT8
*) InputSection
+ sizeof (EFI_GUID_DEFINED_SECTION
),
1494 SectionLength
- sizeof (EFI_GUID_DEFINED_SECTION
),
1498 if (EFI_ERROR (Status
)) {
1502 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
1507 // Allocate scratch buffer
1509 ScratchBuffer
= CoreAllocateBootServicesPool (ScratchSize
);
1510 if (ScratchBuffer
== NULL
) {
1511 return EFI_OUT_OF_RESOURCES
;
1514 // Allocate destination buffer
1516 *OutputBuffer
= CoreAllocateBootServicesPool (*OutputSize
);
1517 if (*OutputBuffer
== NULL
) {
1518 CoreFreePool (ScratchBuffer
);
1519 return EFI_OUT_OF_RESOURCES
;
1523 // Call decompress function
1525 Status
= CustomDecompress (
1526 (GUID
*) ((UINT8
*) InputSection
+ sizeof (EFI_COMMON_SECTION_HEADER
)),
1527 (UINT8
*) InputSection
+ sizeof (EFI_GUID_DEFINED_SECTION
),
1531 if (EFI_ERROR (Status
)) {
1533 // Decompress failed
1535 CoreFreePool (ScratchBuffer
);
1536 CoreFreePool (*OutputBuffer
);
1537 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
1542 // Free unused scratch buffer.
1544 CoreFreePool (ScratchBuffer
);