Home | History | Annotate | Download | only in EsrtDxe
      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