]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / SectionExtraction / CoreSectionExtraction.c
1 /** @file
2 Section Extraction Protocol implementation.
3
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
6 encapsulations.
7
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().
11
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.
14
15 If a GUIDed encapsulation is encountered, there are three possiblilites.
16
17 1) A support protocol is found, in which the stream is simply processed with
18 the support protocol.
19
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.
26
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.
29
30 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
31 SPDX-License-Identifier: BSD-2-Clause-Patent
32
33 **/
34
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
44 typedef 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;
68 } CORE_SECTION_CHILD_NODE;
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
74 typedef 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;
85 } CORE_SECTION_STREAM_NODE;
86
87 #define NULL_STREAM_HANDLE 0
88
89 typedef struct {
90 CORE_SECTION_CHILD_NODE *ChildNode;
91 CORE_SECTION_STREAM_NODE *ParentStream;
92 VOID *Registration;
93 } RPN_EVENT_CONTEXT;
94
95 /**
96 The ExtractSection() function processes the input section and
97 allocates a buffer from the pool in which it returns the section
98 contents. If the section being extracted contains
99 authentication information (the section's
100 GuidedSectionHeader.Attributes field has the
101 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
102 returned in AuthenticationStatus must reflect the results of
103 the authentication operation. Depending on the algorithm and
104 size of the encapsulated data, the time that is required to do
105 a full authentication may be prohibitively long for some
106 classes of systems. To indicate this, use
107 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
108 the security policy driver (see the Platform Initialization
109 Driver Execution Environment Core Interface Specification for
110 more details and the GUID definition). If the
111 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
112 database, then, if possible, full authentication should be
113 skipped and the section contents simply returned in the
114 OutputBuffer. In this case, the
115 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
116 must be set on return. ExtractSection() is callable only from
117 TPL_NOTIFY and below. Behavior of ExtractSection() at any
118 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
119 defined in RaiseTPL() in the UEFI 2.0 specification.
120
121
122 @param This Indicates the
123 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
124 @param InputSection Buffer containing the input GUIDed section
125 to be processed. OutputBuffer OutputBuffer
126 is allocated from boot services pool
127 memory and contains the new section
128 stream. The caller is responsible for
129 freeing this buffer.
130 @param OutputBuffer *OutputBuffer is allocated from boot services
131 pool memory and contains the new section stream.
132 The caller is responsible for freeing this buffer.
133 @param OutputSize A pointer to a caller-allocated UINTN in
134 which the size of OutputBuffer allocation
135 is stored. If the function returns
136 anything other than EFI_SUCCESS, the value
137 of OutputSize is undefined.
138
139 @param AuthenticationStatus A pointer to a caller-allocated
140 UINT32 that indicates the
141 authentication status of the
142 output buffer. If the input
143 section's
144 GuidedSectionHeader.Attributes
145 field has the
146 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
147 bit as clear, AuthenticationStatus
148 must return zero. Both local bits
149 (19:16) and aggregate bits (3:0)
150 in AuthenticationStatus are
151 returned by ExtractSection().
152 These bits reflect the status of
153 the extraction operation. The bit
154 pattern in both regions must be
155 the same, as the local and
156 aggregate authentication statuses
157 have equivalent meaning at this
158 level. If the function returns
159 anything other than EFI_SUCCESS,
160 the value of AuthenticationStatus
161 is undefined.
162
163
164 @retval EFI_SUCCESS The InputSection was successfully
165 processed and the section contents were
166 returned.
167
168 @retval EFI_OUT_OF_RESOURCES The system has insufficient
169 resources to process the
170 request.
171
172 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
173 not match this instance of the
174 GUIDed Section Extraction
175 Protocol.
176
177 **/
178 EFI_STATUS
179 EFIAPI
180 CustomGuidedSectionExtract (
181 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
182 IN CONST VOID *InputSection,
183 OUT VOID **OutputBuffer,
184 OUT UINTN *OutputSize,
185 OUT UINT32 *AuthenticationStatus
186 );
187
188 //
189 // Module globals
190 //
191 LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
192
193 EFI_HANDLE mSectionExtractionHandle = NULL;
194
195 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
196 CustomGuidedSectionExtract
197 };
198
199 /**
200 Entry point of the section extraction code. Initializes an instance of the
201 section extraction interface and installs it on a new handle.
202
203 @param ImageHandle A handle for the image that is initializing this driver
204 @param SystemTable A pointer to the EFI system table
205
206 @retval EFI_SUCCESS Driver initialized successfully
207 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
208
209 **/
210 EFI_STATUS
211 EFIAPI
212 InitializeSectionExtraction (
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) {
231 Status = CoreInstallProtocolInterface (
232 &mSectionExtractionHandle,
233 &ExtractHandlerGuidTable[ExtractHandlerNumber],
234 EFI_NATIVE_INTERFACE,
235 &mCustomGuidedSectionExtractionProtocol
236 );
237 ASSERT_EFI_ERROR (Status);
238 }
239
240 return Status;
241 }
242
243 /**
244 Check if a stream is valid.
245
246 @param SectionStream The section stream to be checked
247 @param SectionStreamLength The length of section stream
248
249 @return A boolean value indicating the validness of the section stream.
250
251 **/
252 BOOLEAN
253 IsValidSectionStream (
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
296 /**
297 Worker function. Constructor for section streams.
298
299 @param SectionStreamLength Size in bytes of the section stream.
300 @param SectionStream Buffer containing the new section stream.
301 @param AllocateBuffer Indicates whether the stream buffer is to be
302 copied or the input buffer is to be used in
303 place. AuthenticationStatus- Indicates the
304 default authentication status for the new
305 stream.
306 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
307 indicates the authentication status of the
308 output buffer. If the input section's
309 GuidedSectionHeader.Attributes field
310 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
311 bit as clear, AuthenticationStatus must return
312 zero. Both local bits (19:16) and aggregate
313 bits (3:0) in AuthenticationStatus are returned
314 by ExtractSection(). These bits reflect the
315 status of the extraction operation. The bit
316 pattern in both regions must be the same, as
317 the local and aggregate authentication statuses
318 have equivalent meaning at this level. If the
319 function returns anything other than
320 EFI_SUCCESS, the value of *AuthenticationStatus
321 is undefined.
322 @param SectionStreamHandle A pointer to a caller allocated section stream
323 handle.
324
325 @retval EFI_SUCCESS Stream was added to stream database.
326 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
327
328 **/
329 EFI_STATUS
330 OpenSectionStreamEx (
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
401 /**
402 SEP member function. This function creates and returns a new section stream
403 handle to represent the new section stream.
404
405 @param SectionStreamLength Size in bytes of the section stream.
406 @param SectionStream Buffer containing the new section stream.
407 @param SectionStreamHandle A pointer to a caller allocated UINTN that on
408 output contains the new section stream handle.
409
410 @retval EFI_SUCCESS The section stream is created successfully.
411 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
412 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
413 of last section.
414
415 **/
416 EFI_STATUS
417 EFIAPI
418 OpenSectionStream (
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
440 /**
441 Worker function. Determine if the input stream:child matches the input type.
442
443 @param Stream Indicates the section stream associated with the
444 child
445 @param Child Indicates the child to check
446 @param SearchType Indicates the type of section to check against
447 for
448 @param SectionDefinitionGuid Indicates the GUID to check against if the type
449 is EFI_SECTION_GUID_DEFINED
450
451 @retval TRUE The child matches
452 @retval FALSE The child doesn't match
453
454 **/
455 BOOLEAN
456 ChildIsType (
457 IN CORE_SECTION_STREAM_NODE *Stream,
458 IN CORE_SECTION_CHILD_NODE *Child,
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
485 /**
486 Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
487
488 @param GuidedSectionGuid The Guided Section GUID.
489 @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
490 for the Guided Section.
491
492 @return TRUE The GuidedSectionGuid could be identified, and the pointer to
493 the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
494 @return FALSE The GuidedSectionGuid could not be identified, or
495 the Guided Section Extraction Protocol has not been installed yet.
496
497 **/
498 BOOLEAN
499 VerifyGuidedSectionGuid (
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
535 /**
536 RPN callback function. Initializes the section stream
537 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
538
539 @param Event The event that fired
540 @param RpnContext A pointer to the context that allows us to identify
541 the relevent encapsulation.
542 **/
543 VOID
544 EFIAPI
545 NotifyGuidedExtraction (
546 IN EFI_EVENT Event,
547 IN VOID *RpnContext
548 )
549 {
550 EFI_STATUS Status;
551 EFI_GUID_DEFINED_SECTION *GuidedHeader;
552 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
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
610 /**
611 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
612
613 @param ParentStream Indicates the parent of the ecnapsulation section (child)
614 @param ChildNode Indicates the child node that is the encapsulation section.
615
616 **/
617 VOID
618 CreateGuidedExtractionRpnEvent (
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,
637 NotifyGuidedExtraction,
638 Context,
639 &Context->Registration
640 );
641 }
642
643 /**
644 Worker function. Constructor for new child nodes.
645
646 @param Stream Indicates the section stream in which to add the
647 child.
648 @param ChildOffset Indicates the offset in Stream that is the
649 beginning of the child section.
650 @param ChildNode Indicates the Callee allocated and initialized
651 child.
652
653 @retval EFI_SUCCESS Child node was found and returned.
654 EFI_OUT_OF_RESOURCES- Memory allocation failed.
655 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
656 handles when the child node is created. If the
657 section type is GUID defined, and the extraction
658 GUID does not exist, and producing the stream
659 requires the GUID, then a protocol error is
660 generated and no child is produced. Values
661 returned by OpenSectionStreamEx.
662
663 **/
664 EFI_STATUS
665 CreateChildNode (
666 IN CORE_SECTION_STREAM_NODE *Stream,
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;
675 EFI_DECOMPRESS_PROTOCOL *Decompress;
676 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
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
688 CORE_SECTION_CHILD_NODE *Node;
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) {
720 case EFI_SECTION_COMPRESSION:
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 (
772 Decompress,
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 (
796 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
950 /**
951 Worker function Recursively searches / builds section stream database
952 looking for requested section.
953
954 @param SourceStream Indicates the section stream in which to do the
955 search.
956 @param SearchType Indicates the type of section to search for.
957 @param SectionInstance Indicates which instance of section to find.
958 This is an in/out parameter and it is 1-based,
959 to deal with recursions.
960 @param SectionDefinitionGuid Guid of section definition
961 @param Depth Nesting depth of encapsulation sections.
962 Callers different from FindChildNode() are
963 responsible for passing in a zero Depth.
964 @param FoundChild Output indicating the child node that is found.
965 @param FoundStream Output indicating which section stream the child
966 was found in. If this stream was generated as a
967 result of an encapsulation section, the
968 streamhandle is visible within the SEP driver
969 only.
970 @param AuthenticationStatus Indicates the authentication status of the found section.
971
972 @retval EFI_SUCCESS Child node was found and returned.
973 EFI_OUT_OF_RESOURCES- Memory allocation failed.
974 @retval EFI_NOT_FOUND Requested child node does not exist.
975 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
976 does not exist
977 @retval EFI_ABORTED Recursion aborted because Depth has been
978 greater than or equal to
979 PcdFwVolDxeMaxEncapsulationDepth.
980
981 **/
982 EFI_STATUS
983 FindChildNode (
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
1145 /**
1146 Worker function. Search stream database for requested stream handle.
1147
1148 @param SearchHandle Indicates which stream to look for.
1149 @param FoundStream Output pointer to the found stream.
1150
1151 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1152 the stream node.
1153 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1154 database.
1155
1156 **/
1157 EFI_STATUS
1158 FindStreamNode (
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
1182 /**
1183 SEP member function. Retrieves requested section from section stream.
1184
1185 @param SectionStreamHandle The section stream from which to extract the
1186 requested section.
1187 @param SectionType A pointer to the type of section to search for.
1188 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1189 then SectionDefinitionGuid indicates which of
1190 these types of sections to search for.
1191 @param SectionInstance Indicates which instance of the requested
1192 section to return.
1193 @param Buffer Double indirection to buffer. If *Buffer is
1194 non-null on input, then the buffer is caller
1195 allocated. If Buffer is NULL, then the buffer
1196 is callee allocated. In either case, the
1197 required buffer size is returned in *BufferSize.
1198 @param BufferSize On input, indicates the size of *Buffer if
1199 *Buffer is non-null on input. On output,
1200 indicates the required size (allocated size if
1201 callee allocated) of *Buffer.
1202 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1203 indicates the authentication status of the
1204 output buffer. If the input section's
1205 GuidedSectionHeader.Attributes field
1206 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1207 bit as clear, AuthenticationStatus must return
1208 zero. Both local bits (19:16) and aggregate
1209 bits (3:0) in AuthenticationStatus are returned
1210 by ExtractSection(). These bits reflect the
1211 status of the extraction operation. The bit
1212 pattern in both regions must be the same, as
1213 the local and aggregate authentication statuses
1214 have equivalent meaning at this level. If the
1215 function returns anything other than
1216 EFI_SUCCESS, the value of *AuthenticationStatus
1217 is undefined.
1218 @param IsFfs3Fv Indicates the FV format.
1219
1220 @retval EFI_SUCCESS Section was retrieved successfully
1221 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1222 section stream with its
1223 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1224 but there was no corresponding GUIDed Section
1225 Extraction Protocol in the handle database.
1226 *Buffer is unmodified.
1227 @retval EFI_NOT_FOUND An error was encountered when parsing the
1228 SectionStream. This indicates the SectionStream
1229 is not correctly formatted.
1230 @retval EFI_NOT_FOUND The requested section does not exist.
1231 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1232 the request.
1233 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1234 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1235 insufficient to contain the requested section.
1236 The input buffer is filled and section contents
1237 are truncated.
1238
1239 **/
1240 EFI_STATUS
1241 EFIAPI
1242 GetSection (
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;
1263 EFI_COMMON_SECTION_HEADER *Section;
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 __FUNCTION__
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
1361 GetSection_Done:
1362 CoreRestoreTpl (OldTpl);
1363
1364 return Status;
1365 }
1366
1367 /**
1368 Worker function. Destructor for child nodes.
1369
1370 @param ChildNode Indicates the node to destroy
1371
1372 **/
1373 VOID
1374 FreeChildNode (
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
1402 /**
1403 SEP member function. Deletes an existing section stream
1404
1405 @param StreamHandleToClose Indicates the stream to close
1406 @param FreeStreamBuffer TRUE - Need to free stream buffer;
1407 FALSE - No need to free stream buffer.
1408
1409 @retval EFI_SUCCESS The section stream is closed sucessfully.
1410 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1411 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1412 of last section.
1413
1414 **/
1415 EFI_STATUS
1416 EFIAPI
1417 CloseSectionStream (
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
1459 /**
1460 The ExtractSection() function processes the input section and
1461 allocates a buffer from the pool in which it returns the section
1462 contents. If the section being extracted contains
1463 authentication information (the section's
1464 GuidedSectionHeader.Attributes field has the
1465 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1466 returned in AuthenticationStatus must reflect the results of
1467 the authentication operation. Depending on the algorithm and
1468 size of the encapsulated data, the time that is required to do
1469 a full authentication may be prohibitively long for some
1470 classes of systems. To indicate this, use
1471 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1472 the security policy driver (see the Platform Initialization
1473 Driver Execution Environment Core Interface Specification for
1474 more details and the GUID definition). If the
1475 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1476 database, then, if possible, full authentication should be
1477 skipped and the section contents simply returned in the
1478 OutputBuffer. In this case, the
1479 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1480 must be set on return. ExtractSection() is callable only from
1481 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1482 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1483 defined in RaiseTPL() in the UEFI 2.0 specification.
1484
1485
1486 @param This Indicates the
1487 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1488 @param InputSection Buffer containing the input GUIDed section
1489 to be processed. OutputBuffer OutputBuffer
1490 is allocated from boot services pool
1491 memory and contains the new section
1492 stream. The caller is responsible for
1493 freeing this buffer.
1494 @param OutputBuffer *OutputBuffer is allocated from boot services
1495 pool memory and contains the new section stream.
1496 The caller is responsible for freeing this buffer.
1497 @param OutputSize A pointer to a caller-allocated UINTN in
1498 which the size of OutputBuffer allocation
1499 is stored. If the function returns
1500 anything other than EFI_SUCCESS, the value
1501 of OutputSize is undefined.
1502
1503 @param AuthenticationStatus A pointer to a caller-allocated
1504 UINT32 that indicates the
1505 authentication status of the
1506 output buffer. If the input
1507 section's
1508 GuidedSectionHeader.Attributes
1509 field has the
1510 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1511 bit as clear, AuthenticationStatus
1512 must return zero. Both local bits
1513 (19:16) and aggregate bits (3:0)
1514 in AuthenticationStatus are
1515 returned by ExtractSection().
1516 These bits reflect the status of
1517 the extraction operation. The bit
1518 pattern in both regions must be
1519 the same, as the local and
1520 aggregate authentication statuses
1521 have equivalent meaning at this
1522 level. If the function returns
1523 anything other than EFI_SUCCESS,
1524 the value of AuthenticationStatus
1525 is undefined.
1526
1527
1528 @retval EFI_SUCCESS The InputSection was successfully
1529 processed and the section contents were
1530 returned.
1531
1532 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1533 resources to process the
1534 request.
1535
1536 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1537 not match this instance of the
1538 GUIDed Section Extraction
1539 Protocol.
1540
1541 **/
1542 EFI_STATUS
1543 EFIAPI
1544 CustomGuidedSectionExtract (
1545 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
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 //
1568 Status = ExtractGuidedSectionGetInfo (
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 }