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