]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
MdeModulePkg/Core/Dxe: limit FwVol encapsulation section recursion
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / SectionExtraction / CoreSectionExtraction.c
CommitLineData
162ed594 1/** @file\r
28a00297 2 Section Extraction Protocol implementation.\r
022c6d45 3\r
28a00297 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
022c6d45 6 encapsulations.\r
7\r
28a00297 8 Children that are encapsulations generate new stream entries\r
022c6d45 9 when they are created. Streams can also be created by calls to\r
28a00297 10 SEP->OpenSectionStream().\r
022c6d45 11\r
28a00297 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
022c6d45 14\r
28a00297 15 If a GUIDed encapsulation is encountered, there are three possiblilites.\r
022c6d45 16\r
28a00297 17 1) A support protocol is found, in which the stream is simply processed with\r
18 the support protocol.\r
022c6d45 19\r
28a00297 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
022c6d45 24 extraction protocol is published.This insures the AuthenticationStatus\r
28a00297 25 does not become stale in the cache.\r
022c6d45 26\r
28a00297 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
23c98c94 29\r
d1102dba 30Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 31SPDX-License-Identifier: BSD-2-Clause-Patent\r
797a9d67 32\r
33**/\r
28a00297 34\r
9c4ac31c 35#include "DxeMain.h"\r
28a00297 36\r
37//\r
38// Local defines and typedefs\r
39//\r
f3f2e05d 40#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')\r
28a00297 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
805c2dd1 63 //\r
d1102dba 64 // If the section REQUIRES an extraction protocol, register for RPN\r
805c2dd1
SZ
65 // when the required GUIDed extraction protocol becomes available.\r
66 //\r
67 EFI_EVENT Event;\r
28a00297 68} CORE_SECTION_CHILD_NODE;\r
69\r
f3f2e05d 70#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')\r
28a00297 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
28a00297 93} RPN_EVENT_CONTEXT;\r
022c6d45 94\r
95\r
162ed594 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
022c6d45 122\r
162ed594 123 @param This Indicates the\r
124 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.\r
162ed594 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
022c6d45 139\r
162ed594 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
d8c79a81 179EFI_STATUS\r
797a9d67 180EFIAPI\r
18fd8d65 181CustomGuidedSectionExtract (\r
23c98c94 182 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,\r
d8c79a81
LG
183 IN CONST VOID *InputSection,\r
184 OUT VOID **OutputBuffer,\r
185 OUT UINTN *OutputSize,\r
186 OUT UINT32 *AuthenticationStatus\r
022c6d45 187 );\r
e94a9ff7 188\r
28a00297 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
18fd8d65
LG
196EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {\r
197 CustomGuidedSectionExtract\r
d8c79a81 198};\r
022c6d45 199\r
162ed594 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
28a00297 212EFI_STATUS\r
213EFIAPI\r
214InitializeSectionExtraction (\r
215 IN EFI_HANDLE ImageHandle,\r
216 IN EFI_SYSTEM_TABLE *SystemTable\r
217 )\r
28a00297 218{\r
219 EFI_STATUS Status;\r
18fd8d65
LG
220 EFI_GUID *ExtractHandlerGuidTable;\r
221 UINTN ExtractHandlerNumber;\r
28a00297 222\r
d8c79a81 223 //\r
022c6d45 224 // Get custom extract guided section method guid list\r
d8c79a81 225 //\r
18fd8d65 226 ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);\r
022c6d45 227\r
797a9d67 228 Status = EFI_SUCCESS;\r
d8c79a81 229 //\r
022c6d45 230 // Install custom guided extraction protocol\r
d8c79a81 231 //\r
18fd8d65 232 while (ExtractHandlerNumber-- > 0) {\r
d8c79a81
LG
233 Status = CoreInstallProtocolInterface (\r
234 &mSectionExtractionHandle,\r
18fd8d65 235 &ExtractHandlerGuidTable [ExtractHandlerNumber],\r
d8c79a81 236 EFI_NATIVE_INTERFACE,\r
18fd8d65 237 &mCustomGuidedSectionExtractionProtocol\r
d8c79a81
LG
238 );\r
239 ASSERT_EFI_ERROR (Status);\r
240 }\r
d8c79a81 241\r
28a00297 242 return Status;\r
243}\r
244\r
162ed594 245\r
246/**\r
de4e6bf9 247 Check if a stream is valid.\r
162ed594 248\r
de4e6bf9 249 @param SectionStream The section stream to be checked\r
250 @param SectionStreamLength The length of section stream\r
162ed594 251\r
de4e6bf9 252 @return A boolean value indicating the validness of the section stream.\r
162ed594 253\r
254**/\r
de4e6bf9 255BOOLEAN\r
256IsValidSectionStream (\r
257 IN VOID *SectionStream,\r
258 IN UINTN SectionStreamLength\r
28a00297 259 )\r
28a00297 260{\r
de4e6bf9 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
6c85d162
SZ
270 if (IS_SECTION2 (SectionHeader)) {\r
271 SectionLength = SECTION2_SIZE (SectionHeader);\r
272 } else {\r
273 SectionLength = SECTION_SIZE (SectionHeader);\r
274 }\r
de4e6bf9 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
28a00297 292 }\r
022c6d45 293\r
de4e6bf9 294 ASSERT (FALSE);\r
295 return FALSE;\r
28a00297 296}\r
022c6d45 297\r
162ed594 298\r
299/**\r
de4e6bf9 300 Worker function. Constructor for section streams.\r
162ed594 301\r
de4e6bf9 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
162ed594 327\r
de4e6bf9 328 @retval EFI_SUCCESS Stream was added to stream database.\r
329 @retval EFI_OUT_OF_RESOURCES memory allocation failed.\r
162ed594 330\r
331**/\r
28a00297 332EFI_STATUS\r
de4e6bf9 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
28a00297 339 )\r
28a00297 340{\r
de4e6bf9 341 CORE_SECTION_STREAM_NODE *NewStream;\r
342 EFI_TPL OldTpl;\r
022c6d45 343\r
28a00297 344 //\r
de4e6bf9 345 // Allocate a new stream\r
28a00297 346 //\r
de4e6bf9 347 NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));\r
348 if (NewStream == NULL) {\r
349 return EFI_OUT_OF_RESOURCES;\r
022c6d45 350 }\r
351\r
de4e6bf9 352 if (AllocateBuffer) {\r
28a00297 353 //\r
de4e6bf9 354 // if we're here, we're double buffering, allocate the buffer and copy the\r
355 // data in\r
28a00297 356 //\r
de4e6bf9 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
28a00297 372 }\r
373 } else {\r
374 //\r
de4e6bf9 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
28a00297 378 //\r
de4e6bf9 379 NewStream->StreamBuffer = SectionStream;\r
28a00297 380 }\r
022c6d45 381\r
de4e6bf9 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
28a00297 396 CoreRestoreTpl (OldTpl);\r
022c6d45 397\r
de4e6bf9 398 *SectionStreamHandle = NewStream->StreamHandle;\r
28a00297 399\r
de4e6bf9 400 return EFI_SUCCESS;\r
401}\r
28a00297 402\r
28a00297 403\r
162ed594 404/**\r
de4e6bf9 405 SEP member function. This function creates and returns a new section stream\r
406 handle to represent the new section stream.\r
28a00297 407\r
de4e6bf9 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
28a00297 412\r
de4e6bf9 413 @retval EFI_SUCCESS The section stream is created successfully.\r
414 @retval EFI_OUT_OF_RESOURCES memory allocation failed.\r
022c6d45 415 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end\r
162ed594 416 of last section.\r
28a00297 417\r
162ed594 418**/\r
419EFI_STATUS\r
420EFIAPI\r
de4e6bf9 421OpenSectionStream (\r
422 IN UINTN SectionStreamLength,\r
423 IN VOID *SectionStream,\r
424 OUT UINTN *SectionStreamHandle\r
162ed594 425 )\r
28a00297 426{\r
28a00297 427 //\r
de4e6bf9 428 // Check to see section stream looks good...\r
28a00297 429 //\r
de4e6bf9 430 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {\r
431 return EFI_INVALID_PARAMETER;\r
28a00297 432 }\r
022c6d45 433\r
de4e6bf9 434 return OpenSectionStreamEx (\r
435 SectionStreamLength,\r
436 SectionStream,\r
eb1cace2 437 FALSE,\r
de4e6bf9 438 0,\r
439 SectionStreamHandle\r
440 );\r
28a00297 441}\r
442\r
443\r
162ed594 444\r
445/**\r
446 Worker function. Determine if the input stream:child matches the input type.\r
447\r
022c6d45 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
162ed594 455\r
022c6d45 456 @retval TRUE The child matches\r
162ed594 457 @retval FALSE The child doesn't match\r
458\r
459**/\r
28a00297 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
28a00297 467{\r
468 EFI_GUID_DEFINED_SECTION *GuidedSection;\r
022c6d45 469\r
28a00297 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
3140ceda 476 if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {\r
28a00297 477 return TRUE;\r
478 }\r
479 GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);\r
6c85d162
SZ
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
28a00297 485}\r
486\r
8472f1f5
SZ
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
d1102dba 496 @return FALSE The GuidedSectionGuid could not be identified, or\r
8472f1f5
SZ
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
4e1005ec
ED
510 Interface = NULL;\r
511\r
8472f1f5
SZ
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
1d6ee65f
LG
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
d1102dba 558\r
1d6ee65f 559 Context = RpnContext;\r
d1102dba 560\r
1d6ee65f
LG
561 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);\r
562 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);\r
8472f1f5
SZ
563\r
564 if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {\r
1d6ee65f
LG
565 return;\r
566 }\r
8472f1f5 567\r
1d6ee65f
LG
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
805c2dd1 607 Context->ChildNode->Event = NULL;\r
1d6ee65f 608 FreePool (Context);\r
d1102dba 609}\r
1d6ee65f
LG
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
d1102dba 625\r
1d6ee65f
LG
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
d1102dba 631\r
1d6ee65f
LG
632 Context->ChildNode = ChildNode;\r
633 Context->ParentStream = ParentStream;\r
d1102dba 634\r
805c2dd1
SZ
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
1d6ee65f 642}\r
28a00297 643\r
162ed594 644/**\r
645 Worker function. Constructor for new child nodes.\r
646\r
022c6d45 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
162ed594 662 returned by OpenSectionStreamEx.\r
663\r
664**/\r
28a00297 665EFI_STATUS\r
666CreateChildNode (\r
667 IN CORE_SECTION_STREAM_NODE *Stream,\r
668 IN UINT32 ChildOffset,\r
8a44cd74 669 OUT CORE_SECTION_CHILD_NODE **ChildNode\r
28a00297 670 )\r
28a00297 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
d8c79a81 676 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
28a00297 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
6c85d162
SZ
683 VOID *CompressionSource;\r
684 UINT32 CompressionSourceSize;\r
685 UINT32 UncompressedLength;\r
686 UINT8 CompressionType;\r
687 UINT16 GuidedSectionAttributes;\r
022c6d45 688\r
28a00297 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
805c2dd1 696 *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));\r
28a00297 697 Node = *ChildNode;\r
698 if (Node == NULL) {\r
699 return EFI_OUT_OF_RESOURCES;\r
700 }\r
022c6d45 701\r
28a00297 702 //\r
703 // Now initialize it\r
704 //\r
705 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;\r
706 Node->Type = SectionHeader->Type;\r
6c85d162
SZ
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
28a00297 712 Node->OffsetInStream = ChildOffset;\r
713 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;\r
714 Node->EncapsulationGuid = NULL;\r
022c6d45 715\r
28a00297 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
8a44cd74
ED
724 if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {\r
725 CoreFreePool (Node);\r
726 return EFI_NOT_FOUND;\r
727 }\r
022c6d45 728\r
28a00297 729 CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;\r
022c6d45 730\r
6c85d162
SZ
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
28a00297 743 //\r
744 // Allocate space for the new stream\r
745 //\r
6c85d162
SZ
746 if (UncompressedLength > 0) {\r
747 NewStreamBufferSize = UncompressedLength;\r
9c4ac31c 748 NewStreamBuffer = AllocatePool (NewStreamBufferSize);\r
28a00297 749 if (NewStreamBuffer == NULL) {\r
750 CoreFreePool (Node);\r
751 return EFI_OUT_OF_RESOURCES;\r
752 }\r
022c6d45 753\r
6c85d162 754 if (CompressionType == EFI_NOT_COMPRESSED) {\r
28a00297 755 //\r
756 // stream is not actually compressed, just encapsulated. So just copy it.\r
757 //\r
6c85d162
SZ
758 CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);\r
759 } else if (CompressionType == EFI_STANDARD_COMPRESSION) {\r
28a00297 760 //\r
761 // Only support the EFI_SATNDARD_COMPRESSION algorithm.\r
022c6d45 762 //\r
28a00297 763\r
764 //\r
765 // Decompress the stream\r
766 //\r
767 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);\r
28a00297 768 ASSERT_EFI_ERROR (Status);\r
20bcdbcb 769 ASSERT (Decompress != NULL);\r
022c6d45 770\r
28a00297 771 Status = Decompress->GetInfo (\r
772 Decompress,\r
6c85d162
SZ
773 CompressionSource,\r
774 CompressionSourceSize,\r
28a00297 775 (UINT32 *)&NewStreamBufferSize,\r
776 &ScratchSize\r
777 );\r
8a44cd74
ED
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
28a00297 786\r
9c4ac31c 787 ScratchBuffer = AllocatePool (ScratchSize);\r
28a00297 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
6c85d162
SZ
796 CompressionSource,\r
797 CompressionSourceSize,\r
28a00297 798 NewStreamBuffer,\r
799 (UINT32)NewStreamBufferSize,\r
800 ScratchBuffer,\r
801 ScratchSize\r
802 );\r
022c6d45 803 CoreFreePool (ScratchBuffer);\r
8a44cd74
ED
804 if (EFI_ERROR (Status)) {\r
805 CoreFreePool (Node);\r
806 CoreFreePool (NewStreamBuffer);\r
807 return Status;\r
808 }\r
28a00297 809 }\r
810 } else {\r
811 NewStreamBuffer = NULL;\r
812 NewStreamBufferSize = 0;\r
813 }\r
022c6d45 814\r
28a00297 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
6c85d162
SZ
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
8472f1f5 838 if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {\r
28a00297 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
022c6d45 854\r
28a00297 855 //\r
022c6d45 856 // Make sure we initialize the new stream with the correct\r
28a00297 857 // authentication status for both aggregate and local status fields.\r
858 //\r
6c85d162 859 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {\r
28a00297 860 //\r
861 // OR in the parent stream's aggregate status.\r
862 //\r
797a9d67 863 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;\r
28a00297 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
022c6d45 871\r
28a00297 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
6c85d162 888 if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {\r
28a00297 889 //\r
d1102dba
LG
890 // If the section REQUIRES an extraction protocol, register for RPN\r
891 // when the required GUIDed extraction protocol becomes available.\r
28a00297 892 //\r
1d6ee65f
LG
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
022c6d45 899\r
9bc25041
LG
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
6c85d162
SZ
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
1d6ee65f
LG
921 if (EFI_ERROR (Status)) {\r
922 CoreFreePool (Node);\r
923 return Status;\r
924 }\r
28a00297 925 }\r
926 }\r
022c6d45 927\r
28a00297 928 break;\r
929\r
930 default:\r
022c6d45 931\r
28a00297 932 //\r
933 // Nothing to do if it's a leaf\r
934 //\r
935 break;\r
936 }\r
022c6d45 937\r
28a00297 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
162ed594 947/**\r
de4e6bf9 948 Worker function Recursively searches / builds section stream database\r
949 looking for requested section.\r
162ed594 950\r
de4e6bf9 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
b9bdfc72
LE
955 This is an in/out parameter and it is 1-based,\r
956 to deal with recursions.\r
de4e6bf9 957 @param SectionDefinitionGuid Guid of section definition\r
47343af3
LE
958 @param Depth Nesting depth of encapsulation sections.\r
959 Callers different from FindChildNode() are\r
960 responsible for passing in a zero Depth.\r
de4e6bf9 961 @param FoundChild Output indicating the child node that is found.\r
962 @param FoundStream Output indicating which section stream the child\r
963 was found in. If this stream was generated as a\r
964 result of an encapsulation section, the\r
965 streamhandle is visible within the SEP driver\r
966 only.\r
967 @param AuthenticationStatus Indicates the authentication status of the found section.\r
968\r
969 @retval EFI_SUCCESS Child node was found and returned.\r
970 EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
971 @retval EFI_NOT_FOUND Requested child node does not exist.\r
972 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol\r
973 does not exist\r
47343af3
LE
974 @retval EFI_ABORTED Recursion aborted because Depth has been\r
975 greater than or equal to\r
976 PcdFwVolDxeMaxEncapsulationDepth.\r
28a00297 977\r
162ed594 978**/\r
de4e6bf9 979EFI_STATUS\r
980FindChildNode (\r
981 IN CORE_SECTION_STREAM_NODE *SourceStream,\r
982 IN EFI_SECTION_TYPE SearchType,\r
983 IN OUT UINTN *SectionInstance,\r
984 IN EFI_GUID *SectionDefinitionGuid,\r
47343af3 985 IN UINT32 Depth,\r
de4e6bf9 986 OUT CORE_SECTION_CHILD_NODE **FoundChild,\r
987 OUT CORE_SECTION_STREAM_NODE **FoundStream,\r
988 OUT UINT32 *AuthenticationStatus\r
28a00297 989 )\r
28a00297 990{\r
de4e6bf9 991 CORE_SECTION_CHILD_NODE *CurrentChildNode;\r
992 CORE_SECTION_CHILD_NODE *RecursedChildNode;\r
993 CORE_SECTION_STREAM_NODE *RecursedFoundStream;\r
994 UINT32 NextChildOffset;\r
995 EFI_STATUS ErrorStatus;\r
996 EFI_STATUS Status;\r
022c6d45 997\r
b9bdfc72
LE
998 ASSERT (*SectionInstance > 0);\r
999\r
47343af3
LE
1000 if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {\r
1001 return EFI_ABORTED;\r
1002 }\r
1003\r
de4e6bf9 1004 CurrentChildNode = NULL;\r
1005 ErrorStatus = EFI_NOT_FOUND;\r
1006\r
1007 if (SourceStream->StreamLength == 0) {\r
1008 return EFI_NOT_FOUND;\r
1009 }\r
1010\r
1011 if (IsListEmpty (&SourceStream->Children) &&\r
1012 SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {\r
28a00297 1013 //\r
de4e6bf9 1014 // This occurs when a section stream exists, but no child sections\r
1015 // have been parsed out yet. Therefore, extract the first child and add it\r
1016 // to the list of children so we can get started.\r
1017 // Section stream may contain an array of zero or more bytes.\r
1018 // So, its size should be >= the size of commen section header.\r
28a00297 1019 //\r
de4e6bf9 1020 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);\r
1021 if (EFI_ERROR (Status)) {\r
1022 return Status;\r
1023 }\r
28a00297 1024 }\r
de4e6bf9 1025\r
28a00297 1026 //\r
de4e6bf9 1027 // At least one child has been parsed out of the section stream. So, walk\r
1028 // through the sections that have already been parsed out looking for the\r
1029 // requested section, if necessary, continue parsing section stream and\r
1030 // adding children until either the requested section is found, or we run\r
1031 // out of data\r
28a00297 1032 //\r
de4e6bf9 1033 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));\r
162ed594 1034\r
de4e6bf9 1035 for (;;) {\r
60cf9cfc 1036 ASSERT (CurrentChildNode != NULL);\r
de4e6bf9 1037 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {\r
1038 //\r
1039 // The type matches, so check the instance count to see if it's the one we want\r
1040 //\r
1041 (*SectionInstance)--;\r
1042 if (*SectionInstance == 0) {\r
1043 //\r
1044 // Got it!\r
1045 //\r
1046 *FoundChild = CurrentChildNode;\r
1047 *FoundStream = SourceStream;\r
1048 *AuthenticationStatus = SourceStream->AuthenticationStatus;\r
1049 return EFI_SUCCESS;\r
1050 }\r
1051 }\r
162ed594 1052\r
b9bdfc72
LE
1053 //\r
1054 // Type mismatch, or we haven't found the desired instance yet.\r
1055 //\r
1056 ASSERT (*SectionInstance > 0);\r
1057\r
de4e6bf9 1058 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
1059 //\r
1060 // If the current node is an encapsulating node, recurse into it...\r
1061 //\r
1062 Status = FindChildNode (\r
1063 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,\r
1064 SearchType,\r
1065 SectionInstance,\r
1066 SectionDefinitionGuid,\r
47343af3 1067 Depth + 1,\r
de4e6bf9 1068 &RecursedChildNode,\r
1069 &RecursedFoundStream,\r
1070 AuthenticationStatus\r
1071 );\r
de4e6bf9 1072 if (*SectionInstance == 0) {\r
b9bdfc72
LE
1073 //\r
1074 // The recursive FindChildNode() call decreased (*SectionInstance) to\r
1075 // zero.\r
1076 //\r
de4e6bf9 1077 ASSERT_EFI_ERROR (Status);\r
1078 *FoundChild = RecursedChildNode;\r
1079 *FoundStream = RecursedFoundStream;\r
1080 return EFI_SUCCESS;\r
1081 } else {\r
47343af3
LE
1082 if (Status == EFI_ABORTED) {\r
1083 //\r
1084 // If the recursive call was aborted due to nesting depth, stop\r
1085 // looking for the requested child node. The skipped subtree could\r
1086 // throw off the instance counting.\r
1087 //\r
1088 return Status;\r
1089 }\r
b9bdfc72 1090 //\r
47343af3
LE
1091 // Save the error code and continue to find the requested child node in\r
1092 // the rest of the stream.\r
b9bdfc72 1093 //\r
de4e6bf9 1094 ErrorStatus = Status;\r
28a00297 1095 }\r
1d6ee65f
LG
1096 } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {\r
1097 //\r
1098 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed\r
1099 // because a required GUIDED section extraction protocol does not exist.\r
1100 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.\r
1101 //\r
1102 ErrorStatus = EFI_PROTOCOL_ERROR;\r
de4e6bf9 1103 }\r
1104\r
1105 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {\r
28a00297 1106 //\r
de4e6bf9 1107 // We haven't found the child node we're interested in yet, but there's\r
1108 // still more nodes that have already been parsed so get the next one\r
1109 // and continue searching..\r
28a00297 1110 //\r
de4e6bf9 1111 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));\r
28a00297 1112 } else {\r
1113 //\r
de4e6bf9 1114 // We've exhausted children that have already been parsed, so see if\r
1115 // there's any more data and continue parsing out more children if there\r
1116 // is.\r
28a00297 1117 //\r
de4e6bf9 1118 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;\r
1119 //\r
1120 // Round up to 4 byte boundary\r
1121 //\r
1122 NextChildOffset += 3;\r
1123 NextChildOffset &= ~(UINTN) 3;\r
1124 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {\r
1125 //\r
1126 // There's an unparsed child remaining in the stream, so create a new child node\r
1127 //\r
1128 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);\r
1129 if (EFI_ERROR (Status)) {\r
1130 return Status;\r
1131 }\r
1132 } else {\r
1133 ASSERT (EFI_ERROR (ErrorStatus));\r
1134 return ErrorStatus;\r
1135 }\r
28a00297 1136 }\r
28a00297 1137 }\r
28a00297 1138}\r
1139\r
1140\r
162ed594 1141/**\r
1142 Worker function. Search stream database for requested stream handle.\r
1143\r
022c6d45 1144 @param SearchHandle Indicates which stream to look for.\r
1145 @param FoundStream Output pointer to the found stream.\r
162ed594 1146\r
022c6d45 1147 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains\r
1148 the stream node.\r
1149 @retval EFI_NOT_FOUND SearchHandle was not found in the stream\r
162ed594 1150 database.\r
1151\r
1152**/\r
28a00297 1153EFI_STATUS\r
1154FindStreamNode (\r
1155 IN UINTN SearchHandle,\r
1156 OUT CORE_SECTION_STREAM_NODE **FoundStream\r
1157 )\r
022c6d45 1158{\r
28a00297 1159 CORE_SECTION_STREAM_NODE *StreamNode;\r
022c6d45 1160\r
28a00297 1161 if (!IsListEmpty (&mStreamRoot)) {\r
1162 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));\r
1163 for (;;) {\r
1164 if (StreamNode->StreamHandle == SearchHandle) {\r
1165 *FoundStream = StreamNode;\r
1166 return EFI_SUCCESS;\r
1167 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {\r
1168 break;\r
1169 } else {\r
1170 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));\r
1171 }\r
1172 }\r
1173 }\r
022c6d45 1174\r
28a00297 1175 return EFI_NOT_FOUND;\r
1176}\r
1177\r
1178\r
162ed594 1179/**\r
de4e6bf9 1180 SEP member function. Retrieves requested section from section stream.\r
162ed594 1181\r
de4e6bf9 1182 @param SectionStreamHandle The section stream from which to extract the\r
1183 requested section.\r
1184 @param SectionType A pointer to the type of section to search for.\r
1185 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,\r
1186 then SectionDefinitionGuid indicates which of\r
1187 these types of sections to search for.\r
1188 @param SectionInstance Indicates which instance of the requested\r
1189 section to return.\r
1190 @param Buffer Double indirection to buffer. If *Buffer is\r
1191 non-null on input, then the buffer is caller\r
1192 allocated. If Buffer is NULL, then the buffer\r
1193 is callee allocated. In either case, the\r
2048c585 1194 required buffer size is returned in *BufferSize.\r
de4e6bf9 1195 @param BufferSize On input, indicates the size of *Buffer if\r
1196 *Buffer is non-null on input. On output,\r
1197 indicates the required size (allocated size if\r
1198 callee allocated) of *Buffer.\r
1199 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that\r
1200 indicates the authentication status of the\r
1201 output buffer. If the input section's\r
1202 GuidedSectionHeader.Attributes field\r
1203 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID\r
1204 bit as clear, AuthenticationStatus must return\r
1205 zero. Both local bits (19:16) and aggregate\r
1206 bits (3:0) in AuthenticationStatus are returned\r
1207 by ExtractSection(). These bits reflect the\r
1208 status of the extraction operation. The bit\r
1209 pattern in both regions must be the same, as\r
1210 the local and aggregate authentication statuses\r
1211 have equivalent meaning at this level. If the\r
1212 function returns anything other than\r
1213 EFI_SUCCESS, the value of *AuthenticationStatus\r
1214 is undefined.\r
6c85d162 1215 @param IsFfs3Fv Indicates the FV format.\r
162ed594 1216\r
de4e6bf9 1217 @retval EFI_SUCCESS Section was retrieved successfully\r
1218 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the\r
1219 section stream with its\r
1220 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,\r
1221 but there was no corresponding GUIDed Section\r
1222 Extraction Protocol in the handle database.\r
1223 *Buffer is unmodified.\r
1224 @retval EFI_NOT_FOUND An error was encountered when parsing the\r
1225 SectionStream. This indicates the SectionStream\r
1226 is not correctly formatted.\r
1227 @retval EFI_NOT_FOUND The requested section does not exist.\r
1228 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process\r
1229 the request.\r
1230 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.\r
1231 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is\r
1232 insufficient to contain the requested section.\r
1233 The input buffer is filled and section contents\r
1234 are truncated.\r
162ed594 1235\r
1236**/\r
de4e6bf9 1237EFI_STATUS\r
1238EFIAPI\r
1239GetSection (\r
1240 IN UINTN SectionStreamHandle,\r
1241 IN EFI_SECTION_TYPE *SectionType,\r
1242 IN EFI_GUID *SectionDefinitionGuid,\r
1243 IN UINTN SectionInstance,\r
1244 IN VOID **Buffer,\r
1245 IN OUT UINTN *BufferSize,\r
6c85d162
SZ
1246 OUT UINT32 *AuthenticationStatus,\r
1247 IN BOOLEAN IsFfs3Fv\r
28a00297 1248 )\r
28a00297 1249{\r
de4e6bf9 1250 CORE_SECTION_STREAM_NODE *StreamNode;\r
1251 EFI_TPL OldTpl;\r
1252 EFI_STATUS Status;\r
1253 CORE_SECTION_CHILD_NODE *ChildNode;\r
1254 CORE_SECTION_STREAM_NODE *ChildStreamNode;\r
1255 UINTN CopySize;\r
1256 UINT32 ExtractedAuthenticationStatus;\r
1257 UINTN Instance;\r
1258 UINT8 *CopyBuffer;\r
1259 UINTN SectionSize;\r
6c85d162 1260 EFI_COMMON_SECTION_HEADER *Section;\r
28a00297 1261\r
022c6d45 1262\r
4e1005ec 1263 ChildStreamNode = NULL;\r
de4e6bf9 1264 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1265 Instance = SectionInstance + 1;\r
28a00297 1266\r
de4e6bf9 1267 //\r
1268 // Locate target stream\r
1269 //\r
1270 Status = FindStreamNode (SectionStreamHandle, &StreamNode);\r
1271 if (EFI_ERROR (Status)) {\r
1272 Status = EFI_INVALID_PARAMETER;\r
1273 goto GetSection_Done;\r
1274 }\r
1275\r
1276 //\r
1277 // Found the stream, now locate and return the appropriate section\r
1278 //\r
1279 if (SectionType == NULL) {\r
1280 //\r
1281 // SectionType == NULL means return the WHOLE section stream...\r
1282 //\r
1283 CopySize = StreamNode->StreamLength;\r
1284 CopyBuffer = StreamNode->StreamBuffer;\r
1285 *AuthenticationStatus = StreamNode->AuthenticationStatus;\r
1286 } else {\r
1287 //\r
1288 // There's a requested section type, so go find it and return it...\r
1289 //\r
1290 Status = FindChildNode (\r
1291 StreamNode,\r
1292 *SectionType,\r
1293 &Instance,\r
1294 SectionDefinitionGuid,\r
47343af3 1295 0, // encapsulation depth\r
de4e6bf9 1296 &ChildNode,\r
1297 &ChildStreamNode,\r
1298 &ExtractedAuthenticationStatus\r
1299 );\r
1300 if (EFI_ERROR (Status)) {\r
47343af3
LE
1301 if (Status == EFI_ABORTED) {\r
1302 DEBUG ((DEBUG_ERROR, "%a: recursion aborted due to nesting depth\n",\r
1303 __FUNCTION__));\r
1304 //\r
1305 // Map "aborted" to "not found".\r
1306 //\r
1307 Status = EFI_NOT_FOUND;\r
1308 }\r
de4e6bf9 1309 goto GetSection_Done;\r
28a00297 1310 }\r
6c85d162
SZ
1311\r
1312 Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);\r
1313\r
1314 if (IS_SECTION2 (Section)) {\r
1315 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);\r
1316 if (!IsFfs3Fv) {\r
1317 DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));\r
1318 Status = EFI_NOT_FOUND;\r
1319 goto GetSection_Done;\r
1320 }\r
1321 CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);\r
1322 CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);\r
1323 } else {\r
1324 CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);\r
1325 CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);\r
1326 }\r
de4e6bf9 1327 *AuthenticationStatus = ExtractedAuthenticationStatus;\r
1328 }\r
28a00297 1329\r
de4e6bf9 1330 SectionSize = CopySize;\r
1331 if (*Buffer != NULL) {\r
28a00297 1332 //\r
de4e6bf9 1333 // Caller allocated buffer. Fill to size and return required size...\r
28a00297 1334 //\r
de4e6bf9 1335 if (*BufferSize < CopySize) {\r
1336 Status = EFI_WARN_BUFFER_TOO_SMALL;\r
1337 CopySize = *BufferSize;\r
1338 }\r
1339 } else {\r
1340 //\r
1341 // Callee allocated buffer. Allocate buffer and return size.\r
1342 //\r
1343 *Buffer = AllocatePool (CopySize);\r
1344 if (*Buffer == NULL) {\r
1345 Status = EFI_OUT_OF_RESOURCES;\r
1346 goto GetSection_Done;\r
1347 }\r
1348 }\r
1349 CopyMem (*Buffer, CopyBuffer, CopySize);\r
1350 *BufferSize = SectionSize;\r
1351\r
1352GetSection_Done:\r
1353 CoreRestoreTpl (OldTpl);\r
1354\r
1355 return Status;\r
1356}\r
1357\r
1358\r
1359/**\r
1360 Worker function. Destructor for child nodes.\r
1361\r
1362 @param ChildNode Indicates the node to destroy\r
022c6d45 1363\r
de4e6bf9 1364**/\r
1365VOID\r
1366FreeChildNode (\r
1367 IN CORE_SECTION_CHILD_NODE *ChildNode\r
1368 )\r
1369{\r
1370 ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);\r
1371 //\r
1372 // Remove the child from it's list\r
1373 //\r
1374 RemoveEntryList (&ChildNode->Link);\r
1375\r
1376 if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
28a00297 1377 //\r
de4e6bf9 1378 // If it's an encapsulating section, we close the resulting section stream.\r
1379 // CloseSectionStream will free all memory associated with the stream.\r
28a00297 1380 //\r
eb1cace2 1381 CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);\r
28a00297 1382 }\r
805c2dd1
SZ
1383\r
1384 if (ChildNode->Event != NULL) {\r
1385 gBS->CloseEvent (ChildNode->Event);\r
1386 }\r
1387\r
de4e6bf9 1388 //\r
1389 // Last, free the child node itself\r
1390 //\r
1391 CoreFreePool (ChildNode);\r
1392}\r
28a00297 1393\r
de4e6bf9 1394\r
1395/**\r
1396 SEP member function. Deletes an existing section stream\r
1397\r
1398 @param StreamHandleToClose Indicates the stream to close\r
eb1cace2
SZ
1399 @param FreeStreamBuffer TRUE - Need to free stream buffer;\r
1400 FALSE - No need to free stream buffer.\r
de4e6bf9 1401\r
1402 @retval EFI_SUCCESS The section stream is closed sucessfully.\r
1403 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
1404 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end\r
1405 of last section.\r
1406\r
1407**/\r
1408EFI_STATUS\r
1409EFIAPI\r
1410CloseSectionStream (\r
eb1cace2
SZ
1411 IN UINTN StreamHandleToClose,\r
1412 IN BOOLEAN FreeStreamBuffer\r
de4e6bf9 1413 )\r
1414{\r
1415 CORE_SECTION_STREAM_NODE *StreamNode;\r
1416 EFI_TPL OldTpl;\r
1417 EFI_STATUS Status;\r
1418 LIST_ENTRY *Link;\r
1419 CORE_SECTION_CHILD_NODE *ChildNode;\r
1420\r
1421 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1422\r
1423 //\r
1424 // Locate target stream\r
1425 //\r
1426 Status = FindStreamNode (StreamHandleToClose, &StreamNode);\r
1427 if (!EFI_ERROR (Status)) {\r
1428 //\r
1429 // Found the stream, so close it\r
1430 //\r
1431 RemoveEntryList (&StreamNode->Link);\r
1432 while (!IsListEmpty (&StreamNode->Children)) {\r
1433 Link = GetFirstNode (&StreamNode->Children);\r
1434 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);\r
1435 FreeChildNode (ChildNode);\r
1436 }\r
eb1cace2
SZ
1437 if (FreeStreamBuffer) {\r
1438 CoreFreePool (StreamNode->StreamBuffer);\r
1439 }\r
de4e6bf9 1440 CoreFreePool (StreamNode);\r
1441 Status = EFI_SUCCESS;\r
1442 } else {\r
1443 Status = EFI_INVALID_PARAMETER;\r
1444 }\r
1445\r
1446 CoreRestoreTpl (OldTpl);\r
1447 return Status;\r
28a00297 1448}\r
d8c79a81 1449\r
e94a9ff7 1450\r
d8c79a81
LG
1451/**\r
1452 The ExtractSection() function processes the input section and\r
1453 allocates a buffer from the pool in which it returns the section\r
1454 contents. If the section being extracted contains\r
1455 authentication information (the section's\r
1456 GuidedSectionHeader.Attributes field has the\r
1457 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values\r
1458 returned in AuthenticationStatus must reflect the results of\r
1459 the authentication operation. Depending on the algorithm and\r
1460 size of the encapsulated data, the time that is required to do\r
1461 a full authentication may be prohibitively long for some\r
1462 classes of systems. To indicate this, use\r
1463 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by\r
1464 the security policy driver (see the Platform Initialization\r
1465 Driver Execution Environment Core Interface Specification for\r
1466 more details and the GUID definition). If the\r
1467 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle\r
1468 database, then, if possible, full authentication should be\r
1469 skipped and the section contents simply returned in the\r
1470 OutputBuffer. In this case, the\r
1471 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus\r
1472 must be set on return. ExtractSection() is callable only from\r
1473 TPL_NOTIFY and below. Behavior of ExtractSection() at any\r
1474 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is\r
1475 defined in RaiseTPL() in the UEFI 2.0 specification.\r
1476\r
022c6d45 1477\r
162ed594 1478 @param This Indicates the\r
1479 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.\r
d8c79a81
LG
1480 @param InputSection Buffer containing the input GUIDed section\r
1481 to be processed. OutputBuffer OutputBuffer\r
1482 is allocated from boot services pool\r
1483 memory and contains the new section\r
1484 stream. The caller is responsible for\r
1485 freeing this buffer.\r
162ed594 1486 @param OutputBuffer *OutputBuffer is allocated from boot services\r
1487 pool memory and contains the new section stream.\r
1488 The caller is responsible for freeing this buffer.\r
d8c79a81
LG
1489 @param OutputSize A pointer to a caller-allocated UINTN in\r
1490 which the size of OutputBuffer allocation\r
1491 is stored. If the function returns\r
1492 anything other than EFI_SUCCESS, the value\r
1493 of OutputSize is undefined.\r
1494\r
1495 @param AuthenticationStatus A pointer to a caller-allocated\r
1496 UINT32 that indicates the\r
1497 authentication status of the\r
1498 output buffer. If the input\r
1499 section's\r
1500 GuidedSectionHeader.Attributes\r
1501 field has the\r
1502 EFI_GUIDED_SECTION_AUTH_STATUS_VAL\r
1503 bit as clear, AuthenticationStatus\r
1504 must return zero. Both local bits\r
1505 (19:16) and aggregate bits (3:0)\r
1506 in AuthenticationStatus are\r
1507 returned by ExtractSection().\r
1508 These bits reflect the status of\r
1509 the extraction operation. The bit\r
1510 pattern in both regions must be\r
1511 the same, as the local and\r
1512 aggregate authentication statuses\r
1513 have equivalent meaning at this\r
1514 level. If the function returns\r
1515 anything other than EFI_SUCCESS,\r
1516 the value of AuthenticationStatus\r
1517 is undefined.\r
1518\r
1519\r
162ed594 1520 @retval EFI_SUCCESS The InputSection was successfully\r
1521 processed and the section contents were\r
1522 returned.\r
d8c79a81 1523\r
162ed594 1524 @retval EFI_OUT_OF_RESOURCES The system has insufficient\r
1525 resources to process the\r
1526 request.\r
d8c79a81
LG
1527\r
1528 @retval EFI_INVALID_PARAMETER The GUID in InputSection does\r
1529 not match this instance of the\r
1530 GUIDed Section Extraction\r
1531 Protocol.\r
1532\r
1533**/\r
1534EFI_STATUS\r
797a9d67 1535EFIAPI\r
18fd8d65 1536CustomGuidedSectionExtract (\r
d8c79a81
LG
1537 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,\r
1538 IN CONST VOID *InputSection,\r
1539 OUT VOID **OutputBuffer,\r
1540 OUT UINTN *OutputSize,\r
1541 OUT UINT32 *AuthenticationStatus\r
1542 )\r
1543{\r
1544 EFI_STATUS Status;\r
18fd8d65
LG
1545 VOID *ScratchBuffer;\r
1546 VOID *AllocatedOutputBuffer;\r
1547 UINT32 OutputBufferSize;\r
1548 UINT32 ScratchBufferSize;\r
1549 UINT16 SectionAttribute;\r
022c6d45 1550\r
d8c79a81 1551 //\r
18fd8d65 1552 // Init local variable\r
d8c79a81 1553 //\r
18fd8d65
LG
1554 ScratchBuffer = NULL;\r
1555 AllocatedOutputBuffer = NULL;\r
1556\r
d8c79a81 1557 //\r
18fd8d65 1558 // Call GetInfo to get the size and attribute of input guided section data.\r
d8c79a81 1559 //\r
18fd8d65 1560 Status = ExtractGuidedSectionGetInfo (\r
162ed594 1561 InputSection,\r
1562 &OutputBufferSize,\r
1563 &ScratchBufferSize,\r
1564 &SectionAttribute\r
1565 );\r
022c6d45 1566\r
d8c79a81 1567 if (EFI_ERROR (Status)) {\r
162ed594 1568 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));\r
18fd8d65
LG
1569 return Status;\r
1570 }\r
022c6d45 1571\r
de4e6bf9 1572 if (ScratchBufferSize > 0) {\r
d8c79a81 1573 //\r
18fd8d65 1574 // Allocate scratch buffer\r
d8c79a81 1575 //\r
9c4ac31c 1576 ScratchBuffer = AllocatePool (ScratchBufferSize);\r
18fd8d65
LG
1577 if (ScratchBuffer == NULL) {\r
1578 return EFI_OUT_OF_RESOURCES;\r
1579 }\r
d8c79a81
LG
1580 }\r
1581\r
022c6d45 1582 if (OutputBufferSize > 0) {\r
18fd8d65
LG
1583 //\r
1584 // Allocate output buffer\r
1585 //\r
9c4ac31c 1586 AllocatedOutputBuffer = AllocatePool (OutputBufferSize);\r
18fd8d65 1587 if (AllocatedOutputBuffer == NULL) {\r
47770322
SZ
1588 if (ScratchBuffer != NULL) {\r
1589 FreePool (ScratchBuffer);\r
1590 }\r
18fd8d65
LG
1591 return EFI_OUT_OF_RESOURCES;\r
1592 }\r
1593 *OutputBuffer = AllocatedOutputBuffer;\r
d8c79a81
LG
1594 }\r
1595\r
1596 //\r
18fd8d65 1597 // Call decode function to extract raw data from the guided section.\r
d8c79a81 1598 //\r
18fd8d65 1599 Status = ExtractGuidedSectionDecode (\r
022c6d45 1600 InputSection,\r
18fd8d65
LG
1601 OutputBuffer,\r
1602 ScratchBuffer,\r
1603 AuthenticationStatus\r
e94a9ff7 1604 );\r
d8c79a81
LG
1605 if (EFI_ERROR (Status)) {\r
1606 //\r
18fd8d65 1607 // Decode failed\r
d8c79a81 1608 //\r
18fd8d65
LG
1609 if (AllocatedOutputBuffer != NULL) {\r
1610 CoreFreePool (AllocatedOutputBuffer);\r
1611 }\r
1612 if (ScratchBuffer != NULL) {\r
1613 CoreFreePool (ScratchBuffer);\r
1614 }\r
162ed594 1615 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));\r
d8c79a81
LG
1616 return Status;\r
1617 }\r
18fd8d65
LG
1618\r
1619 if (*OutputBuffer != AllocatedOutputBuffer) {\r
1620 //\r
022c6d45 1621 // OutputBuffer was returned as a different value,\r
18fd8d65 1622 // so copy section contents to the allocated memory buffer.\r
022c6d45 1623 //\r
18fd8d65
LG
1624 CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);\r
1625 *OutputBuffer = AllocatedOutputBuffer;\r
1626 }\r
1627\r
1628 //\r
1629 // Set real size of output buffer.\r
1630 //\r
1631 *OutputSize = (UINTN) OutputBufferSize;\r
1632\r
d8c79a81
LG
1633 //\r
1634 // Free unused scratch buffer.\r
1635 //\r
18fd8d65
LG
1636 if (ScratchBuffer != NULL) {\r
1637 CoreFreePool (ScratchBuffer);\r
1638 }\r
1639\r
d8c79a81 1640 return EFI_SUCCESS;\r
702887db 1641}\r