1 /** @file
2 Provide generic extract guided section functions for PEI 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 <PiPei.h>
16
17 #include <Library/DebugLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/HobLib.h>
21 #include <Library/ExtractGuidedSectionLib.h>
22
23 #define PEI_EXTRACT_HANDLER_INFO_SIGNATURE SIGNATURE_32 ('P', 'E', 'H', 'I')
24
25 typedef struct {
26 UINT32 Signature;
27 UINT32 NumberOfExtractHandler;
28 GUID *ExtractHandlerGuidTable;
29 EXTRACT_GUIDED_SECTION_DECODE_HANDLER *ExtractDecodeHandlerTable;
30 EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *ExtractGetInfoHandlerTable;
31 } PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO;
32
33 /**
34 Build guid hob for the global memory to store the registered guid and Handler list.
35 If GuidHob exists, HandlerInfo will be directly got from Guid hob data.
36
37 @param[in, out] InfoPointer The pointer to pei handler information structure.
38
39 @retval RETURN_SUCCESS Build Guid hob for the global memory space to store guid and function tables.
40 @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.
41 **/
42 RETURN_STATUS
PeiGetExtractGuidedSectionHandlerInfo(IN OUT PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO ** InfoPointer)43 PeiGetExtractGuidedSectionHandlerInfo (
44 IN OUT PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO **InfoPointer
45 )
46 {
47 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
48 EFI_PEI_HOB_POINTERS Hob;
49
50 //
51 // First try to get handler information from guid hob specified by CallerId.
52 //
53 Hob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GetHobList ());
54 while (Hob.Raw != NULL) {
55 if (CompareGuid (&(Hob.Guid->Name), &gEfiCallerIdGuid)) {
56 HandlerInfo = (PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *) GET_GUID_HOB_DATA (Hob.Guid);
57 if (HandlerInfo->Signature == PEI_EXTRACT_HANDLER_INFO_SIGNATURE) {
58 //
59 // Update Table Pointer when hob start address is changed.
60 //
61 if (HandlerInfo->ExtractHandlerGuidTable != (GUID *) (HandlerInfo + 1)) {
62 HandlerInfo->ExtractHandlerGuidTable = (GUID *) (HandlerInfo + 1);
63 HandlerInfo->ExtractDecodeHandlerTable = (EXTRACT_GUIDED_SECTION_DECODE_HANDLER *) (
64 (UINT8 *)HandlerInfo->ExtractHandlerGuidTable +
65 PcdGet32 (PcdMaximumGuidedExtractHandler) * sizeof (GUID)
66 );
67 HandlerInfo->ExtractGetInfoHandlerTable = (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *) (
68 (UINT8 *)HandlerInfo->ExtractDecodeHandlerTable +
69 PcdGet32 (PcdMaximumGuidedExtractHandler) *
70 sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER)
71 );
72 }
73 //
74 // Return HandlerInfo pointer.
75 //
76 *InfoPointer = HandlerInfo;
77 return EFI_SUCCESS;
78 }
79 }
80 Hob.Raw = GET_NEXT_HOB (Hob);
81 Hob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, Hob.Raw);
82 }
83
84 //
85 // If Guid Hob is not found, Build CallerId Guid hob to store Handler Info
86 //
87 HandlerInfo = BuildGuidHob (
88 &gEfiCallerIdGuid,
89 sizeof (PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO) +
90 PcdGet32 (PcdMaximumGuidedExtractHandler) *
91 (sizeof (GUID) + sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER) + sizeof (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER))
92 );
93 if (HandlerInfo == NULL) {
94 //
95 // No enough resource to build guid hob.
96 //
97 *InfoPointer = NULL;
98 return EFI_OUT_OF_RESOURCES;
99 }
100 //
101 // Init HandlerInfo structure
102 //
103 HandlerInfo->Signature = PEI_EXTRACT_HANDLER_INFO_SIGNATURE;
104 HandlerInfo->NumberOfExtractHandler = 0;
105 HandlerInfo->ExtractHandlerGuidTable = (GUID *) (HandlerInfo + 1);
106 HandlerInfo->ExtractDecodeHandlerTable = (EXTRACT_GUIDED_SECTION_DECODE_HANDLER *) (
107 (UINT8 *)HandlerInfo->ExtractHandlerGuidTable +
108 PcdGet32 (PcdMaximumGuidedExtractHandler) * sizeof (GUID)
109 );
110 HandlerInfo->ExtractGetInfoHandlerTable = (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *) (
111 (UINT8 *)HandlerInfo->ExtractDecodeHandlerTable +
112 PcdGet32 (PcdMaximumGuidedExtractHandler) *
113 sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER)
114 );
115 //
116 // return the created HandlerInfo.
117 //
118 *InfoPointer = HandlerInfo;
119 return EFI_SUCCESS;
120 }
121
122 /**
123 Retrieve the list GUIDs that have been registered through ExtractGuidedSectionRegisterHandlers().
124
125 Sets ExtractHandlerGuidTable so it points at a callee allocated array of registered GUIDs.
126 The total number of GUIDs in the array are returned. Since the array of GUIDs is callee allocated
127 and caller must treat this array of GUIDs as read-only data.
128 If ExtractHandlerGuidTable is NULL, then ASSERT().
129
130 @param[out] ExtractHandlerGuidTable A pointer to the array of GUIDs that have been registered through
131 ExtractGuidedSectionRegisterHandlers().
132
133 @return the number of the supported extract guided Handler.
134
135 **/
136 UINTN
137 EFIAPI
ExtractGuidedSectionGetGuidList(OUT GUID ** ExtractHandlerGuidTable)138 ExtractGuidedSectionGetGuidList (
139 OUT GUID **ExtractHandlerGuidTable
140 )
141 {
142 EFI_STATUS Status;
143 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
144
145 ASSERT (ExtractHandlerGuidTable != NULL);
146
147 //
148 // Get all registered handler information
149 //
150 Status = PeiGetExtractGuidedSectionHandlerInfo (&HandlerInfo);
151 if (EFI_ERROR (Status)) {
152 *ExtractHandlerGuidTable = NULL;
153 return 0;
154 }
155
156 //
157 // Get GuidTable and Table Number
158 //
159 ASSERT (HandlerInfo != NULL);
160 *ExtractHandlerGuidTable = HandlerInfo->ExtractHandlerGuidTable;
161 return HandlerInfo->NumberOfExtractHandler;
162 }
163
164 /**
165 Registers handlers of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER and EXTRACT_GUIDED_SECTION_DECODE_HANDLER
166 for a specific GUID section type.
167
168 Registers the handlers specified by GetInfoHandler and DecodeHandler with the GUID specified by SectionGuid.
169 If the GUID value specified by SectionGuid has already been registered, then return RETURN_ALREADY_STARTED.
170 If there are not enough resources available to register the handlers then RETURN_OUT_OF_RESOURCES is returned.
171
172 If SectionGuid is NULL, then ASSERT().
173 If GetInfoHandler is NULL, then ASSERT().
174 If DecodeHandler is NULL, then ASSERT().
175
176 @param[in] SectionGuid A pointer to the GUID associated with the the handlers
177 of the GUIDed section type being registered.
178 @param[in] GetInfoHandler The pointer to a function that examines a GUIDed section and returns the
179 size of the decoded buffer and the size of an optional scratch buffer
180 required to actually decode the data in a GUIDed section.
181 @param[in] DecodeHandler The pointer to a function that decodes a GUIDed section into a caller
182 allocated output buffer.
183
184 @retval RETURN_SUCCESS The handlers were registered.
185 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to register the handlers.
186
187 **/
188 RETURN_STATUS
189 EFIAPI
ExtractGuidedSectionRegisterHandlers(IN CONST GUID * SectionGuid,IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler,IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler)190 ExtractGuidedSectionRegisterHandlers (
191 IN CONST GUID *SectionGuid,
192 IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler,
193 IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler
194 )
195 {
196 EFI_STATUS Status;
197 UINT32 Index;
198 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
199
200 //
201 // Check input parameter
202 //
203 ASSERT (SectionGuid != NULL);
204 ASSERT (GetInfoHandler != NULL);
205 ASSERT (DecodeHandler != NULL);
206
207
208
209 //
210 // Get the registered handler information
211 //
212 Status = PeiGetExtractGuidedSectionHandlerInfo (&HandlerInfo);
213 if (EFI_ERROR (Status)) {
214 return Status;
215 }
216
217 //
218 // Search the match registered GetInfo handler for the input guided section.
219 //
220 ASSERT (HandlerInfo != NULL);
221 for (Index = 0; Index < HandlerInfo->NumberOfExtractHandler; Index ++) {
222 if (CompareGuid (HandlerInfo->ExtractHandlerGuidTable + Index, SectionGuid)) {
223 //
224 // If the guided handler has been registered before, only update its handler.
225 //
226 HandlerInfo->ExtractDecodeHandlerTable [Index] = DecodeHandler;
227 HandlerInfo->ExtractGetInfoHandlerTable [Index] = GetInfoHandler;
228 return RETURN_SUCCESS;
229 }
230 }
231
232 //
233 // Check the global table is enough to contain new Handler.
234 //
235 if (HandlerInfo->NumberOfExtractHandler >= PcdGet32 (PcdMaximumGuidedExtractHandler)) {
236 return RETURN_OUT_OF_RESOURCES;
237 }
238
239 //
240 // Register new Handler and guid value.
241 //
242 CopyGuid (HandlerInfo->ExtractHandlerGuidTable + HandlerInfo->NumberOfExtractHandler, SectionGuid);
243 HandlerInfo->ExtractDecodeHandlerTable [HandlerInfo->NumberOfExtractHandler] = DecodeHandler;
244 HandlerInfo->ExtractGetInfoHandlerTable [HandlerInfo->NumberOfExtractHandler++] = GetInfoHandler;
245
246 //
247 // Build the Guided Section GUID HOB to record the GUID itself.
248 // Then the content of the GUIDed HOB will be the same as the GUID value itself.
249 //
250 BuildGuidDataHob (
251 (EFI_GUID *) SectionGuid,
252 (VOID *) SectionGuid,
253 sizeof (GUID)
254 );
255
256 return RETURN_SUCCESS;
257 }
258
259 /**
260 Retrieves a GUID from a GUIDed section and uses that GUID to select an associated handler of type
261 EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers().
262 The selected handler is used to retrieve and return the size of the decoded buffer and the size of an
263 optional scratch buffer required to actually decode the data in a GUIDed section.
264
265 Examines a GUIDed section specified by InputSection.
266 If GUID for InputSection does not match any of the GUIDs registered through ExtractGuidedSectionRegisterHandlers(),
267 then RETURN_UNSUPPORTED is returned.
268 If the GUID of InputSection does match the GUID that this handler supports, then the the associated handler
269 of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers()
270 is used to retrieve the OututBufferSize, ScratchSize, and Attributes values. The return status from the handler of
271 type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER is returned.
272
273 If InputSection is NULL, then ASSERT().
274 If OutputBufferSize is NULL, then ASSERT().
275 If ScratchBufferSize is NULL, then ASSERT().
276 If SectionAttribute is NULL, then ASSERT().
277
278 @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
279 @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required if the buffer
280 specified by InputSection were decoded.
281 @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space if the buffer specified by
282 InputSection were decoded.
283 @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes field of
284 EFI_GUID_DEFINED_SECTION in the PI Specification.
285
286 @retval RETURN_SUCCESS Get the required information successfully.
287 @retval RETURN_UNSUPPORTED The GUID from the section specified by InputSection does not match any of
288 the GUIDs registered with ExtractGuidedSectionRegisterHandlers().
289 @retval Others The return status from the handler associated with the GUID retrieved from
290 the section specified by InputSection.
291
292 **/
293 RETURN_STATUS
294 EFIAPI
ExtractGuidedSectionGetInfo(IN CONST VOID * InputSection,OUT UINT32 * OutputBufferSize,OUT UINT32 * ScratchBufferSize,OUT UINT16 * SectionAttribute)295 ExtractGuidedSectionGetInfo (
296 IN CONST VOID *InputSection,
297 OUT UINT32 *OutputBufferSize,
298 OUT UINT32 *ScratchBufferSize,
299 OUT UINT16 *SectionAttribute
300 )
301 {
302 UINT32 Index;
303 EFI_STATUS Status;
304 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
305 EFI_GUID *SectionDefinitionGuid;
306
307 //
308 // Check input parameter
309 //
310 ASSERT (InputSection != NULL);
311 ASSERT (OutputBufferSize != NULL);
312 ASSERT (ScratchBufferSize != NULL);
313 ASSERT (SectionAttribute != NULL);
314
315 //
316 // Get all registered handler information.
317 //
318 Status = PeiGetExtractGuidedSectionHandlerInfo (&HandlerInfo);
319 if (EFI_ERROR (Status)) {
320 return Status;
321 }
322
323 if (IS_SECTION2 (InputSection)) {
324 SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
325 } else {
326 SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
327 }
328
329 //
330 // Search the match registered GetInfo handler for the input guided section.
331 //
332 ASSERT (HandlerInfo != NULL);
333 for (Index = 0; Index < HandlerInfo->NumberOfExtractHandler; Index ++) {
334 if (CompareGuid (HandlerInfo->ExtractHandlerGuidTable + Index, SectionDefinitionGuid)) {
335 //
336 // Call the match handler to get information for the input section data.
337 //
338 return HandlerInfo->ExtractGetInfoHandlerTable [Index] (
339 InputSection,
340 OutputBufferSize,
341 ScratchBufferSize,
342 SectionAttribute
343 );
344 }
345 }
346
347 //
348 // Not found, the input guided section is not supported.
349 //
350 return RETURN_UNSUPPORTED;
351 }
352
353 /**
354 Retrieves the GUID from a GUIDed section and uses that GUID to select an associated handler of type
355 EXTRACT_GUIDED_SECTION_DECODE_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers().
356 The selected handler is used to decode the data in a GUIDed section and return the result in a caller
357 allocated output buffer.
358
359 Decodes the GUIDed section specified by InputSection.
360 If GUID for InputSection does not match any of the GUIDs registered through ExtractGuidedSectionRegisterHandlers(),
361 then RETURN_UNSUPPORTED is returned.
362 If the GUID of InputSection does match the GUID that this handler supports, then the the associated handler
363 of type EXTRACT_GUIDED_SECTION_DECODE_HANDLER that was registered with ExtractGuidedSectionRegisterHandlers()
364 is used to decode InputSection into the buffer specified by OutputBuffer and the authentication status of this
365 decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the data in InputSection,
366 then OutputBuffer is set to point at the data in InputSection. Otherwise, the decoded data will be placed in caller
367 allocated buffer specified by OutputBuffer. This function is responsible for computing the EFI_AUTH_STATUS_PLATFORM_OVERRIDE
368 bit of in AuthenticationStatus. The return status from the handler of type EXTRACT_GUIDED_SECTION_DECODE_HANDLER is returned.
369
370 If InputSection is NULL, then ASSERT().
371 If OutputBuffer is NULL, then ASSERT().
372 If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
373 If AuthenticationStatus is NULL, then ASSERT().
374
375 @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
376 @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
377 @param[in] ScratchBuffer A caller allocated buffer that may be required by this function as a scratch buffer to perform the decode operation.
378 @param[out] AuthenticationStatus
379 A pointer to the authentication status of the decoded output buffer. See the definition
380 of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI section of the PI
381 Specification.
382
383 @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
384 @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
385 @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
386
387 **/
388 RETURN_STATUS
389 EFIAPI
ExtractGuidedSectionDecode(IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,IN VOID * ScratchBuffer,OPTIONAL OUT UINT32 * AuthenticationStatus)390 ExtractGuidedSectionDecode (
391 IN CONST VOID *InputSection,
392 OUT VOID **OutputBuffer,
393 IN VOID *ScratchBuffer, OPTIONAL
394 OUT UINT32 *AuthenticationStatus
395 )
396 {
397 UINT32 Index;
398 EFI_STATUS Status;
399 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
400 EFI_GUID *SectionDefinitionGuid;
401
402 //
403 // Check input parameter
404 //
405 ASSERT (InputSection != NULL);
406 ASSERT (OutputBuffer != NULL);
407 ASSERT (AuthenticationStatus != NULL);
408
409 //
410 // Get all registered handler information.
411 //
412 Status = PeiGetExtractGuidedSectionHandlerInfo (&HandlerInfo);
413 if (EFI_ERROR (Status)) {
414 return Status;
415 }
416
417 if (IS_SECTION2 (InputSection)) {
418 SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
419 } else {
420 SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
421 }
422
423 //
424 // Search the match registered Extract handler for the input guided section.
425 //
426 ASSERT (HandlerInfo != NULL);
427 for (Index = 0; Index < HandlerInfo->NumberOfExtractHandler; Index ++) {
428 if (CompareGuid (HandlerInfo->ExtractHandlerGuidTable + Index, SectionDefinitionGuid)) {
429 //
430 // Call the match handler to extract raw data for the input guided section.
431 //
432 return HandlerInfo->ExtractDecodeHandlerTable [Index] (
433 InputSection,
434 OutputBuffer,
435 ScratchBuffer,
436 AuthenticationStatus
437 );
438 }
439 }
440
441 //
442 // Not found, the input guided section is not supported.
443 //
444 return RETURN_UNSUPPORTED;
445 }
446
447 /**
448 Retrieves handlers of type EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER and
449 EXTRACT_GUIDED_SECTION_DECODE_HANDLER for a specific GUID section type.
450
451 Retrieves the handlers associated with SectionGuid and returns them in
452 GetInfoHandler and DecodeHandler.
453
454 If the GUID value specified by SectionGuid has not been registered, then
455 return RETURN_NOT_FOUND.
456
457 If SectionGuid is NULL, then ASSERT().
458
459 @param[in] SectionGuid A pointer to the GUID associated with the handlersof the GUIDed
460 section type being retrieved.
461 @param[out] GetInfoHandler Pointer to a function that examines a GUIDed section and returns
462 the size of the decoded buffer and the size of an optional scratch
463 buffer required to actually decode the data in a GUIDed section.
464 This is an optional parameter that may be NULL. If it is NULL, then
465 the previously registered handler is not returned.
466 @param[out] DecodeHandler Pointer to a function that decodes a GUIDed section into a caller
467 allocated output buffer. This is an optional parameter that may be NULL.
468 If it is NULL, then the previously registered handler is not returned.
469
470 @retval RETURN_SUCCESS The handlers were retrieved.
471 @retval RETURN_NOT_FOUND No handlers have been registered with the specified GUID.
472
473 **/
474 RETURN_STATUS
475 EFIAPI
ExtractGuidedSectionGetHandlers(IN CONST GUID * SectionGuid,OUT EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER * GetInfoHandler,OPTIONAL OUT EXTRACT_GUIDED_SECTION_DECODE_HANDLER * DecodeHandler OPTIONAL)476 ExtractGuidedSectionGetHandlers (
477 IN CONST GUID *SectionGuid,
478 OUT EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *GetInfoHandler, OPTIONAL
479 OUT EXTRACT_GUIDED_SECTION_DECODE_HANDLER *DecodeHandler OPTIONAL
480 )
481 {
482 EFI_STATUS Status;
483 UINT32 Index;
484 PEI_EXTRACT_GUIDED_SECTION_HANDLER_INFO *HandlerInfo;
485
486 //
487 // Check input parameter
488 //
489 ASSERT (SectionGuid != NULL);
490
491 //
492 // Get the registered handler information
493 //
494 Status = PeiGetExtractGuidedSectionHandlerInfo (&HandlerInfo);
495 if (EFI_ERROR (Status)) {
496 return Status;
497 }
498
499 //
500 // Search the match registered GetInfo handler for the input guided section.
501 //
502 ASSERT (HandlerInfo != NULL);
503 for (Index = 0; Index < HandlerInfo->NumberOfExtractHandler; Index ++) {
504 if (CompareGuid (HandlerInfo->ExtractHandlerGuidTable + Index, SectionGuid)) {
505
506 //
507 // If the guided handler has been registered before, then return the registered handlers.
508 //
509 if (GetInfoHandler != NULL) {
510 *GetInfoHandler = HandlerInfo->ExtractGetInfoHandlerTable[Index];
511 }
512 if (DecodeHandler != NULL) {
513 *DecodeHandler = HandlerInfo->ExtractDecodeHandlerTable[Index];
514 }
515 return RETURN_SUCCESS;
516 }
517 }
518 return RETURN_NOT_FOUND;
519 }
520