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