2 Implementation functions and structures for var check services.
4 Copyright (c) 2015 - 2016, 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
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.
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>
21 #include <Guid/GlobalVariable.h>
22 #include <Guid/HardwareErrorVariable.h>
24 BOOLEAN mVarCheckLibEndOfDxe
= FALSE
;
26 #define VAR_CHECK_TABLE_SIZE 0x8
28 UINTN mVarCheckLibEndOfDxeCallbackCount
= 0;
29 UINTN mVarCheckLibEndOfDxeCallbackMaxCount
= 0;
30 VAR_CHECK_END_OF_DXE_CALLBACK
*mVarCheckLibEndOfDxeCallback
= NULL
;
32 UINTN mVarCheckLibAddressPointerCount
= 0;
33 UINTN mVarCheckLibAddressPointerMaxCount
= 0;
34 VOID
***mVarCheckLibAddressPointer
= NULL
;
36 UINTN mNumberOfVarCheckHandler
= 0;
37 UINTN mMaxNumberOfVarCheckHandler
= 0;
38 VAR_CHECK_SET_VARIABLE_CHECK_HANDLER
*mVarCheckHandlerTable
= NULL
;
42 VAR_CHECK_VARIABLE_PROPERTY VariableProperty
;
44 } VAR_CHECK_VARIABLE_ENTRY
;
46 UINTN mNumberOfVarCheckVariable
= 0;
47 UINTN mMaxNumberOfVarCheckVariable
= 0;
48 VARIABLE_ENTRY_PROPERTY
**mVarCheckVariableTable
= NULL
;
51 // Handle variables with wildcard name specially.
53 VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName
[] = {
55 &gEfiGlobalVariableGuid
,
62 &gEfiGlobalVariableGuid
,
69 &gEfiGlobalVariableGuid
,
76 &gEfiGlobalVariableGuid
,
83 &gEfiGlobalVariableGuid
,
84 L
"PlatformRecovery####",
90 &gEfiHardwareErrorVariableGuid
,
99 Check if a Unicode character is an upper case hexadecimal character.
101 This function checks if a Unicode character is an upper case
102 hexadecimal character. The valid upper case hexadecimal character is
103 L'0' to L'9', or L'A' to L'F'.
106 @param[in] Char The character to check against.
108 @retval TRUE If the Char is an upper case hexadecmial character.
109 @retval FALSE If the Char is not an upper case hexadecmial character.
114 VarCheckInternalIsHexaDecimalDigitCharacter (
118 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F'));
122 Variable property get with wildcard name.
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.
128 @return Pointer to variable property.
131 VAR_CHECK_VARIABLE_PROPERTY
*
132 VariablePropertyGetWithWildcardName (
133 IN CHAR16
*VariableName
,
134 IN EFI_GUID
*VendorGuid
,
135 IN BOOLEAN WildcardMatch
141 NameLength
= StrLen (VariableName
) - 4;
142 for (Index
= 0; Index
< sizeof (mVarCheckVariableWithWildcardName
)/sizeof (mVarCheckVariableWithWildcardName
[0]); Index
++) {
143 if (CompareGuid (mVarCheckVariableWithWildcardName
[Index
].Guid
, VendorGuid
)){
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
;
154 if (StrCmp (mVarCheckVariableWithWildcardName
[Index
].Name
, VariableName
) == 0) {
155 return &mVarCheckVariableWithWildcardName
[Index
].VariableProperty
;
164 Variable property get function.
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.
170 @return Pointer to the property of variable specified by the Name and Guid.
173 VAR_CHECK_VARIABLE_PROPERTY
*
174 VariablePropertyGetFunction (
177 IN BOOLEAN WildcardMatch
181 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
182 CHAR16
*VariableName
;
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
;
192 return VariablePropertyGetWithWildcardName (Name
, Guid
, WildcardMatch
);
196 Var check add table entry.
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.
203 @retval EFI_SUCCESS Reallocate memory successfully.
204 @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
208 VarCheckAddTableEntry (
209 IN OUT UINTN
**Table
,
210 IN OUT UINTN
*MaxNumber
,
211 IN OUT UINTN
*CurrentNumber
,
218 // Check whether the table is enough to store new entry.
220 if (*CurrentNumber
== *MaxNumber
) {
222 // Reallocate memory for the table.
224 TempTable
= ReallocateRuntimePool (
225 *MaxNumber
* sizeof (UINTN
),
226 (*MaxNumber
+ VAR_CHECK_TABLE_SIZE
) * sizeof (UINTN
),
231 // No enough resource to allocate.
233 if (TempTable
== NULL
) {
234 return EFI_OUT_OF_RESOURCES
;
239 // Increase max number.
241 *MaxNumber
+= VAR_CHECK_TABLE_SIZE
;
245 // Add entry to the table.
247 (*Table
)[*CurrentNumber
] = Entry
;
254 Register END_OF_DXE callback.
255 The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
257 @param[in] Callback END_OF_DXE callback.
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.
268 VarCheckLibRegisterEndOfDxeCallback (
269 IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
274 if (Callback
== NULL
) {
275 return EFI_INVALID_PARAMETER
;
278 if (mVarCheckLibEndOfDxe
) {
279 return EFI_ACCESS_DENIED
;
282 Status
= VarCheckAddTableEntry (
283 (UINTN
**) &mVarCheckLibEndOfDxeCallback
,
284 &mVarCheckLibEndOfDxeCallbackMaxCount
,
285 &mVarCheckLibEndOfDxeCallbackCount
,
289 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback
, Status
));
295 Var check initialize at END_OF_DXE.
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.
301 @param[in, out] AddressPointerCount Output pointer to address pointer count.
303 @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
308 VarCheckLibInitializeAtEndOfDxe (
309 IN OUT UINTN
*AddressPointerCount OPTIONAL
316 for (Index
= 0; Index
< mVarCheckLibEndOfDxeCallbackCount
; Index
++) {
318 // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
320 mVarCheckLibEndOfDxeCallback
[Index
] ();
322 if (mVarCheckLibEndOfDxeCallback
!= NULL
) {
324 // Free the callback buffer.
326 mVarCheckLibEndOfDxeCallbackCount
= 0;
327 mVarCheckLibEndOfDxeCallbackMaxCount
= 0;
328 FreePool ((VOID
*) mVarCheckLibEndOfDxeCallback
);
329 mVarCheckLibEndOfDxeCallback
= NULL
;
332 mVarCheckLibEndOfDxe
= TRUE
;
334 if (AddressPointerCount
== NULL
) {
335 if (mVarCheckLibAddressPointer
!= NULL
) {
337 // Free the address pointer buffer.
339 mVarCheckLibAddressPointerCount
= 0;
340 mVarCheckLibAddressPointerMaxCount
= 0;
341 FreePool ((VOID
*) mVarCheckLibAddressPointer
);
342 mVarCheckLibAddressPointer
= NULL
;
348 // Get the total count needed.
349 // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
351 TotalCount
= mVarCheckLibAddressPointerCount
+ (mNumberOfVarCheckHandler
+ 1) + (mNumberOfVarCheckVariable
+ 1);
352 TempTable
= ReallocateRuntimePool (
353 mVarCheckLibAddressPointerMaxCount
* sizeof (VOID
**),
354 TotalCount
* sizeof (VOID
**),
355 (VOID
*) mVarCheckLibAddressPointer
358 if (TempTable
!= NULL
) {
359 mVarCheckLibAddressPointer
= (VOID
***) TempTable
;
362 // Cover VarCheckHandler and the entries.
364 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
;
365 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
366 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
[Index
];
370 // Cover VarCheckVariable and the entries.
372 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
;
373 for (Index
= 0; Index
< mNumberOfVarCheckVariable
; Index
++) {
374 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
[Index
];
377 ASSERT (mVarCheckLibAddressPointerCount
== TotalCount
);
378 mVarCheckLibAddressPointerMaxCount
= mVarCheckLibAddressPointerCount
;
381 *AddressPointerCount
= mVarCheckLibAddressPointerCount
;
382 return mVarCheckLibAddressPointer
;
386 Register address pointer.
387 The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
389 @param[in] AddressPointer Address pointer.
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.
400 VarCheckLibRegisterAddressPointer (
401 IN VOID
**AddressPointer
406 if (AddressPointer
== NULL
) {
407 return EFI_INVALID_PARAMETER
;
410 if (mVarCheckLibEndOfDxe
) {
411 return EFI_ACCESS_DENIED
;
414 Status
= VarCheckAddTableEntry(
415 (UINTN
**) &mVarCheckLibAddressPointer
,
416 &mVarCheckLibAddressPointerMaxCount
,
417 &mVarCheckLibAddressPointerCount
,
418 (UINTN
) AddressPointer
421 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer
, Status
));
427 Register SetVariable check handler.
429 @param[in] Handler Pointer to check handler.
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.
442 VarCheckLibRegisterSetVariableCheckHandler (
443 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
448 if (Handler
== NULL
) {
449 return EFI_INVALID_PARAMETER
;
452 if (mVarCheckLibEndOfDxe
) {
453 return EFI_ACCESS_DENIED
;
456 Status
= VarCheckAddTableEntry(
457 (UINTN
**) &mVarCheckHandlerTable
,
458 &mMaxNumberOfVarCheckHandler
,
459 &mNumberOfVarCheckHandler
,
463 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler
, Status
));
469 Variable property set.
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.
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.
485 VarCheckLibVariablePropertySet (
488 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
492 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
493 CHAR16
*VariableName
;
494 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
496 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
497 return EFI_INVALID_PARAMETER
;
500 if (VariableProperty
== NULL
) {
501 return EFI_INVALID_PARAMETER
;
504 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
505 return EFI_INVALID_PARAMETER
;
508 if (mVarCheckLibEndOfDxe
) {
509 return EFI_ACCESS_DENIED
;
512 Status
= EFI_SUCCESS
;
515 // Get the pointer of property data for set.
517 Property
= VariablePropertyGetFunction (Name
, Guid
, FALSE
);
518 if (Property
!= NULL
) {
519 CopyMem (Property
, VariableProperty
, sizeof (*VariableProperty
));
521 Entry
= AllocateRuntimeZeroPool (sizeof (*Entry
) + StrSize (Name
));
523 return EFI_OUT_OF_RESOURCES
;
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
));
530 Status
= VarCheckAddTableEntry(
531 (UINTN
**) &mVarCheckVariableTable
,
532 &mMaxNumberOfVarCheckVariable
,
533 &mNumberOfVarCheckVariable
,
537 if (EFI_ERROR (Status
)) {
546 Variable property get.
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.
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.
559 VarCheckLibVariablePropertyGet (
562 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
565 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
567 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
568 return EFI_INVALID_PARAMETER
;
571 if (VariableProperty
== NULL
) {
572 return EFI_INVALID_PARAMETER
;
575 Property
= VariablePropertyGetFunction (Name
, Guid
, TRUE
);
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.
581 if ((Property
!= NULL
) && (Property
->Revision
== VAR_CHECK_VARIABLE_PROPERTY_REVISION
)) {
582 CopyMem (VariableProperty
, Property
, sizeof (*VariableProperty
));
586 return EFI_NOT_FOUND
;
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.
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.
608 VarCheckLibSetVariableCheck (
609 IN CHAR16
*VariableName
,
610 IN EFI_GUID
*VendorGuid
,
611 IN UINT32 Attributes
,
614 IN VAR_CHECK_REQUEST_SOURCE RequestSource
619 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
621 if (!mVarCheckLibEndOfDxe
) {
623 // Only do check after End Of Dxe.
628 Property
= VariablePropertyGetFunction (VariableName
, VendorGuid
, TRUE
);
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.
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
;
639 if (!((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0))) {
641 // Not to delete variable.
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
;
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
;
656 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
657 Status
= mVarCheckHandlerTable
[Index
] (
664 if (EFI_ERROR (Status
)) {
665 DEBUG ((EFI_D_INFO
, "Variable Check handler fail %r - %g:%s\n", Status
, VendorGuid
, VariableName
));