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