Home | History | Annotate | Download | only in VarCheckLib
      1 /** @file
      2   Implementation functions and structures for var check services.
      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 <Library/VarCheckLib.h>
     16 #include <Library/BaseLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/DebugLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 
     21 #include <Guid/GlobalVariable.h>
     22 #include <Guid/HardwareErrorVariable.h>
     23 
     24 BOOLEAN mVarCheckLibEndOfDxe    = FALSE;
     25 
     26 #define VAR_CHECK_TABLE_SIZE    0x8
     27 
     28 UINTN                                   mVarCheckLibEndOfDxeCallbackCount = 0;
     29 UINTN                                   mVarCheckLibEndOfDxeCallbackMaxCount = 0;
     30 VAR_CHECK_END_OF_DXE_CALLBACK           *mVarCheckLibEndOfDxeCallback = NULL;
     31 
     32 UINTN                                   mVarCheckLibAddressPointerCount = 0;
     33 UINTN                                   mVarCheckLibAddressPointerMaxCount = 0;
     34 VOID                                    ***mVarCheckLibAddressPointer = NULL;
     35 
     36 UINTN                                   mNumberOfVarCheckHandler = 0;
     37 UINTN                                   mMaxNumberOfVarCheckHandler = 0;
     38 VAR_CHECK_SET_VARIABLE_CHECK_HANDLER    *mVarCheckHandlerTable = NULL;
     39 
     40 typedef struct {
     41   EFI_GUID                      Guid;
     42   VAR_CHECK_VARIABLE_PROPERTY   VariableProperty;
     43   //CHAR16                        *Name;
     44 } VAR_CHECK_VARIABLE_ENTRY;
     45 
     46 UINTN                                   mNumberOfVarCheckVariable = 0;
     47 UINTN                                   mMaxNumberOfVarCheckVariable = 0;
     48 VARIABLE_ENTRY_PROPERTY                 **mVarCheckVariableTable = NULL;
     49 
     50 //
     51 // Handle variables with wildcard name specially.
     52 //
     53 VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = {
     54   {
     55     &gEfiGlobalVariableGuid,
     56     L"Boot####",
     57     {
     58       0
     59     },
     60   },
     61   {
     62     &gEfiGlobalVariableGuid,
     63     L"Driver####",
     64     {
     65       0
     66     },
     67   },
     68   {
     69     &gEfiGlobalVariableGuid,
     70     L"SysPrep####",
     71     {
     72       0
     73     },
     74   },
     75   {
     76     &gEfiGlobalVariableGuid,
     77     L"Key####",
     78     {
     79       0
     80     },
     81   },
     82   {
     83     &gEfiGlobalVariableGuid,
     84     L"PlatformRecovery####",
     85     {
     86       0
     87     },
     88   },
     89   {
     90     &gEfiHardwareErrorVariableGuid,
     91     L"HwErrRec####",
     92     {
     93       0
     94     },
     95   },
     96 };
     97 
     98 /**
     99   Check if a Unicode character is a hexadecimal character.
    100 
    101   This function checks if a Unicode character is a
    102   hexadecimal character.  The valid hexadecimal character is
    103   L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
    104 
    105 
    106   @param[in] Char       The character to check against.
    107 
    108   @retval TRUE          If the Char is a hexadecmial character.
    109   @retval FALSE         If the Char is not a hexadecmial character.
    110 
    111 **/
    112 BOOLEAN
    113 EFIAPI
    114 VarCheckInternalIsHexaDecimalDigitCharacter (
    115   IN CHAR16             Char
    116   )
    117 {
    118   return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
    119 }
    120 
    121 /**
    122   Variable property get with wildcard name.
    123 
    124   @param[in] VariableName       Pointer to variable name.
    125   @param[in] VendorGuid         Pointer to variable vendor GUID.
    126   @param[in] WildcardMatch      Try wildcard match or not.
    127 
    128   @return Pointer to variable property.
    129 
    130 **/
    131 VAR_CHECK_VARIABLE_PROPERTY *
    132 VariablePropertyGetWithWildcardName (
    133   IN CHAR16                         *VariableName,
    134   IN EFI_GUID                       *VendorGuid,
    135   IN BOOLEAN                        WildcardMatch
    136   )
    137 {
    138   UINTN     Index;
    139   UINTN     NameLength;
    140 
    141   NameLength = StrLen (VariableName) - 4;
    142   for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) {
    143     if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)){
    144       if (WildcardMatch) {
    145         if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) &&
    146             (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) &&
    147             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
    148             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
    149             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
    150             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
    151           return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
    152         }
    153       }
    154       if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) {
    155         return  &mVarCheckVariableWithWildcardName[Index].VariableProperty;
    156       }
    157     }
    158   }
    159 
    160   return NULL;
    161 }
    162 
    163 /**
    164   Variable property get function.
    165 
    166   @param[in] Name           Pointer to the variable name.
    167   @param[in] Guid           Pointer to the vendor GUID.
    168   @param[in] WildcardMatch  Try wildcard match or not.
    169 
    170   @return Pointer to the property of variable specified by the Name and Guid.
    171 
    172 **/
    173 VAR_CHECK_VARIABLE_PROPERTY *
    174 VariablePropertyGetFunction (
    175   IN CHAR16                 *Name,
    176   IN EFI_GUID               *Guid,
    177   IN BOOLEAN                WildcardMatch
    178   )
    179 {
    180   UINTN                     Index;
    181   VAR_CHECK_VARIABLE_ENTRY  *Entry;
    182   CHAR16                    *VariableName;
    183 
    184   for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
    185     Entry = (VAR_CHECK_VARIABLE_ENTRY *) mVarCheckVariableTable[Index];
    186     VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
    187     if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) {
    188       return &Entry->VariableProperty;
    189     }
    190   }
    191 
    192   return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch);
    193 }
    194 
    195 /**
    196   Var check add table entry.
    197 
    198   @param[in, out] Table         Pointer to table buffer.
    199   @param[in, out] MaxNumber     Pointer to maximum number of entry in the table.
    200   @param[in, out] CurrentNumber Pointer to current number of entry in the table.
    201   @param[in]      Entry         Entry will be added to the table.
    202 
    203   @retval EFI_SUCCESS           Reallocate memory successfully.
    204   @retval EFI_OUT_OF_RESOURCES  No enough memory to allocate.
    205 
    206 **/
    207 EFI_STATUS
    208 VarCheckAddTableEntry (
    209   IN OUT UINTN      **Table,
    210   IN OUT UINTN      *MaxNumber,
    211   IN OUT UINTN      *CurrentNumber,
    212   IN UINTN          Entry
    213   )
    214 {
    215   UINTN     *TempTable;
    216 
    217   //
    218   // Check whether the table is enough to store new entry.
    219   //
    220   if (*CurrentNumber == *MaxNumber) {
    221     //
    222     // Reallocate memory for the table.
    223     //
    224     TempTable = ReallocateRuntimePool (
    225                   *MaxNumber * sizeof (UINTN),
    226                   (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN),
    227                   *Table
    228                   );
    229 
    230     //
    231     // No enough resource to allocate.
    232     //
    233     if (TempTable == NULL) {
    234       return EFI_OUT_OF_RESOURCES;
    235     }
    236 
    237     *Table = TempTable;
    238     //
    239     // Increase max number.
    240     //
    241     *MaxNumber += VAR_CHECK_TABLE_SIZE;
    242   }
    243 
    244   //
    245   // Add entry to the table.
    246   //
    247   (*Table)[*CurrentNumber] = Entry;
    248   (*CurrentNumber)++;
    249 
    250   return EFI_SUCCESS;
    251 }
    252 
    253 /**
    254   Register END_OF_DXE callback.
    255   The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
    256 
    257   @param[in] Callback           END_OF_DXE callback.
    258 
    259   @retval EFI_SUCCESS           The callback was registered successfully.
    260   @retval EFI_INVALID_PARAMETER Callback is NULL.
    261   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    262                                 already been signaled.
    263   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the callback register request.
    264 
    265 **/
    266 EFI_STATUS
    267 EFIAPI
    268 VarCheckLibRegisterEndOfDxeCallback (
    269   IN VAR_CHECK_END_OF_DXE_CALLBACK  Callback
    270   )
    271 {
    272   EFI_STATUS    Status;
    273 
    274   if (Callback == NULL) {
    275     return EFI_INVALID_PARAMETER;
    276   }
    277 
    278   if (mVarCheckLibEndOfDxe) {
    279     return EFI_ACCESS_DENIED;
    280   }
    281 
    282   Status = VarCheckAddTableEntry (
    283            (UINTN **) &mVarCheckLibEndOfDxeCallback,
    284            &mVarCheckLibEndOfDxeCallbackMaxCount,
    285            &mVarCheckLibEndOfDxeCallbackCount,
    286            (UINTN) Callback
    287            );
    288 
    289   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status));
    290 
    291   return Status;
    292 }
    293 
    294 /**
    295   Var check initialize at END_OF_DXE.
    296 
    297   This function needs to be called at END_OF_DXE.
    298   Address pointers may be returned,
    299   and caller needs to ConvertPointer() for the pointers.
    300 
    301   @param[in, out] AddressPointerCount   Output pointer to address pointer count.
    302 
    303   @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
    304 
    305 **/
    306 VOID ***
    307 EFIAPI
    308 VarCheckLibInitializeAtEndOfDxe (
    309   IN OUT UINTN                  *AddressPointerCount OPTIONAL
    310   )
    311 {
    312   VOID                          *TempTable;
    313   UINTN                         TotalCount;
    314   UINTN                         Index;
    315 
    316   for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) {
    317     //
    318     // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
    319     //
    320     mVarCheckLibEndOfDxeCallback[Index] ();
    321   }
    322   if (mVarCheckLibEndOfDxeCallback != NULL) {
    323     //
    324     // Free the callback buffer.
    325     //
    326     mVarCheckLibEndOfDxeCallbackCount = 0;
    327     mVarCheckLibEndOfDxeCallbackMaxCount = 0;
    328     FreePool ((VOID *) mVarCheckLibEndOfDxeCallback);
    329     mVarCheckLibEndOfDxeCallback = NULL;
    330   }
    331 
    332   mVarCheckLibEndOfDxe = TRUE;
    333 
    334   if (AddressPointerCount == NULL) {
    335     if (mVarCheckLibAddressPointer != NULL) {
    336       //
    337       // Free the address pointer buffer.
    338       //
    339       mVarCheckLibAddressPointerCount = 0;
    340       mVarCheckLibAddressPointerMaxCount = 0;
    341       FreePool ((VOID *) mVarCheckLibAddressPointer);
    342       mVarCheckLibAddressPointer = NULL;
    343     }
    344     return NULL;
    345   }
    346 
    347   //
    348   // Get the total count needed.
    349   // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
    350   //
    351   TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1);
    352   TempTable = ReallocateRuntimePool (
    353                 mVarCheckLibAddressPointerMaxCount * sizeof (VOID **),
    354                 TotalCount * sizeof (VOID **),
    355                 (VOID *) mVarCheckLibAddressPointer
    356                 );
    357 
    358   if (TempTable != NULL) {
    359     mVarCheckLibAddressPointer = (VOID ***) TempTable;
    360 
    361     //
    362     // Cover VarCheckHandler and the entries.
    363     //
    364     mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable;
    365     for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
    366       mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable[Index];
    367     }
    368 
    369     //
    370     // Cover VarCheckVariable and the entries.
    371     //
    372     mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable;
    373     for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
    374       mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable[Index];
    375     }
    376 
    377     ASSERT (mVarCheckLibAddressPointerCount == TotalCount);
    378     mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount;
    379   }
    380 
    381   *AddressPointerCount = mVarCheckLibAddressPointerCount;
    382   return mVarCheckLibAddressPointer;
    383 }
    384 
    385 /**
    386   Register address pointer.
    387   The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
    388 
    389   @param[in] AddressPointer     Address pointer.
    390 
    391   @retval EFI_SUCCESS           The address pointer was registered successfully.
    392   @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
    393   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    394                                 already been signaled.
    395   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the address pointer register request.
    396 
    397 **/
    398 EFI_STATUS
    399 EFIAPI
    400 VarCheckLibRegisterAddressPointer (
    401   IN VOID                       **AddressPointer
    402   )
    403 {
    404   EFI_STATUS    Status;
    405 
    406   if (AddressPointer == NULL) {
    407     return EFI_INVALID_PARAMETER;
    408   }
    409 
    410   if (mVarCheckLibEndOfDxe) {
    411     return EFI_ACCESS_DENIED;
    412   }
    413 
    414   Status = VarCheckAddTableEntry(
    415            (UINTN **) &mVarCheckLibAddressPointer,
    416            &mVarCheckLibAddressPointerMaxCount,
    417            &mVarCheckLibAddressPointerCount,
    418            (UINTN) AddressPointer
    419            );
    420 
    421   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status));
    422 
    423   return Status;
    424 }
    425 
    426 /**
    427   Register SetVariable check handler.
    428 
    429   @param[in] Handler            Pointer to check handler.
    430 
    431   @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
    432   @retval EFI_INVALID_PARAMETER Handler is NULL.
    433   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    434                                 already been signaled.
    435   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
    436   @retval EFI_UNSUPPORTED       This interface is not implemented.
    437                                 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
    438 
    439 **/
    440 EFI_STATUS
    441 EFIAPI
    442 VarCheckLibRegisterSetVariableCheckHandler (
    443   IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler
    444   )
    445 {
    446   EFI_STATUS    Status;
    447 
    448   if (Handler == NULL) {
    449     return EFI_INVALID_PARAMETER;
    450   }
    451 
    452   if (mVarCheckLibEndOfDxe) {
    453     return EFI_ACCESS_DENIED;
    454   }
    455 
    456   Status =  VarCheckAddTableEntry(
    457              (UINTN **) &mVarCheckHandlerTable,
    458              &mMaxNumberOfVarCheckHandler,
    459              &mNumberOfVarCheckHandler,
    460              (UINTN) Handler
    461              );
    462 
    463   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status));
    464 
    465   return Status;
    466 }
    467 
    468 /**
    469   Variable property set.
    470 
    471   @param[in] Name               Pointer to the variable name.
    472   @param[in] Guid               Pointer to the vendor GUID.
    473   @param[in] VariableProperty   Pointer to the input variable property.
    474 
    475   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
    476   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
    477                                 or the fields of VariableProperty are not valid.
    478   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    479                                 already been signaled.
    480   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
    481 
    482 **/
    483 EFI_STATUS
    484 EFIAPI
    485 VarCheckLibVariablePropertySet (
    486   IN CHAR16                         *Name,
    487   IN EFI_GUID                       *Guid,
    488   IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty
    489   )
    490 {
    491   EFI_STATUS                    Status;
    492   VAR_CHECK_VARIABLE_ENTRY      *Entry;
    493   CHAR16                        *VariableName;
    494   VAR_CHECK_VARIABLE_PROPERTY   *Property;
    495 
    496   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
    497     return EFI_INVALID_PARAMETER;
    498   }
    499 
    500   if (VariableProperty == NULL) {
    501     return EFI_INVALID_PARAMETER;
    502   }
    503 
    504   if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
    505     return EFI_INVALID_PARAMETER;
    506   }
    507 
    508   if (mVarCheckLibEndOfDxe) {
    509     return EFI_ACCESS_DENIED;
    510   }
    511 
    512   Status = EFI_SUCCESS;
    513 
    514   //
    515   // Get the pointer of property data for set.
    516   //
    517   Property = VariablePropertyGetFunction (Name, Guid, FALSE);
    518   if (Property != NULL) {
    519     CopyMem (Property, VariableProperty, sizeof (*VariableProperty));
    520   } else {
    521     Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name));
    522     if (Entry == NULL) {
    523       return EFI_OUT_OF_RESOURCES;
    524     }
    525     VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
    526     StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name);
    527     CopyGuid (&Entry->Guid, Guid);
    528     CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty));
    529 
    530     Status = VarCheckAddTableEntry(
    531                (UINTN **) &mVarCheckVariableTable,
    532                &mMaxNumberOfVarCheckVariable,
    533                &mNumberOfVarCheckVariable,
    534                (UINTN) Entry
    535                );
    536 
    537     if (EFI_ERROR (Status)) {
    538       FreePool (Entry);
    539     }
    540   }
    541 
    542   return Status;
    543 }
    544 
    545 /**
    546   Variable property get.
    547 
    548   @param[in]  Name              Pointer to the variable name.
    549   @param[in]  Guid              Pointer to the vendor GUID.
    550   @param[out] VariableProperty  Pointer to the output variable property.
    551 
    552   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
    553   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
    554   @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
    555 
    556 **/
    557 EFI_STATUS
    558 EFIAPI
    559 VarCheckLibVariablePropertyGet (
    560   IN CHAR16                         *Name,
    561   IN EFI_GUID                       *Guid,
    562   OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty
    563   )
    564 {
    565   VAR_CHECK_VARIABLE_PROPERTY   *Property;
    566 
    567   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
    568     return EFI_INVALID_PARAMETER;
    569   }
    570 
    571   if (VariableProperty == NULL) {
    572     return EFI_INVALID_PARAMETER;
    573   }
    574 
    575   Property = VariablePropertyGetFunction (Name, Guid, TRUE);
    576   //
    577   // Also check the property revision before using the property data.
    578   // There is no property set to this variable(wildcard name)
    579   // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
    580   //
    581   if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
    582     CopyMem (VariableProperty, Property, sizeof (*VariableProperty));
    583     return EFI_SUCCESS;
    584   }
    585 
    586   return EFI_NOT_FOUND;
    587 }
    588 
    589 /**
    590   SetVariable check.
    591 
    592   @param[in] VariableName       Name of Variable to set.
    593   @param[in] VendorGuid         Variable vendor GUID.
    594   @param[in] Attributes         Attribute value of the variable.
    595   @param[in] DataSize           Size of Data to set.
    596   @param[in] Data               Data pointer.
    597   @param[in] RequestSource      Request source.
    598 
    599   @retval EFI_SUCCESS           The SetVariable check result was success.
    600   @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
    601                                 DataSize and Data value was supplied.
    602   @retval EFI_WRITE_PROTECTED   The variable in question is read-only.
    603   @retval Others                The other return status from check handler.
    604 
    605 **/
    606 EFI_STATUS
    607 EFIAPI
    608 VarCheckLibSetVariableCheck (
    609   IN CHAR16                     *VariableName,
    610   IN EFI_GUID                   *VendorGuid,
    611   IN UINT32                     Attributes,
    612   IN UINTN                      DataSize,
    613   IN VOID                       *Data,
    614   IN VAR_CHECK_REQUEST_SOURCE   RequestSource
    615   )
    616 {
    617   EFI_STATUS                    Status;
    618   UINTN                         Index;
    619   VAR_CHECK_VARIABLE_PROPERTY   *Property;
    620 
    621   if (!mVarCheckLibEndOfDxe) {
    622     //
    623     // Only do check after End Of Dxe.
    624     //
    625     return EFI_SUCCESS;
    626   }
    627 
    628   Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE);
    629   //
    630   // Also check the property revision before using the property data.
    631   // There is no property set to this variable(wildcard name)
    632   // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
    633   //
    634   if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
    635     if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) {
    636       DEBUG ((EFI_D_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName));
    637       return EFI_WRITE_PROTECTED;
    638     }
    639     if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) {
    640       //
    641       // Not to delete variable.
    642       //
    643       if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) {
    644         DEBUG ((EFI_D_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
    645         return EFI_INVALID_PARAMETER;
    646       }
    647       if (DataSize != 0) {
    648         if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) {
    649           DEBUG ((EFI_D_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
    650           return EFI_INVALID_PARAMETER;
    651         }
    652       }
    653     }
    654   }
    655 
    656   for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
    657     Status = mVarCheckHandlerTable[Index] (
    658                VariableName,
    659                VendorGuid,
    660                Attributes,
    661                DataSize,
    662                Data
    663                );
    664     if (EFI_ERROR (Status)) {
    665       DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName));
    666       return Status;
    667     }
    668   }
    669   return EFI_SUCCESS;
    670 }
    671