mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
896 lines
22 KiB
C
896 lines
22 KiB
C
/** @file
|
|
Copyright (C) 2019, vit9696. All rights reserved.
|
|
|
|
All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
**/
|
|
|
|
#include "OpenRuntimePrivate.h"
|
|
|
|
#include <Guid/OcVariable.h>
|
|
#include <Guid/GlobalVariable.h>
|
|
#include <Guid/ImageAuthentication.h>
|
|
#include <Guid/MicrosoftVariable.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/OcBootManagementLib.h>
|
|
#include <Library/OcDevicePathLib.h>
|
|
#include <Library/OcGuardLib.h>
|
|
#include <Library/OcStringLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
/**
|
|
Runtime accessible variables (all read only).
|
|
**/
|
|
STATIC EFI_GET_TIME mStoredGetTime;
|
|
STATIC EFI_SET_TIME mStoredSetTime;
|
|
STATIC EFI_GET_WAKEUP_TIME mStoredGetWakeupTime;
|
|
STATIC EFI_SET_WAKEUP_TIME mStoredSetWakeupTime;
|
|
STATIC EFI_GET_VARIABLE mStoredGetVariable;
|
|
STATIC EFI_GET_NEXT_VARIABLE_NAME mStoredGetNextVariableName;
|
|
STATIC EFI_SET_VARIABLE mStoredSetVariable;
|
|
STATIC EFI_GET_NEXT_HIGH_MONO_COUNT mStoredGetNextHighMonotonicCount;
|
|
STATIC EFI_RESET_SYSTEM mStoredResetSystem;
|
|
STATIC EFI_SET_VIRTUAL_ADDRESS_MAP mSetVirtualAddressMap;
|
|
|
|
/**
|
|
Configurations to use.
|
|
**/
|
|
OC_FWRT_CONFIG gMainConfig;
|
|
OC_FWRT_CONFIG gOverrideConfig;
|
|
OC_FWRT_CONFIG *gCurrentConfig;
|
|
|
|
/**
|
|
Boot phase accessible variables.
|
|
**/
|
|
STATIC EFI_EVENT mTranslateEvent;
|
|
STATIC EFI_GET_VARIABLE mCustomGetVariable;
|
|
STATIC EFI_SET_VIRTUAL_ADDRESS_MAP mCustomSetVirtualAddressMap;
|
|
STATIC BOOLEAN mCustomSetVirtualAddressMapEnabled;
|
|
STATIC BOOLEAN mKernelStarted;
|
|
#ifdef OC_DEBUG_VAR_SERVICE ///< For file logging disable TPL checking in OcLogAddEntry.
|
|
STATIC BOOLEAN mInsideVarService;
|
|
#endif
|
|
|
|
STATIC
|
|
VOID
|
|
WriteUnprotectorPrologue (
|
|
OUT BOOLEAN *Ints,
|
|
OUT BOOLEAN *Wp
|
|
)
|
|
{
|
|
IA32_CR0 Cr0;
|
|
|
|
if (gCurrentConfig->WriteUnprotector) {
|
|
*Ints = SaveAndDisableInterrupts ();
|
|
Cr0.UintN = AsmReadCr0 ();
|
|
if (Cr0.Bits.WP == 1) {
|
|
*Wp = TRUE;
|
|
Cr0.Bits.WP = 0;
|
|
AsmWriteCr0 (Cr0.UintN);
|
|
} else {
|
|
*Wp = FALSE;
|
|
}
|
|
} else {
|
|
*Ints = FALSE;
|
|
*Wp = FALSE;
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
WriteUnprotectorEpilogue (
|
|
IN BOOLEAN Ints,
|
|
IN BOOLEAN Wp
|
|
)
|
|
{
|
|
IA32_CR0 Cr0;
|
|
|
|
if (gCurrentConfig->WriteUnprotector) {
|
|
if (Wp) {
|
|
Cr0.UintN = AsmReadCr0 ();
|
|
Cr0.Bits.WP = 1;
|
|
AsmWriteCr0 (Cr0.UintN);
|
|
}
|
|
|
|
if (Ints) {
|
|
EnableInterrupts ();
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
IsEfiBootVar (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT CHAR16 *NewVariableName OPTIONAL
|
|
)
|
|
{
|
|
UINTN Size;
|
|
|
|
if (!CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (StrnCmp (L"Boot", VariableName, L_STR_LEN (L"Boot")) != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Return OC option path if requested.
|
|
//
|
|
// Many modern AMI BIOSes (e.g. ASUS ROG STRIX Z370-F GAMING)
|
|
// have bugs in AMI Post Manager protocol implementation in AMI TSE.
|
|
//
|
|
// The handshake function, responsible for obtaining firmware
|
|
// boot option list, calls gRT->GetNextVariableName and then matches
|
|
// every Boot#### variable as a potential boot option regardless
|
|
// of the GUID namespace it is in.
|
|
//
|
|
// The correct way is to only check for Boot#### variables under the
|
|
// gEfiGlobalVariableGuid VendorGuid. Due to these bugs however, the
|
|
// boot option list on most ASUS firmware, and perhaps other vendors, is
|
|
// corrupted (e.g. duplicated options) if Boot#### variables are present
|
|
// outside gEfiGlobalVariableGuid.
|
|
//
|
|
// This is the case with OpenCore as we store macOS-specific boot options
|
|
// in a separate GUID (gOcVendorVariableGuid). To workaround the issue
|
|
// we store Boot options with a different prefix - OCBt. This way
|
|
// Boot0001 becomes OCBt0001 and Bootorder becomes OCBtOrder.
|
|
//
|
|
// One of the ways to reproduce the issue is to enable Fast Boot
|
|
// and let an ExitBootServices handler try to update BootOrder.
|
|
// It can be easily noticed by BootFlow GetVariable with an uninitialised
|
|
// size argument.
|
|
//
|
|
if (NewVariableName != NULL) {
|
|
Size = StrSize (VariableName);
|
|
if (Size > OC_VARIABLE_NAME_SIZE * sizeof (CHAR16)) {
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMem (&NewVariableName[0], OC_VENDOR_BOOT_VARIABLE_PREFIX, L_STR_SIZE_NT (OC_VENDOR_BOOT_VARIABLE_PREFIX));
|
|
CopyMem (
|
|
&NewVariableName[L_STR_LEN (OC_VENDOR_BOOT_VARIABLE_PREFIX)],
|
|
&VariableName[L_STR_LEN (OC_VENDOR_BOOT_VARIABLE_PREFIX)],
|
|
Size - L_STR_SIZE_NT (OC_VENDOR_BOOT_VARIABLE_PREFIX)
|
|
);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
IsOcBootVar (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT CHAR16 *NewVariableName OPTIONAL
|
|
)
|
|
{
|
|
UINTN Size;
|
|
|
|
if (!CompareGuid (VendorGuid, &gOcVendorVariableGuid)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (StrnCmp (OC_VENDOR_BOOT_VARIABLE_PREFIX, VariableName, L_STR_LEN (OC_VENDOR_BOOT_VARIABLE_PREFIX)) != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Return boot option if requested.
|
|
//
|
|
if (NewVariableName != NULL) {
|
|
Size = StrSize (VariableName);
|
|
if (Size > OC_VARIABLE_NAME_SIZE * sizeof (CHAR16)) {
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMem (NewVariableName, L"Boot", L_STR_SIZE_NT (L"Boot"));
|
|
CopyMem (
|
|
&NewVariableName[L_STR_LEN (L"Boot")],
|
|
&VariableName[L_STR_LEN (L"Boot")],
|
|
Size - L_STR_SIZE_NT (L"Boot")
|
|
);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapGetTime (
|
|
OUT EFI_TIME *Time,
|
|
OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredGetTime (
|
|
Time,
|
|
Capabilities
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// On old AMI firmware, such as found in the GA-Z87X-UD4H, there is a chance
|
|
// of getting 2047 (EFI_UNSPECIFIED_TIMEZONE) from GetTime. This is valid,
|
|
// yet is disliked by some software including but not limited to UEFI Shell.
|
|
// See the patch: https://lists.01.org/pipermail/edk2-devel/2018-May/024534.html
|
|
// As a workaround we make sure this does not happen at all.
|
|
//
|
|
if (Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) {
|
|
Time->TimeZone = 0;
|
|
}
|
|
}
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapSetTime (
|
|
IN EFI_TIME *Time
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredSetTime (
|
|
Time
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapGetWakeupTime (
|
|
OUT BOOLEAN *Enabled,
|
|
OUT BOOLEAN *Pending,
|
|
OUT EFI_TIME *Time
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredGetWakeupTime (
|
|
Enabled,
|
|
Pending,
|
|
Time
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapSetWakeupTime (
|
|
IN BOOLEAN Enable,
|
|
IN EFI_TIME *Time OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredSetWakeupTime (
|
|
Enable,
|
|
Time
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapGetVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 TempName[OC_VARIABLE_NAME_SIZE];
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
//
|
|
// Perform early checks for speedup.
|
|
//
|
|
if ( (VariableName == NULL)
|
|
|| (VendorGuid == NULL)
|
|
|| (DataSize == NULL)
|
|
|| ((Data == NULL) && (*DataSize != 0)))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
#ifdef OC_DEBUG_VAR_SERVICE
|
|
if (!mInsideVarService && (StrCmp (VariableName, L"EfiTime") != 0)) {
|
|
mInsideVarService = TRUE;
|
|
DEBUG ((DEBUG_INFO, "GETVAR %g:%s (%u)\n", VendorGuid, VariableName, (UINT32)*DataSize));
|
|
mInsideVarService = FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Abort access to write-only variables.
|
|
//
|
|
if ( gCurrentConfig->RestrictedVariables
|
|
&& mKernelStarted
|
|
&& CompareGuid (VendorGuid, &gOcWriteOnlyVariableGuid))
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Redirect Boot-prefixed variables to our own GUID.
|
|
//
|
|
if (gCurrentConfig->BootVariableRedirect && IsEfiBootVar (VariableName, VendorGuid, TempName)) {
|
|
VariableName = TempName;
|
|
VendorGuid = &gOcVendorVariableGuid;
|
|
}
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = (mCustomGetVariable != NULL ? mCustomGetVariable : mStoredGetVariable)(
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
DataSize,
|
|
Data
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapGetNextVariableName (
|
|
IN OUT UINTN *VariableNameSize,
|
|
IN OUT CHAR16 *VariableName,
|
|
IN OUT EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN Size;
|
|
CHAR16 TempName[OC_VARIABLE_NAME_SIZE];
|
|
EFI_GUID TempGuid;
|
|
BOOLEAN StartBootVar;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
#ifdef OC_DEBUG_VAR_SERVICE
|
|
if (!mInsideVarService) {
|
|
mInsideVarService = TRUE;
|
|
DEBUG ((DEBUG_INFO, "NEXVAR %g:%s (%u/%u)\n", VendorGuid, VariableName, (UINT32)*VariableNameSize));
|
|
mInsideVarService = FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Perform initial checks as per spec. Last check is part of:
|
|
// Null-terminator is not found in the first VariableNameSize
|
|
// bytes of the input VariableName buffer.
|
|
//
|
|
if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Checking that VariableName never exceeds *VariableNameSize and is always null-terminated.
|
|
//
|
|
Size = 0;
|
|
for (Index = 0; Index < *VariableNameSize; ++Index) {
|
|
if (VariableName[Index] == L'\0') {
|
|
Size = (Index + 1) * sizeof (CHAR16);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Also assume that too large variables do not exist, as we cannot work with them anyway.
|
|
//
|
|
if ((Size == 0) || (Size > sizeof (TempName))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
//
|
|
// In case we do not redirect, simply do nothing.
|
|
//
|
|
if (!gCurrentConfig->BootVariableRedirect) {
|
|
Status = mStoredGetNextVariableName (VariableNameSize, VariableName, VendorGuid);
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Copy vendor and variable name to internal buffer.
|
|
//
|
|
CopyGuid (&TempGuid, VendorGuid);
|
|
StrnCpyS (TempName, ARRAY_SIZE (TempName), VariableName, StrLen (VariableName));
|
|
|
|
StartBootVar = FALSE;
|
|
|
|
//
|
|
// In case we are not yet iterating EfiBoot variables,
|
|
// then go through the whole variable list and return
|
|
// variables except EfiBoot.
|
|
//
|
|
if (!IsEfiBootVar (TempName, &TempGuid, TempName)) {
|
|
while (TRUE) {
|
|
//
|
|
// Request for variables.
|
|
//
|
|
Size = sizeof (TempName);
|
|
Status = mStoredGetNextVariableName (&Size, TempName, &TempGuid);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (!IsEfiBootVar (TempName, &TempGuid, NULL)) {
|
|
Size = StrSize (TempName); ///< Not guaranteed to be updated with EFI_SUCCESS.
|
|
|
|
if (*VariableNameSize >= Size) {
|
|
//
|
|
// Return this variable.
|
|
//
|
|
CopyGuid (VendorGuid, &TempGuid);
|
|
StrnCpyS (
|
|
VariableName,
|
|
*VariableNameSize / sizeof (CHAR16),
|
|
TempName,
|
|
StrLen (TempName)
|
|
);
|
|
*VariableNameSize = Size; ///< This is NOT explicitly required by the spec.
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
//
|
|
// Request more space.
|
|
//
|
|
*VariableNameSize = Size;
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return Status;
|
|
} else {
|
|
//
|
|
// EfiBoot variables are handled outside of this loop.
|
|
//
|
|
}
|
|
} else if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// This means sizeof (TempName) is too small for this system.
|
|
// At this step we cannot do anything, but let's replace error
|
|
// with something sensible.
|
|
//
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return EFI_DEVICE_ERROR;
|
|
} else if (Status == EFI_NOT_FOUND) {
|
|
//
|
|
// End of normal variable list.
|
|
// This means it is the time for boot variables to be searched
|
|
// from the beginning.
|
|
//
|
|
StartBootVar = TRUE;
|
|
break;
|
|
} else {
|
|
//
|
|
// We got EFI_UNSUPPORTED, EFI_DEVICE_ERROR or EFI_INVALID_PARAMETER.
|
|
// Return as is.
|
|
//
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle EfiBoot variables now.
|
|
// When StartBootVar is TRUE we start from the beginning.
|
|
// Otherwise we have boot variable in TempGuid/TempName.
|
|
//
|
|
|
|
if (StartBootVar) {
|
|
//
|
|
// It is not required to zero guid, but let's do it just in case.
|
|
//
|
|
TempName[0] = L'\0';
|
|
ZeroMem (&TempGuid, sizeof (TempGuid));
|
|
} else {
|
|
//
|
|
// Switch to real GUID as stored in variable storage.
|
|
// TempName is already updated with the new name.
|
|
//
|
|
CopyGuid (&TempGuid, &gOcVendorVariableGuid);
|
|
}
|
|
|
|
//
|
|
// Find next EfiBoot variable.
|
|
//
|
|
while (TRUE) {
|
|
Size = sizeof (TempName);
|
|
Status = mStoredGetNextVariableName (&Size, TempName, &TempGuid);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (IsOcBootVar (TempName, &TempGuid, TempName)) {
|
|
Size = StrSize (TempName); ///< Not guaranteed to be updated with EFI_SUCCESS.
|
|
|
|
if (*VariableNameSize >= Size) {
|
|
//
|
|
// Return this variable.
|
|
//
|
|
CopyGuid (VendorGuid, &gEfiGlobalVariableGuid);
|
|
StrnCpyS (
|
|
VariableName,
|
|
*VariableNameSize / sizeof (CHAR16),
|
|
TempName,
|
|
StrLen (TempName)
|
|
);
|
|
*VariableNameSize = Size; ///< This is NOT explicitly required by the spec.
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
//
|
|
// Request more space.
|
|
//
|
|
*VariableNameSize = Size;
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return Status;
|
|
}
|
|
} else {
|
|
//
|
|
// This is some error, but let us not care which and just exit cleanly.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Report this is the end.
|
|
//
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapSetVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
IN UINTN DataSize,
|
|
IN VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 TempName[OC_VARIABLE_NAME_SIZE];
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
#ifdef OC_DEBUG_VAR_SERVICE
|
|
if (!mInsideVarService) {
|
|
mInsideVarService = TRUE;
|
|
DEBUG ((DEBUG_INFO, "SETVAR %g:%s (%u/%u)\n", VendorGuid, VariableName, (UINT32)DataSize, Attributes));
|
|
mInsideVarService = FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Abort access when running with read-only NVRAM.
|
|
//
|
|
if (gCurrentConfig->WriteProtection && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Abort access to read-only variables.
|
|
//
|
|
if ( gCurrentConfig->RestrictedVariables
|
|
&& mKernelStarted
|
|
&& CompareGuid (VendorGuid, &gOcReadOnlyVariableGuid))
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
//
|
|
// Abort access to SecureBoot variables.
|
|
//
|
|
if (gCurrentConfig->ProtectSecureBoot) {
|
|
if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
|
|
if ( (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)
|
|
|| (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) {
|
|
if ( (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0)
|
|
|| (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0)
|
|
|| (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)
|
|
|| (StrCmp (VariableName, L"dbr" /* EFI_IMAGE_SECURITY_DATABASE3 */) == 0))
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
} else if (CompareGuid (VendorGuid, &gMicrosoftVariableGuid)) {
|
|
//
|
|
// CurrentActivePolicy, CurrentPolicy, RevocationList, WindowsBootChainSvn, whatever.
|
|
//
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Redirect Boot-prefixed variables to our own GUID.
|
|
//
|
|
if ( gCurrentConfig->BootVariableRedirect
|
|
&& IsEfiBootVar (VariableName, VendorGuid, TempName))
|
|
{
|
|
VariableName = TempName;
|
|
VendorGuid = &gOcVendorVariableGuid;
|
|
}
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredSetVariable (
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
DataSize,
|
|
Data
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapGetNextHighMonotonicCount (
|
|
OUT UINT32 *Count
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
Status = mStoredGetNextHighMonotonicCount (
|
|
Count
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
WrapResetSystem (
|
|
IN EFI_RESET_TYPE ResetType,
|
|
IN EFI_STATUS ResetStatus,
|
|
IN UINTN DataSize,
|
|
IN VOID *ResetData OPTIONAL
|
|
)
|
|
{
|
|
BOOLEAN Ints;
|
|
BOOLEAN Wp;
|
|
|
|
WriteUnprotectorPrologue (&Ints, &Wp);
|
|
|
|
mStoredResetSystem (
|
|
ResetType,
|
|
ResetStatus,
|
|
DataSize,
|
|
ResetData
|
|
);
|
|
|
|
WriteUnprotectorEpilogue (Ints, Wp);
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WrapSetVirtualAddressMap (
|
|
IN UINTN MemoryMapSize,
|
|
IN UINTN DescriptorSize,
|
|
IN UINT32 DescriptorVersion,
|
|
IN EFI_MEMORY_DESCRIPTOR *MemoryMap
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// This is the time for us to remove our hacks.
|
|
// Make SetVirtualAddressMap useable once again.
|
|
// We do not need to recover BS, since they already are invalid.
|
|
//
|
|
gRT->SetVirtualAddressMap = mSetVirtualAddressMap;
|
|
gRT->Hdr.CRC32 = 0;
|
|
gRT->Hdr.CRC32 = CalculateCrc32 (gRT, gRT->Hdr.HeaderSize);
|
|
|
|
if (!mCustomSetVirtualAddressMapEnabled) {
|
|
Status = gRT->SetVirtualAddressMap (
|
|
MemoryMapSize,
|
|
DescriptorSize,
|
|
DescriptorVersion,
|
|
MemoryMap
|
|
);
|
|
} else {
|
|
Status = mCustomSetVirtualAddressMap (
|
|
MemoryMapSize,
|
|
DescriptorSize,
|
|
DescriptorVersion,
|
|
MemoryMap
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FwOnGetVariable (
|
|
IN EFI_GET_VARIABLE GetVariable,
|
|
OUT EFI_GET_VARIABLE *OrgGetVariable OPTIONAL
|
|
)
|
|
{
|
|
if (mCustomGetVariable != NULL) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
mCustomGetVariable = GetVariable;
|
|
|
|
if (OrgGetVariable != NULL) {
|
|
*OrgGetVariable = mStoredGetVariable;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FwOnSetAddressMap (
|
|
IN EFI_SET_VIRTUAL_ADDRESS_MAP SetAddressMap OPTIONAL,
|
|
IN BOOLEAN Enabled
|
|
)
|
|
{
|
|
if (SetAddressMap != NULL) {
|
|
if (mCustomSetVirtualAddressMap != NULL) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
mCustomSetVirtualAddressMap = SetAddressMap;
|
|
} else if (mCustomSetVirtualAddressMap == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
mCustomSetVirtualAddressMapEnabled = Enabled;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
TranslateAddressesHandler (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredGetTime);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredSetTime);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredGetWakeupTime);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredSetWakeupTime);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredGetVariable);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredGetNextVariableName);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredSetVariable);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredGetNextHighMonotonicCount);
|
|
gRT->ConvertPointer (0, (VOID **)&mStoredResetSystem);
|
|
|
|
gRT->ConvertPointer (0, (VOID **)&gCurrentConfig);
|
|
mCustomGetVariable = NULL;
|
|
|
|
//
|
|
// Ideally we do that from ExitBootServices, but VirtualAddressChange is fine as well.
|
|
//
|
|
mKernelStarted = TRUE;
|
|
}
|
|
|
|
VOID
|
|
RedirectRuntimeServices (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
mStoredGetTime = gRT->GetTime;
|
|
mStoredSetTime = gRT->SetTime;
|
|
mStoredGetWakeupTime = gRT->GetWakeupTime;
|
|
mStoredSetWakeupTime = gRT->SetWakeupTime;
|
|
mStoredGetVariable = gRT->GetVariable;
|
|
mStoredGetNextVariableName = gRT->GetNextVariableName;
|
|
mStoredSetVariable = gRT->SetVariable;
|
|
mStoredGetNextHighMonotonicCount = gRT->GetNextHighMonotonicCount;
|
|
mStoredResetSystem = gRT->ResetSystem;
|
|
mSetVirtualAddressMap = gRT->SetVirtualAddressMap;
|
|
|
|
gRT->GetTime = WrapGetTime;
|
|
gRT->SetTime = WrapSetTime;
|
|
gRT->GetWakeupTime = WrapGetWakeupTime;
|
|
gRT->SetWakeupTime = WrapSetWakeupTime;
|
|
gRT->GetVariable = WrapGetVariable;
|
|
gRT->GetNextVariableName = WrapGetNextVariableName;
|
|
gRT->SetVariable = WrapSetVariable;
|
|
gRT->GetNextHighMonotonicCount = WrapGetNextHighMonotonicCount;
|
|
gRT->ResetSystem = WrapResetSystem;
|
|
gRT->SetVirtualAddressMap = WrapSetVirtualAddressMap;
|
|
|
|
gRT->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32 (gRT, gRT->Hdr.HeaderSize, &gRT->Hdr.CRC32);
|
|
|
|
Status = gBS->CreateEvent (
|
|
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
|
|
TPL_CALLBACK,
|
|
TranslateAddressesHandler,
|
|
NULL,
|
|
&mTranslateEvent
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|