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