]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / 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 //
217 // Module globals
218 //
219 LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
220
221 EFI_HANDLE mSectionExtractionHandle = NULL;
222
223 EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = {
224 OpenSectionStream,
225 GetSection,
226 CloseSectionStream
227 };
228
229
230 EFI_STATUS
231 EFIAPI
232 InitializeSectionExtraction (
233 IN EFI_HANDLE ImageHandle,
234 IN EFI_SYSTEM_TABLE *SystemTable
235 )
236 /*++
237
238 Routine Description:
239 Entry point of the section extraction code. Initializes an instance of the
240 section extraction interface and installs it on a new handle.
241
242 Arguments:
243 ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver
244 SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
245
246 Returns:
247 EFI_SUCCESS: Driver initialized successfully
248 EFI_OUT_OF_RESOURCES: Could not allocate needed resources
249
250 --*/
251 {
252 EFI_STATUS Status;
253
254 //
255 // Install SEP to a new handle
256 //
257 Status = CoreInstallProtocolInterface (
258 &mSectionExtractionHandle,
259 &gEfiSectionExtractionProtocolGuid,
260 EFI_NATIVE_INTERFACE,
261 &mSectionExtraction
262 );
263 ASSERT_EFI_ERROR (Status);
264
265 return Status;
266 }
267
268 STATIC
269 EFI_STATUS
270 EFIAPI
271 OpenSectionStream (
272 IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
273 IN UINTN SectionStreamLength,
274 IN VOID *SectionStream,
275 OUT UINTN *SectionStreamHandle
276 )
277 /*++
278
279 Routine Description:
280 SEP member function. This function creates and returns a new section stream
281 handle to represent the new section stream.
282
283 Arguments:
284 This - Indicates the calling context.
285 SectionStreamLength - Size in bytes of the section stream.
286 SectionStream - Buffer containing the new section stream.
287 SectionStreamHandle - A pointer to a caller allocated UINTN that on output
288 contains the new section stream handle.
289
290 Returns:
291 EFI_SUCCESS
292 EFI_OUT_OF_RESOURCES - memory allocation failed.
293 EFI_INVALID_PARAMETER - section stream does not end concident with end of
294 last section.
295
296 --*/
297 {
298 //
299 // Check to see section stream looks good...
300 //
301 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
302 return EFI_INVALID_PARAMETER;
303 }
304
305 return OpenSectionStreamEx (
306 SectionStreamLength,
307 SectionStream,
308 TRUE,
309 0,
310 SectionStreamHandle
311 );
312 }
313
314 STATIC
315 EFI_STATUS
316 EFIAPI
317 GetSection (
318 IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
319 IN UINTN SectionStreamHandle,
320 IN EFI_SECTION_TYPE *SectionType,
321 IN EFI_GUID *SectionDefinitionGuid,
322 IN UINTN SectionInstance,
323 IN VOID **Buffer,
324 IN OUT UINTN *BufferSize,
325 OUT UINT32 *AuthenticationStatus
326 )
327 /*++
328
329 Routine Description:
330 SEP member function. Retrieves requested section from section stream.
331
332 Arguments:
333 This: Pointer to SEP instance.
334 SectionStreamHandle: The section stream from which to extract the requested
335 section.
336 SectionType: A pointer to the type of section to search for.
337 SectionDefinitionGuid: If the section type is EFI_SECTION_GUID_DEFINED, then
338 SectionDefinitionGuid indicates which of these types
339 of sections to search for.
340 SectionInstance: Indicates which instance of the requested section to
341 return.
342 Buffer: Double indirection to buffer. If *Buffer is non-null on
343 input, then the buffer is caller allocated. If
344 *Buffer is NULL, then the buffer is callee allocated.
345 In either case, the requried buffer size is returned
346 in *BufferSize.
347 BufferSize: On input, indicates the size of *Buffer if *Buffer is
348 non-null on input. On output, indicates the required
349 size (allocated size if callee allocated) of *Buffer.
350 AuthenticationStatus: Indicates the authentication status of the retrieved
351 section.
352
353 Returns:
354 EFI_SUCCESS: Section was retrieved successfully
355 EFI_PROTOCOL_ERROR: A GUID defined section was encountered in the section
356 stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
357 bit set, but there was no corresponding GUIDed Section
358 Extraction Protocol in the handle database. *Buffer is
359 unmodified.
360 EFI_NOT_FOUND: An error was encountered when parsing the SectionStream.
361 This indicates the SectionStream is not correctly
362 formatted.
363 EFI_NOT_FOUND: The requested section does not exist.
364 EFI_OUT_OF_RESOURCES: The system has insufficient resources to process the
365 request.
366 EFI_INVALID_PARAMETER: The SectionStreamHandle does not exist.
367 EFI_WARN_TOO_SMALL: The size of the caller allocated input buffer is
368 insufficient to contain the requested section. The
369 input buffer is filled and contents are section contents
370 are truncated.
371
372 --*/
373 {
374 CORE_SECTION_STREAM_NODE *StreamNode;
375 EFI_TPL OldTpl;
376 EFI_STATUS Status;
377 CORE_SECTION_CHILD_NODE *ChildNode;
378 CORE_SECTION_STREAM_NODE *ChildStreamNode;
379 UINTN CopySize;
380 UINT32 ExtractedAuthenticationStatus;
381 UINTN Instance;
382 UINT8 *CopyBuffer;
383 UINTN SectionSize;
384
385
386 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
387 Instance = SectionInstance + 1;
388
389 //
390 // Locate target stream
391 //
392 Status = FindStreamNode (SectionStreamHandle, &StreamNode);
393 if (EFI_ERROR (Status)) {
394 Status = EFI_INVALID_PARAMETER;
395 goto GetSection_Done;
396 }
397
398 //
399 // Found the stream, now locate and return the appropriate section
400 //
401 if (SectionType == NULL) {
402 //
403 // SectionType == NULL means return the WHOLE section stream...
404 //
405 CopySize = StreamNode->StreamLength;
406 CopyBuffer = StreamNode->StreamBuffer;
407 *AuthenticationStatus = StreamNode->AuthenticationStatus;
408 } else {
409 //
410 // There's a requested section type, so go find it and return it...
411 //
412 Status = FindChildNode (
413 StreamNode,
414 *SectionType,
415 &Instance,
416 SectionDefinitionGuid,
417 &ChildNode,
418 &ChildStreamNode,
419 &ExtractedAuthenticationStatus
420 );
421 if (EFI_ERROR (Status)) {
422 goto GetSection_Done;
423 }
424 CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER);
425 CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER);
426 *AuthenticationStatus = ExtractedAuthenticationStatus;
427 }
428
429 SectionSize = CopySize;
430 if (*Buffer != NULL) {
431 //
432 // Caller allocated buffer. Fill to size and return required size...
433 //
434 if (*BufferSize < CopySize) {
435 Status = EFI_WARN_BUFFER_TOO_SMALL;
436 CopySize = *BufferSize;
437 }
438 } else {
439 //
440 // Callee allocated buffer. Allocate buffer and return size.
441 //
442 *Buffer = CoreAllocateBootServicesPool (CopySize);
443 if (*Buffer == NULL) {
444 Status = EFI_OUT_OF_RESOURCES;
445 goto GetSection_Done;
446 }
447 }
448 CopyMem (*Buffer, CopyBuffer, CopySize);
449 *BufferSize = SectionSize;
450
451 GetSection_Done:
452 CoreRestoreTpl (OldTpl);
453 return Status;
454 }
455
456
457 STATIC
458 EFI_STATUS
459 EFIAPI
460 CloseSectionStream (
461 IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
462 IN UINTN StreamHandleToClose
463 )
464 /*++
465
466 Routine Description:
467 SEP member function. Deletes an existing section stream
468
469 Arguments:
470 This - Indicates the calling context.
471 StreamHandleToClose - Indicates the stream to close
472
473 Returns:
474 EFI_SUCCESS
475 EFI_OUT_OF_RESOURCES - memory allocation failed.
476 EFI_INVALID_PARAMETER - section stream does not end concident with end of
477 last section.
478
479 --*/
480 {
481 CORE_SECTION_STREAM_NODE *StreamNode;
482 EFI_TPL OldTpl;
483 EFI_STATUS Status;
484 LIST_ENTRY *Link;
485 CORE_SECTION_CHILD_NODE *ChildNode;
486
487 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
488
489 //
490 // Locate target stream
491 //
492 Status = FindStreamNode (StreamHandleToClose, &StreamNode);
493 if (!EFI_ERROR (Status)) {
494 //
495 // Found the stream, so close it
496 //
497 RemoveEntryList (&StreamNode->Link);
498 while (!IsListEmpty (&StreamNode->Children)) {
499 Link = GetFirstNode (&StreamNode->Children);
500 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
501 FreeChildNode (ChildNode);
502 }
503 CoreFreePool (StreamNode->StreamBuffer);
504 CoreFreePool (StreamNode);
505 Status = EFI_SUCCESS;
506 } else {
507 Status = EFI_INVALID_PARAMETER;
508 }
509
510 CoreRestoreTpl (OldTpl);
511 return Status;
512 }
513
514
515 STATIC
516 BOOLEAN
517 ChildIsType (
518 IN CORE_SECTION_STREAM_NODE *Stream,
519 IN CORE_SECTION_CHILD_NODE *Child,
520 IN EFI_SECTION_TYPE SearchType,
521 IN EFI_GUID *SectionDefinitionGuid
522 )
523 /*++
524
525 Routine Description:
526 Worker function. Determine if the input stream:child matches the input type.
527
528 Arguments:
529 Stream - Indicates the section stream associated with the child
530 Child - Indicates the child to check
531 SearchType - Indicates the type of section to check against for
532 SectionDefinitionGuid - Indicates the GUID to check against if the type is
533 EFI_SECTION_GUID_DEFINED
534 Returns:
535 TRUE - The child matches
536 FALSE - The child doesn't match
537
538 --*/
539 {
540 EFI_GUID_DEFINED_SECTION *GuidedSection;
541
542 if (SearchType == EFI_SECTION_ALL) {
543 return TRUE;
544 }
545 if (Child->Type != SearchType) {
546 return FALSE;
547 }
548 if (SearchType != EFI_SECTION_GUID_DEFINED) {
549 return TRUE;
550 }
551 GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
552 return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
553 }
554
555
556 STATIC
557 EFI_STATUS
558 FindChildNode (
559 IN CORE_SECTION_STREAM_NODE *SourceStream,
560 IN EFI_SECTION_TYPE SearchType,
561 IN OUT UINTN *SectionInstance,
562 IN EFI_GUID *SectionDefinitionGuid,
563 OUT CORE_SECTION_CHILD_NODE **FoundChild,
564 OUT CORE_SECTION_STREAM_NODE **FoundStream,
565 OUT UINT32 *AuthenticationStatus
566 )
567 /*++
568
569 Routine Description:
570 Worker function Recursively searches / builds section stream database
571 looking for requested section.
572
573 Arguments:
574 SourceStream - Indicates the section stream in which to do the search.
575 SearchType - Indicates the type of section to search for.
576 SectionInstance - Indicates which instance of section to find. This is
577 an in/out parameter to deal with recursions.
578 SectionDefinitionGuid - Guid of section definition
579 FoundChild - Output indicating the child node that is found.
580 FoundStream - Output indicating which section stream the child was
581 found in. If this stream was generated as a result of
582 an encapsulation section, the streamhandle is visible
583 within the SEP driver only.
584 AuthenticationStatus- Indicates the authentication status of the found section.
585
586 Returns:
587 EFI_SUCCESS - Child node was found and returned.
588 EFI_OUT_OF_RESOURCES- Memory allocation failed.
589 EFI_NOT_FOUND - Requested child node does not exist.
590 EFI_PROTOCOL_ERROR - a required GUIDED section extraction protocol does not
591 exist
592
593 --*/
594 {
595 CORE_SECTION_CHILD_NODE *CurrentChildNode;
596 CORE_SECTION_CHILD_NODE *RecursedChildNode;
597 CORE_SECTION_STREAM_NODE *RecursedFoundStream;
598 UINT32 NextChildOffset;
599 EFI_STATUS ErrorStatus;
600 EFI_STATUS Status;
601
602 CurrentChildNode = NULL;
603 ErrorStatus = EFI_NOT_FOUND;
604
605 if (SourceStream->StreamLength == 0) {
606 return EFI_NOT_FOUND;
607 }
608
609 if (IsListEmpty (&SourceStream->Children) &&
610 SourceStream->StreamLength > sizeof (EFI_COMMON_SECTION_HEADER)) {
611 //
612 // This occurs when a section stream exists, but no child sections
613 // have been parsed out yet. Therefore, extract the first child and add it
614 // to the list of children so we can get started.
615 //
616 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
617 if (EFI_ERROR (Status)) {
618 return Status;
619 }
620 }
621
622 //
623 // At least one child has been parsed out of the section stream. So, walk
624 // through the sections that have already been parsed out looking for the
625 // requested section, if necessary, continue parsing section stream and
626 // adding children until either the requested section is found, or we run
627 // out of data
628 //
629 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
630
631 for (;;) {
632 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
633 //
634 // The type matches, so check the instance count to see if it's the one we want
635 //
636 (*SectionInstance)--;
637 if (*SectionInstance == 0) {
638 //
639 // Got it!
640 //
641 *FoundChild = CurrentChildNode;
642 *FoundStream = SourceStream;
643 *AuthenticationStatus = SourceStream->AuthenticationStatus;
644 return EFI_SUCCESS;
645 }
646 }
647
648 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
649 //
650 // If the current node is an encapsulating node, recurse into it...
651 //
652 Status = FindChildNode (
653 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
654 SearchType,
655 SectionInstance,
656 SectionDefinitionGuid,
657 &RecursedChildNode,
658 &RecursedFoundStream,
659 AuthenticationStatus
660 );
661 //
662 // If the status is not EFI_SUCCESS, just save the error code and continue
663 // to find the request child node in the rest stream.
664 //
665 if (*SectionInstance == 0) {
666 ASSERT_EFI_ERROR (Status);
667 *FoundChild = RecursedChildNode;
668 *FoundStream = RecursedFoundStream;
669 return EFI_SUCCESS;
670 } else {
671 ErrorStatus = Status;
672 }
673 }
674
675 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
676 //
677 // We haven't found the child node we're interested in yet, but there's
678 // still more nodes that have already been parsed so get the next one
679 // and continue searching..
680 //
681 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
682 } else {
683 //
684 // We've exhausted children that have already been parsed, so see if
685 // there's any more data and continue parsing out more children if there
686 // is.
687 //
688 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
689 //
690 // Round up to 4 byte boundary
691 //
692 NextChildOffset += 3;
693 NextChildOffset &= ~(UINTN)3;
694 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
695 //
696 // There's an unparsed child remaining in the stream, so create a new child node
697 //
698 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
699 if (EFI_ERROR (Status)) {
700 return Status;
701 }
702 } else {
703 ASSERT (EFI_ERROR (ErrorStatus));
704 return ErrorStatus;
705 }
706 }
707 }
708 }
709
710
711 STATIC
712 EFI_STATUS
713 CreateChildNode (
714 IN CORE_SECTION_STREAM_NODE *Stream,
715 IN UINT32 ChildOffset,
716 OUT CORE_SECTION_CHILD_NODE **ChildNode
717 )
718 /*++
719
720 Routine Description:
721 Worker function. Constructor for new child nodes.
722
723 Arguments:
724 Stream - Indicates the section stream in which to add the child.
725 ChildOffset - Indicates the offset in Stream that is the beginning
726 of the child section.
727 ChildNode - Indicates the Callee allocated and initialized child.
728
729 Returns:
730 EFI_SUCCESS - Child node was found and returned.
731 EFI_OUT_OF_RESOURCES- Memory allocation failed.
732 EFI_PROTOCOL_ERROR - Encapsulation sections produce new stream handles when
733 the child node is created. If the section type is GUID
734 defined, and the extraction GUID does not exist, and
735 producing the stream requires the GUID, then a protocol
736 error is generated and no child is produced.
737 Values returned by OpenSectionStreamEx.
738
739 --*/
740 {
741 EFI_STATUS Status;
742 EFI_COMMON_SECTION_HEADER *SectionHeader;
743 EFI_COMPRESSION_SECTION *CompressionHeader;
744 EFI_GUID_DEFINED_SECTION *GuidedHeader;
745 EFI_TIANO_DECOMPRESS_PROTOCOL *Decompress;
746 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
747 VOID *NewStreamBuffer;
748 VOID *ScratchBuffer;
749 UINT32 ScratchSize;
750 UINTN NewStreamBufferSize;
751 UINT32 AuthenticationStatus;
752 UINT32 SectionLength;
753
754 CORE_SECTION_CHILD_NODE *Node;
755
756 SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
757
758 //
759 // Allocate a new node
760 //
761 *ChildNode = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_CHILD_NODE));
762 Node = *ChildNode;
763 if (Node == NULL) {
764 return EFI_OUT_OF_RESOURCES;
765 }
766
767 //
768 // Now initialize it
769 //
770 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
771 Node->Type = SectionHeader->Type;
772 Node->Size = SECTION_SIZE (SectionHeader);
773 Node->OffsetInStream = ChildOffset;
774 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
775 Node->EncapsulationGuid = NULL;
776
777 //
778 // If it's an encapsulating section, then create the new section stream also
779 //
780 switch (Node->Type) {
781 case EFI_SECTION_COMPRESSION:
782 //
783 // Get the CompressionSectionHeader
784 //
785 ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));
786
787 CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
788
789 //
790 // Allocate space for the new stream
791 //
792 if (CompressionHeader->UncompressedLength > 0) {
793 NewStreamBufferSize = CompressionHeader->UncompressedLength;
794 NewStreamBuffer = CoreAllocateBootServicesPool (NewStreamBufferSize);
795 if (NewStreamBuffer == NULL) {
796 CoreFreePool (Node);
797 return EFI_OUT_OF_RESOURCES;
798 }
799
800 if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) {
801 //
802 // stream is not actually compressed, just encapsulated. So just copy it.
803 //
804 CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize);
805 } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION ||
806 CompressionHeader->CompressionType == EFI_CUSTOMIZED_COMPRESSION) {
807 //
808 // Decompress the stream
809 //
810 if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) {
811 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
812 } else {
813 Status = CoreLocateProtocol (&gEfiCustomizedDecompressProtocolGuid, NULL, (VOID **)&Decompress);
814 }
815
816 ASSERT_EFI_ERROR (Status);
817
818 Status = Decompress->GetInfo (
819 Decompress,
820 CompressionHeader + 1,
821 Node->Size - sizeof (EFI_COMPRESSION_SECTION),
822 (UINT32 *)&NewStreamBufferSize,
823 &ScratchSize
824 );
825 ASSERT_EFI_ERROR (Status);
826 ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength);
827
828 ScratchBuffer = CoreAllocateBootServicesPool (ScratchSize);
829 if (ScratchBuffer == NULL) {
830 CoreFreePool (Node);
831 CoreFreePool (NewStreamBuffer);
832 return EFI_OUT_OF_RESOURCES;
833 }
834
835 Status = Decompress->Decompress (
836 Decompress,
837 CompressionHeader + 1,
838 Node->Size - sizeof (EFI_COMPRESSION_SECTION),
839 NewStreamBuffer,
840 (UINT32)NewStreamBufferSize,
841 ScratchBuffer,
842 ScratchSize
843 );
844 ASSERT_EFI_ERROR (Status);
845 CoreFreePool (ScratchBuffer);
846 }
847 } else {
848 NewStreamBuffer = NULL;
849 NewStreamBufferSize = 0;
850 }
851
852 Status = OpenSectionStreamEx (
853 NewStreamBufferSize,
854 NewStreamBuffer,
855 FALSE,
856 Stream->AuthenticationStatus,
857 &Node->EncapsulatedStreamHandle
858 );
859 if (EFI_ERROR (Status)) {
860 CoreFreePool (Node);
861 CoreFreePool (NewStreamBuffer);
862 return Status;
863 }
864 break;
865
866 case EFI_SECTION_GUID_DEFINED:
867 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
868 Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
869 Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
870 if (!EFI_ERROR (Status)) {
871 //
872 // NewStreamBuffer is always allocated by ExtractSection... No caller
873 // allocation here.
874 //
875 Status = GuidedExtraction->ExtractSection (
876 GuidedExtraction,
877 GuidedHeader,
878 &NewStreamBuffer,
879 &NewStreamBufferSize,
880 &AuthenticationStatus
881 );
882 if (EFI_ERROR (Status)) {
883 CoreFreePool (*ChildNode);
884 return EFI_PROTOCOL_ERROR;
885 }
886
887 //
888 // Make sure we initialize the new stream with the correct
889 // authentication status for both aggregate and local status fields.
890 //
891 if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
892 //
893 // OR in the parent stream's aggregate status.
894 //
895 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;
896 } else {
897 //
898 // since there's no authentication data contributed by the section,
899 // just inherit the full value from our immediate parent.
900 //
901 AuthenticationStatus = Stream->AuthenticationStatus;
902 }
903
904 Status = OpenSectionStreamEx (
905 NewStreamBufferSize,
906 NewStreamBuffer,
907 FALSE,
908 AuthenticationStatus,
909 &Node->EncapsulatedStreamHandle
910 );
911 if (EFI_ERROR (Status)) {
912 CoreFreePool (*ChildNode);
913 CoreFreePool (NewStreamBuffer);
914 return Status;
915 }
916 } else {
917 //
918 // There's no GUIDed section extraction protocol available.
919 //
920 if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {
921 //
922 // If the section REQUIRES an extraction protocol, then we're toast
923 //
924 CoreFreePool (*ChildNode);
925 return EFI_PROTOCOL_ERROR;
926 }
927
928 //
929 // Figure out the proper authentication status
930 //
931 AuthenticationStatus = Stream->AuthenticationStatus;
932 if (GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
933 //
934 // The local status of the new stream is contained in
935 // AuthenticaionStatus. This value needs to be ORed into the
936 // Aggregate bits also...
937 //
938
939 //
940 // Clear out and initialize the local status
941 //
942 AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL;
943 AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED;
944 //
945 // OR local status into aggregate status
946 //
947 AuthenticationStatus |= AuthenticationStatus >> 16;
948 }
949
950 SectionLength = SECTION_SIZE (GuidedHeader);
951 Status = OpenSectionStreamEx (
952 SectionLength - GuidedHeader->DataOffset,
953 (UINT8 *) GuidedHeader + GuidedHeader->DataOffset,
954 TRUE,
955 AuthenticationStatus,
956 &Node->EncapsulatedStreamHandle
957 );
958 if (EFI_ERROR (Status)) {
959 CoreFreePool (Node);
960 return Status;
961 }
962 }
963
964 if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) ==
965 (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) {
966 //
967 // Need to register for RPN for when the required GUIDed extraction
968 // protocol becomes available. This will enable us to refresh the
969 // AuthenticationStatus cached in the Stream if it's ever requested
970 // again.
971 //
972 CreateGuidedExtractionRpnEvent (Stream, Node);
973 }
974
975 break;
976
977 default:
978
979 //
980 // Nothing to do if it's a leaf
981 //
982 break;
983 }
984
985 //
986 // Last, add the new child node to the stream
987 //
988 InsertTailList (&Stream->Children, &Node->Link);
989
990 return EFI_SUCCESS;
991 }
992
993
994 STATIC
995 VOID
996 CreateGuidedExtractionRpnEvent (
997 IN CORE_SECTION_STREAM_NODE *ParentStream,
998 IN CORE_SECTION_CHILD_NODE *ChildNode
999 )
1000 /*++
1001
1002 Routine Description:
1003 Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
1004 cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
1005
1006 Arguments:
1007 ParentStream - Indicates the parent of the ecnapsulation section (child)
1008 ChildNode - Indicates the child node that is the encapsulation section.
1009
1010 Returns:
1011 None
1012
1013 --*/
1014 {
1015 RPN_EVENT_CONTEXT *Context;
1016
1017 //
1018 // Allocate new event structure and context
1019 //
1020 Context = CoreAllocateBootServicesPool (sizeof (RPN_EVENT_CONTEXT));
1021 ASSERT (Context != NULL);
1022
1023 Context->ChildNode = ChildNode;
1024 Context->ParentStream = ParentStream;
1025
1026 Context->Event = CoreCreateProtocolNotifyEvent (
1027 Context->ChildNode->EncapsulationGuid,
1028 TPL_NOTIFY,
1029 NotifyGuidedExtraction,
1030 Context,
1031 &Context->Registration,
1032 FALSE
1033 );
1034 }
1035
1036
1037 STATIC
1038 VOID
1039 EFIAPI
1040 NotifyGuidedExtraction (
1041 IN EFI_EVENT Event,
1042 IN VOID *RpnContext
1043 )
1044 /*++
1045
1046 Routine Description:
1047 RPN callback function. Removes a stale section stream and re-initializes it
1048 with an updated AuthenticationStatus.
1049
1050 Arguments:
1051 Event - The event that fired
1052 RpnContext - A pointer to the context that allows us to identify
1053 the relevent encapsulation...
1054
1055 Returns:
1056 None
1057
1058 --*/
1059 {
1060 EFI_STATUS Status;
1061 EFI_GUID_DEFINED_SECTION *GuidedHeader;
1062 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
1063 VOID *NewStreamBuffer;
1064 UINTN NewStreamBufferSize;
1065 UINT32 AuthenticationStatus;
1066 RPN_EVENT_CONTEXT *Context;
1067
1068 Context = RpnContext;
1069
1070 Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle);
1071 if (!EFI_ERROR (Status)) {
1072 //
1073 // The stream closed successfully, so re-open the stream with correct AuthenticationStatus
1074 //
1075
1076 GuidedHeader = (EFI_GUID_DEFINED_SECTION *)
1077 (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
1078 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
1079
1080 Status = CoreLocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);
1081 ASSERT_EFI_ERROR (Status);
1082
1083
1084 Status = GuidedExtraction->ExtractSection (
1085 GuidedExtraction,
1086 GuidedHeader,
1087 &NewStreamBuffer,
1088 &NewStreamBufferSize,
1089 &AuthenticationStatus
1090 );
1091 ASSERT_EFI_ERROR (Status);
1092 //
1093 // OR in the parent stream's aggregagate status.
1094 //
1095 AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;
1096 Status = OpenSectionStreamEx (
1097 NewStreamBufferSize,
1098 NewStreamBuffer,
1099 FALSE,
1100 AuthenticationStatus,
1101 &Context->ChildNode->EncapsulatedStreamHandle
1102 );
1103 ASSERT_EFI_ERROR (Status);
1104 }
1105
1106 //
1107 // If above, the stream did not close successfully, it indicates it's
1108 // alread been closed by someone, so just destroy the event and be done with
1109 // it.
1110 //
1111
1112 CoreCloseEvent (Event);
1113 CoreFreePool (Context);
1114 }
1115
1116
1117 STATIC
1118 VOID
1119 FreeChildNode (
1120 IN CORE_SECTION_CHILD_NODE *ChildNode
1121 )
1122 /*++
1123
1124 Routine Description:
1125 Worker function. Destructor for child nodes.
1126
1127 Arguments:
1128 ChildNode - Indicates the node to destroy
1129
1130 Returns:
1131 none
1132
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 (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle);
1147 }
1148 //
1149 // Last, free the child node itself
1150 //
1151 CoreFreePool (ChildNode);
1152 }
1153
1154
1155 STATIC
1156 EFI_STATUS
1157 OpenSectionStreamEx (
1158 IN UINTN SectionStreamLength,
1159 IN VOID *SectionStream,
1160 IN BOOLEAN AllocateBuffer,
1161 IN UINT32 AuthenticationStatus,
1162 OUT UINTN *SectionStreamHandle
1163 )
1164 /*++
1165
1166 Routine Description:
1167 Worker function. Constructor for section streams.
1168
1169 Arguments:
1170 SectionStreamLength - Size in bytes of the section stream.
1171 SectionStream - Buffer containing the new section stream.
1172 AllocateBuffer - Indicates whether the stream buffer is to be copied
1173 or the input buffer is to be used in place.
1174 AuthenticationStatus- Indicates the default authentication status for the
1175 new stream.
1176 SectionStreamHandle - A pointer to a caller allocated section stream handle.
1177
1178 Returns:
1179 EFI_SUCCESS - Stream was added to stream database.
1180 EFI_OUT_OF_RESOURCES - memory allocation failed.
1181
1182 --*/
1183 {
1184 CORE_SECTION_STREAM_NODE *NewStream;
1185 EFI_TPL OldTpl;
1186
1187 //
1188 // Allocate a new stream
1189 //
1190 NewStream = CoreAllocateBootServicesPool (sizeof (CORE_SECTION_STREAM_NODE));
1191 if (NewStream == NULL) {
1192 return EFI_OUT_OF_RESOURCES;
1193 }
1194
1195 if (AllocateBuffer) {
1196 //
1197 // if we're here, we're double buffering, allocate the buffer and copy the
1198 // data in
1199 //
1200 if (SectionStreamLength > 0) {
1201 NewStream->StreamBuffer = CoreAllocateBootServicesPool (SectionStreamLength);
1202 if (NewStream->StreamBuffer == NULL) {
1203 CoreFreePool (NewStream);
1204 return EFI_OUT_OF_RESOURCES;
1205 }
1206 //
1207 // Copy in stream data
1208 //
1209 CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
1210 } else {
1211 //
1212 // It's possible to have a zero length section stream.
1213 //
1214 NewStream->StreamBuffer = NULL;
1215 }
1216 } else {
1217 //
1218 // If were here, the caller has supplied the buffer (it's an internal call)
1219 // so just assign the buffer. This happens when we open section streams
1220 // as a result of expanding an encapsulating section.
1221 //
1222 NewStream->StreamBuffer = SectionStream;
1223 }
1224
1225 //
1226 // Initialize the rest of the section stream
1227 //
1228 NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
1229 NewStream->StreamHandle = (UINTN) NewStream;
1230 NewStream->StreamLength = SectionStreamLength;
1231 InitializeListHead (&NewStream->Children);
1232 NewStream->AuthenticationStatus = AuthenticationStatus;
1233
1234 //
1235 // Add new stream to stream list
1236 //
1237 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1238 InsertTailList (&mStreamRoot, &NewStream->Link);
1239 CoreRestoreTpl (OldTpl);
1240
1241 *SectionStreamHandle = NewStream->StreamHandle;
1242
1243 return EFI_SUCCESS;
1244 }
1245
1246
1247 STATIC
1248 EFI_STATUS
1249 FindStreamNode (
1250 IN UINTN SearchHandle,
1251 OUT CORE_SECTION_STREAM_NODE **FoundStream
1252 )
1253 /*++
1254
1255 Routine Description:
1256 Worker function. Search stream database for requested stream handle.
1257
1258 Arguments:
1259 SearchHandle - Indicates which stream to look for.
1260 FoundStream - Output pointer to the found stream.
1261
1262 Returns:
1263 EFI_SUCCESS - StreamHandle was found and *FoundStream contains
1264 the stream node.
1265 EFI_NOT_FOUND - SearchHandle was not found in the stream database.
1266
1267 --*/
1268 {
1269 CORE_SECTION_STREAM_NODE *StreamNode;
1270
1271 if (!IsListEmpty (&mStreamRoot)) {
1272 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
1273 for (;;) {
1274 if (StreamNode->StreamHandle == SearchHandle) {
1275 *FoundStream = StreamNode;
1276 return EFI_SUCCESS;
1277 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
1278 break;
1279 } else {
1280 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
1281 }
1282 }
1283 }
1284
1285 return EFI_NOT_FOUND;
1286 }
1287
1288
1289 STATIC
1290 BOOLEAN
1291 IsValidSectionStream (
1292 IN VOID *SectionStream,
1293 IN UINTN SectionStreamLength
1294 )
1295 /*++
1296
1297 Routine Description:
1298 Check if a stream is valid.
1299
1300 Arguments:
1301 SectionStream - The section stream to be checked
1302 SectionStreamLength - The length of section stream
1303
1304 Returns:
1305 TRUE
1306 FALSE
1307
1308 --*/
1309 {
1310 UINTN TotalLength;
1311 UINTN SectionLength;
1312 EFI_COMMON_SECTION_HEADER *SectionHeader;
1313 EFI_COMMON_SECTION_HEADER *NextSectionHeader;
1314
1315 TotalLength = 0;
1316 SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
1317
1318 while (TotalLength < SectionStreamLength) {
1319 SectionLength = SECTION_SIZE (SectionHeader);
1320 TotalLength += SectionLength;
1321
1322 if (TotalLength == SectionStreamLength) {
1323 return TRUE;
1324 }
1325
1326 //
1327 // Move to the next byte following the section...
1328 //
1329 SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
1330
1331 //
1332 // Figure out where the next section begins
1333 //
1334 NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) SectionHeader + 3);
1335 NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader & ~(UINTN)3);
1336 TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
1337 SectionHeader = NextSectionHeader;
1338 }
1339
1340 ASSERT (FALSE);
1341 return FALSE;
1342 }