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