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 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 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 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 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 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 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