1 /** @file 2 Esrt management implementation. 3 4 Copyright (c) 2015, 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 "EsrtImpl.h" 16 17 /** 18 Find Esrt Entry stored in ESRT repository. 19 20 @param[in] FwClass Firmware class guid in Esrt entry 21 @param[in] Attribute Esrt from Non FMP or FMP instance 22 @param[out] Entry Esrt entry returned 23 24 @retval EFI_SUCCESS Successfully find an Esrt entry 25 @retval EF_NOT_FOUND No Esrt entry found 26 27 **/ 28 EFI_STATUS 29 GetEsrtEntry ( 30 IN EFI_GUID *FwClass, 31 IN UINTN Attribute, 32 OUT EFI_SYSTEM_RESOURCE_ENTRY *Entry 33 ) 34 { 35 EFI_STATUS Status; 36 CHAR16 *VariableName; 37 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository; 38 UINTN RepositorySize; 39 UINTN Index; 40 UINTN EsrtNum; 41 42 EsrtRepository = NULL; 43 44 // 45 // Get Esrt index buffer 46 // 47 if (Attribute == ESRT_FROM_FMP) { 48 VariableName = EFI_ESRT_FMP_VARIABLE_NAME; 49 } else { 50 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME; 51 } 52 53 Status = GetVariable2 ( 54 VariableName, 55 &gEfiCallerIdGuid, 56 (VOID **) &EsrtRepository, 57 &RepositorySize 58 ); 59 60 if (EFI_ERROR(Status)) { 61 goto EXIT; 62 } 63 64 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) { 65 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n")); 66 Status = EFI_ABORTED; 67 goto EXIT; 68 } 69 70 Status = EFI_NOT_FOUND; 71 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY); 72 for (Index = 0; Index < EsrtNum; Index++) { 73 if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) { 74 CopyMem(Entry, &EsrtRepository[Index], sizeof(EFI_SYSTEM_RESOURCE_ENTRY)); 75 Status = EFI_SUCCESS; 76 break; 77 } 78 } 79 80 EXIT: 81 if (EsrtRepository != NULL) { 82 FreePool(EsrtRepository); 83 } 84 85 return Status; 86 } 87 88 /** 89 Insert a new ESRT entry into ESRT Cache repository. 90 91 @param[in] Entry Esrt entry to be set 92 @param[in] Attribute Esrt from Esrt private protocol or FMP instance 93 94 @retval EFI_SUCCESS Successfully set a variable. 95 96 **/ 97 EFI_STATUS 98 InsertEsrtEntry( 99 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry, 100 UINTN Attribute 101 ) 102 { 103 EFI_STATUS Status; 104 CHAR16 *VariableName; 105 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository; 106 UINTN RepositorySize; 107 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepositoryNew; 108 109 EsrtRepository = NULL; 110 EsrtRepositoryNew = NULL; 111 112 // 113 // Get Esrt index buffer 114 // 115 if (Attribute == ESRT_FROM_FMP) { 116 VariableName = EFI_ESRT_FMP_VARIABLE_NAME; 117 } else { 118 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME; 119 } 120 121 Status = GetVariable2 ( 122 VariableName, 123 &gEfiCallerIdGuid, 124 (VOID **) &EsrtRepository, 125 &RepositorySize 126 ); 127 128 if (Status == EFI_NOT_FOUND) { 129 // 130 // If not exist, create new Esrt cache repository 131 // 132 Status = gRT->SetVariable( 133 VariableName, 134 &gEfiCallerIdGuid, 135 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 136 sizeof(EFI_SYSTEM_RESOURCE_ENTRY), 137 Entry 138 ); 139 return Status; 140 141 } else if (Status == EFI_SUCCESS) { 142 // 143 // if exist, update Esrt cache repository 144 // 145 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) { 146 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n")); 147 // 148 // Repository is corrupt. Clear Repository before insert new entry 149 // 150 Status = gRT->SetVariable( 151 VariableName, 152 &gEfiCallerIdGuid, 153 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 154 0, 155 EsrtRepository 156 ); 157 FreePool(EsrtRepository); 158 RepositorySize = 0; 159 EsrtRepository = NULL; 160 } 161 162 // 163 // Check Repository size constraint 164 // 165 if ((Attribute == ESRT_FROM_FMP && RepositorySize >= PcdGet32(PcdMaxFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) 166 ||(Attribute == ESRT_FROM_NONFMP && RepositorySize >= PcdGet32(PcdMaxNonFmpEsrtCacheNum) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) ) { 167 Status = EFI_OUT_OF_RESOURCES; 168 goto EXIT; 169 } 170 171 EsrtRepositoryNew = AllocatePool(RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY)); 172 if (EsrtRepositoryNew == NULL) { 173 Status = EFI_OUT_OF_RESOURCES; 174 goto EXIT; 175 } 176 177 if (RepositorySize != 0 && EsrtRepository != NULL) { 178 CopyMem(EsrtRepositoryNew, EsrtRepository, RepositorySize); 179 } 180 CopyMem((UINT8 *)EsrtRepositoryNew + RepositorySize, Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY)); 181 182 Status = gRT->SetVariable( 183 VariableName, 184 &gEfiCallerIdGuid, 185 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 186 RepositorySize + sizeof(EFI_SYSTEM_RESOURCE_ENTRY), 187 EsrtRepositoryNew 188 ); 189 } 190 191 EXIT: 192 if (EsrtRepository != NULL) { 193 FreePool(EsrtRepository); 194 } 195 196 if (EsrtRepositoryNew != NULL) { 197 FreePool(EsrtRepositoryNew); 198 } 199 200 return Status; 201 } 202 203 /** 204 Delete ESRT Entry from ESRT repository. 205 206 @param[in] FwClass FwClass of Esrt entry to delete 207 @param[in] Attribute Esrt from Esrt private protocol or FMP instance 208 209 @retval EFI_SUCCESS Insert all entries Successfully 210 @retval EFI_NOT_FOUND ESRT entry with FwClass doesn't exsit 211 212 **/ 213 EFI_STATUS 214 DeleteEsrtEntry( 215 IN EFI_GUID *FwClass, 216 IN UINTN Attribute 217 ) 218 { 219 EFI_STATUS Status; 220 CHAR16 *VariableName; 221 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository; 222 UINTN RepositorySize; 223 UINTN Index; 224 UINTN EsrtNum; 225 226 EsrtRepository = NULL; 227 228 // 229 // Get Esrt index buffer 230 // 231 if (Attribute == ESRT_FROM_FMP) { 232 VariableName = EFI_ESRT_FMP_VARIABLE_NAME; 233 } else { 234 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME; 235 } 236 237 Status = GetVariable2 ( 238 VariableName, 239 &gEfiCallerIdGuid, 240 (VOID **) &EsrtRepository, 241 &RepositorySize 242 ); 243 244 if (EFI_ERROR(Status)) { 245 goto EXIT; 246 } 247 248 if ((RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY)) != 0) { 249 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n")); 250 // 251 // Repository is corrupt. Clear Repository before insert new entry 252 // 253 Status = gRT->SetVariable( 254 VariableName, 255 &gEfiCallerIdGuid, 256 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 257 0, 258 EsrtRepository 259 ); 260 goto EXIT; 261 } 262 263 Status = EFI_NOT_FOUND; 264 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY); 265 for (Index = 0; Index < EsrtNum; Index++) { 266 // 267 // Delete Esrt entry if it is found in repository 268 // 269 if (CompareGuid(FwClass, &EsrtRepository[Index].FwClass)) { 270 // 271 // If delete Esrt entry is not at the rail 272 // 273 if (Index < EsrtNum - 1) { 274 CopyMem(&EsrtRepository[Index], &EsrtRepository[Index + 1], (EsrtNum - Index - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY)); 275 } 276 277 // 278 // Update New Repository 279 // 280 Status = gRT->SetVariable( 281 VariableName, 282 &gEfiCallerIdGuid, 283 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 284 (EsrtNum - 1) * sizeof(EFI_SYSTEM_RESOURCE_ENTRY), 285 EsrtRepository 286 ); 287 break; 288 } 289 } 290 291 EXIT: 292 if (EsrtRepository != NULL) { 293 FreePool(EsrtRepository); 294 } 295 296 return Status; 297 298 } 299 300 /** 301 Update one ESRT entry in ESRT repository 302 303 @param[in] Entry Esrt entry to be set 304 @param[in] Attribute Esrt from Non Esrt or FMP instance 305 306 @retval EFI_SUCCESS Successfully Update a variable. 307 @retval EFI_NOT_FOUND The Esrt enry doesn't exist 308 309 **/ 310 EFI_STATUS 311 UpdateEsrtEntry( 312 IN EFI_SYSTEM_RESOURCE_ENTRY *Entry, 313 UINTN Attribute 314 ) 315 { 316 EFI_STATUS Status; 317 CHAR16 *VariableName; 318 EFI_SYSTEM_RESOURCE_ENTRY *EsrtRepository; 319 UINTN RepositorySize; 320 UINTN Index; 321 UINTN EsrtNum; 322 323 EsrtRepository = NULL; 324 325 // 326 // Get Esrt index buffer 327 // 328 if (Attribute == ESRT_FROM_FMP) { 329 VariableName = EFI_ESRT_FMP_VARIABLE_NAME; 330 } else { 331 VariableName = EFI_ESRT_NONFMP_VARIABLE_NAME; 332 } 333 334 Status = GetVariable2 ( 335 VariableName, 336 &gEfiCallerIdGuid, 337 (VOID **) &EsrtRepository, 338 &RepositorySize 339 ); 340 341 if (!EFI_ERROR(Status)) { 342 // 343 // if exist, update Esrt cache repository 344 // 345 if (RepositorySize % sizeof(EFI_SYSTEM_RESOURCE_ENTRY) != 0) { 346 DEBUG((EFI_D_ERROR, "Repository Corrupt. Need to rebuild Repository.\n")); 347 // 348 // Repository is corrupt. Clear Repository before insert new entry 349 // 350 Status = gRT->SetVariable( 351 VariableName, 352 &gEfiCallerIdGuid, 353 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 354 0, 355 EsrtRepository 356 ); 357 Status = EFI_NOT_FOUND; 358 goto EXIT; 359 } 360 361 Status = EFI_NOT_FOUND; 362 EsrtNum = RepositorySize/sizeof(EFI_SYSTEM_RESOURCE_ENTRY); 363 for (Index = 0; Index < EsrtNum; Index++) { 364 // 365 // Update Esrt entry if it is found in repository 366 // 367 if (CompareGuid(&Entry->FwClass, &EsrtRepository[Index].FwClass)) { 368 369 CopyMem(&EsrtRepository[Index], Entry, sizeof(EFI_SYSTEM_RESOURCE_ENTRY)); 370 // 371 // Update New Repository 372 // 373 Status = gRT->SetVariable( 374 VariableName, 375 &gEfiCallerIdGuid, 376 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 377 RepositorySize, 378 EsrtRepository 379 ); 380 break; 381 } 382 } 383 } 384 385 EXIT: 386 if (EsrtRepository != NULL) { 387 FreePool(EsrtRepository); 388 } 389 390 return Status; 391 } 392 393 /** 394 Init one ESRT entry according to input FmpImageInfo (V1, V2, V3) . 395 396 @param[in, out] EsrtEntry Esrt entry to be Init 397 @param[in] FmpImageInfo FMP image info descriptor 398 @param[in] DescriptorVersion FMP Image info descriptor version 399 400 **/ 401 VOID 402 SetEsrtEntryFromFmpInfo ( 403 IN OUT EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry, 404 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo, 405 IN UINT32 DescriptorVersion 406 ) 407 { 408 EsrtEntry->FwVersion = FmpImageInfo->Version; 409 EsrtEntry->FwClass = FmpImageInfo->ImageTypeId; 410 EsrtEntry->FwType = ESRT_FW_TYPE_DEVICEFIRMWARE; 411 EsrtEntry->LowestSupportedFwVersion = 0; 412 EsrtEntry->CapsuleFlags = 0; 413 EsrtEntry->LastAttemptVersion = 0; 414 EsrtEntry->LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; 415 416 if (DescriptorVersion >= 2) { 417 // 418 // LowestSupportedImageVersion only available in FMP V2 or higher 419 // 420 EsrtEntry->LowestSupportedFwVersion = FmpImageInfo->LowestSupportedImageVersion; 421 } 422 423 if (DescriptorVersion >= 3) { 424 // 425 // LastAttemptVersion & LastAttemptStatus only available in FMP V3 or higher 426 // 427 EsrtEntry->LastAttemptVersion = FmpImageInfo->LastAttemptVersion; 428 EsrtEntry->LastAttemptStatus = FmpImageInfo->LastAttemptStatus; 429 } 430 431 // 432 // Set capsule customized flag 433 // 434 if ((FmpImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0 435 && (FmpImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) { 436 EsrtEntry->CapsuleFlags = PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag); 437 } 438 } 439