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