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