2 Implementation functions and structures for var check services.
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
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 &gEfiHardwareErrorVariableGuid
,
92 Check if a Unicode character is a hexadecimal character.
94 This function checks if a Unicode character is a
95 hexadecimal character. The valid hexadecimal character is
96 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
99 @param[in] Char The character to check against.
101 @retval TRUE If the Char is a hexadecmial character.
102 @retval FALSE If the Char is not a hexadecmial character.
107 VarCheckInternalIsHexaDecimalDigitCharacter (
111 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
115 Variable property get with wildcard name.
117 @param[in] VariableName Pointer to variable name.
118 @param[in] VendorGuid Pointer to variable vendor GUID.
119 @param[in] WildcardMatch Try wildcard match or not.
121 @return Pointer to variable property.
124 VAR_CHECK_VARIABLE_PROPERTY
*
125 VariablePropertyGetWithWildcardName (
126 IN CHAR16
*VariableName
,
127 IN EFI_GUID
*VendorGuid
,
128 IN BOOLEAN WildcardMatch
134 NameLength
= StrLen (VariableName
) - 4;
135 for (Index
= 0; Index
< sizeof (mVarCheckVariableWithWildcardName
)/sizeof (mVarCheckVariableWithWildcardName
[0]); Index
++) {
136 if (CompareGuid (mVarCheckVariableWithWildcardName
[Index
].Guid
, VendorGuid
)){
138 if ((StrLen (VariableName
) == StrLen (mVarCheckVariableWithWildcardName
[Index
].Name
)) &&
139 (StrnCmp (VariableName
, mVarCheckVariableWithWildcardName
[Index
].Name
, NameLength
) == 0) &&
140 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
]) &&
141 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 1]) &&
142 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 2]) &&
143 VarCheckInternalIsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 3])) {
144 return &mVarCheckVariableWithWildcardName
[Index
].VariableProperty
;
147 if (StrCmp (mVarCheckVariableWithWildcardName
[Index
].Name
, VariableName
) == 0) {
148 return &mVarCheckVariableWithWildcardName
[Index
].VariableProperty
;
157 Variable property get function.
159 @param[in] Name Pointer to the variable name.
160 @param[in] Guid Pointer to the vendor GUID.
161 @param[in] WildcardMatch Try wildcard match or not.
163 @return Pointer to the property of variable specified by the Name and Guid.
166 VAR_CHECK_VARIABLE_PROPERTY
*
167 VariablePropertyGetFunction (
170 IN BOOLEAN WildcardMatch
174 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
175 CHAR16
*VariableName
;
177 for (Index
= 0; Index
< mNumberOfVarCheckVariable
; Index
++) {
178 Entry
= (VAR_CHECK_VARIABLE_ENTRY
*) mVarCheckVariableTable
[Index
];
179 VariableName
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
180 if (CompareGuid (&Entry
->Guid
, Guid
) && (StrCmp (VariableName
, Name
) == 0)) {
181 return &Entry
->VariableProperty
;
185 return VariablePropertyGetWithWildcardName (Name
, Guid
, WildcardMatch
);
189 Var check add table entry.
191 @param[in, out] Table Pointer to table buffer.
192 @param[in, out] MaxNumber Pointer to maximum number of entry in the table.
193 @param[in, out] CurrentNumber Pointer to current number of entry in the table.
194 @param[in] Entry Entry will be added to the table.
196 @retval EFI_SUCCESS Reallocate memory successfully.
197 @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
201 VarCheckAddTableEntry (
202 IN OUT UINTN
**Table
,
203 IN OUT UINTN
*MaxNumber
,
204 IN OUT UINTN
*CurrentNumber
,
211 // Check whether the table is enough to store new entry.
213 if (*CurrentNumber
== *MaxNumber
) {
215 // Reallocate memory for the table.
217 TempTable
= ReallocateRuntimePool (
218 *MaxNumber
* sizeof (UINTN
),
219 (*MaxNumber
+ VAR_CHECK_TABLE_SIZE
) * sizeof (UINTN
),
224 // No enough resource to allocate.
226 if (TempTable
== NULL
) {
227 return EFI_OUT_OF_RESOURCES
;
232 // Increase max number.
234 *MaxNumber
+= VAR_CHECK_TABLE_SIZE
;
238 // Add entry to the table.
240 (*Table
)[*CurrentNumber
] = Entry
;
247 Register END_OF_DXE callback.
248 The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
250 @param[in] Callback END_OF_DXE callback.
252 @retval EFI_SUCCESS The callback was registered successfully.
253 @retval EFI_INVALID_PARAMETER Callback is NULL.
254 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
255 already been signaled.
256 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request.
261 VarCheckLibRegisterEndOfDxeCallback (
262 IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
267 if (Callback
== NULL
) {
268 return EFI_INVALID_PARAMETER
;
271 if (mVarCheckLibEndOfDxe
) {
272 return EFI_ACCESS_DENIED
;
275 Status
= VarCheckAddTableEntry (
276 (UINTN
**) &mVarCheckLibEndOfDxeCallback
,
277 &mVarCheckLibEndOfDxeCallbackMaxCount
,
278 &mVarCheckLibEndOfDxeCallbackCount
,
282 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback
, Status
));
288 Var check initialize at END_OF_DXE.
290 This function needs to be called at END_OF_DXE.
291 Address pointers may be returned,
292 and caller needs to ConvertPointer() for the pointers.
294 @param[in, out] AddressPointerCount Output pointer to address pointer count.
296 @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
301 VarCheckLibInitializeAtEndOfDxe (
302 IN OUT UINTN
*AddressPointerCount OPTIONAL
309 for (Index
= 0; Index
< mVarCheckLibEndOfDxeCallbackCount
; Index
++) {
311 // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
313 mVarCheckLibEndOfDxeCallback
[Index
] ();
315 if (mVarCheckLibEndOfDxeCallback
!= NULL
) {
317 // Free the callback buffer.
319 mVarCheckLibEndOfDxeCallbackCount
= 0;
320 mVarCheckLibEndOfDxeCallbackMaxCount
= 0;
321 FreePool ((VOID
*) mVarCheckLibEndOfDxeCallback
);
322 mVarCheckLibEndOfDxeCallback
= NULL
;
325 mVarCheckLibEndOfDxe
= TRUE
;
327 if (AddressPointerCount
== NULL
) {
328 if (mVarCheckLibAddressPointer
!= NULL
) {
330 // Free the address pointer buffer.
332 mVarCheckLibAddressPointerCount
= 0;
333 mVarCheckLibAddressPointerMaxCount
= 0;
334 FreePool ((VOID
*) mVarCheckLibAddressPointer
);
335 mVarCheckLibAddressPointer
= NULL
;
341 // Get the total count needed.
342 // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
344 TotalCount
= mVarCheckLibAddressPointerCount
+ (mNumberOfVarCheckHandler
+ 1) + (mNumberOfVarCheckVariable
+ 1);
345 TempTable
= ReallocateRuntimePool (
346 mVarCheckLibAddressPointerMaxCount
* sizeof (VOID
**),
347 TotalCount
* sizeof (VOID
**),
348 (VOID
*) mVarCheckLibAddressPointer
351 if (TempTable
!= NULL
) {
352 mVarCheckLibAddressPointer
= (VOID
***) TempTable
;
355 // Cover VarCheckHandler and the entries.
357 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
;
358 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
359 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckHandlerTable
[Index
];
363 // Cover VarCheckVariable and the entries.
365 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
;
366 for (Index
= 0; Index
< mNumberOfVarCheckVariable
; Index
++) {
367 mVarCheckLibAddressPointer
[mVarCheckLibAddressPointerCount
++] = (VOID
**) &mVarCheckVariableTable
[Index
];
370 ASSERT (mVarCheckLibAddressPointerCount
== TotalCount
);
371 mVarCheckLibAddressPointerMaxCount
= mVarCheckLibAddressPointerCount
;
374 *AddressPointerCount
= mVarCheckLibAddressPointerCount
;
375 return mVarCheckLibAddressPointer
;
379 Register address pointer.
380 The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
382 @param[in] AddressPointer Address pointer.
384 @retval EFI_SUCCESS The address pointer was registered successfully.
385 @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
386 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
387 already been signaled.
388 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request.
393 VarCheckLibRegisterAddressPointer (
394 IN VOID
**AddressPointer
399 if (AddressPointer
== NULL
) {
400 return EFI_INVALID_PARAMETER
;
403 if (mVarCheckLibEndOfDxe
) {
404 return EFI_ACCESS_DENIED
;
407 Status
= VarCheckAddTableEntry(
408 (UINTN
**) &mVarCheckLibAddressPointer
,
409 &mVarCheckLibAddressPointerMaxCount
,
410 &mVarCheckLibAddressPointerCount
,
411 (UINTN
) AddressPointer
414 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer
, Status
));
420 Register SetVariable check handler.
422 @param[in] Handler Pointer to check handler.
424 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
425 @retval EFI_INVALID_PARAMETER Handler is NULL.
426 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
427 already been signaled.
428 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
429 @retval EFI_UNSUPPORTED This interface is not implemented.
430 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
435 VarCheckLibRegisterSetVariableCheckHandler (
436 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
441 if (Handler
== NULL
) {
442 return EFI_INVALID_PARAMETER
;
445 if (mVarCheckLibEndOfDxe
) {
446 return EFI_ACCESS_DENIED
;
449 Status
= VarCheckAddTableEntry(
450 (UINTN
**) &mVarCheckHandlerTable
,
451 &mMaxNumberOfVarCheckHandler
,
452 &mNumberOfVarCheckHandler
,
456 DEBUG ((EFI_D_INFO
, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler
, Status
));
462 Variable property set.
464 @param[in] Name Pointer to the variable name.
465 @param[in] Guid Pointer to the vendor GUID.
466 @param[in] VariableProperty Pointer to the input variable property.
468 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
469 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
470 or the fields of VariableProperty are not valid.
471 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
472 already been signaled.
473 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
478 VarCheckLibVariablePropertySet (
481 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
485 VAR_CHECK_VARIABLE_ENTRY
*Entry
;
486 CHAR16
*VariableName
;
487 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
489 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
490 return EFI_INVALID_PARAMETER
;
493 if (VariableProperty
== NULL
) {
494 return EFI_INVALID_PARAMETER
;
497 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
498 return EFI_INVALID_PARAMETER
;
501 if (mVarCheckLibEndOfDxe
) {
502 return EFI_ACCESS_DENIED
;
505 Status
= EFI_SUCCESS
;
508 // Get the pointer of property data for set.
510 Property
= VariablePropertyGetFunction (Name
, Guid
, FALSE
);
511 if (Property
!= NULL
) {
512 CopyMem (Property
, VariableProperty
, sizeof (*VariableProperty
));
514 Entry
= AllocateRuntimeZeroPool (sizeof (*Entry
) + StrSize (Name
));
516 return EFI_OUT_OF_RESOURCES
;
518 VariableName
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
519 StrCpyS (VariableName
, StrSize (Name
)/sizeof (CHAR16
), Name
);
520 CopyGuid (&Entry
->Guid
, Guid
);
521 CopyMem (&Entry
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
523 Status
= VarCheckAddTableEntry(
524 (UINTN
**) &mVarCheckVariableTable
,
525 &mMaxNumberOfVarCheckVariable
,
526 &mNumberOfVarCheckVariable
,
530 if (EFI_ERROR (Status
)) {
539 Variable property get.
541 @param[in] Name Pointer to the variable name.
542 @param[in] Guid Pointer to the vendor GUID.
543 @param[out] VariableProperty Pointer to the output variable property.
545 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
546 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
547 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
552 VarCheckLibVariablePropertyGet (
555 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
558 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
560 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
561 return EFI_INVALID_PARAMETER
;
564 if (VariableProperty
== NULL
) {
565 return EFI_INVALID_PARAMETER
;
568 Property
= VariablePropertyGetFunction (Name
, Guid
, TRUE
);
570 // Also check the property revision before using the property data.
571 // There is no property set to this variable(wildcard name)
572 // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
574 if ((Property
!= NULL
) && (Property
->Revision
== VAR_CHECK_VARIABLE_PROPERTY_REVISION
)) {
575 CopyMem (VariableProperty
, Property
, sizeof (*VariableProperty
));
579 return EFI_NOT_FOUND
;
585 @param[in] VariableName Name of Variable to set.
586 @param[in] VendorGuid Variable vendor GUID.
587 @param[in] Attributes Attribute value of the variable.
588 @param[in] DataSize Size of Data to set.
589 @param[in] Data Data pointer.
590 @param[in] RequestSource Request source.
592 @retval EFI_SUCCESS The SetVariable check result was success.
593 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
594 DataSize and Data value was supplied.
595 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
596 @retval Others The other return status from check handler.
601 VarCheckLibSetVariableCheck (
602 IN CHAR16
*VariableName
,
603 IN EFI_GUID
*VendorGuid
,
604 IN UINT32 Attributes
,
607 IN VAR_CHECK_REQUEST_SOURCE RequestSource
612 VAR_CHECK_VARIABLE_PROPERTY
*Property
;
614 if (!mVarCheckLibEndOfDxe
) {
616 // Only do check after End Of Dxe.
621 Property
= VariablePropertyGetFunction (VariableName
, VendorGuid
, TRUE
);
623 // Also check the property revision before using the property data.
624 // There is no property set to this variable(wildcard name)
625 // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
627 if ((Property
!= NULL
) && (Property
->Revision
== VAR_CHECK_VARIABLE_PROPERTY_REVISION
)) {
628 if ((RequestSource
!= VarCheckFromTrusted
) && ((Property
->Property
& VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
) != 0)) {
629 DEBUG ((EFI_D_INFO
, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED
, VendorGuid
, VariableName
));
630 return EFI_WRITE_PROTECTED
;
632 if (!((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0))) {
634 // Not to delete variable.
636 if ((Property
->Attributes
!= 0) && ((Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Property
->Attributes
)) {
637 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
));
638 return EFI_INVALID_PARAMETER
;
641 if ((DataSize
< Property
->MinSize
) || (DataSize
> Property
->MaxSize
)) {
642 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
));
643 return EFI_INVALID_PARAMETER
;
649 for (Index
= 0; Index
< mNumberOfVarCheckHandler
; Index
++) {
650 Status
= mVarCheckHandlerTable
[Index
] (
657 if (EFI_ERROR (Status
)) {
658 DEBUG ((EFI_D_INFO
, "Variable Check handler fail %r - %g:%s\n", Status
, VendorGuid
, VariableName
));