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