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