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