1 /** @file
2   Provide generic extract guided section functions for Dxe phase.
3 
4   Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <PiDxe.h>
16 
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/ExtractGuidedSectionLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 
23 #define EXTRACT_HANDLER_TABLE_SIZE   0x10
24 
25 UINT32               mNumberOfExtractHandler = 0;
26 UINT32               mMaxNumberOfExtractHandler = 0;
27 
28 GUID                 *mExtractHandlerGuidTable = NULL;
29 EXTRACT_GUIDED_SECTION_DECODE_HANDLER   *mExtractDecodeHandlerTable = NULL;
30 EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *mExtractGetInfoHandlerTable = NULL;
31 
32 /**
33   Reallocates more global memory to store the registered guid and Handler list.
34 
35   @retval  RETURN_SUCCESS            Reallocated more global memory space to store guid and function tables.
36   @retval  RETURN_OUT_OF_RESOURCES   Not enough memory to allocate.
37 **/
38 RETURN_STATUS
39 EFIAPI
ReallocateExtractHandlerTable()40 ReallocateExtractHandlerTable (
41   )
42 {
43   //
44   // Reallocate memory for GuidTable
45   //
46   mExtractHandlerGuidTable = ReallocatePool (
47                                mMaxNumberOfExtractHandler * sizeof (GUID),
48                                (mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (GUID),
49                                mExtractHandlerGuidTable
50                              );
51 
52   if (mExtractHandlerGuidTable == NULL) {
53     goto Done;
54   }
55 
56   //
57   // Reallocate memory for Decode handler Table
58   //
59   mExtractDecodeHandlerTable = ReallocatePool (
60                                mMaxNumberOfExtractHandler * sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER),
61                                (mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER),
62                                mExtractDecodeHandlerTable
63                              );
64 
65   if (mExtractDecodeHandlerTable == NULL) {
66     goto Done;
67   }
68 
69   //
70   // Reallocate memory for GetInfo handler Table
71   //
72   mExtractGetInfoHandlerTable = ReallocatePool (
73                                mMaxNumberOfExtractHandler * sizeof (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER),
74                                (mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER),
75                                mExtractGetInfoHandlerTable
76                              );
77 
78   if (mExtractGetInfoHandlerTable == NULL) {
79     goto Done;
80   }
81 
82   //
83   // Increase max handler number
84   //
85   mMaxNumberOfExtractHandler = mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE;
86   return RETURN_SUCCESS;
87 
88 Done:
89   if (mExtractHandlerGuidTable != NULL) {
90     FreePool (mExtractHandlerGuidTable);
91   }
92   if (mExtractDecodeHandlerTable != NULL) {
93     FreePool (mExtractDecodeHandlerTable);
94   }
95   if (mExtractGetInfoHandlerTable != NULL) {
96     FreePool (mExtractGetInfoHandlerTable);
97   }
98 
99   return RETURN_OUT_OF_RESOURCES;
100 }
101 /**
102   Constructor allocates the global memory to store the registered guid and Handler list.
103 
104   @param  ImageHandle   The firmware allocated handle for the EFI image.
105   @param  SystemTable   A pointer to the EFI System Table.
106 
107   @retval  RETURN_SUCCESS            Allocated the global memory space to store guid and function tables.
108   @retval  RETURN_OUT_OF_RESOURCES   Not enough memory to allocate.
109 **/
110 RETURN_STATUS
111 EFIAPI
DxeExtractGuidedSectionLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)112 DxeExtractGuidedSectionLibConstructor (
113   IN EFI_HANDLE        ImageHandle,
114   IN EFI_SYSTEM_TABLE  *SystemTable
115   )
116 {
117   return ReallocateExtractHandlerTable ();
118 }
119 
120 /**
121   Retrieve the list GUIDs that have been registered through ExtractGuidedSectionRegisterHandlers().
122 
123   Sets ExtractHandlerGuidTable so it points at a callee allocated array of registered GUIDs.
124   The total number of GUIDs in the array are returned. Since the array of GUIDs is callee allocated
125   and caller must treat this array of GUIDs as read-only data.
126   If ExtractHandlerGuidTable is NULL, then ASSERT().
127 
128   @param[out]  ExtractHandlerGuidTable  A pointer to the array of GUIDs that have been registered through
129                                         ExtractGuidedSectionRegisterHandlers().
130 
131   @return The number of the supported extract guided Handler.
132 
133 **/
134 UINTN
135 EFIAPI
ExtractGuidedSectionGetGuidList(OUT GUID ** ExtractHandlerGuidTable)136 ExtractGuidedSectionGetGuidList (
137   OUT  GUID  **ExtractHandlerGuidTable
138   )
139 {
140   ASSERT (ExtractHandlerGuidTable != NULL);
141 
142   *ExtractHandlerGuidTable = mExtractHandlerGuidTable;
143   return mNumberOfExtractHandler;
144 }
145 
146 /**
147   Registers handlers of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER and EXTRACT_GUIDED_SECTION_DECODE_HANDLER
148   for a specific GUID section type.
149 
150   Registers the handlers specified by GetInfoHandler and DecodeHandler with the GUID specified by SectionGuid.
151   If the GUID value specified by SectionGuid has already been registered, then return RETURN_ALREADY_STARTED.
152   If there are not enough resources available to register the handlers  then RETURN_OUT_OF_RESOURCES is returned.
153 
154   If SectionGuid is NULL, then ASSERT().
155   If GetInfoHandler is NULL, then ASSERT().
156   If DecodeHandler is NULL, then ASSERT().
157 
158   @param[in]  SectionGuid    A pointer to the GUID associated with the the handlers
159                              of the GUIDed section type being registered.
160   @param[in]  GetInfoHandler The pointer to a function that examines a GUIDed section and returns the
161                              size of the decoded buffer and the size of an optional scratch buffer
162                              required to actually decode the data in a GUIDed section.
163   @param[in]  DecodeHandler  The pointer to a function that decodes a GUIDed section into a caller
164                              allocated output buffer.
165 
166   @retval  RETURN_SUCCESS           The handlers were registered.
167   @retval  RETURN_OUT_OF_RESOURCES  There are not enough resources available to register the handlers.
168 
169 **/
170 RETURN_STATUS
171 EFIAPI
ExtractGuidedSectionRegisterHandlers(IN CONST GUID * SectionGuid,IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler,IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler)172 ExtractGuidedSectionRegisterHandlers (
173   IN CONST  GUID                                     *SectionGuid,
174   IN        EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER  GetInfoHandler,
175   IN        EXTRACT_GUIDED_SECTION_DECODE_HANDLER    DecodeHandler
176   )
177 {
178   UINT32 Index;
179   VOID   *GuidData;
180 
181   //
182   // Check input paramter.
183   //
184   ASSERT (SectionGuid != NULL);
185   ASSERT (GetInfoHandler != NULL);
186   ASSERT (DecodeHandler != NULL);
187 
188   //
189   // Search the match registered GetInfo handler for the input guided section.
190   //
191   for (Index = 0; Index < mNumberOfExtractHandler; Index ++) {
192     if (CompareGuid (&mExtractHandlerGuidTable[Index], SectionGuid)) {
193       //
194       // If the guided handler has been registered before, only update its handler.
195       //
196       mExtractDecodeHandlerTable [Index] = DecodeHandler;
197       mExtractGetInfoHandlerTable [Index] = GetInfoHandler;
198       return RETURN_SUCCESS;
199     }
200   }
201 
202   //
203   // Check the global table is enough to contain new Handler.
204   //
205   if (mNumberOfExtractHandler >= mMaxNumberOfExtractHandler) {
206     if (ReallocateExtractHandlerTable () != RETURN_SUCCESS) {
207       return RETURN_OUT_OF_RESOURCES;
208     }
209   }
210 
211   //
212   // Register new Handler and guid value.
213   //
214   CopyGuid (&mExtractHandlerGuidTable [mNumberOfExtractHandler], SectionGuid);
215   mExtractDecodeHandlerTable [mNumberOfExtractHandler] = DecodeHandler;
216   mExtractGetInfoHandlerTable [mNumberOfExtractHandler++] = GetInfoHandler;
217 
218   //
219   // Install the Guided Section GUID configuration table to record the GUID itself.
220   // Then the content of the configuration table buffer will be the same as the GUID value itself.
221   //
222   GuidData = AllocateCopyPool (sizeof (GUID), (VOID *) SectionGuid);
223   if (GuidData != NULL) {
224     gBS->InstallConfigurationTable ((EFI_GUID *) SectionGuid, GuidData);
225   }
226 
227   return RETURN_SUCCESS;
228 }
229 
230 /**
231   Retrieves a GUID from a GUIDed section and uses that GUID to select an associated handler of type
232   EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers().
233   The selected handler is used to retrieve and return the size of the decoded buffer and the size of an
234   optional scratch buffer required to actually decode the data in a GUIDed section.
235 
236   Examines a GUIDed section specified by InputSection.
237   If GUID for InputSection does not match any of the GUIDs registered through ExtractGuidedSectionRegisterHandlers(),
238   then RETURN_UNSUPPORTED is returned.
239   If the GUID of InputSection does match the GUID that this handler supports, then the the associated handler
240   of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers()
241   is used to retrieve the OututBufferSize, ScratchSize, and Attributes values. The return status from the handler of
242   type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER is returned.
243 
244   If InputSection is NULL, then ASSERT().
245   If OutputBufferSize is NULL, then ASSERT().
246   If ScratchBufferSize is NULL, then ASSERT().
247   If SectionAttribute is NULL, then ASSERT().
248 
249   @param[in]  InputSection       A pointer to a GUIDed section of an FFS formatted file.
250   @param[out] OutputBufferSize   A pointer to the size, in bytes, of an output buffer required if the buffer
251                                  specified by InputSection were decoded.
252   @param[out] ScratchBufferSize  A pointer to the size, in bytes, required as scratch space if the buffer specified by
253                                  InputSection were decoded.
254   @param[out] SectionAttribute   A pointer to the attributes of the GUIDed section.  See the Attributes field of
255                                  EFI_GUID_DEFINED_SECTION in the PI Specification.
256 
257   @retval  RETURN_SUCCESS      Successfully obtained the required information.
258   @retval  RETURN_UNSUPPORTED  The GUID from the section specified by InputSection does not match any of
259                                the GUIDs registered with ExtractGuidedSectionRegisterHandlers().
260   @retval  Others              The return status from the handler associated with the GUID retrieved from
261                                the section specified by InputSection.
262 
263 **/
264 RETURN_STATUS
265 EFIAPI
ExtractGuidedSectionGetInfo(IN CONST VOID * InputSection,OUT UINT32 * OutputBufferSize,OUT UINT32 * ScratchBufferSize,OUT UINT16 * SectionAttribute)266 ExtractGuidedSectionGetInfo (
267   IN  CONST VOID    *InputSection,
268   OUT       UINT32  *OutputBufferSize,
269   OUT       UINT32  *ScratchBufferSize,
270   OUT       UINT16  *SectionAttribute
271   )
272 {
273   UINT32 Index;
274   EFI_GUID *SectionDefinitionGuid;
275 
276   ASSERT (InputSection != NULL);
277   ASSERT (OutputBufferSize != NULL);
278   ASSERT (ScratchBufferSize != NULL);
279   ASSERT (SectionAttribute != NULL);
280 
281   if (IS_SECTION2 (InputSection)) {
282     SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
283   } else {
284     SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
285   }
286 
287   //
288   // Search the match registered GetInfo handler for the input guided section.
289   //
290   for (Index = 0; Index < mNumberOfExtractHandler; Index ++) {
291     if (CompareGuid (&mExtractHandlerGuidTable[Index], SectionDefinitionGuid)) {
292       //
293       // Call the match handler to getinfo for the input section data.
294       //
295       return mExtractGetInfoHandlerTable [Index] (
296                 InputSection,
297                 OutputBufferSize,
298                 ScratchBufferSize,
299                 SectionAttribute
300               );
301     }
302   }
303 
304   //
305   // Not found, the input guided section is not supported.
306   //
307   return RETURN_UNSUPPORTED;
308 }
309 
310 /**
311   Retrieves the GUID from a GUIDed section and uses that GUID to select an associated handler of type
312   EXTRACT_GUIDED_SECTION_DECODE_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers().
313   The selected handler is used to decode the data in a GUIDed section and return the result in a caller
314   allocated output buffer.
315 
316   Decodes the GUIDed section specified by InputSection.
317   If GUID for InputSection does not match any of the GUIDs registered through ExtractGuidedSectionRegisterHandlers(),
318   then RETURN_UNSUPPORTED is returned.
319   If the GUID of InputSection does match the GUID that this handler supports, then the the associated handler
320   of type EXTRACT_GUIDED_SECTION_DECODE_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers()
321   is used to decode InputSection into the buffer specified by OutputBuffer and the authentication status of this
322   decode operation is returned in AuthenticationStatus.  If the decoded buffer is identical to the data in InputSection,
323   then OutputBuffer is set to point at the data in InputSection.  Otherwise, the decoded data will be placed in caller
324   allocated buffer specified by OutputBuffer.    This function is responsible for computing the  EFI_AUTH_STATUS_PLATFORM_OVERRIDE
325   bit of in AuthenticationStatus.  The return status from the handler of type EXTRACT_GUIDED_SECTION_DECODE_HANDLER is returned.
326 
327   If InputSection is NULL, then ASSERT().
328   If OutputBuffer is NULL, then ASSERT().
329   If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
330   If AuthenticationStatus is NULL, then ASSERT().
331 
332   @param[in]  InputSection   A pointer to a GUIDed section of an FFS formatted file.
333   @param[out] OutputBuffer   A pointer to a buffer that contains the result of a decode operation.
334   @param[in]  ScratchBuffer  A caller allocated buffer that may be required by this function as a scratch buffer to perform the decode operation.
335   @param[out] AuthenticationStatus
336                              A pointer to the authentication status of the decoded output buffer. See the definition
337                              of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI section of the PI
338                              Specification.
339 
340   @retval  RETURN_SUCCESS           The buffer specified by InputSection was decoded.
341   @retval  RETURN_UNSUPPORTED       The section specified by InputSection does not match the GUID this handler supports.
342   @retval  RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
343 
344 **/
345 RETURN_STATUS
346 EFIAPI
ExtractGuidedSectionDecode(IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,IN VOID * ScratchBuffer,OPTIONAL OUT UINT32 * AuthenticationStatus)347 ExtractGuidedSectionDecode (
348   IN  CONST VOID    *InputSection,
349   OUT       VOID    **OutputBuffer,
350   IN        VOID    *ScratchBuffer,        OPTIONAL
351   OUT       UINT32  *AuthenticationStatus
352   )
353 {
354   UINT32 Index;
355   EFI_GUID *SectionDefinitionGuid;
356 
357   //
358   // Check the input parameters
359   //
360   ASSERT (InputSection != NULL);
361   ASSERT (OutputBuffer != NULL);
362   ASSERT (AuthenticationStatus != NULL);
363 
364   if (IS_SECTION2 (InputSection)) {
365     SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
366   } else {
367     SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
368   }
369 
370   //
371   // Search the match registered extract handler for the input guided section.
372   //
373   for (Index = 0; Index < mNumberOfExtractHandler; Index ++) {
374     if (CompareGuid (&mExtractHandlerGuidTable[Index], SectionDefinitionGuid)) {
375       //
376       // Call the match handler to extract raw data for the input section data.
377       //
378       return mExtractDecodeHandlerTable [Index] (
379                 InputSection,
380                 OutputBuffer,
381                 ScratchBuffer,
382                 AuthenticationStatus
383               );
384     }
385   }
386 
387   //
388   // Not found, the input guided section is not supported.
389   //
390   return RETURN_UNSUPPORTED;
391 }
392 
393 /**
394   Retrieves handlers of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER and
395   EXTRACT_GUIDED_SECTION_DECODE_HANDLER for a specific GUID section type.
396 
397   Retrieves the handlers associated with SectionGuid and returns them in
398   GetInfoHandler and DecodeHandler.
399 
400   If the GUID value specified by SectionGuid has not been registered, then
401   return RETURN_NOT_FOUND.
402 
403   If SectionGuid is NULL, then ASSERT().
404 
405   @param[in]  SectionGuid    A pointer to the GUID associated with the handlersof the GUIDed
406                              section type being retrieved.
407   @param[out] GetInfoHandler Pointer to a function that examines a GUIDed section and returns
408                              the size of the decoded buffer and the size of an optional scratch
409                              buffer required to actually decode the data in a GUIDed section.
410                              This is an optional parameter that may be NULL. If it is NULL, then
411                              the previously registered handler is not returned.
412   @param[out] DecodeHandler  Pointer to a function that decodes a GUIDed section into a caller
413                              allocated output buffer. This is an optional parameter that may be NULL.
414                              If it is NULL, then the previously registered handler is not returned.
415 
416   @retval  RETURN_SUCCESS     The handlers were retrieved.
417   @retval  RETURN_NOT_FOUND   No handlers have been registered with the specified GUID.
418 
419 **/
420 RETURN_STATUS
421 EFIAPI
ExtractGuidedSectionGetHandlers(IN CONST GUID * SectionGuid,OUT EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER * GetInfoHandler,OPTIONAL OUT EXTRACT_GUIDED_SECTION_DECODE_HANDLER * DecodeHandler OPTIONAL)422 ExtractGuidedSectionGetHandlers (
423   IN CONST   GUID                                     *SectionGuid,
424   OUT        EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER  *GetInfoHandler,  OPTIONAL
425   OUT        EXTRACT_GUIDED_SECTION_DECODE_HANDLER    *DecodeHandler    OPTIONAL
426   )
427 {
428   UINT32 Index;
429 
430   //
431   // Check input parameter.
432   //
433   ASSERT (SectionGuid != NULL);
434 
435   //
436   // Search the match registered GetInfo handler for the input guided section.
437   //
438   for (Index = 0; Index < mNumberOfExtractHandler; Index ++) {
439     if (CompareGuid (&mExtractHandlerGuidTable[Index], SectionGuid)) {
440 
441       //
442       // If the guided handler has been registered before, then return the registered handlers.
443       //
444       if (GetInfoHandler != NULL) {
445         *GetInfoHandler = mExtractGetInfoHandlerTable[Index];
446       }
447       if (DecodeHandler != NULL) {
448         *DecodeHandler = mExtractDecodeHandlerTable[Index];
449       }
450       return RETURN_SUCCESS;
451     }
452   }
453   return RETURN_NOT_FOUND;
454 }
455