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