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