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