2017-07-06 15:21:12 +02:00
|
|
|
/** @file
|
|
|
|
|
|
|
|
Define Secure Encrypted Virtualization (SEV) base library helper function
|
|
|
|
|
2021-01-07 19:48:12 +01:00
|
|
|
Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.<BR>
|
2017-07-06 15:21:12 +02:00
|
|
|
|
2019-04-04 01:06:33 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2017-07-06 15:21:12 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#ifndef _MEM_ENCRYPT_SEV_LIB_H_
|
|
|
|
#define _MEM_ENCRYPT_SEV_LIB_H_
|
|
|
|
|
|
|
|
#include <Base.h>
|
|
|
|
|
2021-01-07 19:48:23 +01:00
|
|
|
//
|
|
|
|
// Define the maximum number of #VCs allowed (e.g. the level of nesting
|
|
|
|
// that is allowed => 2 allows for 1 nested #VCs). I this value is changed,
|
|
|
|
// be sure to increase the size of
|
|
|
|
// gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
|
|
|
|
// in any FDF file using this PCD.
|
|
|
|
//
|
|
|
|
#define VMGEXIT_MAXIMUM_VC_COUNT 2
|
|
|
|
|
|
|
|
//
|
|
|
|
// Per-CPU data mapping structure
|
|
|
|
// Use UINT32 for cached indicators and compare to a specific value
|
|
|
|
// so that the hypervisor can't indicate a value is cached by just
|
|
|
|
// writing random data to that area.
|
|
|
|
//
|
|
|
|
typedef struct {
|
|
|
|
UINT32 Dr7Cached;
|
|
|
|
UINT64 Dr7;
|
|
|
|
|
|
|
|
UINTN VcCount;
|
|
|
|
VOID *GhcbBackupPages;
|
|
|
|
} SEV_ES_PER_CPU_DATA;
|
|
|
|
|
2021-01-07 19:48:12 +01:00
|
|
|
//
|
|
|
|
// Internal structure for holding SEV-ES information needed during SEC phase
|
|
|
|
// and valid only during SEC phase and early PEI during platform
|
|
|
|
// initialization.
|
|
|
|
//
|
|
|
|
// This structure is also used by assembler files:
|
|
|
|
// OvmfPkg/ResetVector/ResetVector.nasmb
|
|
|
|
// OvmfPkg/ResetVector/Ia32/PageTables64.asm
|
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108
To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.
The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.
The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.
The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.
To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>
2021-01-07 19:48:13 +01:00
|
|
|
// OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
|
2021-01-07 19:48:12 +01:00
|
|
|
// any changes must stay in sync with its usage.
|
|
|
|
//
|
|
|
|
typedef struct _SEC_SEV_ES_WORK_AREA {
|
|
|
|
UINT8 SevEsEnabled;
|
OvmfPkg/ResetVector: Validate the encryption bit position for SEV/SEV-ES
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108
To help mitigate against ROP attacks, add some checks to validate the
encryption bit position that is reported by the hypervisor.
The first check is to ensure that the hypervisor reports a bit position
above bit 31. After extracting the encryption bit position from the CPUID
information, the code checks that the value is above 31. If the value is
not above 31, then the bit position is not valid, so the code enters a
HLT loop.
The second check is specific to SEV-ES guests and is a two step process.
The first step will obtain random data using RDRAND and store that data to
memory before paging is enabled. When paging is not enabled, all writes to
memory are encrypted. The random data is maintained in registers, which
are protected. The second step is that, after enabling paging, the random
data in memory is compared to the register contents. If they don't match,
then the reported bit position is not valid, so the code enters a HLT
loop.
The third check is after switching to 64-bit long mode. Use the fact that
instruction fetches are automatically decrypted, while a memory fetch is
decrypted only if the encryption bit is set in the page table. By
comparing the bytes of an instruction fetch against a memory read of that
same instruction, the encryption bit position can be validated. If the
compare is not equal, then SEV/SEV-ES is active but the reported bit
position is not valid, so the code enters a HLT loop.
To keep the changes local to the OvmfPkg, an OvmfPkg version of the
Flat32ToFlat64.asm file has been created based on the UefiCpuPkg file
UefiCpuPkg/ResetVector/Vtf0/Ia32/Flat32ToFlat64.asm.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <cb9c5ab23ab02096cd964ed64115046cc706ce67.1610045305.git.thomas.lendacky@amd.com>
2021-01-07 19:48:13 +01:00
|
|
|
UINT8 Reserved1[7];
|
|
|
|
|
|
|
|
UINT64 RandomData;
|
2021-01-07 19:48:15 +01:00
|
|
|
|
|
|
|
UINT64 EncryptionMask;
|
2021-01-07 19:48:12 +01:00
|
|
|
} SEC_SEV_ES_WORK_AREA;
|
|
|
|
|
2021-01-07 19:48:22 +01:00
|
|
|
//
|
|
|
|
// Memory encryption address range states.
|
|
|
|
//
|
|
|
|
typedef enum {
|
|
|
|
MemEncryptSevAddressRangeUnencrypted,
|
|
|
|
MemEncryptSevAddressRangeEncrypted,
|
|
|
|
MemEncryptSevAddressRangeMixed,
|
|
|
|
MemEncryptSevAddressRangeError,
|
|
|
|
} MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE;
|
|
|
|
|
2020-08-12 22:21:39 +02:00
|
|
|
/**
|
|
|
|
Returns a boolean to indicate whether SEV-ES is enabled.
|
|
|
|
|
|
|
|
@retval TRUE SEV-ES is enabled
|
|
|
|
@retval FALSE SEV-ES is not enabled
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevEsIsEnabled (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
2017-07-06 15:21:12 +02:00
|
|
|
/**
|
|
|
|
Returns a boolean to indicate whether SEV is enabled
|
|
|
|
|
2018-03-01 14:41:01 +01:00
|
|
|
@retval TRUE SEV is enabled
|
2017-07-06 15:21:12 +02:00
|
|
|
@retval FALSE SEV is not enabled
|
2018-03-01 14:41:01 +01:00
|
|
|
**/
|
2017-07-06 15:21:12 +02:00
|
|
|
BOOLEAN
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevIsEnabled (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
2018-03-01 14:41:01 +01:00
|
|
|
This function clears memory encryption bit for the memory region specified by
|
|
|
|
BaseAddress and NumPages from the current page table context.
|
|
|
|
|
|
|
|
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
|
|
|
|
current CR3)
|
|
|
|
@param[in] BaseAddress The physical address that is the start
|
|
|
|
address of a memory region.
|
|
|
|
@param[in] NumPages The number of pages from start memory
|
|
|
|
region.
|
|
|
|
|
|
|
|
@retval RETURN_SUCCESS The attributes were cleared for the
|
|
|
|
memory region.
|
|
|
|
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
|
|
|
|
@retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
|
|
|
|
is not supported
|
|
|
|
**/
|
2017-07-06 15:21:12 +02:00
|
|
|
RETURN_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevClearPageEncMask (
|
|
|
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
|
|
|
IN PHYSICAL_ADDRESS BaseAddress,
|
2021-05-19 20:19:49 +02:00
|
|
|
IN UINTN NumPages
|
2017-07-06 15:21:12 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
This function sets memory encryption bit for the memory region specified by
|
2018-03-01 14:41:01 +01:00
|
|
|
BaseAddress and NumPages from the current page table context.
|
2017-07-06 15:21:12 +02:00
|
|
|
|
2018-03-01 14:41:01 +01:00
|
|
|
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
|
|
|
|
current CR3)
|
|
|
|
@param[in] BaseAddress The physical address that is the start
|
|
|
|
address of a memory region.
|
|
|
|
@param[in] NumPages The number of pages from start memory
|
|
|
|
region.
|
2017-07-06 15:21:12 +02:00
|
|
|
|
2018-03-01 14:41:01 +01:00
|
|
|
@retval RETURN_SUCCESS The attributes were set for the memory
|
|
|
|
region.
|
|
|
|
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
|
|
|
|
@retval RETURN_UNSUPPORTED Setting the memory encryption attribute
|
|
|
|
is not supported
|
|
|
|
**/
|
2017-07-06 15:21:12 +02:00
|
|
|
RETURN_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevSetPageEncMask (
|
|
|
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
|
|
|
IN PHYSICAL_ADDRESS BaseAddress,
|
2021-05-19 20:19:49 +02:00
|
|
|
IN UINTN NumPages
|
2017-07-06 15:21:12 +02:00
|
|
|
);
|
2018-03-01 17:31:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
|
|
|
|
Save State Map.
|
|
|
|
|
|
|
|
@param[out] BaseAddress The base address of the lowest-address page that
|
|
|
|
covers the initial SMRAM Save State Map.
|
|
|
|
|
|
|
|
@param[out] NumberOfPages The number of pages in the page range that covers
|
|
|
|
the initial SMRAM Save State Map.
|
|
|
|
|
|
|
|
@retval RETURN_SUCCESS BaseAddress and NumberOfPages have been set on
|
|
|
|
output.
|
|
|
|
|
|
|
|
@retval RETURN_UNSUPPORTED SMM is unavailable.
|
|
|
|
**/
|
|
|
|
RETURN_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevLocateInitialSmramSaveStateMapPages (
|
|
|
|
OUT UINTN *BaseAddress,
|
|
|
|
OUT UINTN *NumberOfPages
|
|
|
|
);
|
2021-01-07 19:48:16 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Returns the SEV encryption mask.
|
|
|
|
|
|
|
|
@return The SEV pagetable encryption mask
|
|
|
|
**/
|
|
|
|
UINT64
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevGetEncryptionMask (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
2021-01-07 19:48:22 +01:00
|
|
|
/**
|
|
|
|
Returns the encryption state of the specified virtual address range.
|
|
|
|
|
|
|
|
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
|
|
|
|
current CR3)
|
|
|
|
@param[in] BaseAddress Base address to check
|
|
|
|
@param[in] Length Length of virtual address range
|
|
|
|
|
|
|
|
@retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
|
|
|
|
unencrypted
|
|
|
|
@retval MemEncryptSevAddressRangeEncrypted Address range is mapped
|
|
|
|
encrypted
|
|
|
|
@retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
|
|
|
|
@retval MemEncryptSevAddressRangeError Address range is not mapped
|
|
|
|
**/
|
|
|
|
MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevGetAddressRangeState (
|
|
|
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
|
|
|
IN PHYSICAL_ADDRESS BaseAddress,
|
|
|
|
IN UINTN Length
|
|
|
|
);
|
|
|
|
|
2021-05-19 20:19:45 +02:00
|
|
|
/**
|
|
|
|
This function clears memory encryption bit for the MMIO region specified by
|
|
|
|
BaseAddress and NumPages.
|
|
|
|
|
|
|
|
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
|
|
|
|
current CR3)
|
|
|
|
@param[in] BaseAddress The physical address that is the start
|
|
|
|
address of a MMIO region.
|
|
|
|
@param[in] NumPages The number of pages from start memory
|
|
|
|
region.
|
|
|
|
|
|
|
|
@retval RETURN_SUCCESS The attributes were cleared for the
|
|
|
|
memory region.
|
|
|
|
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
|
|
|
|
@retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
|
|
|
|
is not supported
|
|
|
|
**/
|
|
|
|
RETURN_STATUS
|
|
|
|
EFIAPI
|
|
|
|
MemEncryptSevClearMmioPageEncMask (
|
|
|
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
|
|
|
IN PHYSICAL_ADDRESS BaseAddress,
|
|
|
|
IN UINTN NumPages
|
|
|
|
);
|
|
|
|
|
2017-07-06 15:21:12 +02:00
|
|
|
#endif // _MEM_ENCRYPT_SEV_LIB_H_
|