1/** @file
2  Implementation functions and structures for var check services.
3
4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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
24BOOLEAN mVarCheckLibEndOfDxe    = FALSE;
25
26#define VAR_CHECK_TABLE_SIZE    0x8
27
28UINTN                                   mVarCheckLibEndOfDxeCallbackCount = 0;
29UINTN                                   mVarCheckLibEndOfDxeCallbackMaxCount = 0;
30VAR_CHECK_END_OF_DXE_CALLBACK           *mVarCheckLibEndOfDxeCallback = NULL;
31
32UINTN                                   mVarCheckLibAddressPointerCount = 0;
33UINTN                                   mVarCheckLibAddressPointerMaxCount = 0;
34VOID                                    ***mVarCheckLibAddressPointer = NULL;
35
36UINTN                                   mNumberOfVarCheckHandler = 0;
37UINTN                                   mMaxNumberOfVarCheckHandler = 0;
38VAR_CHECK_SET_VARIABLE_CHECK_HANDLER    *mVarCheckHandlerTable = NULL;
39
40typedef struct {
41  EFI_GUID                      Guid;
42  VAR_CHECK_VARIABLE_PROPERTY   VariableProperty;
43  //CHAR16                        *Name;
44} VAR_CHECK_VARIABLE_ENTRY;
45
46UINTN                                   mNumberOfVarCheckVariable = 0;
47UINTN                                   mMaxNumberOfVarCheckVariable = 0;
48VARIABLE_ENTRY_PROPERTY                 **mVarCheckVariableTable = NULL;
49
50//
51// Handle variables with wildcard name specially.
52//
53VARIABLE_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**/
112BOOLEAN
113EFIAPI
114VarCheckInternalIsHexaDecimalDigitCharacter (
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**/
131VAR_CHECK_VARIABLE_PROPERTY *
132VariablePropertyGetWithWildcardName (
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**/
173VAR_CHECK_VARIABLE_PROPERTY *
174VariablePropertyGetFunction (
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**/
207EFI_STATUS
208VarCheckAddTableEntry (
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**/
266EFI_STATUS
267EFIAPI
268VarCheckLibRegisterEndOfDxeCallback (
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**/
306VOID ***
307EFIAPI
308VarCheckLibInitializeAtEndOfDxe (
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**/
398EFI_STATUS
399EFIAPI
400VarCheckLibRegisterAddressPointer (
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**/
440EFI_STATUS
441EFIAPI
442VarCheckLibRegisterSetVariableCheckHandler (
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**/
483EFI_STATUS
484EFIAPI
485VarCheckLibVariablePropertySet (
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**/
557EFI_STATUS
558EFIAPI
559VarCheckLibVariablePropertyGet (
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**/
606EFI_STATUS
607EFIAPI
608VarCheckLibSetVariableCheck (
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