Exposing SEV CPUID leaf informs the guest of SEV support,
but activation of the features requires setting bit 0 in
the SEV MSR (0xc0010131).
sev_emulated_enable() is implemented to enable the MSR only when
emulation is active. This is invoked from helper_rdmsr() to control
MSR write behavior.
SEV MSR activation prompts OVMF to use C-bits in PTEs, altering paging.
To address this, C-bits are reset in all PTEs and CR3 via
sev_emulated_convert_pte().
This change enables the features of the guest adding to QEMU arguments:
-cpu "EPYC-Milan" \
-accel tcg \
-object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
-machine memory-encryption=sev0
A SEV capable cpu profile must be selected to enable the emulation.
Signed-off-by: Tommaso Califano <[email protected]>
---
target/i386/cpu.h | 2 ++
target/i386/sev.c | 18 ++++++++++++++++
target/i386/sev.h | 3 +++
target/i386/tcg/system/excp_helper.c | 31 ++++++++++++++++++++++++++++
target/i386/tcg/system/misc_helper.c | 13 ++++++++++++
5 files changed, 67 insertions(+)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 0b539155c4..dc2f82837f 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -659,6 +659,8 @@ typedef enum X86Seg {
#define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT)
#define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT)
+/* AMD SEV MSR */
+#define MSR_AMD64_SEV 0xc0010131
/* CPUID feature bits available in XCR0 */
#define CPUID_XSTATE_XCR0_MASK (XSTATE_FP_MASK | XSTATE_SSE_MASK | \
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 2502e860e2..cdadd83ab5 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -690,6 +690,14 @@ static int sev_set_cpu_context(uint16_t cpu_index, const
void *ctx,
return 0;
}
+bool
+sev_emulated_enabled(void)
+{
+ ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
+
+ return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_EMULATED);
+}
+
bool
sev_enabled(void)
{
@@ -731,6 +739,16 @@ sev_get_reduced_phys_bits(void)
return sev_common ? sev_common->reduced_phys_bits : 0;
}
+uint64_t
+sev_emulated_convert_pte(uint64_t pte)
+{
+ if (unlikely(sev_emulated_enabled())) {
+ pte &= ~(1ULL << sev_get_cbit_position());
+ }
+
+ return pte;
+}
+
static SevInfo *sev_get_info(void)
{
SevInfo *info;
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 839656e2be..d69275d40f 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -24,10 +24,12 @@
#define sev_enabled() 0
#define sev_es_enabled() 0
#define sev_snp_enabled() 0
+#define sev_emulated_enabled() 0
#else
bool sev_enabled(void);
bool sev_es_enabled(void);
bool sev_snp_enabled(void);
+bool sev_emulated_enabled(void);
#endif
#if !defined(CONFIG_USER_ONLY)
@@ -197,5 +199,6 @@ void pc_system_parse_sev_metadata(uint8_t *flash_ptr,
size_t flash_size);
uint32_t sev_get_cbit_position(void);
uint32_t sev_get_reduced_phys_bits(void);
+uint64_t sev_emulated_convert_pte(uint64_t);
#endif
diff --git a/target/i386/tcg/system/excp_helper.c
b/target/i386/tcg/system/excp_helper.c
index d7ea77c855..307a4a7e6b 100644
--- a/target/i386/tcg/system/excp_helper.c
+++ b/target/i386/tcg/system/excp_helper.c
@@ -26,6 +26,7 @@
#include "exec/target_page.h"
#include "exec/tlb-flags.h"
#include "tcg/helper-tcg.h"
+#include "sev.h"
typedef struct TranslateParams {
target_ulong addr;
@@ -160,7 +161,13 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
int prot;
restart_all:
+#ifdef CONFIG_SEV
+ rsvd_mask = ~MAKE_64BIT_MASK(0,
+ env_archcpu(env)->phys_bits - sev_get_reduced_phys_bits());
+ rsvd_mask = sev_emulated_convert_pte(rsvd_mask);
+#else
rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
+#endif
rsvd_mask &= PG_ADDRESS_MASK;
if (!(pg_mode & PG_MODE_NXE)) {
rsvd_mask |= PG_NX_MASK;
@@ -179,6 +186,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
}
restart_5:
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -203,6 +213,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
}
restart_4:
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -223,6 +236,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
}
restart_3_lma:
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -251,6 +267,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
rsvd_mask |= PG_HI_USER_MASK;
restart_3_nolma:
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -272,6 +291,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
}
restart_2_pae:
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -297,6 +319,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
return false;
}
pte = ptw_ldq(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -316,6 +341,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
}
restart_2_nopae:
pte = ptw_ldl(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
@@ -344,6 +372,9 @@ static bool mmu_translate(CPUX86State *env, const
TranslateParams *in,
return false;
}
pte = ptw_ldl(&pte_trans, ra);
+ #ifdef CONFIG_SEV
+ pte = sev_emulated_convert_pte(pte);
+ #endif
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
diff --git a/target/i386/tcg/system/misc_helper.c
b/target/i386/tcg/system/misc_helper.c
index bb79d4e470..aa6ed5cda1 100644
--- a/target/i386/tcg/system/misc_helper.c
+++ b/target/i386/tcg/system/misc_helper.c
@@ -27,6 +27,7 @@
#include "exec/cputlb.h"
#include "tcg/helper-tcg.h"
#include "hw/i386/apic.h"
+#include "target/i386/sev.h"
void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
{
@@ -89,6 +90,10 @@ void helper_write_crN(CPUX86State *env, int reg,
target_ulong t0)
cpu_x86_update_cr0(env, t0);
break;
case 3:
+ #ifdef CONFIG_SEV
+ /* If SEV emulation is active, reset the C-bit */
+ t0 = sev_emulated_convert_pte(t0);
+ #endif
if ((env->efer & MSR_EFER_LMA) &&
(t0 & ((~0ULL) << env_archcpu(env)->phys_bits))) {
cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
@@ -468,6 +473,14 @@ void helper_rdmsr(CPUX86State *env)
case MSR_IA32_UCODE_REV:
val = x86_cpu->ucode_rev;
break;
+ case MSR_AMD64_SEV:
+ if (sev_emulated_enabled()) {
+ val = 1;
+ } else {
+ /* XXX: exception? */
+ val = 0;
+ }
+ break;
case MSR_CORE_THREAD_COUNT: {
val = cpu_x86_get_msr_core_thread_count(x86_cpu);
break;
--
2.53.0