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