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