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