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

Reply via email to