1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 6 This program and the accompanying materials are licensed and made available under 7 8 the terms and conditions of the BSD License that accompanies this distribution. 9 10 The full text of the license may be found at 11 12 http://opensource.org/licenses/bsd-license.php. 13 14 15 16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 21 22 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. PeimInitializeRecovery(IN CONST EFI_PEI_SERVICES ** PeiServices)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. PlatformRecoveryModule(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_MODULE_PPI * This)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