]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
Enhance FV2.ReadSection() to read GUIDED section raw data when its extraction guided...
[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
cd5ebaa0
HT
30Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
272 SectionLength = SECTION_SIZE (SectionHeader);\r
273 TotalLength += SectionLength;\r
274\r
275 if (TotalLength == SectionStreamLength) {\r
276 return TRUE;\r
277 }\r
278\r
279 //\r
280 // Move to the next byte following the section...\r
281 //\r
282 SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);\r
283\r
284 //\r
285 // Figure out where the next section begins\r
286 //\r
287 NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);\r
288 TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;\r
289 SectionHeader = NextSectionHeader;\r
28a00297 290 }\r
022c6d45 291\r
de4e6bf9 292 ASSERT (FALSE);\r
293 return FALSE;\r
28a00297 294}\r
022c6d45 295\r
162ed594 296\r
297/**\r
de4e6bf9 298 Worker function. Constructor for section streams.\r
162ed594 299\r
de4e6bf9 300 @param SectionStreamLength Size in bytes of the section stream.\r
301 @param SectionStream Buffer containing the new section stream.\r
302 @param AllocateBuffer Indicates whether the stream buffer is to be\r
303 copied or the input buffer is to be used in\r
304 place. AuthenticationStatus- Indicates the\r
305 default authentication status for the new\r
306 stream.\r
307 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that\r
308 indicates the authentication status of the\r
309 output buffer. If the input section's\r
310 GuidedSectionHeader.Attributes field\r
311 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID\r
312 bit as clear, AuthenticationStatus must return\r
313 zero. Both local bits (19:16) and aggregate\r
314 bits (3:0) in AuthenticationStatus are returned\r
315 by ExtractSection(). These bits reflect the\r
316 status of the extraction operation. The bit\r
317 pattern in both regions must be the same, as\r
318 the local and aggregate authentication statuses\r
319 have equivalent meaning at this level. If the\r
320 function returns anything other than\r
321 EFI_SUCCESS, the value of *AuthenticationStatus\r
322 is undefined.\r
323 @param SectionStreamHandle A pointer to a caller allocated section stream\r
324 handle.\r
162ed594 325\r
de4e6bf9 326 @retval EFI_SUCCESS Stream was added to stream database.\r
327 @retval EFI_OUT_OF_RESOURCES memory allocation failed.\r
162ed594 328\r
329**/\r
28a00297 330EFI_STATUS\r
de4e6bf9 331OpenSectionStreamEx (\r
332 IN UINTN SectionStreamLength,\r
333 IN VOID *SectionStream,\r
334 IN BOOLEAN AllocateBuffer,\r
335 IN UINT32 AuthenticationStatus,\r
336 OUT UINTN *SectionStreamHandle\r
28a00297 337 )\r
28a00297 338{\r
de4e6bf9 339 CORE_SECTION_STREAM_NODE *NewStream;\r
340 EFI_TPL OldTpl;\r
022c6d45 341\r
28a00297 342 //\r
de4e6bf9 343 // Allocate a new stream\r
28a00297 344 //\r
de4e6bf9 345 NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));\r
346 if (NewStream == NULL) {\r
347 return EFI_OUT_OF_RESOURCES;\r
022c6d45 348 }\r
349\r
de4e6bf9 350 if (AllocateBuffer) {\r
28a00297 351 //\r
de4e6bf9 352 // if we're here, we're double buffering, allocate the buffer and copy the\r
353 // data in\r
28a00297 354 //\r
de4e6bf9 355 if (SectionStreamLength > 0) {\r
356 NewStream->StreamBuffer = AllocatePool (SectionStreamLength);\r
357 if (NewStream->StreamBuffer == NULL) {\r
358 CoreFreePool (NewStream);\r
359 return EFI_OUT_OF_RESOURCES;\r
360 }\r
361 //\r
362 // Copy in stream data\r
363 //\r
364 CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);\r
365 } else {\r
366 //\r
367 // It's possible to have a zero length section stream.\r
368 //\r
369 NewStream->StreamBuffer = NULL;\r
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
383 NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;\r
384 NewStream->StreamHandle = (UINTN) NewStream;\r
385 NewStream->StreamLength = SectionStreamLength;\r
386 InitializeListHead (&NewStream->Children);\r
387 NewStream->AuthenticationStatus = AuthenticationStatus;\r
388\r
389 //\r
390 // Add new stream to stream list\r
391 //\r
392 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
393 InsertTailList (&mStreamRoot, &NewStream->Link);\r
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
28a00297 401\r
162ed594 402/**\r
de4e6bf9 403 SEP member function. This function creates and returns a new section stream\r
404 handle to represent the new section stream.\r
28a00297 405\r
de4e6bf9 406 @param SectionStreamLength Size in bytes of the section stream.\r
407 @param SectionStream Buffer containing the new section stream.\r
408 @param SectionStreamHandle A pointer to a caller allocated UINTN that on\r
409 output contains the new section stream handle.\r
28a00297 410\r
de4e6bf9 411 @retval EFI_SUCCESS The section stream is created successfully.\r
412 @retval EFI_OUT_OF_RESOURCES memory allocation failed.\r
022c6d45 413 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end\r
162ed594 414 of last section.\r
28a00297 415\r
162ed594 416**/\r
417EFI_STATUS\r
418EFIAPI\r
de4e6bf9 419OpenSectionStream (\r
420 IN UINTN SectionStreamLength,\r
421 IN VOID *SectionStream,\r
422 OUT UINTN *SectionStreamHandle\r
162ed594 423 )\r
28a00297 424{\r
28a00297 425 //\r
de4e6bf9 426 // Check to see section stream looks good...\r
28a00297 427 //\r
de4e6bf9 428 if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {\r
429 return EFI_INVALID_PARAMETER;\r
28a00297 430 }\r
022c6d45 431\r
de4e6bf9 432 return OpenSectionStreamEx (\r
433 SectionStreamLength,\r
434 SectionStream,\r
435 TRUE,\r
436 0,\r
437 SectionStreamHandle\r
438 );\r
28a00297 439}\r
440\r
441\r
162ed594 442\r
443/**\r
444 Worker function. Determine if the input stream:child matches the input type.\r
445\r
022c6d45 446 @param Stream Indicates the section stream associated with the\r
447 child\r
448 @param Child Indicates the child to check\r
449 @param SearchType Indicates the type of section to check against\r
450 for\r
451 @param SectionDefinitionGuid Indicates the GUID to check against if the type\r
452 is EFI_SECTION_GUID_DEFINED\r
162ed594 453\r
022c6d45 454 @retval TRUE The child matches\r
162ed594 455 @retval FALSE The child doesn't match\r
456\r
457**/\r
28a00297 458BOOLEAN\r
459ChildIsType (\r
460 IN CORE_SECTION_STREAM_NODE *Stream,\r
461 IN CORE_SECTION_CHILD_NODE *Child,\r
462 IN EFI_SECTION_TYPE SearchType,\r
463 IN EFI_GUID *SectionDefinitionGuid\r
464 )\r
28a00297 465{\r
466 EFI_GUID_DEFINED_SECTION *GuidedSection;\r
022c6d45 467\r
28a00297 468 if (SearchType == EFI_SECTION_ALL) {\r
469 return TRUE;\r
470 }\r
471 if (Child->Type != SearchType) {\r
472 return FALSE;\r
473 }\r
3140ceda 474 if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {\r
28a00297 475 return TRUE;\r
476 }\r
477 GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);\r
478 return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);\r
479}\r
480\r
1d6ee65f
LG
481/**\r
482 RPN callback function. Initializes the section stream\r
483 when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.\r
484\r
485 @param Event The event that fired\r
486 @param RpnContext A pointer to the context that allows us to identify\r
487 the relevent encapsulation.\r
488**/\r
489VOID\r
490EFIAPI\r
491NotifyGuidedExtraction (\r
492 IN EFI_EVENT Event,\r
493 IN VOID *RpnContext\r
494 )\r
495{\r
496 EFI_STATUS Status;\r
497 EFI_GUID_DEFINED_SECTION *GuidedHeader;\r
498 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;\r
499 VOID *NewStreamBuffer;\r
500 UINTN NewStreamBufferSize;\r
501 UINT32 AuthenticationStatus;\r
502 RPN_EVENT_CONTEXT *Context;\r
503 \r
504 Context = RpnContext;\r
505 \r
506 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);\r
507 ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);\r
508 \r
509 Status = gBS->LocateProtocol (Context->ChildNode->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);\r
510 if (EFI_ERROR (Status)) {\r
511 return;\r
512 }\r
513 \r
514 Status = GuidedExtraction->ExtractSection (\r
515 GuidedExtraction,\r
516 GuidedHeader,\r
517 &NewStreamBuffer,\r
518 &NewStreamBufferSize,\r
519 &AuthenticationStatus\r
520 );\r
521 ASSERT_EFI_ERROR (Status);\r
522\r
523 //\r
524 // Make sure we initialize the new stream with the correct\r
525 // authentication status for both aggregate and local status fields.\r
526 //\r
527 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {\r
528 //\r
529 // OR in the parent stream's aggregate status.\r
530 //\r
531 AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;\r
532 } else {\r
533 //\r
534 // since there's no authentication data contributed by the section,\r
535 // just inherit the full value from our immediate parent.\r
536 //\r
537 AuthenticationStatus = Context->ParentStream->AuthenticationStatus;\r
538 }\r
539\r
540 Status = OpenSectionStreamEx (\r
541 NewStreamBufferSize,\r
542 NewStreamBuffer,\r
543 FALSE,\r
544 AuthenticationStatus,\r
545 &Context->ChildNode->EncapsulatedStreamHandle\r
546 );\r
547 ASSERT_EFI_ERROR (Status);\r
548\r
549 //\r
550 // Close the event when done.\r
551 //\r
552 gBS->CloseEvent (Event);\r
553 FreePool (Context);\r
554} \r
555\r
556/**\r
557 Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...\r
558\r
559 @param ParentStream Indicates the parent of the ecnapsulation section (child)\r
560 @param ChildNode Indicates the child node that is the encapsulation section.\r
561\r
562**/\r
563VOID\r
564CreateGuidedExtractionRpnEvent (\r
565 IN CORE_SECTION_STREAM_NODE *ParentStream,\r
566 IN CORE_SECTION_CHILD_NODE *ChildNode\r
567 )\r
568{\r
569 RPN_EVENT_CONTEXT *Context;\r
570 \r
571 //\r
572 // Allocate new event structure and context\r
573 //\r
574 Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));\r
575 ASSERT (Context != NULL);\r
576 \r
577 Context->ChildNode = ChildNode;\r
578 Context->ParentStream = ParentStream;\r
579 \r
580 Context->Event = EfiCreateProtocolNotifyEvent (\r
581 Context->ChildNode->EncapsulationGuid,\r
582 TPL_NOTIFY,\r
583 NotifyGuidedExtraction,\r
584 Context,\r
585 &Context->Registration\r
586 );\r
587}\r
28a00297 588\r
162ed594 589/**\r
590 Worker function. Constructor for new child nodes.\r
591\r
022c6d45 592 @param Stream Indicates the section stream in which to add the\r
593 child.\r
594 @param ChildOffset Indicates the offset in Stream that is the\r
595 beginning of the child section.\r
596 @param ChildNode Indicates the Callee allocated and initialized\r
597 child.\r
598\r
599 @retval EFI_SUCCESS Child node was found and returned.\r
600 EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
601 @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream\r
602 handles when the child node is created. If the\r
603 section type is GUID defined, and the extraction\r
604 GUID does not exist, and producing the stream\r
605 requires the GUID, then a protocol error is\r
606 generated and no child is produced. Values\r
162ed594 607 returned by OpenSectionStreamEx.\r
608\r
609**/\r
28a00297 610EFI_STATUS\r
611CreateChildNode (\r
612 IN CORE_SECTION_STREAM_NODE *Stream,\r
613 IN UINT32 ChildOffset,\r
614 OUT CORE_SECTION_CHILD_NODE **ChildNode\r
615 )\r
28a00297 616{\r
617 EFI_STATUS Status;\r
618 EFI_COMMON_SECTION_HEADER *SectionHeader;\r
619 EFI_COMPRESSION_SECTION *CompressionHeader;\r
620 EFI_GUID_DEFINED_SECTION *GuidedHeader;\r
d8c79a81 621 EFI_DECOMPRESS_PROTOCOL *Decompress;\r
28a00297 622 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;\r
623 VOID *NewStreamBuffer;\r
624 VOID *ScratchBuffer;\r
625 UINT32 ScratchSize;\r
626 UINTN NewStreamBufferSize;\r
627 UINT32 AuthenticationStatus;\r
628 UINT32 SectionLength;\r
022c6d45 629\r
28a00297 630 CORE_SECTION_CHILD_NODE *Node;\r
631\r
632 SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);\r
633\r
634 //\r
635 // Allocate a new node\r
636 //\r
9c4ac31c 637 *ChildNode = AllocatePool (sizeof (CORE_SECTION_CHILD_NODE));\r
28a00297 638 Node = *ChildNode;\r
639 if (Node == NULL) {\r
640 return EFI_OUT_OF_RESOURCES;\r
641 }\r
022c6d45 642\r
28a00297 643 //\r
644 // Now initialize it\r
645 //\r
646 Node->Signature = CORE_SECTION_CHILD_SIGNATURE;\r
647 Node->Type = SectionHeader->Type;\r
648 Node->Size = SECTION_SIZE (SectionHeader);\r
649 Node->OffsetInStream = ChildOffset;\r
650 Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;\r
651 Node->EncapsulationGuid = NULL;\r
022c6d45 652\r
28a00297 653 //\r
654 // If it's an encapsulating section, then create the new section stream also\r
655 //\r
656 switch (Node->Type) {\r
657 case EFI_SECTION_COMPRESSION:\r
658 //\r
659 // Get the CompressionSectionHeader\r
660 //\r
661 ASSERT (Node->Size >= sizeof (EFI_COMPRESSION_SECTION));\r
022c6d45 662\r
28a00297 663 CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;\r
022c6d45 664\r
28a00297 665 //\r
666 // Allocate space for the new stream\r
667 //\r
668 if (CompressionHeader->UncompressedLength > 0) {\r
669 NewStreamBufferSize = CompressionHeader->UncompressedLength;\r
9c4ac31c 670 NewStreamBuffer = AllocatePool (NewStreamBufferSize);\r
28a00297 671 if (NewStreamBuffer == NULL) {\r
672 CoreFreePool (Node);\r
673 return EFI_OUT_OF_RESOURCES;\r
674 }\r
022c6d45 675\r
28a00297 676 if (CompressionHeader->CompressionType == EFI_NOT_COMPRESSED) {\r
677 //\r
678 // stream is not actually compressed, just encapsulated. So just copy it.\r
679 //\r
680 CopyMem (NewStreamBuffer, CompressionHeader + 1, NewStreamBufferSize);\r
681 } else if (CompressionHeader->CompressionType == EFI_STANDARD_COMPRESSION) {\r
682 //\r
683 // Only support the EFI_SATNDARD_COMPRESSION algorithm.\r
022c6d45 684 //\r
28a00297 685\r
686 //\r
687 // Decompress the stream\r
688 //\r
689 Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);\r
28a00297 690 ASSERT_EFI_ERROR (Status);\r
20bcdbcb 691 ASSERT (Decompress != NULL);\r
022c6d45 692\r
28a00297 693 Status = Decompress->GetInfo (\r
694 Decompress,\r
695 CompressionHeader + 1,\r
696 Node->Size - sizeof (EFI_COMPRESSION_SECTION),\r
697 (UINT32 *)&NewStreamBufferSize,\r
698 &ScratchSize\r
699 );\r
700 ASSERT_EFI_ERROR (Status);\r
701 ASSERT (NewStreamBufferSize == CompressionHeader->UncompressedLength);\r
702\r
9c4ac31c 703 ScratchBuffer = AllocatePool (ScratchSize);\r
28a00297 704 if (ScratchBuffer == NULL) {\r
705 CoreFreePool (Node);\r
706 CoreFreePool (NewStreamBuffer);\r
707 return EFI_OUT_OF_RESOURCES;\r
708 }\r
709\r
710 Status = Decompress->Decompress (\r
711 Decompress,\r
712 CompressionHeader + 1,\r
713 Node->Size - sizeof (EFI_COMPRESSION_SECTION),\r
714 NewStreamBuffer,\r
715 (UINT32)NewStreamBufferSize,\r
716 ScratchBuffer,\r
717 ScratchSize\r
718 );\r
719 ASSERT_EFI_ERROR (Status);\r
022c6d45 720 CoreFreePool (ScratchBuffer);\r
28a00297 721 }\r
722 } else {\r
723 NewStreamBuffer = NULL;\r
724 NewStreamBufferSize = 0;\r
725 }\r
022c6d45 726\r
28a00297 727 Status = OpenSectionStreamEx (\r
728 NewStreamBufferSize,\r
729 NewStreamBuffer,\r
730 FALSE,\r
731 Stream->AuthenticationStatus,\r
732 &Node->EncapsulatedStreamHandle\r
733 );\r
734 if (EFI_ERROR (Status)) {\r
735 CoreFreePool (Node);\r
736 CoreFreePool (NewStreamBuffer);\r
737 return Status;\r
738 }\r
739 break;\r
740\r
741 case EFI_SECTION_GUID_DEFINED:\r
742 GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;\r
743 Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;\r
744 Status = CoreLocateProtocol (Node->EncapsulationGuid, NULL, (VOID **)&GuidedExtraction);\r
d2fbaaab 745 if (!EFI_ERROR (Status) && GuidedExtraction != NULL) {\r
28a00297 746 //\r
747 // NewStreamBuffer is always allocated by ExtractSection... No caller\r
748 // allocation here.\r
749 //\r
750 Status = GuidedExtraction->ExtractSection (\r
751 GuidedExtraction,\r
752 GuidedHeader,\r
753 &NewStreamBuffer,\r
754 &NewStreamBufferSize,\r
755 &AuthenticationStatus\r
756 );\r
757 if (EFI_ERROR (Status)) {\r
758 CoreFreePool (*ChildNode);\r
759 return EFI_PROTOCOL_ERROR;\r
760 }\r
022c6d45 761\r
28a00297 762 //\r
022c6d45 763 // Make sure we initialize the new stream with the correct\r
28a00297 764 // authentication status for both aggregate and local status fields.\r
765 //\r
6e536468 766 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {\r
28a00297 767 //\r
768 // OR in the parent stream's aggregate status.\r
769 //\r
797a9d67 770 AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;\r
28a00297 771 } else {\r
772 //\r
773 // since there's no authentication data contributed by the section,\r
774 // just inherit the full value from our immediate parent.\r
775 //\r
776 AuthenticationStatus = Stream->AuthenticationStatus;\r
777 }\r
022c6d45 778\r
28a00297 779 Status = OpenSectionStreamEx (\r
780 NewStreamBufferSize,\r
781 NewStreamBuffer,\r
782 FALSE,\r
783 AuthenticationStatus,\r
784 &Node->EncapsulatedStreamHandle\r
785 );\r
786 if (EFI_ERROR (Status)) {\r
787 CoreFreePool (*ChildNode);\r
788 CoreFreePool (NewStreamBuffer);\r
789 return Status;\r
790 }\r
791 } else {\r
792 //\r
793 // There's no GUIDed section extraction protocol available.\r
794 //\r
6e536468 795 if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {\r
28a00297 796 //\r
1d6ee65f
LG
797 // If the section REQUIRES an extraction protocol, register for RPN \r
798 // when the required GUIDed extraction protocol becomes available. \r
28a00297 799 //\r
1d6ee65f
LG
800 CreateGuidedExtractionRpnEvent (Stream, Node);\r
801 } else {\r
802 //\r
803 // Figure out the proper authentication status\r
804 //\r
805 AuthenticationStatus = Stream->AuthenticationStatus;\r
022c6d45 806\r
1d6ee65f
LG
807 SectionLength = SECTION_SIZE (GuidedHeader);\r
808 Status = OpenSectionStreamEx (\r
809 SectionLength - GuidedHeader->DataOffset,\r
810 (UINT8 *) GuidedHeader + GuidedHeader->DataOffset,\r
811 TRUE,\r
812 AuthenticationStatus,\r
813 &Node->EncapsulatedStreamHandle\r
814 );\r
815 if (EFI_ERROR (Status)) {\r
816 CoreFreePool (Node);\r
817 return Status;\r
818 }\r
28a00297 819 }\r
820 }\r
022c6d45 821\r
28a00297 822 break;\r
823\r
824 default:\r
022c6d45 825\r
28a00297 826 //\r
827 // Nothing to do if it's a leaf\r
828 //\r
829 break;\r
830 }\r
022c6d45 831\r
28a00297 832 //\r
833 // Last, add the new child node to the stream\r
834 //\r
835 InsertTailList (&Stream->Children, &Node->Link);\r
836\r
837 return EFI_SUCCESS;\r
838}\r
839\r
840\r
162ed594 841/**\r
de4e6bf9 842 Worker function Recursively searches / builds section stream database\r
843 looking for requested section.\r
162ed594 844\r
de4e6bf9 845 @param SourceStream Indicates the section stream in which to do the\r
846 search.\r
847 @param SearchType Indicates the type of section to search for.\r
848 @param SectionInstance Indicates which instance of section to find.\r
849 This is an in/out parameter to deal with\r
850 recursions.\r
851 @param SectionDefinitionGuid Guid of section definition\r
852 @param FoundChild Output indicating the child node that is found.\r
853 @param FoundStream Output indicating which section stream the child\r
854 was found in. If this stream was generated as a\r
855 result of an encapsulation section, the\r
856 streamhandle is visible within the SEP driver\r
857 only.\r
858 @param AuthenticationStatus Indicates the authentication status of the found section.\r
859\r
860 @retval EFI_SUCCESS Child node was found and returned.\r
861 EFI_OUT_OF_RESOURCES- Memory allocation failed.\r
862 @retval EFI_NOT_FOUND Requested child node does not exist.\r
863 @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol\r
864 does not exist\r
28a00297 865\r
162ed594 866**/\r
de4e6bf9 867EFI_STATUS\r
868FindChildNode (\r
869 IN CORE_SECTION_STREAM_NODE *SourceStream,\r
870 IN EFI_SECTION_TYPE SearchType,\r
871 IN OUT UINTN *SectionInstance,\r
872 IN EFI_GUID *SectionDefinitionGuid,\r
873 OUT CORE_SECTION_CHILD_NODE **FoundChild,\r
874 OUT CORE_SECTION_STREAM_NODE **FoundStream,\r
875 OUT UINT32 *AuthenticationStatus\r
28a00297 876 )\r
28a00297 877{\r
de4e6bf9 878 CORE_SECTION_CHILD_NODE *CurrentChildNode;\r
879 CORE_SECTION_CHILD_NODE *RecursedChildNode;\r
880 CORE_SECTION_STREAM_NODE *RecursedFoundStream;\r
881 UINT32 NextChildOffset;\r
882 EFI_STATUS ErrorStatus;\r
883 EFI_STATUS Status;\r
022c6d45 884\r
de4e6bf9 885 CurrentChildNode = NULL;\r
886 ErrorStatus = EFI_NOT_FOUND;\r
887\r
888 if (SourceStream->StreamLength == 0) {\r
889 return EFI_NOT_FOUND;\r
890 }\r
891\r
892 if (IsListEmpty (&SourceStream->Children) &&\r
893 SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {\r
28a00297 894 //\r
de4e6bf9 895 // This occurs when a section stream exists, but no child sections\r
896 // have been parsed out yet. Therefore, extract the first child and add it\r
897 // to the list of children so we can get started.\r
898 // Section stream may contain an array of zero or more bytes.\r
899 // So, its size should be >= the size of commen section header.\r
28a00297 900 //\r
de4e6bf9 901 Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);\r
902 if (EFI_ERROR (Status)) {\r
903 return Status;\r
904 }\r
28a00297 905 }\r
de4e6bf9 906\r
28a00297 907 //\r
de4e6bf9 908 // At least one child has been parsed out of the section stream. So, walk\r
909 // through the sections that have already been parsed out looking for the\r
910 // requested section, if necessary, continue parsing section stream and\r
911 // adding children until either the requested section is found, or we run\r
912 // out of data\r
28a00297 913 //\r
de4e6bf9 914 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));\r
162ed594 915\r
de4e6bf9 916 for (;;) {\r
60cf9cfc 917 ASSERT (CurrentChildNode != NULL);\r
de4e6bf9 918 if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {\r
919 //\r
920 // The type matches, so check the instance count to see if it's the one we want\r
921 //\r
922 (*SectionInstance)--;\r
923 if (*SectionInstance == 0) {\r
924 //\r
925 // Got it!\r
926 //\r
927 *FoundChild = CurrentChildNode;\r
928 *FoundStream = SourceStream;\r
929 *AuthenticationStatus = SourceStream->AuthenticationStatus;\r
930 return EFI_SUCCESS;\r
931 }\r
932 }\r
162ed594 933\r
de4e6bf9 934 if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
935 //\r
936 // If the current node is an encapsulating node, recurse into it...\r
937 //\r
938 Status = FindChildNode (\r
939 (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,\r
940 SearchType,\r
941 SectionInstance,\r
942 SectionDefinitionGuid,\r
943 &RecursedChildNode,\r
944 &RecursedFoundStream,\r
945 AuthenticationStatus\r
946 );\r
947 //\r
948 // If the status is not EFI_SUCCESS, just save the error code and continue\r
949 // to find the request child node in the rest stream.\r
950 //\r
951 if (*SectionInstance == 0) {\r
952 ASSERT_EFI_ERROR (Status);\r
953 *FoundChild = RecursedChildNode;\r
954 *FoundStream = RecursedFoundStream;\r
955 return EFI_SUCCESS;\r
956 } else {\r
957 ErrorStatus = Status;\r
28a00297 958 }\r
1d6ee65f
LG
959 } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {\r
960 //\r
961 // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed\r
962 // because a required GUIDED section extraction protocol does not exist.\r
963 // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.\r
964 //\r
965 ErrorStatus = EFI_PROTOCOL_ERROR;\r
de4e6bf9 966 }\r
967\r
968 if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {\r
28a00297 969 //\r
de4e6bf9 970 // We haven't found the child node we're interested in yet, but there's\r
971 // still more nodes that have already been parsed so get the next one\r
972 // and continue searching..\r
28a00297 973 //\r
de4e6bf9 974 CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));\r
28a00297 975 } else {\r
976 //\r
de4e6bf9 977 // We've exhausted children that have already been parsed, so see if\r
978 // there's any more data and continue parsing out more children if there\r
979 // is.\r
28a00297 980 //\r
de4e6bf9 981 NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;\r
982 //\r
983 // Round up to 4 byte boundary\r
984 //\r
985 NextChildOffset += 3;\r
986 NextChildOffset &= ~(UINTN) 3;\r
987 if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {\r
988 //\r
989 // There's an unparsed child remaining in the stream, so create a new child node\r
990 //\r
991 Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);\r
992 if (EFI_ERROR (Status)) {\r
993 return Status;\r
994 }\r
995 } else {\r
996 ASSERT (EFI_ERROR (ErrorStatus));\r
997 return ErrorStatus;\r
998 }\r
28a00297 999 }\r
28a00297 1000 }\r
28a00297 1001}\r
1002\r
1003\r
162ed594 1004/**\r
1005 Worker function. Search stream database for requested stream handle.\r
1006\r
022c6d45 1007 @param SearchHandle Indicates which stream to look for.\r
1008 @param FoundStream Output pointer to the found stream.\r
162ed594 1009\r
022c6d45 1010 @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains\r
1011 the stream node.\r
1012 @retval EFI_NOT_FOUND SearchHandle was not found in the stream\r
162ed594 1013 database.\r
1014\r
1015**/\r
28a00297 1016EFI_STATUS\r
1017FindStreamNode (\r
1018 IN UINTN SearchHandle,\r
1019 OUT CORE_SECTION_STREAM_NODE **FoundStream\r
1020 )\r
022c6d45 1021{\r
28a00297 1022 CORE_SECTION_STREAM_NODE *StreamNode;\r
022c6d45 1023\r
28a00297 1024 if (!IsListEmpty (&mStreamRoot)) {\r
1025 StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));\r
1026 for (;;) {\r
1027 if (StreamNode->StreamHandle == SearchHandle) {\r
1028 *FoundStream = StreamNode;\r
1029 return EFI_SUCCESS;\r
1030 } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {\r
1031 break;\r
1032 } else {\r
1033 StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));\r
1034 }\r
1035 }\r
1036 }\r
022c6d45 1037\r
28a00297 1038 return EFI_NOT_FOUND;\r
1039}\r
1040\r
1041\r
162ed594 1042/**\r
de4e6bf9 1043 SEP member function. Retrieves requested section from section stream.\r
162ed594 1044\r
de4e6bf9 1045 @param SectionStreamHandle The section stream from which to extract the\r
1046 requested section.\r
1047 @param SectionType A pointer to the type of section to search for.\r
1048 @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,\r
1049 then SectionDefinitionGuid indicates which of\r
1050 these types of sections to search for.\r
1051 @param SectionInstance Indicates which instance of the requested\r
1052 section to return.\r
1053 @param Buffer Double indirection to buffer. If *Buffer is\r
1054 non-null on input, then the buffer is caller\r
1055 allocated. If Buffer is NULL, then the buffer\r
1056 is callee allocated. In either case, the\r
1057 requried buffer size is returned in *BufferSize.\r
1058 @param BufferSize On input, indicates the size of *Buffer if\r
1059 *Buffer is non-null on input. On output,\r
1060 indicates the required size (allocated size if\r
1061 callee allocated) of *Buffer.\r
1062 @param AuthenticationStatus A pointer to a caller-allocated UINT32 that\r
1063 indicates the authentication status of the\r
1064 output buffer. If the input section's\r
1065 GuidedSectionHeader.Attributes field\r
1066 has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID\r
1067 bit as clear, AuthenticationStatus must return\r
1068 zero. Both local bits (19:16) and aggregate\r
1069 bits (3:0) in AuthenticationStatus are returned\r
1070 by ExtractSection(). These bits reflect the\r
1071 status of the extraction operation. The bit\r
1072 pattern in both regions must be the same, as\r
1073 the local and aggregate authentication statuses\r
1074 have equivalent meaning at this level. If the\r
1075 function returns anything other than\r
1076 EFI_SUCCESS, the value of *AuthenticationStatus\r
1077 is undefined.\r
162ed594 1078\r
de4e6bf9 1079 @retval EFI_SUCCESS Section was retrieved successfully\r
1080 @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the\r
1081 section stream with its\r
1082 EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,\r
1083 but there was no corresponding GUIDed Section\r
1084 Extraction Protocol in the handle database.\r
1085 *Buffer is unmodified.\r
1086 @retval EFI_NOT_FOUND An error was encountered when parsing the\r
1087 SectionStream. This indicates the SectionStream\r
1088 is not correctly formatted.\r
1089 @retval EFI_NOT_FOUND The requested section does not exist.\r
1090 @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process\r
1091 the request.\r
1092 @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.\r
1093 @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is\r
1094 insufficient to contain the requested section.\r
1095 The input buffer is filled and section contents\r
1096 are truncated.\r
162ed594 1097\r
1098**/\r
de4e6bf9 1099EFI_STATUS\r
1100EFIAPI\r
1101GetSection (\r
1102 IN UINTN SectionStreamHandle,\r
1103 IN EFI_SECTION_TYPE *SectionType,\r
1104 IN EFI_GUID *SectionDefinitionGuid,\r
1105 IN UINTN SectionInstance,\r
1106 IN VOID **Buffer,\r
1107 IN OUT UINTN *BufferSize,\r
1108 OUT UINT32 *AuthenticationStatus\r
28a00297 1109 )\r
28a00297 1110{\r
de4e6bf9 1111 CORE_SECTION_STREAM_NODE *StreamNode;\r
1112 EFI_TPL OldTpl;\r
1113 EFI_STATUS Status;\r
1114 CORE_SECTION_CHILD_NODE *ChildNode;\r
1115 CORE_SECTION_STREAM_NODE *ChildStreamNode;\r
1116 UINTN CopySize;\r
1117 UINT32 ExtractedAuthenticationStatus;\r
1118 UINTN Instance;\r
1119 UINT8 *CopyBuffer;\r
1120 UINTN SectionSize;\r
28a00297 1121\r
022c6d45 1122\r
de4e6bf9 1123 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1124 Instance = SectionInstance + 1;\r
28a00297 1125\r
de4e6bf9 1126 //\r
1127 // Locate target stream\r
1128 //\r
1129 Status = FindStreamNode (SectionStreamHandle, &StreamNode);\r
1130 if (EFI_ERROR (Status)) {\r
1131 Status = EFI_INVALID_PARAMETER;\r
1132 goto GetSection_Done;\r
1133 }\r
1134\r
1135 //\r
1136 // Found the stream, now locate and return the appropriate section\r
1137 //\r
1138 if (SectionType == NULL) {\r
1139 //\r
1140 // SectionType == NULL means return the WHOLE section stream...\r
1141 //\r
1142 CopySize = StreamNode->StreamLength;\r
1143 CopyBuffer = StreamNode->StreamBuffer;\r
1144 *AuthenticationStatus = StreamNode->AuthenticationStatus;\r
1145 } else {\r
1146 //\r
1147 // There's a requested section type, so go find it and return it...\r
1148 //\r
1149 Status = FindChildNode (\r
1150 StreamNode,\r
1151 *SectionType,\r
1152 &Instance,\r
1153 SectionDefinitionGuid,\r
1154 &ChildNode,\r
1155 &ChildStreamNode,\r
1156 &ExtractedAuthenticationStatus\r
1157 );\r
1158 if (EFI_ERROR (Status)) {\r
1159 goto GetSection_Done;\r
28a00297 1160 }\r
de4e6bf9 1161 CopySize = ChildNode->Size - sizeof (EFI_COMMON_SECTION_HEADER);\r
1162 CopyBuffer = ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream + sizeof (EFI_COMMON_SECTION_HEADER);\r
1163 *AuthenticationStatus = ExtractedAuthenticationStatus;\r
1164 }\r
28a00297 1165\r
de4e6bf9 1166 SectionSize = CopySize;\r
1167 if (*Buffer != NULL) {\r
28a00297 1168 //\r
de4e6bf9 1169 // Caller allocated buffer. Fill to size and return required size...\r
28a00297 1170 //\r
de4e6bf9 1171 if (*BufferSize < CopySize) {\r
1172 Status = EFI_WARN_BUFFER_TOO_SMALL;\r
1173 CopySize = *BufferSize;\r
1174 }\r
1175 } else {\r
1176 //\r
1177 // Callee allocated buffer. Allocate buffer and return size.\r
1178 //\r
1179 *Buffer = AllocatePool (CopySize);\r
1180 if (*Buffer == NULL) {\r
1181 Status = EFI_OUT_OF_RESOURCES;\r
1182 goto GetSection_Done;\r
1183 }\r
1184 }\r
1185 CopyMem (*Buffer, CopyBuffer, CopySize);\r
1186 *BufferSize = SectionSize;\r
1187\r
1188GetSection_Done:\r
1189 CoreRestoreTpl (OldTpl);\r
1190\r
1191 return Status;\r
1192}\r
1193\r
1194\r
1195/**\r
1196 Worker function. Destructor for child nodes.\r
1197\r
1198 @param ChildNode Indicates the node to destroy\r
022c6d45 1199\r
de4e6bf9 1200**/\r
1201VOID\r
1202FreeChildNode (\r
1203 IN CORE_SECTION_CHILD_NODE *ChildNode\r
1204 )\r
1205{\r
1206 ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);\r
1207 //\r
1208 // Remove the child from it's list\r
1209 //\r
1210 RemoveEntryList (&ChildNode->Link);\r
1211\r
1212 if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {\r
28a00297 1213 //\r
de4e6bf9 1214 // If it's an encapsulating section, we close the resulting section stream.\r
1215 // CloseSectionStream will free all memory associated with the stream.\r
28a00297 1216 //\r
de4e6bf9 1217 CloseSectionStream (ChildNode->EncapsulatedStreamHandle);\r
28a00297 1218 }\r
de4e6bf9 1219 //\r
1220 // Last, free the child node itself\r
1221 //\r
1222 CoreFreePool (ChildNode);\r
1223}\r
28a00297 1224\r
de4e6bf9 1225\r
1226/**\r
1227 SEP member function. Deletes an existing section stream\r
1228\r
1229 @param StreamHandleToClose Indicates the stream to close\r
1230\r
1231 @retval EFI_SUCCESS The section stream is closed sucessfully.\r
1232 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
1233 @retval EFI_INVALID_PARAMETER Section stream does not end concident with end\r
1234 of last section.\r
1235\r
1236**/\r
1237EFI_STATUS\r
1238EFIAPI\r
1239CloseSectionStream (\r
1240 IN UINTN StreamHandleToClose\r
1241 )\r
1242{\r
1243 CORE_SECTION_STREAM_NODE *StreamNode;\r
1244 EFI_TPL OldTpl;\r
1245 EFI_STATUS Status;\r
1246 LIST_ENTRY *Link;\r
1247 CORE_SECTION_CHILD_NODE *ChildNode;\r
1248\r
1249 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1250\r
1251 //\r
1252 // Locate target stream\r
1253 //\r
1254 Status = FindStreamNode (StreamHandleToClose, &StreamNode);\r
1255 if (!EFI_ERROR (Status)) {\r
1256 //\r
1257 // Found the stream, so close it\r
1258 //\r
1259 RemoveEntryList (&StreamNode->Link);\r
1260 while (!IsListEmpty (&StreamNode->Children)) {\r
1261 Link = GetFirstNode (&StreamNode->Children);\r
1262 ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);\r
1263 FreeChildNode (ChildNode);\r
1264 }\r
1265 CoreFreePool (StreamNode->StreamBuffer);\r
1266 CoreFreePool (StreamNode);\r
1267 Status = EFI_SUCCESS;\r
1268 } else {\r
1269 Status = EFI_INVALID_PARAMETER;\r
1270 }\r
1271\r
1272 CoreRestoreTpl (OldTpl);\r
1273 return Status;\r
28a00297 1274}\r
d8c79a81 1275\r
e94a9ff7 1276\r
d8c79a81
LG
1277/**\r
1278 The ExtractSection() function processes the input section and\r
1279 allocates a buffer from the pool in which it returns the section\r
1280 contents. If the section being extracted contains\r
1281 authentication information (the section's\r
1282 GuidedSectionHeader.Attributes field has the\r
1283 EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values\r
1284 returned in AuthenticationStatus must reflect the results of\r
1285 the authentication operation. Depending on the algorithm and\r
1286 size of the encapsulated data, the time that is required to do\r
1287 a full authentication may be prohibitively long for some\r
1288 classes of systems. To indicate this, use\r
1289 EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by\r
1290 the security policy driver (see the Platform Initialization\r
1291 Driver Execution Environment Core Interface Specification for\r
1292 more details and the GUID definition). If the\r
1293 EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle\r
1294 database, then, if possible, full authentication should be\r
1295 skipped and the section contents simply returned in the\r
1296 OutputBuffer. In this case, the\r
1297 EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus\r
1298 must be set on return. ExtractSection() is callable only from\r
1299 TPL_NOTIFY and below. Behavior of ExtractSection() at any\r
1300 EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is\r
1301 defined in RaiseTPL() in the UEFI 2.0 specification.\r
1302\r
022c6d45 1303\r
162ed594 1304 @param This Indicates the\r
1305 EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.\r
d8c79a81
LG
1306 @param InputSection Buffer containing the input GUIDed section\r
1307 to be processed. OutputBuffer OutputBuffer\r
1308 is allocated from boot services pool\r
1309 memory and contains the new section\r
1310 stream. The caller is responsible for\r
1311 freeing this buffer.\r
162ed594 1312 @param OutputBuffer *OutputBuffer is allocated from boot services\r
1313 pool memory and contains the new section stream.\r
1314 The caller is responsible for freeing this buffer.\r
d8c79a81
LG
1315 @param OutputSize A pointer to a caller-allocated UINTN in\r
1316 which the size of OutputBuffer allocation\r
1317 is stored. If the function returns\r
1318 anything other than EFI_SUCCESS, the value\r
1319 of OutputSize is undefined.\r
1320\r
1321 @param AuthenticationStatus A pointer to a caller-allocated\r
1322 UINT32 that indicates the\r
1323 authentication status of the\r
1324 output buffer. If the input\r
1325 section's\r
1326 GuidedSectionHeader.Attributes\r
1327 field has the\r
1328 EFI_GUIDED_SECTION_AUTH_STATUS_VAL\r
1329 bit as clear, AuthenticationStatus\r
1330 must return zero. Both local bits\r
1331 (19:16) and aggregate bits (3:0)\r
1332 in AuthenticationStatus are\r
1333 returned by ExtractSection().\r
1334 These bits reflect the status of\r
1335 the extraction operation. The bit\r
1336 pattern in both regions must be\r
1337 the same, as the local and\r
1338 aggregate authentication statuses\r
1339 have equivalent meaning at this\r
1340 level. If the function returns\r
1341 anything other than EFI_SUCCESS,\r
1342 the value of AuthenticationStatus\r
1343 is undefined.\r
1344\r
1345\r
162ed594 1346 @retval EFI_SUCCESS The InputSection was successfully\r
1347 processed and the section contents were\r
1348 returned.\r
d8c79a81 1349\r
162ed594 1350 @retval EFI_OUT_OF_RESOURCES The system has insufficient\r
1351 resources to process the\r
1352 request.\r
d8c79a81
LG
1353\r
1354 @retval EFI_INVALID_PARAMETER The GUID in InputSection does\r
1355 not match this instance of the\r
1356 GUIDed Section Extraction\r
1357 Protocol.\r
1358\r
1359**/\r
1360EFI_STATUS\r
797a9d67 1361EFIAPI\r
18fd8d65 1362CustomGuidedSectionExtract (\r
d8c79a81
LG
1363 IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,\r
1364 IN CONST VOID *InputSection,\r
1365 OUT VOID **OutputBuffer,\r
1366 OUT UINTN *OutputSize,\r
1367 OUT UINT32 *AuthenticationStatus\r
1368 )\r
1369{\r
1370 EFI_STATUS Status;\r
18fd8d65
LG
1371 VOID *ScratchBuffer;\r
1372 VOID *AllocatedOutputBuffer;\r
1373 UINT32 OutputBufferSize;\r
1374 UINT32 ScratchBufferSize;\r
1375 UINT16 SectionAttribute;\r
022c6d45 1376\r
d8c79a81 1377 //\r
18fd8d65 1378 // Init local variable\r
d8c79a81 1379 //\r
18fd8d65
LG
1380 ScratchBuffer = NULL;\r
1381 AllocatedOutputBuffer = NULL;\r
1382\r
d8c79a81 1383 //\r
18fd8d65 1384 // Call GetInfo to get the size and attribute of input guided section data.\r
d8c79a81 1385 //\r
18fd8d65 1386 Status = ExtractGuidedSectionGetInfo (\r
162ed594 1387 InputSection,\r
1388 &OutputBufferSize,\r
1389 &ScratchBufferSize,\r
1390 &SectionAttribute\r
1391 );\r
022c6d45 1392\r
d8c79a81 1393 if (EFI_ERROR (Status)) {\r
162ed594 1394 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));\r
18fd8d65
LG
1395 return Status;\r
1396 }\r
022c6d45 1397\r
de4e6bf9 1398 if (ScratchBufferSize > 0) {\r
d8c79a81 1399 //\r
18fd8d65 1400 // Allocate scratch buffer\r
d8c79a81 1401 //\r
9c4ac31c 1402 ScratchBuffer = AllocatePool (ScratchBufferSize);\r
18fd8d65
LG
1403 if (ScratchBuffer == NULL) {\r
1404 return EFI_OUT_OF_RESOURCES;\r
1405 }\r
d8c79a81
LG
1406 }\r
1407\r
022c6d45 1408 if (OutputBufferSize > 0) {\r
18fd8d65
LG
1409 //\r
1410 // Allocate output buffer\r
1411 //\r
9c4ac31c 1412 AllocatedOutputBuffer = AllocatePool (OutputBufferSize);\r
18fd8d65 1413 if (AllocatedOutputBuffer == NULL) {\r
de4e6bf9 1414 FreePool (ScratchBuffer);\r
18fd8d65
LG
1415 return EFI_OUT_OF_RESOURCES;\r
1416 }\r
1417 *OutputBuffer = AllocatedOutputBuffer;\r
d8c79a81
LG
1418 }\r
1419\r
1420 //\r
18fd8d65 1421 // Call decode function to extract raw data from the guided section.\r
d8c79a81 1422 //\r
18fd8d65 1423 Status = ExtractGuidedSectionDecode (\r
022c6d45 1424 InputSection,\r
18fd8d65
LG
1425 OutputBuffer,\r
1426 ScratchBuffer,\r
1427 AuthenticationStatus\r
e94a9ff7 1428 );\r
d8c79a81
LG
1429 if (EFI_ERROR (Status)) {\r
1430 //\r
18fd8d65 1431 // Decode failed\r
d8c79a81 1432 //\r
18fd8d65
LG
1433 if (AllocatedOutputBuffer != NULL) {\r
1434 CoreFreePool (AllocatedOutputBuffer);\r
1435 }\r
1436 if (ScratchBuffer != NULL) {\r
1437 CoreFreePool (ScratchBuffer);\r
1438 }\r
162ed594 1439 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));\r
d8c79a81
LG
1440 return Status;\r
1441 }\r
18fd8d65
LG
1442\r
1443 if (*OutputBuffer != AllocatedOutputBuffer) {\r
1444 //\r
022c6d45 1445 // OutputBuffer was returned as a different value,\r
18fd8d65 1446 // so copy section contents to the allocated memory buffer.\r
022c6d45 1447 //\r
18fd8d65
LG
1448 CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);\r
1449 *OutputBuffer = AllocatedOutputBuffer;\r
1450 }\r
1451\r
1452 //\r
1453 // Set real size of output buffer.\r
1454 //\r
1455 *OutputSize = (UINTN) OutputBufferSize;\r
1456\r
d8c79a81
LG
1457 //\r
1458 // Free unused scratch buffer.\r
1459 //\r
18fd8d65
LG
1460 if (ScratchBuffer != NULL) {\r
1461 CoreFreePool (ScratchBuffer);\r
1462 }\r
1463\r
d8c79a81 1464 return EFI_SUCCESS;\r
702887db 1465}\r