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