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