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