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