1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 23 Module Name: 24 25 26 Recovery.c 27 28 Abstract: 29 30 Tiano PEIM to provide the platform recovery functionality. 31 32 --*/ 33 34 #include "PlatformEarlyInit.h" 35 36 #define PEI_FVMAIN_COMPACT_GUID \ 37 {0x4A538818, 0x5AE0, 0x4eb2, 0xB2, 0xEB, 0x48, 0x8b, 0x23, 0x65, 0x70, 0x22}; 38 39 EFI_GUID FvMainCompactFileGuid = PEI_FVMAIN_COMPACT_GUID; 40 41 // 42 // Required Service 43 // 44 EFI_STATUS 45 EFIAPI 46 PlatformRecoveryModule ( 47 IN CONST EFI_PEI_SERVICES **PeiServices, 48 IN EFI_PEI_RECOVERY_MODULE_PPI *This 49 ); 50 51 // 52 // Module globals 53 // 54 55 typedef struct { 56 EFI_GUID CapsuleGuid; 57 UINT32 HeaderSize; 58 UINT32 Flags; 59 UINT32 CapsuleImageSize; 60 UINT32 SequenceNumber; 61 EFI_GUID InstanceId; 62 UINT32 OffsetToSplitInformation; 63 UINT32 OffsetToCapsuleBody; 64 UINT32 OffsetToOemDefinedHeader; 65 UINT32 OffsetToAuthorInformation; 66 UINT32 OffsetToRevisionInformation; 67 UINT32 OffsetToShortDescription; 68 UINT32 OffsetToLongDescription; 69 UINT32 OffsetToApplicableDevices; 70 } OLD_EFI_CAPSULE_HEADER; 71 72 73 static EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = { 74 PlatformRecoveryModule 75 }; 76 77 static EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = { 78 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 79 &gEfiPeiRecoveryModulePpiGuid, 80 &mRecoveryPpi 81 }; 82 83 /** 84 Provide the functionality of the Recovery Module. 85 86 @param PeiServices General purpose services available to every PEIM. 87 88 @retval Status EFI_SUCCESS if the interface could be successfully 89 installed 90 91 **/ 92 EFI_STATUS 93 EFIAPI 94 PeimInitializeRecovery ( 95 IN CONST EFI_PEI_SERVICES **PeiServices 96 ) 97 { 98 EFI_STATUS Status; 99 100 Status = (*PeiServices)->InstallPpi ( 101 PeiServices, 102 &mRecoveryPpiList 103 ); 104 105 return Status; 106 } 107 108 /** 109 Provide the functionality of the Ea Recovery Module. 110 111 @param PeiServices General purpose services available to every PEIM. 112 @param This Pointer to PEI_RECOVERY_MODULE_INTERFACE. 113 114 @retval EFI_SUCCESS If the interface could be successfully 115 installed. 116 @retval EFI_UNSUPPORTED Not supported. 117 118 **/ 119 EFI_STATUS 120 EFIAPI 121 PlatformRecoveryModule ( 122 IN CONST EFI_PEI_SERVICES **PeiServices, 123 IN EFI_PEI_RECOVERY_MODULE_PPI *This 124 ) 125 { 126 EFI_STATUS Status; 127 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryModule; 128 UINTN NumberOfImageProviders; 129 BOOLEAN ProviderAvailable; 130 UINTN NumberRecoveryCapsules; 131 UINTN RecoveryCapsuleSize; 132 EFI_GUID DeviceId; 133 BOOLEAN ImageFound; 134 EFI_PHYSICAL_ADDRESS Address; 135 VOID *Buffer; 136 OLD_EFI_CAPSULE_HEADER *CapsuleHeader; 137 EFI_PEI_HOB_POINTERS Hob; 138 EFI_PEI_HOB_POINTERS HobOld; 139 EFI_HOB_CAPSULE_VOLUME *CapsuleHob; 140 BOOLEAN HobUpdate; 141 EFI_FIRMWARE_VOLUME_HEADER *FvHeader; 142 UINTN Index; 143 BOOLEAN FoundFvMain; 144 BOOLEAN FoundCapsule; 145 static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID; 146 EFI_PEI_STALL_PPI *StallPpi; 147 148 (*PeiServices)->ReportStatusCode ( 149 PeiServices, 150 EFI_PROGRESS_CODE, 151 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_RECOVERY_BEGIN, 152 0, 153 NULL, 154 NULL 155 ); 156 157 Status = (**PeiServices).LocatePpi ( 158 PeiServices, 159 &gEfiPeiStallPpiGuid, 160 0, 161 NULL, 162 &StallPpi 163 ); 164 ASSERT_EFI_ERROR (Status); 165 166 StallPpi->Stall( 167 PeiServices, 168 StallPpi, 169 5000000 170 ); 171 172 173 Index = 0; 174 175 Status = EFI_SUCCESS; 176 HobUpdate = FALSE; 177 178 ProviderAvailable = TRUE; 179 ImageFound = FALSE; 180 NumberOfImageProviders = 0; 181 182 DeviceRecoveryModule = NULL; 183 184 FoundCapsule = FALSE; 185 FoundFvMain = FALSE; 186 187 DEBUG ((EFI_D_ERROR | EFI_D_LOAD, "Recovery Entry\n")); 188 189 // 190 // Search the platform for some recovery capsule if the DXE IPL 191 // discovered a recovery condition and has requested a load. 192 // 193 while (ProviderAvailable == TRUE) { 194 195 Status = (*PeiServices)->LocatePpi ( 196 PeiServices, 197 &gEfiPeiDeviceRecoveryModulePpiGuid, 198 Index, 199 NULL, 200 &DeviceRecoveryModule 201 ); 202 203 if (!EFI_ERROR (Status)) { 204 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n")); 205 NumberOfImageProviders++; 206 207 Status = DeviceRecoveryModule->GetNumberRecoveryCapsules ( 208 (EFI_PEI_SERVICES**)PeiServices, 209 DeviceRecoveryModule, 210 &NumberRecoveryCapsules 211 ); 212 213 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules)); 214 215 if (NumberRecoveryCapsules == 0) { 216 Index++; 217 } else { 218 break; 219 } 220 } else { 221 ProviderAvailable = FALSE; 222 } 223 } 224 225 // 226 // If there is an image provider, get the capsule ID 227 // 228 if (ProviderAvailable) { 229 RecoveryCapsuleSize = 0; 230 231 Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo ( 232 (EFI_PEI_SERVICES**)PeiServices, 233 DeviceRecoveryModule, 234 0, 235 &RecoveryCapsuleSize, 236 &DeviceId 237 ); 238 239 if (EFI_ERROR (Status)) { 240 return Status; 241 } 242 243 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize)); 244 245 // 246 // Only support the 2 capsule types known 247 // Future enhancement is to rank-order the selection 248 // 249 if ((!CompareGuid (&DeviceId, &gRecoveryOnFatIdeDiskGuid)) && 250 (!CompareGuid (&DeviceId, &gRecoveryOnFatFloppyDiskGuid)) && 251 (!CompareGuid (&DeviceId, &gRecoveryOnDataCdGuid)) && 252 (!CompareGuid (&DeviceId, &gRecoveryOnFatUsbDiskGuid)) 253 ) { 254 return EFI_UNSUPPORTED; 255 } 256 257 Buffer = NULL; 258 Status = (*PeiServices)->AllocatePages ( 259 PeiServices, 260 EfiBootServicesCode, 261 (RecoveryCapsuleSize - 1) / 0x1000 + 1, 262 &Address 263 ); 264 265 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "AllocatePage Returns: %r\n", Status)); 266 267 if (EFI_ERROR(Status)) { 268 return Status; 269 } 270 271 Buffer = (UINT8 *) (UINTN) Address; 272 273 (*PeiServices)->ReportStatusCode ( 274 PeiServices, 275 EFI_PROGRESS_CODE, 276 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD, 277 0, 278 NULL, 279 NULL 280 ); 281 282 Status = DeviceRecoveryModule->LoadRecoveryCapsule ( 283 (EFI_PEI_SERVICES**)PeiServices, 284 DeviceRecoveryModule, 285 0, 286 Buffer 287 ); 288 289 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status)); 290 291 if (EFI_ERROR (Status)) { 292 return Status; 293 } 294 295 // 296 // Update FV Hob if found 297 // 298 Status = (*PeiServices)->GetHobList (PeiServices, &Hob.Raw); 299 HobOld.Raw = Hob.Raw; 300 while (!END_OF_HOB_LIST (Hob)) { 301 if (Hob.Header->HobType == EFI_HOB_TYPE_FV) { 302 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob FV Length: %x\n", Hob.FirmwareVolume->Length)); 303 // 304 // BUGBUG Why is it a FV hob if it is greater than 0x50000? 305 // 306 if (Hob.FirmwareVolume->Length > 0x50000) { 307 HobUpdate = TRUE; 308 // 309 // This looks like the Hob we are interested in 310 // 311 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n")); 312 Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer; 313 Hob.FirmwareVolume->Length = RecoveryCapsuleSize; 314 } 315 } 316 Hob.Raw = GET_NEXT_HOB (Hob); 317 } 318 319 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer; 320 CapsuleHeader = (OLD_EFI_CAPSULE_HEADER *)Buffer; 321 322 // 323 // Check if top of file is a capsule 324 // 325 if (CompareGuid ((EFI_GUID *)CapsuleHeader, &mEfiCapsuleHeaderGuid)) { 326 FoundCapsule = TRUE; 327 } else if (FvHeader->Signature == EFI_FVH_SIGNATURE) { 328 // 329 // Assume the Firmware volume is a "FVMAIN" image 330 // 331 FoundFvMain = TRUE; 332 } 333 334 if (FoundFvMain) { 335 // 336 // build FV Hob if it is not built before 337 // 338 if (!HobUpdate) { 339 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n")); 340 341 BuildFvHob ( 342 (UINTN)FvHeader, 343 FvHeader->FvLength 344 ); 345 } 346 } 347 348 if (FoundCapsule) { 349 // 350 // Build capsule hob 351 // 352 Status = (*PeiServices)->CreateHob ( 353 PeiServices, 354 EFI_HOB_TYPE_CV, 355 sizeof (EFI_HOB_CAPSULE_VOLUME), 356 &CapsuleHob 357 ); 358 if (EFI_ERROR (Status)) { 359 return Status; 360 } 361 CapsuleHob->BaseAddress = (UINT64)((UINTN)CapsuleHeader + (UINTN)CapsuleHeader->OffsetToCapsuleBody); 362 CapsuleHob->Length = (UINT64)((UINTN)CapsuleHeader->CapsuleImageSize -(UINTN)CapsuleHeader->OffsetToCapsuleBody); 363 (*PeiServices)->ReportStatusCode ( 364 PeiServices, 365 EFI_PROGRESS_CODE, 366 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_START, 367 0, 368 NULL, 369 NULL 370 ); 371 } 372 } 373 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status)); 374 return Status; 375 } 376