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