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