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