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