2 Implementation functions and structures for var check services.
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/VarCheckLib.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemoryAllocationLib.h>
15 #include <Guid/GlobalVariable.h>
16 #include <Guid/HardwareErrorVariable.h>
18 BOOLEAN mVarCheckLibEndOfDxe
= FALSE
;
20 #define VAR_CHECK_TABLE_SIZE 0x8
22 UINTN mVarCheckLibEndOfDxeCallbackCount
= 0;
23 UINTN mVarCheckLibEndOfDxeCallbackMaxCount
= 0;
24 VAR_CHECK_END_OF_DXE_CALLBACK
*mVarCheckLibEndOfDxeCallback
= NULL
;
26 UINTN mVarCheckLibAddressPointerCount
= 0;
27 UINTN mVarCheckLibAddressPointerMaxCount
= 0;
28 VOID
***mVarCheckLibAddressPointer
= NULL
;
30 UINTN mNumberOfVarCheckHandler
= 0;
31 UINTN mMaxNumberOfVarCheckHandler
= 0;
32 VAR_CHECK_SET_VARIABLE_CHECK_HANDLER
*mVarCheckHandlerTable
= NULL
;
36 VAR_CHECK_VARIABLE_PROPERTY VariableProperty
;
38 } VAR_CHECK_VARIABLE_ENTRY
;
40 UINTN mNumberOfVarCheckVariable
= 0;
41 UINTN mMaxNumberOfVarCheckVariable
= 0;
42 VARIABLE_ENTRY_PROPERTY
**mVarCheckVariableTable
= NULL
;
45 // Handle variables with wildcard name specially.
47 VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName
[] = {
49 &gEfiGlobalVariableGuid
,
56 &gEfiGlobalVariableGuid
,
63 &gEfiGlobalVariableGuid
,
70 &gEfiGlobalVariableGuid
,
77 &gEfiGlobalVariableGuid
,
78 L
"PlatformRecovery####",
84 &gEfiHardwareErrorVariableGuid
,
93 Check if a Unicode character is an upper case hexadecimal character.
95 This function checks if a Unicode character is an upper case
96 hexadecimal character. The valid upper case hexadecimal character is
97 L'0' to L'9', or L'A' to L'F'.
100 @param[in] Char The character to check against.
102 @retval TRUE If the Char is an upper case hexadecmial character.
103 @retval FALSE If the Char is not an upper case hexadecmial character.
108 VarCheckInternalIsHexaDecimalDigitCharacter (
112 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F'));
116 Variable property get with wildcard name.
118 @param[in] VariableName Pointer to variable name.
119 @param[in] VendorGuid Pointer to variable vendor GUID.
120 @param[in] WildcardMatch Try wildcard match or not.
122 @return Pointer to variable property.
125 VAR_CHECK_VARIABLE_PROPERTY
*
126 VariablePropertyGetWithWildcardName (
127 IN CHAR16
*VariableName
,
128 IN EFI_GUID
*VendorGuid
,
129 IN BOOLEAN WildcardMatch
135 NameLength
= StrLen (VariableName
) - 4;
136 for (Index
= 0; Index
< sizeof (mVarCheckVariableWithWildcardName
)/sizeof (mVarCheckVariableWithWildcardName
[0]); Index
++) {
137 if (CompareGuid (mVarCheckVariableWithWildcardName
[Index
].Guid
, VendorGuid
)){
139 if ((StrLen (VariableName
) == StrLen (mVarCheckVariableWithWildcardName
[Index
].Name
)) &&
140 (StrnCmp (VariableName
, mVarCheckVariableWithWildcardName
[Index
].Name
, NameLength
) == 0) &&
141 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
]) &&
142 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 1]) &&
143 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 2]) &&
144 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 3])) {
145 return &mVarCheckVariableWithWildcardName
[Index
].VariableProperty
;
148 if (StrCmp (mVarCheckVariableWithWildcardName
[Index
].Name
, VariableName
) == 0) {
149 return &mVarCheckVariableWithWildcardName
[Index
].VariableProperty
;
158 Variable property get function.
160 @param[in] Name Pointer to the variable name.
161 @param[in] Guid Pointer to the vendor GUID.
162 @param[in] WildcardMatch Try wildcard match or not.
164 @return Pointer to the property of variable specified by the Name and Guid.
167 VAR_CHECK_VARIABLE_PROPERTY
*
168 VariablePropertyGetFunction (
171 IN BOOLEAN WildcardMatch
175 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
176 CHAR16
*VariableName
;
178 for (Index
= 0; Index
< mNumberOfVarCheckVariable
; Index
++) {
179 Entry
= (VAR_CHECK_VARIABLE_ENTRY
*) mVarCheckVariableTable
[Index
];
180 VariableName
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
181 if (CompareGuid (&Entry
->Guid
, Guid
) && (StrCmp (VariableName
, Name
) == 0)) {
182 return &Entry
->VariableProperty
;
186 return VariablePropertyGetWithWildcardName (Name
, Guid
, WildcardMatch
);
190 Var check add table entry.
192 @param[in, out] Table Pointer to table buffer.
193 @param[in, out] MaxNumber Pointer to maximum number of entry in the table.
194 @param[in, out] CurrentNumber Pointer to current number of entry in the table.
195 @param[in] Entry Entry will be added to the table.
197 @retval EFI_SUCCESS Reallocate memory successfully.
198 @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
202 VarCheckAddTableEntry (
203 IN OUT UINTN
**Table
,
204 IN OUT UINTN
*MaxNumber
,
205 IN OUT UINTN
*CurrentNumber
,
212 // Check whether the table is enough to store new entry.
214 if (*CurrentNumber
== *MaxNumber
) {
216 // Reallocate memory for the table.
218 TempTable
= ReallocateRuntimePool (
219 *MaxNumber
* sizeof (UINTN
),
220 (*MaxNumber
+ VAR_CHECK_TABLE_SIZE
) * sizeof (UINTN
),
225 // No enough resource to allocate.
227 if (TempTable
== NULL
) {
228 return EFI_OUT_OF_RESOURCES
;
233 // Increase max number.
235 *MaxNumber
+= VAR_CHECK_TABLE_SIZE
;
239 // Add entry to the table.
241 (*Table
)[*CurrentNumber
] = Entry
;
248 Register END_OF_DXE callback.
249 The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
251 @param[in] Callback END_OF_DXE callback.
253 @retval EFI_SUCCESS The callback was registered successfully.
254 @retval EFI_INVALID_PARAMETER Callback is NULL.
255 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
256 already been signaled.
257 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request.
262 VarCheckLibRegisterEndOfDxeCallback (
263 IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
268 if (Callback
== NULL
) {
269 return EFI_INVALID_PARAMETER
;
272 if (mVarCheckLibEndOfDxe
) {
273 return EFI_ACCESS_DENIED
;
276 Status
= VarCheckAddTableEntry (
277 (UINTN
**) &mVarCheckLibEndOfDxeCallback
,
278 &mVarCheckLibEndOfDxeCallbackMaxCount
,
279 &mVarCheckLibEndOfDxeCallbackCount
,
283 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback
, Status
));
289 Var check initialize at END_OF_DXE.
291 This function needs to be called at END_OF_DXE.
292 Address pointers may be returned,
293 and caller needs to ConvertPointer() for the pointers.
295 @param[in, out] AddressPointerCount Output pointer to address pointer count.
297 @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
302 VarCheckLibInitializeAtEndOfDxe (
303 IN OUT UINTN
*AddressPointerCount OPTIONAL
310 for (Index
= 0; Index
< mVarCheckLibEndOfDxeCallbackCount
; Index
++) {
312 // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
314 mVarCheckLibEndOfDxeCallback
[Index
] ();
316 if (mVarCheckLibEndOfDxeCallback
!= NULL
) {
318 // Free the callback buffer.
320 mVarCheckLibEndOfDxeCallbackCount
= 0;
321 mVarCheckLibEndOfDxeCallbackMaxCount
= 0;
322 FreePool ((VOID
*) mVarCheckLibEndOfDxeCallback
);
323 mVarCheckLibEndOfDxeCallback
= NULL
;
326 mVarCheckLibEndOfDxe
= TRUE
;
328 if (AddressPointerCount
== NULL
) {
329 if (mVarCheckLibAddressPointer
!= NULL
) {
331 // Free the address pointer buffer.
333 mVarCheckLibAddressPointerCount
= 0;
334 mVarCheckLibAddressPointerMaxCount
= 0;
335 FreePool ((VOID
*) mVarCheckLibAddressPointer
);
336 mVarCheckLibAddressPointer
= NULL
;
342 // Get the total count needed.
343 // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
345 TotalCount
= mVarCheckLibAddressPointerCount
+ (mNumberOfVarCheckHandler
+ 1) + (mNumberOfVarCheckVariable
+ 1);
346 TempTable
= ReallocateRuntimePool (
347 mVarCheckLibAddressPointerMaxCount
* sizeof (VOID
**),
348 TotalCount
* sizeof (VOID
**),
349 (VOID
*) mVarCheckLibAddressPointer
352 if (TempTable
!= NULL
) {
353 mVarCheckLibAddressPointer
= (VOID
***) TempTable
;
356 // Cover VarCheckHandler and the entries.
358 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
;
359 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
360 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
[Index
];
364 // Cover VarCheckVariable and the entries.
366 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
;
367 for (Index
= 0; Index
< mNumberOfVarCheckVariable
; Index
++) {
368 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
[Index
];
371 ASSERT (mVarCheckLibAddressPointerCount
== TotalCount
);
372 mVarCheckLibAddressPointerMaxCount
= mVarCheckLibAddressPointerCount
;
375 *AddressPointerCount
= mVarCheckLibAddressPointerCount
;
376 return mVarCheckLibAddressPointer
;
380 Register address pointer.
381 The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
383 @param[in] AddressPointer Address pointer.
385 @retval EFI_SUCCESS The address pointer was registered successfully.
386 @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
387 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
388 already been signaled.
389 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request.
394 VarCheckLibRegisterAddressPointer (
395 IN VOID
**AddressPointer
400 if (AddressPointer
== NULL
) {
401 return EFI_INVALID_PARAMETER
;
404 if (mVarCheckLibEndOfDxe
) {
405 return EFI_ACCESS_DENIED
;
408 Status
= VarCheckAddTableEntry(
409 (UINTN
**) &mVarCheckLibAddressPointer
,
410 &mVarCheckLibAddressPointerMaxCount
,
411 &mVarCheckLibAddressPointerCount
,
412 (UINTN
) AddressPointer
415 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer
, Status
));
421 Register SetVariable check handler.
423 @param[in] Handler Pointer to check handler.
425 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
426 @retval EFI_INVALID_PARAMETER Handler is NULL.
427 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
428 already been signaled.
429 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
430 @retval EFI_UNSUPPORTED This interface is not implemented.
431 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
436 VarCheckLibRegisterSetVariableCheckHandler (
437 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
442 if (Handler
== NULL
) {
443 return EFI_INVALID_PARAMETER
;
446 if (mVarCheckLibEndOfDxe
) {
447 return EFI_ACCESS_DENIED
;
450 Status
= VarCheckAddTableEntry(
451 (UINTN
**) &mVarCheckHandlerTable
,
452 &mMaxNumberOfVarCheckHandler
,
453 &mNumberOfVarCheckHandler
,
457 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler
, Status
));
463 Variable property set.
465 @param[in] Name Pointer to the variable name.
466 @param[in] Guid Pointer to the vendor GUID.
467 @param[in] VariableProperty Pointer to the input variable property.
469 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
470 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
471 or the fields of VariableProperty are not valid.
472 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
473 already been signaled.
474 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
479 VarCheckLibVariablePropertySet (
482 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
486 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
487 CHAR16
*VariableName
;
488 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
490 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
491 return EFI_INVALID_PARAMETER
;
494 if (VariableProperty
== NULL
) {
495 return EFI_INVALID_PARAMETER
;
498 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
499 return EFI_INVALID_PARAMETER
;
502 if (mVarCheckLibEndOfDxe
) {
503 return EFI_ACCESS_DENIED
;
506 Status
= EFI_SUCCESS
;
509 // Get the pointer of property data for set.
511 Property
= VariablePropertyGetFunction (Name
, Guid
, FALSE
);
512 if (Property
!= NULL
) {
513 CopyMem (Property
, VariableProperty
, sizeof (*VariableProperty
));
515 Entry
= AllocateRuntimeZeroPool (sizeof (*Entry
) + StrSize (Name
));
517 return EFI_OUT_OF_RESOURCES
;
519 VariableName
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
520 StrCpyS (VariableName
, StrSize (Name
)/sizeof (CHAR16
), Name
);
521 CopyGuid (&Entry
->Guid
, Guid
);
522 CopyMem (&Entry
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
524 Status
= VarCheckAddTableEntry(
525 (UINTN
**) &mVarCheckVariableTable
,
526 &mMaxNumberOfVarCheckVariable
,
527 &mNumberOfVarCheckVariable
,
531 if (EFI_ERROR (Status
)) {
540 Variable property get.
542 @param[in] Name Pointer to the variable name.
543 @param[in] Guid Pointer to the vendor GUID.
544 @param[out] VariableProperty Pointer to the output variable property.
546 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
547 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
548 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
553 VarCheckLibVariablePropertyGet (
556 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
559 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
561 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
562 return EFI_INVALID_PARAMETER
;
565 if (VariableProperty
== NULL
) {
566 return EFI_INVALID_PARAMETER
;
569 Property
= VariablePropertyGetFunction (Name
, Guid
, TRUE
);
571 // Also check the property revision before using the property data.
572 // There is no property set to this variable(wildcard name)
573 // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
575 if ((Property
!= NULL
) && (Property
->Revision
== VAR_CHECK_VARIABLE_PROPERTY_REVISION
)) {
576 CopyMem (VariableProperty
, Property
, sizeof (*VariableProperty
));
580 return EFI_NOT_FOUND
;
586 @param[in] VariableName Name of Variable to set.
587 @param[in] VendorGuid Variable vendor GUID.
588 @param[in] Attributes Attribute value of the variable.
589 @param[in] DataSize Size of Data to set.
590 @param[in] Data Data pointer.
591 @param[in] RequestSource Request source.
593 @retval EFI_SUCCESS The SetVariable check result was success.
594 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
595 DataSize and Data value was supplied.
596 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
597 @retval Others The other return status from check handler.
602 VarCheckLibSetVariableCheck (
603 IN CHAR16
*VariableName
,
604 IN EFI_GUID
*VendorGuid
,
605 IN UINT32 Attributes
,
608 IN VAR_CHECK_REQUEST_SOURCE RequestSource
613 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
615 if (!mVarCheckLibEndOfDxe
) {
617 // Only do check after End Of Dxe.
622 Property
= VariablePropertyGetFunction (VariableName
, VendorGuid
, TRUE
);
624 // Also check the property revision before using the property data.
625 // There is no property set to this variable(wildcard name)
626 // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
628 if ((Property
!= NULL
) && (Property
->Revision
== VAR_CHECK_VARIABLE_PROPERTY_REVISION
)) {
629 if ((RequestSource
!= VarCheckFromTrusted
) && ((Property
->Property
& VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
) != 0)) {
630 DEBUG ((EFI_D_INFO
, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED
, VendorGuid
, VariableName
));
631 return EFI_WRITE_PROTECTED
;
633 if (!((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0))) {
635 // Not to delete variable.
637 if ((Property
->Attributes
!= 0) && ((Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Property
->Attributes
)) {
638 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
));
639 return EFI_INVALID_PARAMETER
;
642 if ((DataSize
< Property
->MinSize
) || (DataSize
> Property
->MaxSize
)) {
643 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
));
644 return EFI_INVALID_PARAMETER
;
650 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
651 Status
= mVarCheckHandlerTable
[Index
] (
658 if (EFI_ERROR (Status
)) {
659 DEBUG ((EFI_D_INFO
, "Variable Check handler fail %r - %g:%s\n", Status
, VendorGuid
, VariableName
));