TianoCore EDK2 master
Loading...
Searching...
No Matches
CoreSectionExtraction.c
Go to the documentation of this file.
1
35#include "DxeMain.h"
36
37//
38// Local defines and typedefs
39//
40#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
41#define CHILD_SECTION_NODE_FROM_LINK(Node) \
42 CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
43
44typedef struct {
45 UINT32 Signature;
46 LIST_ENTRY Link;
47 UINT32 Type;
48 UINT32 Size;
49 //
50 // StreamBase + OffsetInStream == pointer to section header in stream. The
51 // stream base is always known when walking the sections within.
52 //
53 UINT32 OffsetInStream;
54 //
55 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
56 // encapsulating section. Otherwise, it contains the stream handle
57 // of the encapsulated stream. This handle is ALWAYS produced any time an
58 // encapsulating child is encountered, irrespective of whether the
59 // encapsulated stream is processed further.
60 //
61 UINTN EncapsulatedStreamHandle;
62 EFI_GUID *EncapsulationGuid;
63 //
64 // If the section REQUIRES an extraction protocol, register for RPN
65 // when the required GUIDed extraction protocol becomes available.
66 //
67 EFI_EVENT Event;
69
70#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
71#define STREAM_NODE_FROM_LINK(Node) \
72 CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
73
74typedef struct {
75 UINT32 Signature;
76 LIST_ENTRY Link;
77 UINTN StreamHandle;
78 UINT8 *StreamBuffer;
79 UINTN StreamLength;
80 LIST_ENTRY Children;
81 //
82 // Authentication status is from GUIDed encapsulations.
83 //
84 UINT32 AuthenticationStatus;
86
87#define NULL_STREAM_HANDLE 0
88
89typedef struct {
90 CORE_SECTION_CHILD_NODE *ChildNode;
91 CORE_SECTION_STREAM_NODE *ParentStream;
92 VOID *Registration;
94
179EFIAPI
182 IN CONST VOID *InputSection,
183 OUT VOID **OutputBuffer,
184 OUT UINTN *OutputSize,
185 OUT UINT32 *AuthenticationStatus
186 );
187
188//
189// Module globals
190//
191LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
192
193EFI_HANDLE mSectionExtractionHandle = NULL;
194
195EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
197};
198
211EFIAPI
213 IN EFI_HANDLE ImageHandle,
214 IN EFI_SYSTEM_TABLE *SystemTable
215 )
216{
217 EFI_STATUS Status;
218 EFI_GUID *ExtractHandlerGuidTable;
219 UINTN ExtractHandlerNumber;
220
221 //
222 // Get custom extract guided section method guid list
223 //
224 ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
225
226 Status = EFI_SUCCESS;
227 //
228 // Install custom guided extraction protocol
229 //
230 while (ExtractHandlerNumber-- > 0) {
232 &mSectionExtractionHandle,
233 &ExtractHandlerGuidTable[ExtractHandlerNumber],
235 &mCustomGuidedSectionExtractionProtocol
236 );
237 ASSERT_EFI_ERROR (Status);
238 }
239
240 return Status;
241}
242
252BOOLEAN
254 IN VOID *SectionStream,
255 IN UINTN SectionStreamLength
256 )
257{
258 UINTN TotalLength;
259 UINTN SectionLength;
260 EFI_COMMON_SECTION_HEADER *SectionHeader;
261 EFI_COMMON_SECTION_HEADER *NextSectionHeader;
262
263 TotalLength = 0;
264 SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
265
266 while (TotalLength < SectionStreamLength) {
267 if (IS_SECTION2 (SectionHeader)) {
268 SectionLength = SECTION2_SIZE (SectionHeader);
269 } else {
270 SectionLength = SECTION_SIZE (SectionHeader);
271 }
272
273 TotalLength += SectionLength;
274
275 if (TotalLength == SectionStreamLength) {
276 return TRUE;
277 }
278
279 //
280 // Move to the next byte following the section...
281 //
282 SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)SectionHeader + SectionLength);
283
284 //
285 // Figure out where the next section begins
286 //
287 NextSectionHeader = ALIGN_POINTER (SectionHeader, 4);
288 TotalLength += (UINTN)NextSectionHeader - (UINTN)SectionHeader;
289 SectionHeader = NextSectionHeader;
290 }
291
292 ASSERT (FALSE);
293 return FALSE;
294}
295
331 IN UINTN SectionStreamLength,
332 IN VOID *SectionStream,
333 IN BOOLEAN AllocateBuffer,
334 IN UINT32 AuthenticationStatus,
335 OUT UINTN *SectionStreamHandle
336 )
337{
338 CORE_SECTION_STREAM_NODE *NewStream;
339 EFI_TPL OldTpl;
340
341 //
342 // Allocate a new stream
343 //
344 NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
345 if (NewStream == NULL) {
346 return EFI_OUT_OF_RESOURCES;
347 }
348
349 if (AllocateBuffer) {
350 //
351 // if we're here, we're double buffering, allocate the buffer and copy the
352 // data in
353 //
354 if (SectionStreamLength > 0) {
355 NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
356 if (NewStream->StreamBuffer == NULL) {
357 CoreFreePool (NewStream);
358 return EFI_OUT_OF_RESOURCES;
359 }
360
361 //
362 // Copy in stream data
363 //
364 CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
365 } else {
366 //
367 // It's possible to have a zero length section stream.
368 //
369 NewStream->StreamBuffer = NULL;
370 }
371 } else {
372 //
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.
376 //
377 NewStream->StreamBuffer = SectionStream;
378 }
379
380 //
381 // Initialize the rest of the section stream
382 //
383 NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
384 NewStream->StreamHandle = (UINTN)NewStream;
385 NewStream->StreamLength = SectionStreamLength;
386 InitializeListHead (&NewStream->Children);
387 NewStream->AuthenticationStatus = AuthenticationStatus;
388
389 //
390 // Add new stream to stream list
391 //
392 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
393 InsertTailList (&mStreamRoot, &NewStream->Link);
394 CoreRestoreTpl (OldTpl);
395
396 *SectionStreamHandle = NewStream->StreamHandle;
397
398 return EFI_SUCCESS;
399}
400
417EFIAPI
419 IN UINTN SectionStreamLength,
420 IN VOID *SectionStream,
421 OUT UINTN *SectionStreamHandle
422 )
423{
424 //
425 // Check to see section stream looks good...
426 //
427 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
428 return EFI_INVALID_PARAMETER;
429 }
430
431 return OpenSectionStreamEx (
432 SectionStreamLength,
433 SectionStream,
434 FALSE,
435 0,
436 SectionStreamHandle
437 );
438}
439
455BOOLEAN
459 IN EFI_SECTION_TYPE SearchType,
460 IN EFI_GUID *SectionDefinitionGuid
461 )
462{
463 EFI_GUID_DEFINED_SECTION *GuidedSection;
464
465 if (SearchType == EFI_SECTION_ALL) {
466 return TRUE;
467 }
468
469 if (Child->Type != SearchType) {
470 return FALSE;
471 }
472
473 if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
474 return TRUE;
475 }
476
477 GuidedSection = (EFI_GUID_DEFINED_SECTION *)(Stream->StreamBuffer + Child->OffsetInStream);
478 if (IS_SECTION2 (GuidedSection)) {
479 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *)GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
480 } else {
481 return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
482 }
483}
484
498BOOLEAN
500 IN EFI_GUID *GuidedSectionGuid,
501 OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction
502 )
503{
504 EFI_GUID *GuidRecorded;
505 VOID *Interface;
506 EFI_STATUS Status;
507
508 Interface = NULL;
509
510 //
511 // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
512 //
513 Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **)&GuidRecorded);
514 if (Status == EFI_SUCCESS) {
515 if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
516 //
517 // Found the recorded GuidedSectionGuid.
518 //
519 Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **)&Interface);
520 if (!EFI_ERROR (Status) && (Interface != NULL)) {
521 //
522 // Found the supported Guided Section Extraction Porotocol for the Guided Section.
523 //
524 *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *)Interface;
525 return TRUE;
526 }
527
528 return FALSE;
529 }
530 }
531
532 return FALSE;
533}
534
543VOID
544EFIAPI
546 IN EFI_EVENT Event,
547 IN VOID *RpnContext
548 )
549{
550 EFI_STATUS Status;
551 EFI_GUID_DEFINED_SECTION *GuidedHeader;
553 VOID *NewStreamBuffer;
554 UINTN NewStreamBufferSize;
555 UINT32 AuthenticationStatus;
556 RPN_EVENT_CONTEXT *Context;
557
558 Context = RpnContext;
559
560 GuidedHeader = (EFI_GUID_DEFINED_SECTION *)(Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
561 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
562
563 if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
564 return;
565 }
566
567 Status = GuidedExtraction->ExtractSection (
568 GuidedExtraction,
569 GuidedHeader,
570 &NewStreamBuffer,
571 &NewStreamBufferSize,
572 &AuthenticationStatus
573 );
574 ASSERT_EFI_ERROR (Status);
575
576 //
577 // Make sure we initialize the new stream with the correct
578 // authentication status for both aggregate and local status fields.
579 //
580 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
581 //
582 // OR in the parent stream's aggregate status.
583 //
584 AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
585 } else {
586 //
587 // since there's no authentication data contributed by the section,
588 // just inherit the full value from our immediate parent.
589 //
590 AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
591 }
592
593 Status = OpenSectionStreamEx (
594 NewStreamBufferSize,
595 NewStreamBuffer,
596 FALSE,
597 AuthenticationStatus,
598 &Context->ChildNode->EncapsulatedStreamHandle
599 );
600 ASSERT_EFI_ERROR (Status);
601
602 //
603 // Close the event when done.
604 //
605 gBS->CloseEvent (Event);
606 Context->ChildNode->Event = NULL;
607 FreePool (Context);
608}
609
617VOID
619 IN CORE_SECTION_STREAM_NODE *ParentStream,
620 IN CORE_SECTION_CHILD_NODE *ChildNode
621 )
622{
623 RPN_EVENT_CONTEXT *Context;
624
625 //
626 // Allocate new event structure and context
627 //
628 Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
629 ASSERT (Context != NULL);
630
631 Context->ChildNode = ChildNode;
632 Context->ParentStream = ParentStream;
633
634 Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
635 Context->ChildNode->EncapsulationGuid,
636 TPL_NOTIFY,
638 Context,
639 &Context->Registration
640 );
641}
642
667 IN UINT32 ChildOffset,
668 OUT CORE_SECTION_CHILD_NODE **ChildNode
669 )
670{
671 EFI_STATUS Status;
672 EFI_COMMON_SECTION_HEADER *SectionHeader;
673 EFI_COMPRESSION_SECTION *CompressionHeader;
674 EFI_GUID_DEFINED_SECTION *GuidedHeader;
677 VOID *NewStreamBuffer;
678 VOID *ScratchBuffer;
679 UINT32 ScratchSize;
680 UINTN NewStreamBufferSize;
681 UINT32 AuthenticationStatus;
682 VOID *CompressionSource;
683 UINT32 CompressionSourceSize;
684 UINT32 UncompressedLength;
685 UINT8 CompressionType;
686 UINT16 GuidedSectionAttributes;
687
689
690 SectionHeader = (EFI_COMMON_SECTION_HEADER *)(Stream->StreamBuffer + ChildOffset);
691
692 //
693 // Allocate a new node
694 //
695 *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
696 Node = *ChildNode;
697 if (Node == NULL) {
698 return EFI_OUT_OF_RESOURCES;
699 }
700
701 //
702 // Now initialize it
703 //
704 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
705 Node->Type = SectionHeader->Type;
706 if (IS_SECTION2 (SectionHeader)) {
707 Node->Size = SECTION2_SIZE (SectionHeader);
708 } else {
709 Node->Size = SECTION_SIZE (SectionHeader);
710 }
711
712 Node->OffsetInStream = ChildOffset;
713 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
714 Node->EncapsulationGuid = NULL;
715
716 //
717 // If it's an encapsulating section, then create the new section stream also
718 //
719 switch (Node->Type) {
721 //
722 // Get the CompressionSectionHeader
723 //
724 if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
725 CoreFreePool (Node);
726 return EFI_NOT_FOUND;
727 }
728
729 CompressionHeader = (EFI_COMPRESSION_SECTION *)SectionHeader;
730
731 if (IS_SECTION2 (CompressionHeader)) {
732 CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
733 CompressionSourceSize = (UINT32)(SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
734 UncompressedLength = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->UncompressedLength;
735 CompressionType = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->CompressionType;
736 } else {
737 CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
738 CompressionSourceSize = (UINT32)(SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
739 UncompressedLength = CompressionHeader->UncompressedLength;
740 CompressionType = CompressionHeader->CompressionType;
741 }
742
743 //
744 // Allocate space for the new stream
745 //
746 if (UncompressedLength > 0) {
747 NewStreamBufferSize = UncompressedLength;
748 NewStreamBuffer = AllocatePool (NewStreamBufferSize);
749 if (NewStreamBuffer == NULL) {
750 CoreFreePool (Node);
751 return EFI_OUT_OF_RESOURCES;
752 }
753
754 if (CompressionType == EFI_NOT_COMPRESSED) {
755 //
756 // stream is not actually compressed, just encapsulated. So just copy it.
757 //
758 CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
759 } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
760 //
761 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
762 //
763
764 //
765 // Decompress the stream
766 //
767 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
768 ASSERT_EFI_ERROR (Status);
769 ASSERT (Decompress != NULL);
770
771 Status = Decompress->GetInfo (
773 CompressionSource,
774 CompressionSourceSize,
775 (UINT32 *)&NewStreamBufferSize,
776 &ScratchSize
777 );
778 if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
779 CoreFreePool (Node);
780 CoreFreePool (NewStreamBuffer);
781 if (!EFI_ERROR (Status)) {
782 Status = EFI_BAD_BUFFER_SIZE;
783 }
784
785 return Status;
786 }
787
788 ScratchBuffer = AllocatePool (ScratchSize);
789 if (ScratchBuffer == NULL) {
790 CoreFreePool (Node);
791 CoreFreePool (NewStreamBuffer);
792 return EFI_OUT_OF_RESOURCES;
793 }
794
795 Status = Decompress->Decompress (
797 CompressionSource,
798 CompressionSourceSize,
799 NewStreamBuffer,
800 (UINT32)NewStreamBufferSize,
801 ScratchBuffer,
802 ScratchSize
803 );
804 CoreFreePool (ScratchBuffer);
805 if (EFI_ERROR (Status)) {
806 CoreFreePool (Node);
807 CoreFreePool (NewStreamBuffer);
808 return Status;
809 }
810 }
811 } else {
812 NewStreamBuffer = NULL;
813 NewStreamBufferSize = 0;
814 }
815
816 Status = OpenSectionStreamEx (
817 NewStreamBufferSize,
818 NewStreamBuffer,
819 FALSE,
820 Stream->AuthenticationStatus,
821 &Node->EncapsulatedStreamHandle
822 );
823 if (EFI_ERROR (Status)) {
824 CoreFreePool (Node);
825 CoreFreePool (NewStreamBuffer);
826 return Status;
827 }
828
829 break;
830
831 case EFI_SECTION_GUID_DEFINED:
832 GuidedHeader = (EFI_GUID_DEFINED_SECTION *)SectionHeader;
833 if (IS_SECTION2 (GuidedHeader)) {
834 Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->SectionDefinitionGuid);
835 GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->Attributes;
836 } else {
837 Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
838 GuidedSectionAttributes = GuidedHeader->Attributes;
839 }
840
841 if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
842 //
843 // NewStreamBuffer is always allocated by ExtractSection... No caller
844 // allocation here.
845 //
846 Status = GuidedExtraction->ExtractSection (
847 GuidedExtraction,
848 GuidedHeader,
849 &NewStreamBuffer,
850 &NewStreamBufferSize,
851 &AuthenticationStatus
852 );
853 if (EFI_ERROR (Status)) {
854 CoreFreePool (*ChildNode);
855 return EFI_PROTOCOL_ERROR;
856 }
857
858 //
859 // Make sure we initialize the new stream with the correct
860 // authentication status for both aggregate and local status fields.
861 //
862 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
863 //
864 // OR in the parent stream's aggregate status.
865 //
866 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
867 } else {
868 //
869 // since there's no authentication data contributed by the section,
870 // just inherit the full value from our immediate parent.
871 //
872 AuthenticationStatus = Stream->AuthenticationStatus;
873 }
874
875 Status = OpenSectionStreamEx (
876 NewStreamBufferSize,
877 NewStreamBuffer,
878 FALSE,
879 AuthenticationStatus,
880 &Node->EncapsulatedStreamHandle
881 );
882 if (EFI_ERROR (Status)) {
883 CoreFreePool (*ChildNode);
884 CoreFreePool (NewStreamBuffer);
885 return Status;
886 }
887 } else {
888 //
889 // There's no GUIDed section extraction protocol available.
890 //
891 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
892 //
893 // If the section REQUIRES an extraction protocol, register for RPN
894 // when the required GUIDed extraction protocol becomes available.
895 //
896 CreateGuidedExtractionRpnEvent (Stream, Node);
897 } else {
898 //
899 // Figure out the proper authentication status
900 //
901 AuthenticationStatus = Stream->AuthenticationStatus;
902
903 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
904 AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
905 }
906
907 if (IS_SECTION2 (GuidedHeader)) {
908 Status = OpenSectionStreamEx (
909 SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
910 (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
911 TRUE,
912 AuthenticationStatus,
913 &Node->EncapsulatedStreamHandle
914 );
915 } else {
916 Status = OpenSectionStreamEx (
917 SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
918 (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
919 TRUE,
920 AuthenticationStatus,
921 &Node->EncapsulatedStreamHandle
922 );
923 }
924
925 if (EFI_ERROR (Status)) {
926 CoreFreePool (Node);
927 return Status;
928 }
929 }
930 }
931
932 break;
933
934 default:
935
936 //
937 // Nothing to do if it's a leaf
938 //
939 break;
940 }
941
942 //
943 // Last, add the new child node to the stream
944 //
945 InsertTailList (&Stream->Children, &Node->Link);
946
947 return EFI_SUCCESS;
948}
949
984 IN CORE_SECTION_STREAM_NODE *SourceStream,
985 IN EFI_SECTION_TYPE SearchType,
986 IN OUT UINTN *SectionInstance,
987 IN EFI_GUID *SectionDefinitionGuid,
988 IN UINT32 Depth,
989 OUT CORE_SECTION_CHILD_NODE **FoundChild,
990 OUT CORE_SECTION_STREAM_NODE **FoundStream,
991 OUT UINT32 *AuthenticationStatus
992 )
993{
994 CORE_SECTION_CHILD_NODE *CurrentChildNode;
995 CORE_SECTION_CHILD_NODE *RecursedChildNode;
996 CORE_SECTION_STREAM_NODE *RecursedFoundStream;
997 UINT32 NextChildOffset;
998 EFI_STATUS ErrorStatus;
999 EFI_STATUS Status;
1000
1001 ASSERT (*SectionInstance > 0);
1002
1003 if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {
1004 return EFI_ABORTED;
1005 }
1006
1007 CurrentChildNode = NULL;
1008 ErrorStatus = EFI_NOT_FOUND;
1009
1010 if (SourceStream->StreamLength == 0) {
1011 return EFI_NOT_FOUND;
1012 }
1013
1014 if (IsListEmpty (&SourceStream->Children) &&
1015 (SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)))
1016 {
1017 //
1018 // This occurs when a section stream exists, but no child sections
1019 // have been parsed out yet. Therefore, extract the first child and add it
1020 // to the list of children so we can get started.
1021 // Section stream may contain an array of zero or more bytes.
1022 // So, its size should be >= the size of commen section header.
1023 //
1024 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
1025 if (EFI_ERROR (Status)) {
1026 return Status;
1027 }
1028 }
1029
1030 //
1031 // At least one child has been parsed out of the section stream. So, walk
1032 // through the sections that have already been parsed out looking for the
1033 // requested section, if necessary, continue parsing section stream and
1034 // adding children until either the requested section is found, or we run
1035 // out of data
1036 //
1037 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode (&SourceStream->Children));
1038
1039 for ( ; ;) {
1040 ASSERT (CurrentChildNode != NULL);
1041 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
1042 //
1043 // The type matches, so check the instance count to see if it's the one we want
1044 //
1045 (*SectionInstance)--;
1046 if (*SectionInstance == 0) {
1047 //
1048 // Got it!
1049 //
1050 *FoundChild = CurrentChildNode;
1051 *FoundStream = SourceStream;
1052 *AuthenticationStatus = SourceStream->AuthenticationStatus;
1053 return EFI_SUCCESS;
1054 }
1055 }
1056
1057 //
1058 // Type mismatch, or we haven't found the desired instance yet.
1059 //
1060 ASSERT (*SectionInstance > 0);
1061
1062 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1063 //
1064 // If the current node is an encapsulating node, recurse into it...
1065 //
1066 Status = FindChildNode (
1067 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
1068 SearchType,
1069 SectionInstance,
1070 SectionDefinitionGuid,
1071 Depth + 1,
1072 &RecursedChildNode,
1073 &RecursedFoundStream,
1074 AuthenticationStatus
1075 );
1076 if (*SectionInstance == 0) {
1077 //
1078 // The recursive FindChildNode() call decreased (*SectionInstance) to
1079 // zero.
1080 //
1081 ASSERT_EFI_ERROR (Status);
1082 *FoundChild = RecursedChildNode;
1083 *FoundStream = RecursedFoundStream;
1084 return EFI_SUCCESS;
1085 } else {
1086 if (Status == EFI_ABORTED) {
1087 //
1088 // If the recursive call was aborted due to nesting depth, stop
1089 // looking for the requested child node. The skipped subtree could
1090 // throw off the instance counting.
1091 //
1092 return Status;
1093 }
1094
1095 //
1096 // Save the error code and continue to find the requested child node in
1097 // the rest of the stream.
1098 //
1099 ErrorStatus = Status;
1100 }
1101 } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
1102 //
1103 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1104 // because a required GUIDED section extraction protocol does not exist.
1105 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1106 //
1107 ErrorStatus = EFI_PROTOCOL_ERROR;
1108 }
1109
1110 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
1111 //
1112 // We haven't found the child node we're interested in yet, but there's
1113 // still more nodes that have already been parsed so get the next one
1114 // and continue searching..
1115 //
1116 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
1117 } else {
1118 //
1119 // We've exhausted children that have already been parsed, so see if
1120 // there's any more data and continue parsing out more children if there
1121 // is.
1122 //
1123 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
1124 //
1125 // Round up to 4 byte boundary
1126 //
1127 NextChildOffset += 3;
1128 NextChildOffset &= ~(UINTN)3;
1129 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
1130 //
1131 // There's an unparsed child remaining in the stream, so create a new child node
1132 //
1133 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
1134 if (EFI_ERROR (Status)) {
1135 return Status;
1136 }
1137 } else {
1138 ASSERT (EFI_ERROR (ErrorStatus));
1139 return ErrorStatus;
1140 }
1141 }
1142 }
1143}
1144
1159 IN UINTN SearchHandle,
1160 OUT CORE_SECTION_STREAM_NODE **FoundStream
1161 )
1162{
1163 CORE_SECTION_STREAM_NODE *StreamNode;
1164
1165 if (!IsListEmpty (&mStreamRoot)) {
1166 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
1167 for ( ; ;) {
1168 if (StreamNode->StreamHandle == SearchHandle) {
1169 *FoundStream = StreamNode;
1170 return EFI_SUCCESS;
1171 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
1172 break;
1173 } else {
1174 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
1175 }
1176 }
1177 }
1178
1179 return EFI_NOT_FOUND;
1180}
1181
1241EFIAPI
1243 IN UINTN SectionStreamHandle,
1244 IN EFI_SECTION_TYPE *SectionType,
1245 IN EFI_GUID *SectionDefinitionGuid,
1246 IN UINTN SectionInstance,
1247 IN VOID **Buffer,
1248 IN OUT UINTN *BufferSize,
1249 OUT UINT32 *AuthenticationStatus,
1250 IN BOOLEAN IsFfs3Fv
1251 )
1252{
1253 CORE_SECTION_STREAM_NODE *StreamNode;
1254 EFI_TPL OldTpl;
1255 EFI_STATUS Status;
1256 CORE_SECTION_CHILD_NODE *ChildNode;
1257 CORE_SECTION_STREAM_NODE *ChildStreamNode;
1258 UINTN CopySize;
1259 UINT32 ExtractedAuthenticationStatus;
1260 UINTN Instance;
1261 UINT8 *CopyBuffer;
1262 UINTN SectionSize;
1264
1265 ChildStreamNode = NULL;
1266 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1267 Instance = SectionInstance + 1;
1268
1269 //
1270 // Locate target stream
1271 //
1272 Status = FindStreamNode (SectionStreamHandle, &StreamNode);
1273 if (EFI_ERROR (Status)) {
1274 Status = EFI_INVALID_PARAMETER;
1275 goto GetSection_Done;
1276 }
1277
1278 //
1279 // Found the stream, now locate and return the appropriate section
1280 //
1281 if (SectionType == NULL) {
1282 //
1283 // SectionType == NULL means return the WHOLE section stream...
1284 //
1285 CopySize = StreamNode->StreamLength;
1286 CopyBuffer = StreamNode->StreamBuffer;
1287 *AuthenticationStatus = StreamNode->AuthenticationStatus;
1288 } else {
1289 //
1290 // There's a requested section type, so go find it and return it...
1291 //
1292 Status = FindChildNode (
1293 StreamNode,
1294 *SectionType,
1295 &Instance,
1296 SectionDefinitionGuid,
1297 0, // encapsulation depth
1298 &ChildNode,
1299 &ChildStreamNode,
1300 &ExtractedAuthenticationStatus
1301 );
1302 if (EFI_ERROR (Status)) {
1303 if (Status == EFI_ABORTED) {
1304 DEBUG ((
1305 DEBUG_ERROR,
1306 "%a: recursion aborted due to nesting depth\n",
1307 __func__
1308 ));
1309 //
1310 // Map "aborted" to "not found".
1311 //
1312 Status = EFI_NOT_FOUND;
1313 }
1314
1315 goto GetSection_Done;
1316 }
1317
1318 Section = (EFI_COMMON_SECTION_HEADER *)(ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
1319
1320 if (IS_SECTION2 (Section)) {
1321 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
1322 if (!IsFfs3Fv) {
1323 DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
1324 Status = EFI_NOT_FOUND;
1325 goto GetSection_Done;
1326 }
1327
1328 CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
1329 CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2);
1330 } else {
1331 CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
1332 CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER);
1333 }
1334
1335 *AuthenticationStatus = ExtractedAuthenticationStatus;
1336 }
1337
1338 SectionSize = CopySize;
1339 if (*Buffer != NULL) {
1340 //
1341 // Caller allocated buffer. Fill to size and return required size...
1342 //
1343 if (*BufferSize < CopySize) {
1344 Status = EFI_WARN_BUFFER_TOO_SMALL;
1345 CopySize = *BufferSize;
1346 }
1347 } else {
1348 //
1349 // Callee allocated buffer. Allocate buffer and return size.
1350 //
1351 *Buffer = AllocatePool (CopySize);
1352 if (*Buffer == NULL) {
1353 Status = EFI_OUT_OF_RESOURCES;
1354 goto GetSection_Done;
1355 }
1356 }
1357
1358 CopyMem (*Buffer, CopyBuffer, CopySize);
1359 *BufferSize = SectionSize;
1360
1361GetSection_Done:
1362 CoreRestoreTpl (OldTpl);
1363
1364 return Status;
1365}
1366
1373VOID
1375 IN CORE_SECTION_CHILD_NODE *ChildNode
1376 )
1377{
1378 ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
1379 //
1380 // Remove the child from it's list
1381 //
1382 RemoveEntryList (&ChildNode->Link);
1383
1384 if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1385 //
1386 // If it's an encapsulating section, we close the resulting section stream.
1387 // CloseSectionStream will free all memory associated with the stream.
1388 //
1389 CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
1390 }
1391
1392 if (ChildNode->Event != NULL) {
1393 gBS->CloseEvent (ChildNode->Event);
1394 }
1395
1396 //
1397 // Last, free the child node itself
1398 //
1399 CoreFreePool (ChildNode);
1400}
1401
1416EFIAPI
1418 IN UINTN StreamHandleToClose,
1419 IN BOOLEAN FreeStreamBuffer
1420 )
1421{
1422 CORE_SECTION_STREAM_NODE *StreamNode;
1423 EFI_TPL OldTpl;
1424 EFI_STATUS Status;
1425 LIST_ENTRY *Link;
1426 CORE_SECTION_CHILD_NODE *ChildNode;
1427
1428 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1429
1430 //
1431 // Locate target stream
1432 //
1433 Status = FindStreamNode (StreamHandleToClose, &StreamNode);
1434 if (!EFI_ERROR (Status)) {
1435 //
1436 // Found the stream, so close it
1437 //
1438 RemoveEntryList (&StreamNode->Link);
1439 while (!IsListEmpty (&StreamNode->Children)) {
1440 Link = GetFirstNode (&StreamNode->Children);
1441 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
1442 FreeChildNode (ChildNode);
1443 }
1444
1445 if (FreeStreamBuffer) {
1446 CoreFreePool (StreamNode->StreamBuffer);
1447 }
1448
1449 CoreFreePool (StreamNode);
1450 Status = EFI_SUCCESS;
1451 } else {
1452 Status = EFI_INVALID_PARAMETER;
1453 }
1454
1455 CoreRestoreTpl (OldTpl);
1456 return Status;
1457}
1458
1543EFIAPI
1546 IN CONST VOID *InputSection,
1547 OUT VOID **OutputBuffer,
1548 OUT UINTN *OutputSize,
1549 OUT UINT32 *AuthenticationStatus
1550 )
1551{
1552 EFI_STATUS Status;
1553 VOID *ScratchBuffer;
1554 VOID *AllocatedOutputBuffer;
1555 UINT32 OutputBufferSize;
1556 UINT32 ScratchBufferSize;
1557 UINT16 SectionAttribute;
1558
1559 //
1560 // Init local variable
1561 //
1562 ScratchBuffer = NULL;
1563 AllocatedOutputBuffer = NULL;
1564
1565 //
1566 // Call GetInfo to get the size and attribute of input guided section data.
1567 //
1569 InputSection,
1570 &OutputBufferSize,
1571 &ScratchBufferSize,
1572 &SectionAttribute
1573 );
1574
1575 if (EFI_ERROR (Status)) {
1576 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
1577 return Status;
1578 }
1579
1580 if (ScratchBufferSize > 0) {
1581 //
1582 // Allocate scratch buffer
1583 //
1584 ScratchBuffer = AllocatePool (ScratchBufferSize);
1585 if (ScratchBuffer == NULL) {
1586 return EFI_OUT_OF_RESOURCES;
1587 }
1588 }
1589
1590 if (OutputBufferSize > 0) {
1591 //
1592 // Allocate output buffer
1593 //
1594 AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
1595 if (AllocatedOutputBuffer == NULL) {
1596 if (ScratchBuffer != NULL) {
1597 FreePool (ScratchBuffer);
1598 }
1599
1600 return EFI_OUT_OF_RESOURCES;
1601 }
1602
1603 *OutputBuffer = AllocatedOutputBuffer;
1604 }
1605
1606 //
1607 // Call decode function to extract raw data from the guided section.
1608 //
1609 Status = ExtractGuidedSectionDecode (
1610 InputSection,
1611 OutputBuffer,
1612 ScratchBuffer,
1613 AuthenticationStatus
1614 );
1615 if (EFI_ERROR (Status)) {
1616 //
1617 // Decode failed
1618 //
1619 if (AllocatedOutputBuffer != NULL) {
1620 CoreFreePool (AllocatedOutputBuffer);
1621 }
1622
1623 if (ScratchBuffer != NULL) {
1624 CoreFreePool (ScratchBuffer);
1625 }
1626
1627 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
1628 return Status;
1629 }
1630
1631 if (*OutputBuffer != AllocatedOutputBuffer) {
1632 //
1633 // OutputBuffer was returned as a different value,
1634 // so copy section contents to the allocated memory buffer.
1635 //
1636 CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
1637 *OutputBuffer = AllocatedOutputBuffer;
1638 }
1639
1640 //
1641 // Set real size of output buffer.
1642 //
1643 *OutputSize = (UINTN)OutputBufferSize;
1644
1645 //
1646 // Free unused scratch buffer.
1647 //
1648 if (ScratchBuffer != NULL) {
1649 CoreFreePool (ScratchBuffer);
1650 }
1651
1652 return EFI_SUCCESS;
1653}
UINT64 UINTN
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
BOOLEAN EFIAPI IsNodeAtEnd(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:481
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
NODE Child(IN NODE LoopVar6, IN UINT8 LoopVar5)
Definition: Compress.c:265
EFI_STATUS EFIAPI GetSection(IN UINTN SectionStreamHandle, IN EFI_SECTION_TYPE *SectionType, IN EFI_GUID *SectionDefinitionGuid, IN UINTN SectionInstance, IN VOID **Buffer, IN OUT UINTN *BufferSize, OUT UINT32 *AuthenticationStatus, IN BOOLEAN IsFfs3Fv)
VOID FreeChildNode(IN CORE_SECTION_CHILD_NODE *ChildNode)
VOID EFIAPI NotifyGuidedExtraction(IN EFI_EVENT Event, IN VOID *RpnContext)
BOOLEAN VerifyGuidedSectionGuid(IN EFI_GUID *GuidedSectionGuid, OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction)
EFI_STATUS EFIAPI InitializeSectionExtraction(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
VOID CreateGuidedExtractionRpnEvent(IN CORE_SECTION_STREAM_NODE *ParentStream, IN CORE_SECTION_CHILD_NODE *ChildNode)
EFI_STATUS EFIAPI OpenSectionStream(IN UINTN SectionStreamLength, IN VOID *SectionStream, OUT UINTN *SectionStreamHandle)
BOOLEAN ChildIsType(IN CORE_SECTION_STREAM_NODE *Stream, IN CORE_SECTION_CHILD_NODE *Child, IN EFI_SECTION_TYPE SearchType, IN EFI_GUID *SectionDefinitionGuid)
EFI_STATUS EFIAPI CloseSectionStream(IN UINTN StreamHandleToClose, IN BOOLEAN FreeStreamBuffer)
EFI_STATUS OpenSectionStreamEx(IN UINTN SectionStreamLength, IN VOID *SectionStream, IN BOOLEAN AllocateBuffer, IN UINT32 AuthenticationStatus, OUT UINTN *SectionStreamHandle)
EFI_STATUS CreateChildNode(IN CORE_SECTION_STREAM_NODE *Stream, IN UINT32 ChildOffset, OUT CORE_SECTION_CHILD_NODE **ChildNode)
EFI_STATUS FindStreamNode(IN UINTN SearchHandle, OUT CORE_SECTION_STREAM_NODE **FoundStream)
BOOLEAN IsValidSectionStream(IN VOID *SectionStream, IN UINTN SectionStreamLength)
EFI_STATUS FindChildNode(IN CORE_SECTION_STREAM_NODE *SourceStream, IN EFI_SECTION_TYPE SearchType, IN OUT UINTN *SectionInstance, IN EFI_GUID *SectionDefinitionGuid, IN UINT32 Depth, OUT CORE_SECTION_CHILD_NODE **FoundChild, OUT CORE_SECTION_STREAM_NODE **FoundStream, OUT UINT32 *AuthenticationStatus)
EFI_STATUS EFIAPI CustomGuidedSectionExtract(IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This, IN CONST VOID *InputSection, OUT VOID **OutputBuffer, OUT UINTN *OutputSize, OUT UINT32 *AuthenticationStatus)
EFI_STATUS EFIAPI CoreLocateProtocol(IN EFI_GUID *Protocol, IN VOID *Registration OPTIONAL, OUT VOID **Interface)
Definition: Locate.c:575
EFI_TPL EFIAPI CoreRaiseTpl(IN EFI_TPL NewTpl)
Definition: Tpl.c:57
EFI_STATUS EFIAPI CoreInstallProtocolInterface(IN OUT EFI_HANDLE *UserHandle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN VOID *Interface)
Definition: Handle.c:398
VOID EFIAPI CoreRestoreTpl(IN EFI_TPL NewTpl)
Definition: Tpl.c:95
EFI_STATUS EFIAPI CoreFreePool(IN VOID *Buffer)
Definition: Pool.c:591
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI Decompress(IN CONST EFI_PEI_DECOMPRESS_PPI *This, IN CONST EFI_COMPRESSION_SECTION *CompressionSection, OUT VOID **OutputBuffer, OUT UINTN *OutputSize)
Definition: DxeLoad.c:674
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define ALIGN_POINTER(Pointer, Alignment)
Definition: Base.h:963
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED
#define EFI_SECTION_COMPRESSION
#define EFI_SECTION_ALL
#define EFI_NOT_COMPRESSED
#define SECTION_SIZE(SectionHeaderPtr)
RETURN_STATUS EFIAPI ExtractGuidedSectionGetInfo(IN CONST VOID *InputSection, OUT UINT32 *OutputBufferSize, OUT UINT32 *ScratchBufferSize, OUT UINT16 *SectionAttribute)
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI EfiGetSystemConfigurationTable(IN EFI_GUID *TableGuid, OUT VOID **Table)
Definition: UefiLib.c:82
EFI_EVENT EFIAPI EfiCreateProtocolNotifyEvent(IN EFI_GUID *ProtocolGuid, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext OPTIONAL, OUT VOID **Registration)
Definition: UefiLib.c:134
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
EFI_COMMON_SECTION_HEADER CommonHeader
Definition: Base.h:213