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