]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
Clean up DEC files:
[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 - 2010, 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 SectionLength = SECTION_SIZE (SectionHeader);
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 /**
298 Worker function. Constructor for section streams.
299
300 @param SectionStreamLength Size in bytes of the section stream.
301 @param SectionStream Buffer containing the new section stream.
302 @param AllocateBuffer Indicates whether the stream buffer is to be
303 copied or the input buffer is to be used in
304 place. AuthenticationStatus- Indicates the
305 default authentication status for the new
306 stream.
307 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
308 indicates the authentication status of the
309 output buffer. If the input section's
310 GuidedSectionHeader.Attributes field
311 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
312 bit as clear, AuthenticationStatus must return
313 zero. Both local bits (19:16) and aggregate
314 bits (3:0) in AuthenticationStatus are returned
315 by ExtractSection(). These bits reflect the
316 status of the extraction operation. The bit
317 pattern in both regions must be the same, as
318 the local and aggregate authentication statuses
319 have equivalent meaning at this level. If the
320 function returns anything other than
321 EFI_SUCCESS, the value of *AuthenticationStatus
322 is undefined.
323 @param SectionStreamHandle A pointer to a caller allocated section stream
324 handle.
325
326 @retval EFI_SUCCESS Stream was added to stream database.
327 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
328
329 **/
330 EFI_STATUS
331 OpenSectionStreamEx (
332 IN UINTN SectionStreamLength,
333 IN VOID *SectionStream,
334 IN BOOLEAN AllocateBuffer,
335 IN UINT32 AuthenticationStatus,
336 OUT UINTN *SectionStreamHandle
337 )
338 {
339 CORE_SECTION_STREAM_NODE *NewStream;
340 EFI_TPL OldTpl;
341
342 //
343 // Allocate a new stream
344 //
345 NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
346 if (NewStream == NULL) {
347 return EFI_OUT_OF_RESOURCES;
348 }
349
350 if (AllocateBuffer) {
351 //
352 // if we're here, we're double buffering, allocate the buffer and copy the
353 // data in
354 //
355 if (SectionStreamLength > 0) {
356 NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
357 if (NewStream->StreamBuffer == NULL) {
358 CoreFreePool (NewStream);
359 return EFI_OUT_OF_RESOURCES;
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 /**
403 SEP member function. This function creates and returns a new section stream
404 handle to represent the new section stream.
405
406 @param SectionStreamLength Size in bytes of the section stream.
407 @param SectionStream Buffer containing the new section stream.
408 @param SectionStreamHandle A pointer to a caller allocated UINTN that on
409 output contains the new section stream handle.
410
411 @retval EFI_SUCCESS The section stream is created successfully.
412 @retval EFI_OUT_OF_RESOURCES memory allocation failed.
413 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
414 of last section.
415
416 **/
417 EFI_STATUS
418 EFIAPI
419 OpenSectionStream (
420 IN UINTN SectionStreamLength,
421 IN VOID *SectionStream,
422 OUT UINTN *SectionStreamHandle
423 )
424 {
425 //
426 // Check to see section stream looks good...
427 //
428 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
429 return EFI_INVALID_PARAMETER;
430 }
431
432 return OpenSectionStreamEx (
433 SectionStreamLength,
434 SectionStream,
435 TRUE,
436 0,
437 SectionStreamHandle
438 );
439 }
440
441
442
443 /**
444 Worker function. Determine if the input stream:child matches the input type.
445
446 @param Stream Indicates the section stream associated with the
447 child
448 @param Child Indicates the child to check
449 @param SearchType Indicates the type of section to check against
450 for
451 @param SectionDefinitionGuid Indicates the GUID to check against if the type
452 is EFI_SECTION_GUID_DEFINED
453
454 @retval TRUE The child matches
455 @retval FALSE The child doesn't match
456
457 **/
458 BOOLEAN
459 ChildIsType (
460 IN CORE_SECTION_STREAM_NODE *Stream,
461 IN CORE_SECTION_CHILD_NODE *Child,
462 IN EFI_SECTION_TYPE SearchType,
463 IN EFI_GUID *SectionDefinitionGuid
464 )
465 {
466 EFI_GUID_DEFINED_SECTION *GuidedSection;
467
468 if (SearchType == EFI_SECTION_ALL) {
469 return TRUE;
470 }
471 if (Child->Type != SearchType) {
472 return FALSE;
473 }
474 if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
475 return TRUE;
476 }
477 GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
478 return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
479 }
480
481 /**
482 RPN callback function. Initializes the section stream
483 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
484
485 @param Event The event that fired
486 @param RpnContext A pointer to the context that allows us to identify
487 the relevent encapsulation.
488 **/
489 VOID
490 EFIAPI
491 NotifyGuidedExtraction (
492 IN EFI_EVENT Event,
493 IN VOID *RpnContext
494 )
495 {
496 EFI_STATUS Status;
497 EFI_GUID_DEFINED_SECTION *GuidedHeader;
498 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
499 VOID *NewStreamBuffer;
500 UINTN NewStreamBufferSize;
501 UINT32 AuthenticationStatus;
502 RPN_EVENT_CONTEXT *Context;
503
504 Context = RpnContext;
505
506 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
507 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
508
509 Status = gBS->LocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
510 if (EFI_ERROR (Status)) {
511 return;
512 }
513
514 Status = GuidedExtraction->ExtractSection (
515 GuidedExtraction,
516 GuidedHeader,
517 &NewStreamBuffer,
518 &NewStreamBufferSize,
519 &AuthenticationStatus
520 );
521 ASSERT_EFI_ERROR (Status);
522
523 //
524 // Make sure we initialize the new stream with the correct
525 // authentication status for both aggregate and local status fields.
526 //
527 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
528 //
529 // OR in the parent stream's aggregate status.
530 //
531 AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
532 } else {
533 //
534 // since there's no authentication data contributed by the section,
535 // just inherit the full value from our immediate parent.
536 //
537 AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
538 }
539
540 Status = OpenSectionStreamEx (
541 NewStreamBufferSize,
542 NewStreamBuffer,
543 FALSE,
544 AuthenticationStatus,
545 &Context->ChildNode->EncapsulatedStreamHandle
546 );
547 ASSERT_EFI_ERROR (Status);
548
549 //
550 // Close the event when done.
551 //
552 gBS->CloseEvent (Event);
553 FreePool (Context);
554 }
555
556 /**
557 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
558
559 @param ParentStream Indicates the parent of the ecnapsulation section (child)
560 @param ChildNode Indicates the child node that is the encapsulation section.
561
562 **/
563 VOID
564 CreateGuidedExtractionRpnEvent (
565 IN CORE_SECTION_STREAM_NODE *ParentStream,
566 IN CORE_SECTION_CHILD_NODE *ChildNode
567 )
568 {
569 RPN_EVENT_CONTEXT *Context;
570
571 //
572 // Allocate new event structure and context
573 //
574 Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
575 ASSERT (Context != NULL);
576
577 Context->ChildNode = ChildNode;
578 Context->ParentStream = ParentStream;
579
580 Context->Event = EfiCreateProtocolNotifyEvent (
581 Context->ChildNode->EncapsulationGuid,
582 TPL_NOTIFY,
583 NotifyGuidedExtraction,
584 Context,
585 &Context->Registration
586 );
587 }
588
589 /**
590 Worker function. Constructor for new child nodes.
591
592 @param Stream Indicates the section stream in which to add the
593 child.
594 @param ChildOffset Indicates the offset in Stream that is the
595 beginning of the child section.
596 @param ChildNode Indicates the Callee allocated and initialized
597 child.
598
599 @retval EFI_SUCCESS Child node was found and returned.
600 EFI_OUT_OF_RESOURCES- Memory allocation failed.
601 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
602 handles when the child node is created. If the
603 section type is GUID defined, and the extraction
604 GUID does not exist, and producing the stream
605 requires the GUID, then a protocol error is
606 generated and no child is produced. Values
607 returned by OpenSectionStreamEx.
608
609 **/
610 EFI_STATUS
611 CreateChildNode (
612 IN CORE_SECTION_STREAM_NODE *Stream,
613 IN UINT32 ChildOffset,
614 OUT CORE_SECTION_CHILD_NODE **ChildNode
615 )
616 {
617 EFI_STATUS Status;
618 EFI_COMMON_SECTION_HEADER *SectionHeader;
619 EFI_COMPRESSION_SECTION *CompressionHeader;
620 EFI_GUID_DEFINED_SECTION *GuidedHeader;
621 EFI_DECOMPRESS_PROTOCOL *Decompress;
622 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
623 VOID *NewStreamBuffer;
624 VOID *ScratchBuffer;
625 UINT32 ScratchSize;
626 UINTN NewStreamBufferSize;
627 UINT32 AuthenticationStatus;
628 UINT32 SectionLength;
629
630 CORE_SECTION_CHILD_NODE *Node;
631
632 SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
633
634 //
635 // Allocate a new node
636 //
637 *ChildNode = AllocatePool (sizeof (CORE_SECTION_CHILD_NODE));
638 Node = *ChildNode;
639 if (Node == NULL) {
640 return EFI_OUT_OF_RESOURCES;
641 }
642
643 //
644 // Now initialize it
645 //
646 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
647 Node->Type = SectionHeader->Type;
648 Node->Size = SECTION_SIZE (SectionHeader);
649 Node->OffsetInStream = ChildOffset;
650 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
651 Node->EncapsulationGuid = NULL;
652
653 //
654 // If it's an encapsulating section, then create the new section stream also
655 //
656 switch (Node->Type) {
657 case EFI_SECTION_COMPRESSION:
658 //
659 // Get the CompressionSectionHeader
660 //
661 ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));
662
663 CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
664
665 //
666 // Allocate space for the new stream
667 //
668 if (CompressionHeader->UncompressedLength > 0) {
669 NewStreamBufferSize = CompressionHeader->UncompressedLength;
670 NewStreamBuffer = AllocatePool (NewStreamBufferSize);
671 if (NewStreamBuffer == NULL) {
672 CoreFreePool (Node);
673 return EFI_OUT_OF_RESOURCES;
674 }
675
676 if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) {
677 //
678 // stream is not actually compressed, just encapsulated. So just copy it.
679 //
680 CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize);
681 } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) {
682 //
683 // Only support the EFI_SATNDARD_COMPRESSION algorithm.
684 //
685
686 //
687 // Decompress the stream
688 //
689 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
690 ASSERT_EFI_ERROR (Status);
691 ASSERT (Decompress != NULL);
692
693 Status = Decompress->GetInfo (
694 Decompress,
695 CompressionHeader + 1,
696 Node->Size - sizeof (EFI_COMPRESSION_SECTION),
697 (UINT32 *)&NewStreamBufferSize,
698 &ScratchSize
699 );
700 ASSERT_EFI_ERROR (Status);
701 ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength);
702
703 ScratchBuffer = AllocatePool (ScratchSize);
704 if (ScratchBuffer == NULL) {
705 CoreFreePool (Node);
706 CoreFreePool (NewStreamBuffer);
707 return EFI_OUT_OF_RESOURCES;
708 }
709
710 Status = Decompress->Decompress (
711 Decompress,
712 CompressionHeader + 1,
713 Node->Size - sizeof (EFI_COMPRESSION_SECTION),
714 NewStreamBuffer,
715 (UINT32)NewStreamBufferSize,
716 ScratchBuffer,
717 ScratchSize
718 );
719 ASSERT_EFI_ERROR (Status);
720 CoreFreePool (ScratchBuffer);
721 }
722 } else {
723 NewStreamBuffer = NULL;
724 NewStreamBufferSize = 0;
725 }
726
727 Status = OpenSectionStreamEx (
728 NewStreamBufferSize,
729 NewStreamBuffer,
730 FALSE,
731 Stream->AuthenticationStatus,
732 &Node->EncapsulatedStreamHandle
733 );
734 if (EFI_ERROR (Status)) {
735 CoreFreePool (Node);
736 CoreFreePool (NewStreamBuffer);
737 return Status;
738 }
739 break;
740
741 case EFI_SECTION_GUID_DEFINED:
742 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
743 Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
744 Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
745 if (!EFI_ERROR (Status) && GuidedExtraction != NULL) {
746 //
747 // NewStreamBuffer is always allocated by ExtractSection... No caller
748 // allocation here.
749 //
750 Status = GuidedExtraction->ExtractSection (
751 GuidedExtraction,
752 GuidedHeader,
753 &NewStreamBuffer,
754 &NewStreamBufferSize,
755 &AuthenticationStatus
756 );
757 if (EFI_ERROR (Status)) {
758 CoreFreePool (*ChildNode);
759 return EFI_PROTOCOL_ERROR;
760 }
761
762 //
763 // Make sure we initialize the new stream with the correct
764 // authentication status for both aggregate and local status fields.
765 //
766 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
767 //
768 // OR in the parent stream's aggregate status.
769 //
770 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
771 } else {
772 //
773 // since there's no authentication data contributed by the section,
774 // just inherit the full value from our immediate parent.
775 //
776 AuthenticationStatus = Stream->AuthenticationStatus;
777 }
778
779 Status = OpenSectionStreamEx (
780 NewStreamBufferSize,
781 NewStreamBuffer,
782 FALSE,
783 AuthenticationStatus,
784 &Node->EncapsulatedStreamHandle
785 );
786 if (EFI_ERROR (Status)) {
787 CoreFreePool (*ChildNode);
788 CoreFreePool (NewStreamBuffer);
789 return Status;
790 }
791 } else {
792 //
793 // There's no GUIDed section extraction protocol available.
794 //
795 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
796 //
797 // If the section REQUIRES an extraction protocol, register for RPN
798 // when the required GUIDed extraction protocol becomes available.
799 //
800 CreateGuidedExtractionRpnEvent (Stream, Node);
801 } else {
802 //
803 // Figure out the proper authentication status
804 //
805 AuthenticationStatus = Stream->AuthenticationStatus;
806
807 SectionLength = SECTION_SIZE (GuidedHeader);
808 Status = OpenSectionStreamEx (
809 SectionLength - GuidedHeader->DataOffset,
810 (UINT8 *) GuidedHeader + GuidedHeader->DataOffset,
811 TRUE,
812 AuthenticationStatus,
813 &Node->EncapsulatedStreamHandle
814 );
815 if (EFI_ERROR (Status)) {
816 CoreFreePool (Node);
817 return Status;
818 }
819 }
820 }
821
822 break;
823
824 default:
825
826 //
827 // Nothing to do if it's a leaf
828 //
829 break;
830 }
831
832 //
833 // Last, add the new child node to the stream
834 //
835 InsertTailList (&Stream->Children, &Node->Link);
836
837 return EFI_SUCCESS;
838 }
839
840
841 /**
842 Worker function Recursively searches / builds section stream database
843 looking for requested section.
844
845 @param SourceStream Indicates the section stream in which to do the
846 search.
847 @param SearchType Indicates the type of section to search for.
848 @param SectionInstance Indicates which instance of section to find.
849 This is an in/out parameter to deal with
850 recursions.
851 @param SectionDefinitionGuid Guid of section definition
852 @param FoundChild Output indicating the child node that is found.
853 @param FoundStream Output indicating which section stream the child
854 was found in. If this stream was generated as a
855 result of an encapsulation section, the
856 streamhandle is visible within the SEP driver
857 only.
858 @param AuthenticationStatus Indicates the authentication status of the found section.
859
860 @retval EFI_SUCCESS Child node was found and returned.
861 EFI_OUT_OF_RESOURCES- Memory allocation failed.
862 @retval EFI_NOT_FOUND Requested child node does not exist.
863 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
864 does not exist
865
866 **/
867 EFI_STATUS
868 FindChildNode (
869 IN CORE_SECTION_STREAM_NODE *SourceStream,
870 IN EFI_SECTION_TYPE SearchType,
871 IN OUT UINTN *SectionInstance,
872 IN EFI_GUID *SectionDefinitionGuid,
873 OUT CORE_SECTION_CHILD_NODE **FoundChild,
874 OUT CORE_SECTION_STREAM_NODE **FoundStream,
875 OUT UINT32 *AuthenticationStatus
876 )
877 {
878 CORE_SECTION_CHILD_NODE *CurrentChildNode;
879 CORE_SECTION_CHILD_NODE *RecursedChildNode;
880 CORE_SECTION_STREAM_NODE *RecursedFoundStream;
881 UINT32 NextChildOffset;
882 EFI_STATUS ErrorStatus;
883 EFI_STATUS Status;
884
885 CurrentChildNode = NULL;
886 ErrorStatus = EFI_NOT_FOUND;
887
888 if (SourceStream->StreamLength == 0) {
889 return EFI_NOT_FOUND;
890 }
891
892 if (IsListEmpty (&SourceStream->Children) &&
893 SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
894 //
895 // This occurs when a section stream exists, but no child sections
896 // have been parsed out yet. Therefore, extract the first child and add it
897 // to the list of children so we can get started.
898 // Section stream may contain an array of zero or more bytes.
899 // So, its size should be >= the size of commen section header.
900 //
901 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
902 if (EFI_ERROR (Status)) {
903 return Status;
904 }
905 }
906
907 //
908 // At least one child has been parsed out of the section stream. So, walk
909 // through the sections that have already been parsed out looking for the
910 // requested section, if necessary, continue parsing section stream and
911 // adding children until either the requested section is found, or we run
912 // out of data
913 //
914 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
915
916 for (;;) {
917 ASSERT (CurrentChildNode != NULL);
918 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
919 //
920 // The type matches, so check the instance count to see if it's the one we want
921 //
922 (*SectionInstance)--;
923 if (*SectionInstance == 0) {
924 //
925 // Got it!
926 //
927 *FoundChild = CurrentChildNode;
928 *FoundStream = SourceStream;
929 *AuthenticationStatus = SourceStream->AuthenticationStatus;
930 return EFI_SUCCESS;
931 }
932 }
933
934 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
935 //
936 // If the current node is an encapsulating node, recurse into it...
937 //
938 Status = FindChildNode (
939 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
940 SearchType,
941 SectionInstance,
942 SectionDefinitionGuid,
943 &RecursedChildNode,
944 &RecursedFoundStream,
945 AuthenticationStatus
946 );
947 //
948 // If the status is not EFI_SUCCESS, just save the error code and continue
949 // to find the request child node in the rest stream.
950 //
951 if (*SectionInstance == 0) {
952 ASSERT_EFI_ERROR (Status);
953 *FoundChild = RecursedChildNode;
954 *FoundStream = RecursedFoundStream;
955 return EFI_SUCCESS;
956 } else {
957 ErrorStatus = Status;
958 }
959 } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
960 //
961 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
962 // because a required GUIDED section extraction protocol does not exist.
963 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
964 //
965 ErrorStatus = EFI_PROTOCOL_ERROR;
966 }
967
968 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
969 //
970 // We haven't found the child node we're interested in yet, but there's
971 // still more nodes that have already been parsed so get the next one
972 // and continue searching..
973 //
974 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
975 } else {
976 //
977 // We've exhausted children that have already been parsed, so see if
978 // there's any more data and continue parsing out more children if there
979 // is.
980 //
981 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
982 //
983 // Round up to 4 byte boundary
984 //
985 NextChildOffset += 3;
986 NextChildOffset &= ~(UINTN) 3;
987 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
988 //
989 // There's an unparsed child remaining in the stream, so create a new child node
990 //
991 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
992 if (EFI_ERROR (Status)) {
993 return Status;
994 }
995 } else {
996 ASSERT (EFI_ERROR (ErrorStatus));
997 return ErrorStatus;
998 }
999 }
1000 }
1001 }
1002
1003
1004 /**
1005 Worker function. Search stream database for requested stream handle.
1006
1007 @param SearchHandle Indicates which stream to look for.
1008 @param FoundStream Output pointer to the found stream.
1009
1010 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
1011 the stream node.
1012 @retval EFI_NOT_FOUND SearchHandle was not found in the stream
1013 database.
1014
1015 **/
1016 EFI_STATUS
1017 FindStreamNode (
1018 IN UINTN SearchHandle,
1019 OUT CORE_SECTION_STREAM_NODE **FoundStream
1020 )
1021 {
1022 CORE_SECTION_STREAM_NODE *StreamNode;
1023
1024 if (!IsListEmpty (&mStreamRoot)) {
1025 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
1026 for (;;) {
1027 if (StreamNode->StreamHandle == SearchHandle) {
1028 *FoundStream = StreamNode;
1029 return EFI_SUCCESS;
1030 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
1031 break;
1032 } else {
1033 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
1034 }
1035 }
1036 }
1037
1038 return EFI_NOT_FOUND;
1039 }
1040
1041
1042 /**
1043 SEP member function. Retrieves requested section from section stream.
1044
1045 @param SectionStreamHandle The section stream from which to extract the
1046 requested section.
1047 @param SectionType A pointer to the type of section to search for.
1048 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
1049 then SectionDefinitionGuid indicates which of
1050 these types of sections to search for.
1051 @param SectionInstance Indicates which instance of the requested
1052 section to return.
1053 @param Buffer Double indirection to buffer. If *Buffer is
1054 non-null on input, then the buffer is caller
1055 allocated. If Buffer is NULL, then the buffer
1056 is callee allocated. In either case, the
1057 requried buffer size is returned in *BufferSize.
1058 @param BufferSize On input, indicates the size of *Buffer if
1059 *Buffer is non-null on input. On output,
1060 indicates the required size (allocated size if
1061 callee allocated) of *Buffer.
1062 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
1063 indicates the authentication status of the
1064 output buffer. If the input section's
1065 GuidedSectionHeader.Attributes field
1066 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
1067 bit as clear, AuthenticationStatus must return
1068 zero. Both local bits (19:16) and aggregate
1069 bits (3:0) in AuthenticationStatus are returned
1070 by ExtractSection(). These bits reflect the
1071 status of the extraction operation. The bit
1072 pattern in both regions must be the same, as
1073 the local and aggregate authentication statuses
1074 have equivalent meaning at this level. If the
1075 function returns anything other than
1076 EFI_SUCCESS, the value of *AuthenticationStatus
1077 is undefined.
1078
1079 @retval EFI_SUCCESS Section was retrieved successfully
1080 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
1081 section stream with its
1082 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
1083 but there was no corresponding GUIDed Section
1084 Extraction Protocol in the handle database.
1085 *Buffer is unmodified.
1086 @retval EFI_NOT_FOUND An error was encountered when parsing the
1087 SectionStream. This indicates the SectionStream
1088 is not correctly formatted.
1089 @retval EFI_NOT_FOUND The requested section does not exist.
1090 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
1091 the request.
1092 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
1093 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
1094 insufficient to contain the requested section.
1095 The input buffer is filled and section contents
1096 are truncated.
1097
1098 **/
1099 EFI_STATUS
1100 EFIAPI
1101 GetSection (
1102 IN UINTN SectionStreamHandle,
1103 IN EFI_SECTION_TYPE *SectionType,
1104 IN EFI_GUID *SectionDefinitionGuid,
1105 IN UINTN SectionInstance,
1106 IN VOID **Buffer,
1107 IN OUT UINTN *BufferSize,
1108 OUT UINT32 *AuthenticationStatus
1109 )
1110 {
1111 CORE_SECTION_STREAM_NODE *StreamNode;
1112 EFI_TPL OldTpl;
1113 EFI_STATUS Status;
1114 CORE_SECTION_CHILD_NODE *ChildNode;
1115 CORE_SECTION_STREAM_NODE *ChildStreamNode;
1116 UINTN CopySize;
1117 UINT32 ExtractedAuthenticationStatus;
1118 UINTN Instance;
1119 UINT8 *CopyBuffer;
1120 UINTN SectionSize;
1121
1122
1123 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1124 Instance = SectionInstance + 1;
1125
1126 //
1127 // Locate target stream
1128 //
1129 Status = FindStreamNode (SectionStreamHandle, &StreamNode);
1130 if (EFI_ERROR (Status)) {
1131 Status = EFI_INVALID_PARAMETER;
1132 goto GetSection_Done;
1133 }
1134
1135 //
1136 // Found the stream, now locate and return the appropriate section
1137 //
1138 if (SectionType == NULL) {
1139 //
1140 // SectionType == NULL means return the WHOLE section stream...
1141 //
1142 CopySize = StreamNode->StreamLength;
1143 CopyBuffer = StreamNode->StreamBuffer;
1144 *AuthenticationStatus = StreamNode->AuthenticationStatus;
1145 } else {
1146 //
1147 // There's a requested section type, so go find it and return it...
1148 //
1149 Status = FindChildNode (
1150 StreamNode,
1151 *SectionType,
1152 &Instance,
1153 SectionDefinitionGuid,
1154 &ChildNode,
1155 &ChildStreamNode,
1156 &ExtractedAuthenticationStatus
1157 );
1158 if (EFI_ERROR (Status)) {
1159 goto GetSection_Done;
1160 }
1161 CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER);
1162 CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER);
1163 *AuthenticationStatus = ExtractedAuthenticationStatus;
1164 }
1165
1166 SectionSize = CopySize;
1167 if (*Buffer != NULL) {
1168 //
1169 // Caller allocated buffer. Fill to size and return required size...
1170 //
1171 if (*BufferSize < CopySize) {
1172 Status = EFI_WARN_BUFFER_TOO_SMALL;
1173 CopySize = *BufferSize;
1174 }
1175 } else {
1176 //
1177 // Callee allocated buffer. Allocate buffer and return size.
1178 //
1179 *Buffer = AllocatePool (CopySize);
1180 if (*Buffer == NULL) {
1181 Status = EFI_OUT_OF_RESOURCES;
1182 goto GetSection_Done;
1183 }
1184 }
1185 CopyMem (*Buffer, CopyBuffer, CopySize);
1186 *BufferSize = SectionSize;
1187
1188 GetSection_Done:
1189 CoreRestoreTpl (OldTpl);
1190
1191 return Status;
1192 }
1193
1194
1195 /**
1196 Worker function. Destructor for child nodes.
1197
1198 @param ChildNode Indicates the node to destroy
1199
1200 **/
1201 VOID
1202 FreeChildNode (
1203 IN CORE_SECTION_CHILD_NODE *ChildNode
1204 )
1205 {
1206 ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
1207 //
1208 // Remove the child from it's list
1209 //
1210 RemoveEntryList (&ChildNode->Link);
1211
1212 if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
1213 //
1214 // If it's an encapsulating section, we close the resulting section stream.
1215 // CloseSectionStream will free all memory associated with the stream.
1216 //
1217 CloseSectionStream (ChildNode->EncapsulatedStreamHandle);
1218 }
1219 //
1220 // Last, free the child node itself
1221 //
1222 CoreFreePool (ChildNode);
1223 }
1224
1225
1226 /**
1227 SEP member function. Deletes an existing section stream
1228
1229 @param StreamHandleToClose Indicates the stream to close
1230
1231 @retval EFI_SUCCESS The section stream is closed sucessfully.
1232 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1233 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
1234 of last section.
1235
1236 **/
1237 EFI_STATUS
1238 EFIAPI
1239 CloseSectionStream (
1240 IN UINTN StreamHandleToClose
1241 )
1242 {
1243 CORE_SECTION_STREAM_NODE *StreamNode;
1244 EFI_TPL OldTpl;
1245 EFI_STATUS Status;
1246 LIST_ENTRY *Link;
1247 CORE_SECTION_CHILD_NODE *ChildNode;
1248
1249 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1250
1251 //
1252 // Locate target stream
1253 //
1254 Status = FindStreamNode (StreamHandleToClose, &StreamNode);
1255 if (!EFI_ERROR (Status)) {
1256 //
1257 // Found the stream, so close it
1258 //
1259 RemoveEntryList (&StreamNode->Link);
1260 while (!IsListEmpty (&StreamNode->Children)) {
1261 Link = GetFirstNode (&StreamNode->Children);
1262 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
1263 FreeChildNode (ChildNode);
1264 }
1265 CoreFreePool (StreamNode->StreamBuffer);
1266 CoreFreePool (StreamNode);
1267 Status = EFI_SUCCESS;
1268 } else {
1269 Status = EFI_INVALID_PARAMETER;
1270 }
1271
1272 CoreRestoreTpl (OldTpl);
1273 return Status;
1274 }
1275
1276
1277 /**
1278 The ExtractSection() function processes the input section and
1279 allocates a buffer from the pool in which it returns the section
1280 contents. If the section being extracted contains
1281 authentication information (the section's
1282 GuidedSectionHeader.Attributes field has the
1283 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
1284 returned in AuthenticationStatus must reflect the results of
1285 the authentication operation. Depending on the algorithm and
1286 size of the encapsulated data, the time that is required to do
1287 a full authentication may be prohibitively long for some
1288 classes of systems. To indicate this, use
1289 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
1290 the security policy driver (see the Platform Initialization
1291 Driver Execution Environment Core Interface Specification for
1292 more details and the GUID definition). If the
1293 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
1294 database, then, if possible, full authentication should be
1295 skipped and the section contents simply returned in the
1296 OutputBuffer. In this case, the
1297 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
1298 must be set on return. ExtractSection() is callable only from
1299 TPL_NOTIFY and below. Behavior of ExtractSection() at any
1300 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
1301 defined in RaiseTPL() in the UEFI 2.0 specification.
1302
1303
1304 @param This Indicates the
1305 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
1306 @param InputSection Buffer containing the input GUIDed section
1307 to be processed. OutputBuffer OutputBuffer
1308 is allocated from boot services pool
1309 memory and contains the new section
1310 stream. The caller is responsible for
1311 freeing this buffer.
1312 @param OutputBuffer *OutputBuffer is allocated from boot services
1313 pool memory and contains the new section stream.
1314 The caller is responsible for freeing this buffer.
1315 @param OutputSize A pointer to a caller-allocated UINTN in
1316 which the size of OutputBuffer allocation
1317 is stored. If the function returns
1318 anything other than EFI_SUCCESS, the value
1319 of OutputSize is undefined.
1320
1321 @param AuthenticationStatus A pointer to a caller-allocated
1322 UINT32 that indicates the
1323 authentication status of the
1324 output buffer. If the input
1325 section's
1326 GuidedSectionHeader.Attributes
1327 field has the
1328 EFI_GUIDED_SECTION_AUTH_STATUS_VAL
1329 bit as clear, AuthenticationStatus
1330 must return zero. Both local bits
1331 (19:16) and aggregate bits (3:0)
1332 in AuthenticationStatus are
1333 returned by ExtractSection().
1334 These bits reflect the status of
1335 the extraction operation. The bit
1336 pattern in both regions must be
1337 the same, as the local and
1338 aggregate authentication statuses
1339 have equivalent meaning at this
1340 level. If the function returns
1341 anything other than EFI_SUCCESS,
1342 the value of AuthenticationStatus
1343 is undefined.
1344
1345
1346 @retval EFI_SUCCESS The InputSection was successfully
1347 processed and the section contents were
1348 returned.
1349
1350 @retval EFI_OUT_OF_RESOURCES The system has insufficient
1351 resources to process the
1352 request.
1353
1354 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
1355 not match this instance of the
1356 GUIDed Section Extraction
1357 Protocol.
1358
1359 **/
1360 EFI_STATUS
1361 EFIAPI
1362 CustomGuidedSectionExtract (
1363 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
1364 IN CONST VOID *InputSection,
1365 OUT VOID **OutputBuffer,
1366 OUT UINTN *OutputSize,
1367 OUT UINT32 *AuthenticationStatus
1368 )
1369 {
1370 EFI_STATUS Status;
1371 VOID *ScratchBuffer;
1372 VOID *AllocatedOutputBuffer;
1373 UINT32 OutputBufferSize;
1374 UINT32 ScratchBufferSize;
1375 UINT16 SectionAttribute;
1376
1377 //
1378 // Init local variable
1379 //
1380 ScratchBuffer = NULL;
1381 AllocatedOutputBuffer = NULL;
1382
1383 //
1384 // Call GetInfo to get the size and attribute of input guided section data.
1385 //
1386 Status = ExtractGuidedSectionGetInfo (
1387 InputSection,
1388 &OutputBufferSize,
1389 &ScratchBufferSize,
1390 &SectionAttribute
1391 );
1392
1393 if (EFI_ERROR (Status)) {
1394 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
1395 return Status;
1396 }
1397
1398 if (ScratchBufferSize > 0) {
1399 //
1400 // Allocate scratch buffer
1401 //
1402 ScratchBuffer = AllocatePool (ScratchBufferSize);
1403 if (ScratchBuffer == NULL) {
1404 return EFI_OUT_OF_RESOURCES;
1405 }
1406 }
1407
1408 if (OutputBufferSize > 0) {
1409 //
1410 // Allocate output buffer
1411 //
1412 AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
1413 if (AllocatedOutputBuffer == NULL) {
1414 FreePool (ScratchBuffer);
1415 return EFI_OUT_OF_RESOURCES;
1416 }
1417 *OutputBuffer = AllocatedOutputBuffer;
1418 }
1419
1420 //
1421 // Call decode function to extract raw data from the guided section.
1422 //
1423 Status = ExtractGuidedSectionDecode (
1424 InputSection,
1425 OutputBuffer,
1426 ScratchBuffer,
1427 AuthenticationStatus
1428 );
1429 if (EFI_ERROR (Status)) {
1430 //
1431 // Decode failed
1432 //
1433 if (AllocatedOutputBuffer != NULL) {
1434 CoreFreePool (AllocatedOutputBuffer);
1435 }
1436 if (ScratchBuffer != NULL) {
1437 CoreFreePool (ScratchBuffer);
1438 }
1439 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
1440 return Status;
1441 }
1442
1443 if (*OutputBuffer != AllocatedOutputBuffer) {
1444 //
1445 // OutputBuffer was returned as a different value,
1446 // so copy section contents to the allocated memory buffer.
1447 //
1448 CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
1449 *OutputBuffer = AllocatedOutputBuffer;
1450 }
1451
1452 //
1453 // Set real size of output buffer.
1454 //
1455 *OutputSize = (UINTN) OutputBufferSize;
1456
1457 //
1458 // Free unused scratch buffer.
1459 //
1460 if (ScratchBuffer != NULL) {
1461 CoreFreePool (ScratchBuffer);
1462 }
1463
1464 return EFI_SUCCESS;
1465 }