]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
Add core FFS3 support, DxeCore.
[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 - 2011, Intel Corporation. All rights reserved.<BR>
31 This program and the accompanying materials
32 are licensed and made available under the terms and conditions of the BSD License
33 which accompanies this distribution. The full text of the license may be found at
34 http://opensource.org/licenses/bsd-license.php
35
36 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
37 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
38
39 **/
40
41 #include "DxeMain.h"
42
43 //
44 // Local defines and typedefs
45 //
46 #define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
47 #define CHILD_SECTION_NODE_FROM_LINK(Node) \
48 CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
49
50 typedef struct {
51 UINT32 Signature;
52 LIST_ENTRY Link;
53 UINT32 Type;
54 UINT32 Size;
55 //
56 // StreamBase + OffsetInStream == pointer to section header in stream. The
57 // stream base is always known when walking the sections within.
58 //
59 UINT32 OffsetInStream;
60 //
61 // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
62 // encapsulating section. Otherwise, it contains the stream handle
63 // of the encapsulated stream. This handle is ALWAYS produced any time an
64 // encapsulating child is encountered, irrespective of whether the
65 // encapsulated stream is processed further.
66 //
67 UINTN EncapsulatedStreamHandle;
68 EFI_GUID *EncapsulationGuid;
69 } CORE_SECTION_CHILD_NODE;
70
71 #define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
72 #define STREAM_NODE_FROM_LINK(Node) \
73 CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
74
75 typedef struct {
76 UINT32 Signature;
77 LIST_ENTRY Link;
78 UINTN StreamHandle;
79 UINT8 *StreamBuffer;
80 UINTN StreamLength;
81 LIST_ENTRY Children;
82 //
83 // Authentication status is from GUIDed encapsulations.
84 //
85 UINT32 AuthenticationStatus;
86 } CORE_SECTION_STREAM_NODE;
87
88 #define NULL_STREAM_HANDLE 0
89
90 typedef struct {
91 CORE_SECTION_CHILD_NODE *ChildNode;
92 CORE_SECTION_STREAM_NODE *ParentStream;
93 VOID *Registration;
94 EFI_EVENT Event;
95 } RPN_EVENT_CONTEXT;
96
97
98 /**
99 The ExtractSection() function processes the input section and
100 allocates a buffer from the pool in which it returns the section
101 contents. If the section being extracted contains
102 authentication information (the section's
103 GuidedSectionHeader.Attributes field has the
104 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
105 returned in AuthenticationStatus must reflect the results of
106 the authentication operation. Depending on the algorithm and
107 size of the encapsulated data, the time that is required to do
108 a full authentication may be prohibitively long for some
109 classes of systems. To indicate this, use
110 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
111 the security policy driver (see the Platform Initialization
112 Driver Execution Environment Core Interface Specification for
113 more details and the GUID definition). If the
114 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
115 database, then, if possible, full authentication should be
116 skipped and the section contents simply returned in the
117 OutputBuffer. In this case, the
118 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
119 must be set on return. ExtractSection() is callable only from
120 TPL_NOTIFY and below. Behavior of ExtractSection() at any
121 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
122 defined in RaiseTPL() in the UEFI 2.0 specification.
123
124
125 @param This Indicates the
126 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
127 @param InputSection Buffer containing the input GUIDed section
128 to be processed. OutputBuffer OutputBuffer
129 is allocated from boot services pool
130 memory and contains the new section
131 stream. The caller is responsible for
132 freeing this buffer.
133 @param OutputBuffer *OutputBuffer is allocated from boot services
134 pool memory and contains the new section stream.
135 The caller is responsible for freeing this buffer.
136 @param OutputSize A pointer to a caller-allocated UINTN in
137 which the size of OutputBuffer allocation
138 is stored. If the function returns
139 anything other than EFI_SUCCESS, the value
140 of OutputSize is undefined.
141
142 @param AuthenticationStatus A pointer to a caller-allocated
143 UINT32 that indicates the
144 authentication status of the
145 output buffer. If the input
146 section's
147 GuidedSectionHeader.Attributes
148 field has the
149 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
150 bit as clear, AuthenticationStatus
151 must return zero. Both local bits
152 (19:16) and aggregate bits (3:0)
153 in AuthenticationStatus are
154 returned by ExtractSection().
155 These bits reflect the status of
156 the extraction operation. The bit
157 pattern in both regions must be
158 the same, as the local and
159 aggregate authentication statuses
160 have equivalent meaning at this
161 level. If the function returns
162 anything other than EFI_SUCCESS,
163 the value of AuthenticationStatus
164 is undefined.
165
166
167 @retval EFI_SUCCESS The InputSection was successfully
168 processed and the section contents were
169 returned.
170
171 @retval EFI_OUT_OF_RESOURCES The system has insufficient
172 resources to process the
173 request.
174
175 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
176 not match this instance of the
177 GUIDed Section Extraction
178 Protocol.
179
180 **/
181 EFI_STATUS
182 EFIAPI
183 CustomGuidedSectionExtract (
184 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
185 IN CONST VOID *InputSection,
186 OUT VOID **OutputBuffer,
187 OUT UINTN *OutputSize,
188 OUT UINT32 *AuthenticationStatus
189 );
190
191 //
192 // Module globals
193 //
194 LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
195
196 EFI_HANDLE mSectionExtractionHandle = NULL;
197
198 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
199 CustomGuidedSectionExtract
200 };
201
202
203 /**
204 Entry point of the section extraction code. Initializes an instance of the
205 section extraction interface and installs it on a new handle.
206
207 @param ImageHandle A handle for the image that is initializing this driver
208 @param SystemTable A pointer to the EFI system table
209
210 @retval EFI_SUCCESS Driver initialized successfully
211 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
212
213 **/
214 EFI_STATUS
215 EFIAPI
216 InitializeSectionExtraction (
217 IN EFI_HANDLE ImageHandle,
218 IN EFI_SYSTEM_TABLE *SystemTable
219 )
220 {
221 EFI_STATUS Status;
222 EFI_GUID *ExtractHandlerGuidTable;
223 UINTN ExtractHandlerNumber;
224
225 //
226 // Get custom extract guided section method guid list
227 //
228 ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
229
230 Status = EFI_SUCCESS;
231 //
232 // Install custom guided extraction protocol
233 //
234 while (ExtractHandlerNumber-- > 0) {
235 Status = CoreInstallProtocolInterface (
236 &mSectionExtractionHandle,
237 &ExtractHandlerGuidTable [ExtractHandlerNumber],
238 EFI_NATIVE_INTERFACE,
239 &mCustomGuidedSectionExtractionProtocol
240 );
241 ASSERT_EFI_ERROR (Status);
242 }
243
244 return Status;
245 }
246
247
248 /**
249 Check if a stream is valid.
250
251 @param SectionStream The section stream to be checked
252 @param SectionStreamLength The length of section stream
253
254 @return A boolean value indicating the validness of the section stream.
255
256 **/
257 BOOLEAN
258 IsValidSectionStream (
259 IN VOID *SectionStream,
260 IN UINTN SectionStreamLength
261 )
262 {
263 UINTN TotalLength;
264 UINTN SectionLength;
265 EFI_COMMON_SECTION_HEADER *SectionHeader;
266 EFI_COMMON_SECTION_HEADER *NextSectionHeader;
267
268 TotalLength = 0;
269 SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
270
271 while (TotalLength < SectionStreamLength) {
272 if (IS_SECTION2 (SectionHeader)) {
273 SectionLength = SECTION2_SIZE (SectionHeader);
274 } else {
275 SectionLength = SECTION_SIZE (SectionHeader);
276 }
277 TotalLength += SectionLength;
278
279 if (TotalLength == SectionStreamLength) {
280 return TRUE;
281 }
282
283 //
284 // Move to the next byte following the section...
285 //
286 SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
287
288 //
289 // Figure out where the next section begins
290 //
291 NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
292 TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
293 SectionHeader = NextSectionHeader;
294 }
295
296 ASSERT (FALSE);
297 return FALSE;
298 }
299
300
301 /**
302 Worker function. Constructor for section streams.
303
304 @param SectionStreamLength Size in bytes of the section stream.
305 @param SectionStream Buffer containing the new section stream.
306 @param AllocateBuffer Indicates whether the stream buffer is to be
307 copied or the input buffer is to be used in
308 place. AuthenticationStatus- Indicates the
309 default authentication status for the new
310 stream.
311 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
312 indicates the authentication status of the
313 output buffer. If the input section's
314 GuidedSectionHeader.Attributes field
315 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
316 bit as clear, AuthenticationStatus must return
317 zero. Both local bits (19:16) and aggregate
318 bits (3:0) in AuthenticationStatus are returned
319 by ExtractSection(). These bits reflect the
320 status of the extraction operation. The bit
321 pattern in both regions must be the same, as
322 the local and aggregate authentication statuses
323 have equivalent meaning at this level. If the
324 function returns anything other than
325 EFI_SUCCESS, the value of *AuthenticationStatus
326 is undefined.
327 @param SectionStreamHandle A pointer to a caller allocated section stream
328 handle.
329
330 @retval EFI_SUCCESS Stream was added to stream database.
331 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
332
333 **/
334 EFI_STATUS
335 OpenSectionStreamEx (
336 IN UINTN SectionStreamLength,
337 IN VOID *SectionStream,
338 IN BOOLEAN AllocateBuffer,
339 IN UINT32 AuthenticationStatus,
340 OUT UINTN *SectionStreamHandle
341 )
342 {
343 CORE_SECTION_STREAM_NODE *NewStream;
344 EFI_TPL OldTpl;
345
346 //
347 // Allocate a new stream
348 //
349 NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
350 if (NewStream == NULL) {
351 return EFI_OUT_OF_RESOURCES;
352 }
353
354 if (AllocateBuffer) {
355 //
356 // if we're here, we're double buffering, allocate the buffer and copy the
357 // data in
358 //
359 if (SectionStreamLength > 0) {
360 NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
361 if (NewStream->StreamBuffer == NULL) {
362 CoreFreePool (NewStream);
363 return EFI_OUT_OF_RESOURCES;
364 }
365 //
366 // Copy in stream data
367 //
368 CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
369 } else {
370 //
371 // It's possible to have a zero length section stream.
372 //
373 NewStream->StreamBuffer = NULL;
374 }
375 } else {
376 //
377 // If were here, the caller has supplied the buffer (it's an internal call)
378 // so just assign the buffer. This happens when we open section streams
379 // as a result of expanding an encapsulating section.
380 //
381 NewStream->StreamBuffer = SectionStream;
382 }
383
384 //
385 // Initialize the rest of the section stream
386 //
387 NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
388 NewStream->StreamHandle = (UINTN) NewStream;
389 NewStream->StreamLength = SectionStreamLength;
390 InitializeListHead (&NewStream->Children);
391 NewStream->AuthenticationStatus = AuthenticationStatus;
392
393 //
394 // Add new stream to stream list
395 //
396 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
397 InsertTailList (&mStreamRoot, &NewStream->Link);
398 CoreRestoreTpl (OldTpl);
399
400 *SectionStreamHandle = NewStream->StreamHandle;
401
402 return EFI_SUCCESS;
403 }
404
405
406 /**
407 SEP member function. This function creates and returns a new section stream
408 handle to represent the new section stream.
409
410 @param SectionStreamLength Size in bytes of the section stream.
411 @param SectionStream Buffer containing the new section stream.
412 @param SectionStreamHandle A pointer to a caller allocated UINTN that on
413 output contains the new section stream handle.
414
415 @retval EFI_SUCCESS The section stream is created successfully.
416 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
417 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
418 of last section.
419
420 **/
421 EFI_STATUS
422 EFIAPI
423 OpenSectionStream (
424 IN UINTN SectionStreamLength,
425 IN VOID *SectionStream,
426 OUT UINTN *SectionStreamHandle
427 )
428 {
429 //
430 // Check to see section stream looks good...
431 //
432 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
433 return EFI_INVALID_PARAMETER;
434 }
435
436 return OpenSectionStreamEx (
437 SectionStreamLength,
438 SectionStream,
439 TRUE,
440 0,
441 SectionStreamHandle
442 );
443 }
444
445
446
447 /**
448 Worker function. Determine if the input stream:child matches the input type.
449
450 @param Stream Indicates the section stream associated with the
451 child
452 @param Child Indicates the child to check
453 @param SearchType Indicates the type of section to check against
454 for
455 @param SectionDefinitionGuid Indicates the GUID to check against if the type
456 is EFI_SECTION_GUID_DEFINED
457
458 @retval TRUE The child matches
459 @retval FALSE The child doesn't match
460
461 **/
462 BOOLEAN
463 ChildIsType (
464 IN CORE_SECTION_STREAM_NODE *Stream,
465 IN CORE_SECTION_CHILD_NODE *Child,
466 IN EFI_SECTION_TYPE SearchType,
467 IN EFI_GUID *SectionDefinitionGuid
468 )
469 {
470 EFI_GUID_DEFINED_SECTION *GuidedSection;
471
472 if (SearchType == EFI_SECTION_ALL) {
473 return TRUE;
474 }
475 if (Child->Type != SearchType) {
476 return FALSE;
477 }
478 if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
479 return TRUE;
480 }
481 GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
482 if (IS_SECTION2 (GuidedSection)) {
483 return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *) GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
484 } else {
485 return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
486 }
487 }
488
489 /**
490 RPN callback function. Initializes the section stream
491 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
492
493 @param Event The event that fired
494 @param RpnContext A pointer to the context that allows us to identify
495 the relevent encapsulation.
496 **/
497 VOID
498 EFIAPI
499 NotifyGuidedExtraction (
500 IN EFI_EVENT Event,
501 IN VOID *RpnContext
502 )
503 {
504 EFI_STATUS Status;
505 EFI_GUID_DEFINED_SECTION *GuidedHeader;
506 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
507 VOID *NewStreamBuffer;
508 UINTN NewStreamBufferSize;
509 UINT32 AuthenticationStatus;
510 RPN_EVENT_CONTEXT *Context;
511
512 Context = RpnContext;
513
514 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
515 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
516
517 Status = gBS->LocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
518 if (EFI_ERROR (Status)) {
519 return;
520 }
521
522 Status = GuidedExtraction->ExtractSection (
523 GuidedExtraction,
524 GuidedHeader,
525 &NewStreamBuffer,
526 &NewStreamBufferSize,
527 &AuthenticationStatus
528 );
529 ASSERT_EFI_ERROR (Status);
530
531 //
532 // Make sure we initialize the new stream with the correct
533 // authentication status for both aggregate and local status fields.
534 //
535 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
536 //
537 // OR in the parent stream's aggregate status.
538 //
539 AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
540 } else {
541 //
542 // since there's no authentication data contributed by the section,
543 // just inherit the full value from our immediate parent.
544 //
545 AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
546 }
547
548 Status = OpenSectionStreamEx (
549 NewStreamBufferSize,
550 NewStreamBuffer,
551 FALSE,
552 AuthenticationStatus,
553 &Context->ChildNode->EncapsulatedStreamHandle
554 );
555 ASSERT_EFI_ERROR (Status);
556
557 //
558 // Close the event when done.
559 //
560 gBS->CloseEvent (Event);
561 FreePool (Context);
562 }
563
564 /**
565 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
566
567 @param ParentStream Indicates the parent of the ecnapsulation section (child)
568 @param ChildNode Indicates the child node that is the encapsulation section.
569
570 **/
571 VOID
572 CreateGuidedExtractionRpnEvent (
573 IN CORE_SECTION_STREAM_NODE *ParentStream,
574 IN CORE_SECTION_CHILD_NODE *ChildNode
575 )
576 {
577 RPN_EVENT_CONTEXT *Context;
578
579 //
580 // Allocate new event structure and context
581 //
582 Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
583 ASSERT (Context != NULL);
584
585 Context->ChildNode = ChildNode;
586 Context->ParentStream = ParentStream;
587
588 Context->Event = EfiCreateProtocolNotifyEvent (
589 Context->ChildNode->EncapsulationGuid,
590 TPL_NOTIFY,
591 NotifyGuidedExtraction,
592 Context,
593 &Context->Registration
594 );
595 }
596
597 /**
598 Worker function. Constructor for new child nodes.
599
600 @param Stream Indicates the section stream in which to add the
601 child.
602 @param ChildOffset Indicates the offset in Stream that is the
603 beginning of the child section.
604 @param ChildNode Indicates the Callee allocated and initialized
605 child.
606
607 @retval EFI_SUCCESS Child node was found and returned.
608 EFI_OUT_OF_RESOURCES- Memory allocation failed.
609 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
610 handles when the child node is created. If the
611 section type is GUID defined, and the extraction
612 GUID does not exist, and producing the stream
613 requires the GUID, then a protocol error is
614 generated and no child is produced. Values
615 returned by OpenSectionStreamEx.
616
617 **/
618 EFI_STATUS
619 CreateChildNode (
620 IN CORE_SECTION_STREAM_NODE *Stream,
621 IN UINT32 ChildOffset,
622 OUT CORE_SECTION_CHILD_NODE **ChildNode
623 )
624 {
625 EFI_STATUS Status;
626 EFI_COMMON_SECTION_HEADER *SectionHeader;
627 EFI_COMPRESSION_SECTION *CompressionHeader;
628 EFI_GUID_DEFINED_SECTION *GuidedHeader;
629 EFI_DECOMPRESS_PROTOCOL *Decompress;
630 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
631 VOID *NewStreamBuffer;
632 VOID *ScratchBuffer;
633 UINT32 ScratchSize;
634 UINTN NewStreamBufferSize;
635 UINT32 AuthenticationStatus;
636 VOID *CompressionSource;
637 UINT32 CompressionSourceSize;
638 UINT32 UncompressedLength;
639 UINT8 CompressionType;
640 UINT16 GuidedSectionAttributes;
641
642 CORE_SECTION_CHILD_NODE *Node;
643
644 SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
645
646 //
647 // Allocate a new node
648 //
649 *ChildNode = AllocatePool (sizeof (CORE_SECTION_CHILD_NODE));
650 Node = *ChildNode;
651 if (Node == NULL) {
652 return EFI_OUT_OF_RESOURCES;
653 }
654
655 //
656 // Now initialize it
657 //
658 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
659 Node->Type = SectionHeader->Type;
660 if (IS_SECTION2 (SectionHeader)) {
661 Node->Size = SECTION2_SIZE (SectionHeader);
662 } else {
663 Node->Size = SECTION_SIZE (SectionHeader);
664 }
665 Node->OffsetInStream = ChildOffset;
666 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
667 Node->EncapsulationGuid = NULL;
668
669 //
670 // If it's an encapsulating section, then create the new section stream also
671 //
672 switch (Node->Type) {
673 case EFI_SECTION_COMPRESSION:
674 //
675 // Get the CompressionSectionHeader
676 //
677 ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));
678
679 CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
680
681 if (IS_SECTION2 (CompressionHeader)) {
682 CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
683 CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
684 UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->UncompressedLength;
685 CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->CompressionType;
686 } else {
687 CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
688 CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
689 UncompressedLength = CompressionHeader->UncompressedLength;
690 CompressionType = CompressionHeader->CompressionType;
691 }
692
693 //
694 // Allocate space for the new stream
695 //
696 if (UncompressedLength > 0) {
697 NewStreamBufferSize = UncompressedLength;
698 NewStreamBuffer = AllocatePool (NewStreamBufferSize);
699 if (NewStreamBuffer == NULL) {
700 CoreFreePool (Node);
701 return EFI_OUT_OF_RESOURCES;
702 }
703
704 if (CompressionType == EFI_NOT_COMPRESSED) {
705 //
706 // stream is not actually compressed, just encapsulated. So just copy it.
707 //
708 CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
709 } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
710 //
711 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
712 //
713
714 //
715 // Decompress the stream
716 //
717 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
718 ASSERT_EFI_ERROR (Status);
719 ASSERT (Decompress != NULL);
720
721 Status = Decompress->GetInfo (
722 Decompress,
723 CompressionSource,
724 CompressionSourceSize,
725 (UINT32 *)&NewStreamBufferSize,
726 &ScratchSize
727 );
728 ASSERT_EFI_ERROR (Status);
729 ASSERT (NewStreamBufferSize == UncompressedLength);
730
731 ScratchBuffer = AllocatePool (ScratchSize);
732 if (ScratchBuffer == NULL) {
733 CoreFreePool (Node);
734 CoreFreePool (NewStreamBuffer);
735 return EFI_OUT_OF_RESOURCES;
736 }
737
738 Status = Decompress->Decompress (
739 Decompress,
740 CompressionSource,
741 CompressionSourceSize,
742 NewStreamBuffer,
743 (UINT32)NewStreamBufferSize,
744 ScratchBuffer,
745 ScratchSize
746 );
747 ASSERT_EFI_ERROR (Status);
748 CoreFreePool (ScratchBuffer);
749 }
750 } else {
751 NewStreamBuffer = NULL;
752 NewStreamBufferSize = 0;
753 }
754
755 Status = OpenSectionStreamEx (
756 NewStreamBufferSize,
757 NewStreamBuffer,
758 FALSE,
759 Stream->AuthenticationStatus,
760 &Node->EncapsulatedStreamHandle
761 );
762 if (EFI_ERROR (Status)) {
763 CoreFreePool (Node);
764 CoreFreePool (NewStreamBuffer);
765 return Status;
766 }
767 break;
768
769 case EFI_SECTION_GUID_DEFINED:
770 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
771 if (IS_SECTION2 (GuidedHeader)) {
772 Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->SectionDefinitionGuid);
773 GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->Attributes;
774 } else {
775 Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
776 GuidedSectionAttributes = GuidedHeader->Attributes;
777 }
778 Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
779 if (!EFI_ERROR (Status) && GuidedExtraction != NULL) {
780 //
781 // NewStreamBuffer is always allocated by ExtractSection... No caller
782 // allocation here.
783 //
784 Status = GuidedExtraction->ExtractSection (
785 GuidedExtraction,
786 GuidedHeader,
787 &NewStreamBuffer,
788 &NewStreamBufferSize,
789 &AuthenticationStatus
790 );
791 if (EFI_ERROR (Status)) {
792 CoreFreePool (*ChildNode);
793 return EFI_PROTOCOL_ERROR;
794 }
795
796 //
797 // Make sure we initialize the new stream with the correct
798 // authentication status for both aggregate and local status fields.
799 //
800 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
801 //
802 // OR in the parent stream's aggregate status.
803 //
804 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
805 } else {
806 //
807 // since there's no authentication data contributed by the section,
808 // just inherit the full value from our immediate parent.
809 //
810 AuthenticationStatus = Stream->AuthenticationStatus;
811 }
812
813 Status = OpenSectionStreamEx (
814 NewStreamBufferSize,
815 NewStreamBuffer,
816 FALSE,
817 AuthenticationStatus,
818 &Node->EncapsulatedStreamHandle
819 );
820 if (EFI_ERROR (Status)) {
821 CoreFreePool (*ChildNode);
822 CoreFreePool (NewStreamBuffer);
823 return Status;
824 }
825 } else {
826 //
827 // There's no GUIDed section extraction protocol available.
828 //
829 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
830 //
831 // If the section REQUIRES an extraction protocol, register for RPN
832 // when the required GUIDed extraction protocol becomes available.
833 //
834 CreateGuidedExtractionRpnEvent (Stream, Node);
835 } else {
836 //
837 // Figure out the proper authentication status
838 //
839 AuthenticationStatus = Stream->AuthenticationStatus;
840
841 if (IS_SECTION2 (GuidedHeader)) {
842 Status = OpenSectionStreamEx (
843 SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
844 (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
845 TRUE,
846 AuthenticationStatus,
847 &Node->EncapsulatedStreamHandle
848 );
849 } else {
850 Status = OpenSectionStreamEx (
851 SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
852 (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
853 TRUE,
854 AuthenticationStatus,
855 &Node->EncapsulatedStreamHandle
856 );
857 }
858 if (EFI_ERROR (Status)) {
859 CoreFreePool (Node);
860 return Status;
861 }
862 }
863 }
864
865 break;
866
867 default:
868
869 //
870 // Nothing to do if it's a leaf
871 //
872 break;
873 }
874
875 //
876 // Last, add the new child node to the stream
877 //
878 InsertTailList (&Stream->Children, &Node->Link);
879
880 return EFI_SUCCESS;
881 }
882
883
884 /**
885 Worker function Recursively searches / builds section stream database
886 looking for requested section.
887
888 @param SourceStream Indicates the section stream in which to do the
889 search.
890 @param SearchType Indicates the type of section to search for.
891 @param SectionInstance Indicates which instance of section to find.
892 This is an in/out parameter to deal with
893 recursions.
894 @param SectionDefinitionGuid Guid of section definition
895 @param FoundChild Output indicating the child node that is found.
896 @param FoundStream Output indicating which section stream the child
897 was found in. If this stream was generated as a
898 result of an encapsulation section, the
899 streamhandle is visible within the SEP driver
900 only.
901 @param AuthenticationStatus Indicates the authentication status of the found section.
902
903 @retval EFI_SUCCESS Child node was found and returned.
904 EFI_OUT_OF_RESOURCES- Memory allocation failed.
905 @retval EFI_NOT_FOUND Requested child node does not exist.
906 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
907 does not exist
908
909 **/
910 EFI_STATUS
911 FindChildNode (
912 IN CORE_SECTION_STREAM_NODE *SourceStream,
913 IN EFI_SECTION_TYPE SearchType,
914 IN OUT UINTN *SectionInstance,
915 IN EFI_GUID *SectionDefinitionGuid,
916 OUT CORE_SECTION_CHILD_NODE **FoundChild,
917 OUT CORE_SECTION_STREAM_NODE **FoundStream,
918 OUT UINT32 *AuthenticationStatus
919 )
920 {
921 CORE_SECTION_CHILD_NODE *CurrentChildNode;
922 CORE_SECTION_CHILD_NODE *RecursedChildNode;
923 CORE_SECTION_STREAM_NODE *RecursedFoundStream;
924 UINT32 NextChildOffset;
925 EFI_STATUS ErrorStatus;
926 EFI_STATUS Status;
927
928 CurrentChildNode = NULL;
929 ErrorStatus = EFI_NOT_FOUND;
930
931 if (SourceStream->StreamLength == 0) {
932 return EFI_NOT_FOUND;
933 }
934
935 if (IsListEmpty (&SourceStream->Children) &&
936 SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
937 //
938 // This occurs when a section stream exists, but no child sections
939 // have been parsed out yet. Therefore, extract the first child and add it
940 // to the list of children so we can get started.
941 // Section stream may contain an array of zero or more bytes.
942 // So, its size should be >= the size of commen section header.
943 //
944 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
945 if (EFI_ERROR (Status)) {
946 return Status;
947 }
948 }
949
950 //
951 // At least one child has been parsed out of the section stream. So, walk
952 // through the sections that have already been parsed out looking for the
953 // requested section, if necessary, continue parsing section stream and
954 // adding children until either the requested section is found, or we run
955 // out of data
956 //
957 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
958
959 for (;;) {
960 ASSERT (CurrentChildNode != NULL);
961 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
962 //
963 // The type matches, so check the instance count to see if it's the one we want
964 //
965 (*SectionInstance)--;
966 if (*SectionInstance == 0) {
967 //
968 // Got it!
969 //
970 *FoundChild = CurrentChildNode;
971 *FoundStream = SourceStream;
972 *AuthenticationStatus = SourceStream->AuthenticationStatus;
973 return EFI_SUCCESS;
974 }
975 }
976
977 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
978 //
979 // If the current node is an encapsulating node, recurse into it...
980 //
981 Status = FindChildNode (
982 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
983 SearchType,
984 SectionInstance,
985 SectionDefinitionGuid,
986 &RecursedChildNode,
987 &RecursedFoundStream,
988 AuthenticationStatus
989 );
990 //
991 // If the status is not EFI_SUCCESS, just save the error code and continue
992 // to find the request child node in the rest stream.
993 //
994 if (*SectionInstance == 0) {
995 ASSERT_EFI_ERROR (Status);
996 *FoundChild = RecursedChildNode;
997 *FoundStream = RecursedFoundStream;
998 return EFI_SUCCESS;
999 } else {
1000 ErrorStatus = Status;
1001 }
1002 } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
1003 //
1004 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
1005 // because a required GUIDED section extraction protocol does not exist.
1006 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
1007 //
1008 ErrorStatus = EFI_PROTOCOL_ERROR;
1009 }
1010
1011 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
1012 //
1013 // We haven't found the child node we're interested in yet, but there's
1014 // still more nodes that have already been parsed so get the next one
1015 // and continue searching..
1016 //
1017 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
1018 } else {
1019 //
1020 // We've exhausted children that have already been parsed, so see if
1021 // there's any more data and continue parsing out more children if there
1022 // is.
1023 //
1024 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
1025 //
1026 // Round up to 4 byte boundary
1027 //
1028 NextChildOffset += 3;
1029 NextChildOffset &= ~(UINTN) 3;
1030 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
1031 //
1032 // There's an unparsed child remaining in the stream, so create a new child node
1033 //
1034 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
1035 if (EFI_ERROR (Status)) {
1036 return Status;
1037 }
1038 } else {
1039 ASSERT (EFI_ERROR (ErrorStatus));
1040 return ErrorStatus;
1041 }
1042 }
1043 }
1044 }
1045
1046
1047 /**
1048 Worker function. Search stream database for requested stream handle.
1049
1050 @param SearchHandle Indicates which stream to look for.
1051 @param FoundStream Output pointer to the found stream.
1052
1053 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1054 the stream node.
1055 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1056 database.
1057
1058 **/
1059 EFI_STATUS
1060 FindStreamNode (
1061 IN UINTN SearchHandle,
1062 OUT CORE_SECTION_STREAM_NODE **FoundStream
1063 )
1064 {
1065 CORE_SECTION_STREAM_NODE *StreamNode;
1066
1067 if (!IsListEmpty (&mStreamRoot)) {
1068 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
1069 for (;;) {
1070 if (StreamNode->StreamHandle == SearchHandle) {
1071 *FoundStream = StreamNode;
1072 return EFI_SUCCESS;
1073 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
1074 break;
1075 } else {
1076 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
1077 }
1078 }
1079 }
1080
1081 return EFI_NOT_FOUND;
1082 }
1083
1084
1085 /**
1086 SEP member function. Retrieves requested section from section stream.
1087
1088 @param SectionStreamHandle The section stream from which to extract the
1089 requested section.
1090 @param SectionType A pointer to the type of section to search for.
1091 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1092 then SectionDefinitionGuid indicates which of
1093 these types of sections to search for.
1094 @param SectionInstance Indicates which instance of the requested
1095 section to return.
1096 @param Buffer Double indirection to buffer. If *Buffer is
1097 non-null on input, then the buffer is caller
1098 allocated. If Buffer is NULL, then the buffer
1099 is callee allocated. In either case, the
1100 requried buffer size is returned in *BufferSize.
1101 @param BufferSize On input, indicates the size of *Buffer if
1102 *Buffer is non-null on input. On output,
1103 indicates the required size (allocated size if
1104 callee allocated) of *Buffer.
1105 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1106 indicates the authentication status of the
1107 output buffer. If the input section's
1108 GuidedSectionHeader.Attributes field
1109 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1110 bit as clear, AuthenticationStatus must return
1111 zero. Both local bits (19:16) and aggregate
1112 bits (3:0) in AuthenticationStatus are returned
1113 by ExtractSection(). These bits reflect the
1114 status of the extraction operation. The bit
1115 pattern in both regions must be the same, as
1116 the local and aggregate authentication statuses
1117 have equivalent meaning at this level. If the
1118 function returns anything other than
1119 EFI_SUCCESS, the value of *AuthenticationStatus
1120 is undefined.
1121 @param IsFfs3Fv Indicates the FV format.
1122
1123 @retval EFI_SUCCESS Section was retrieved successfully
1124 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1125 section stream with its
1126 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1127 but there was no corresponding GUIDed Section
1128 Extraction Protocol in the handle database.
1129 *Buffer is unmodified.
1130 @retval EFI_NOT_FOUND An error was encountered when parsing the
1131 SectionStream. This indicates the SectionStream
1132 is not correctly formatted.
1133 @retval EFI_NOT_FOUND The requested section does not exist.
1134 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1135 the request.
1136 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1137 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1138 insufficient to contain the requested section.
1139 The input buffer is filled and section contents
1140 are truncated.
1141
1142 **/
1143 EFI_STATUS
1144 EFIAPI
1145 GetSection (
1146 IN UINTN SectionStreamHandle,
1147 IN EFI_SECTION_TYPE *SectionType,
1148 IN EFI_GUID *SectionDefinitionGuid,
1149 IN UINTN SectionInstance,
1150 IN VOID **Buffer,
1151 IN OUT UINTN *BufferSize,
1152 OUT UINT32 *AuthenticationStatus,
1153 IN BOOLEAN IsFfs3Fv
1154 )
1155 {
1156 CORE_SECTION_STREAM_NODE *StreamNode;
1157 EFI_TPL OldTpl;
1158 EFI_STATUS Status;
1159 CORE_SECTION_CHILD_NODE *ChildNode;
1160 CORE_SECTION_STREAM_NODE *ChildStreamNode;
1161 UINTN CopySize;
1162 UINT32 ExtractedAuthenticationStatus;
1163 UINTN Instance;
1164 UINT8 *CopyBuffer;
1165 UINTN SectionSize;
1166 EFI_COMMON_SECTION_HEADER *Section;
1167
1168
1169 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1170 Instance = SectionInstance + 1;
1171
1172 //
1173 // Locate target stream
1174 //
1175 Status = FindStreamNode (SectionStreamHandle, &StreamNode);
1176 if (EFI_ERROR (Status)) {
1177 Status = EFI_INVALID_PARAMETER;
1178 goto GetSection_Done;
1179 }
1180
1181 //
1182 // Found the stream, now locate and return the appropriate section
1183 //
1184 if (SectionType == NULL) {
1185 //
1186 // SectionType == NULL means return the WHOLE section stream...
1187 //
1188 CopySize = StreamNode->StreamLength;
1189 CopyBuffer = StreamNode->StreamBuffer;
1190 *AuthenticationStatus = StreamNode->AuthenticationStatus;
1191 } else {
1192 //
1193 // There's a requested section type, so go find it and return it...
1194 //
1195 Status = FindChildNode (
1196 StreamNode,
1197 *SectionType,
1198 &Instance,
1199 SectionDefinitionGuid,
1200 &ChildNode,
1201 &ChildStreamNode,
1202 &ExtractedAuthenticationStatus
1203 );
1204 if (EFI_ERROR (Status)) {
1205 goto GetSection_Done;
1206 }
1207
1208 Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
1209
1210 if (IS_SECTION2 (Section)) {
1211 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
1212 if (!IsFfs3Fv) {
1213 DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
1214 Status = EFI_NOT_FOUND;
1215 goto GetSection_Done;
1216 }
1217 CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
1218 CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);
1219 } else {
1220 CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
1221 CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);
1222 }
1223 *AuthenticationStatus = ExtractedAuthenticationStatus;
1224 }
1225
1226 SectionSize = CopySize;
1227 if (*Buffer != NULL) {
1228 //
1229 // Caller allocated buffer. Fill to size and return required size...
1230 //
1231 if (*BufferSize < CopySize) {
1232 Status = EFI_WARN_BUFFER_TOO_SMALL;
1233 CopySize = *BufferSize;
1234 }
1235 } else {
1236 //
1237 // Callee allocated buffer. Allocate buffer and return size.
1238 //
1239 *Buffer = AllocatePool (CopySize);
1240 if (*Buffer == NULL) {
1241 Status = EFI_OUT_OF_RESOURCES;
1242 goto GetSection_Done;
1243 }
1244 }
1245 CopyMem (*Buffer, CopyBuffer, CopySize);
1246 *BufferSize = SectionSize;
1247
1248 GetSection_Done:
1249 CoreRestoreTpl (OldTpl);
1250
1251 return Status;
1252 }
1253
1254
1255 /**
1256 Worker function. Destructor for child nodes.
1257
1258 @param ChildNode Indicates the node to destroy
1259
1260 **/
1261 VOID
1262 FreeChildNode (
1263 IN CORE_SECTION_CHILD_NODE *ChildNode
1264 )
1265 {
1266 ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
1267 //
1268 // Remove the child from it's list
1269 //
1270 RemoveEntryList (&ChildNode->Link);
1271
1272 if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1273 //
1274 // If it's an encapsulating section, we close the resulting section stream.
1275 // CloseSectionStream will free all memory associated with the stream.
1276 //
1277 CloseSectionStream (ChildNode->EncapsulatedStreamHandle);
1278 }
1279 //
1280 // Last, free the child node itself
1281 //
1282 CoreFreePool (ChildNode);
1283 }
1284
1285
1286 /**
1287 SEP member function. Deletes an existing section stream
1288
1289 @param StreamHandleToClose Indicates the stream to close
1290
1291 @retval EFI_SUCCESS The section stream is closed sucessfully.
1292 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1293 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1294 of last section.
1295
1296 **/
1297 EFI_STATUS
1298 EFIAPI
1299 CloseSectionStream (
1300 IN UINTN StreamHandleToClose
1301 )
1302 {
1303 CORE_SECTION_STREAM_NODE *StreamNode;
1304 EFI_TPL OldTpl;
1305 EFI_STATUS Status;
1306 LIST_ENTRY *Link;
1307 CORE_SECTION_CHILD_NODE *ChildNode;
1308
1309 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1310
1311 //
1312 // Locate target stream
1313 //
1314 Status = FindStreamNode (StreamHandleToClose, &StreamNode);
1315 if (!EFI_ERROR (Status)) {
1316 //
1317 // Found the stream, so close it
1318 //
1319 RemoveEntryList (&StreamNode->Link);
1320 while (!IsListEmpty (&StreamNode->Children)) {
1321 Link = GetFirstNode (&StreamNode->Children);
1322 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
1323 FreeChildNode (ChildNode);
1324 }
1325 CoreFreePool (StreamNode->StreamBuffer);
1326 CoreFreePool (StreamNode);
1327 Status = EFI_SUCCESS;
1328 } else {
1329 Status = EFI_INVALID_PARAMETER;
1330 }
1331
1332 CoreRestoreTpl (OldTpl);
1333 return Status;
1334 }
1335
1336
1337 /**
1338 The ExtractSection() function processes the input section and
1339 allocates a buffer from the pool in which it returns the section
1340 contents. If the section being extracted contains
1341 authentication information (the section's
1342 GuidedSectionHeader.Attributes field has the
1343 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1344 returned in AuthenticationStatus must reflect the results of
1345 the authentication operation. Depending on the algorithm and
1346 size of the encapsulated data, the time that is required to do
1347 a full authentication may be prohibitively long for some
1348 classes of systems. To indicate this, use
1349 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1350 the security policy driver (see the Platform Initialization
1351 Driver Execution Environment Core Interface Specification for
1352 more details and the GUID definition). If the
1353 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1354 database, then, if possible, full authentication should be
1355 skipped and the section contents simply returned in the
1356 OutputBuffer. In this case, the
1357 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1358 must be set on return. ExtractSection() is callable only from
1359 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1360 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1361 defined in RaiseTPL() in the UEFI 2.0 specification.
1362
1363
1364 @param This Indicates the
1365 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1366 @param InputSection Buffer containing the input GUIDed section
1367 to be processed. OutputBuffer OutputBuffer
1368 is allocated from boot services pool
1369 memory and contains the new section
1370 stream. The caller is responsible for
1371 freeing this buffer.
1372 @param OutputBuffer *OutputBuffer is allocated from boot services
1373 pool memory and contains the new section stream.
1374 The caller is responsible for freeing this buffer.
1375 @param OutputSize A pointer to a caller-allocated UINTN in
1376 which the size of OutputBuffer allocation
1377 is stored. If the function returns
1378 anything other than EFI_SUCCESS, the value
1379 of OutputSize is undefined.
1380
1381 @param AuthenticationStatus A pointer to a caller-allocated
1382 UINT32 that indicates the
1383 authentication status of the
1384 output buffer. If the input
1385 section's
1386 GuidedSectionHeader.Attributes
1387 field has the
1388 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1389 bit as clear, AuthenticationStatus
1390 must return zero. Both local bits
1391 (19:16) and aggregate bits (3:0)
1392 in AuthenticationStatus are
1393 returned by ExtractSection().
1394 These bits reflect the status of
1395 the extraction operation. The bit
1396 pattern in both regions must be
1397 the same, as the local and
1398 aggregate authentication statuses
1399 have equivalent meaning at this
1400 level. If the function returns
1401 anything other than EFI_SUCCESS,
1402 the value of AuthenticationStatus
1403 is undefined.
1404
1405
1406 @retval EFI_SUCCESS The InputSection was successfully
1407 processed and the section contents were
1408 returned.
1409
1410 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1411 resources to process the
1412 request.
1413
1414 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1415 not match this instance of the
1416 GUIDed Section Extraction
1417 Protocol.
1418
1419 **/
1420 EFI_STATUS
1421 EFIAPI
1422 CustomGuidedSectionExtract (
1423 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
1424 IN CONST VOID *InputSection,
1425 OUT VOID **OutputBuffer,
1426 OUT UINTN *OutputSize,
1427 OUT UINT32 *AuthenticationStatus
1428 )
1429 {
1430 EFI_STATUS Status;
1431 VOID *ScratchBuffer;
1432 VOID *AllocatedOutputBuffer;
1433 UINT32 OutputBufferSize;
1434 UINT32 ScratchBufferSize;
1435 UINT16 SectionAttribute;
1436
1437 //
1438 // Init local variable
1439 //
1440 ScratchBuffer = NULL;
1441 AllocatedOutputBuffer = NULL;
1442
1443 //
1444 // Call GetInfo to get the size and attribute of input guided section data.
1445 //
1446 Status = ExtractGuidedSectionGetInfo (
1447 InputSection,
1448 &OutputBufferSize,
1449 &ScratchBufferSize,
1450 &SectionAttribute
1451 );
1452
1453 if (EFI_ERROR (Status)) {
1454 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
1455 return Status;
1456 }
1457
1458 if (ScratchBufferSize > 0) {
1459 //
1460 // Allocate scratch buffer
1461 //
1462 ScratchBuffer = AllocatePool (ScratchBufferSize);
1463 if (ScratchBuffer == NULL) {
1464 return EFI_OUT_OF_RESOURCES;
1465 }
1466 }
1467
1468 if (OutputBufferSize > 0) {
1469 //
1470 // Allocate output buffer
1471 //
1472 AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
1473 if (AllocatedOutputBuffer == NULL) {
1474 FreePool (ScratchBuffer);
1475 return EFI_OUT_OF_RESOURCES;
1476 }
1477 *OutputBuffer = AllocatedOutputBuffer;
1478 }
1479
1480 //
1481 // Call decode function to extract raw data from the guided section.
1482 //
1483 Status = ExtractGuidedSectionDecode (
1484 InputSection,
1485 OutputBuffer,
1486 ScratchBuffer,
1487 AuthenticationStatus
1488 );
1489 if (EFI_ERROR (Status)) {
1490 //
1491 // Decode failed
1492 //
1493 if (AllocatedOutputBuffer != NULL) {
1494 CoreFreePool (AllocatedOutputBuffer);
1495 }
1496 if (ScratchBuffer != NULL) {
1497 CoreFreePool (ScratchBuffer);
1498 }
1499 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
1500 return Status;
1501 }
1502
1503 if (*OutputBuffer != AllocatedOutputBuffer) {
1504 //
1505 // OutputBuffer was returned as a different value,
1506 // so copy section contents to the allocated memory buffer.
1507 //
1508 CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
1509 *OutputBuffer = AllocatedOutputBuffer;
1510 }
1511
1512 //
1513 // Set real size of output buffer.
1514 //
1515 *OutputSize = (UINTN) OutputBufferSize;
1516
1517 //
1518 // Free unused scratch buffer.
1519 //
1520 if (ScratchBuffer != NULL) {
1521 CoreFreePool (ScratchBuffer);
1522 }
1523
1524 return EFI_SUCCESS;
1525 }