[PATCH] target/i386/tcg: svm: implement GMET

Paolo Bonzini posted 1 patch 5 days, 22 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260327160446.330583-1-pbonzini@redhat.com
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Zhao Liu <zhao1.liu@intel.com>, Richard Henderson <richard.henderson@linaro.org>
target/i386/cpu.h                    |  2 ++
target/i386/svm.h                    |  1 +
target/i386/cpu.c                    |  2 +-
target/i386/tcg/system/excp_helper.c | 20 ++++++++++++++++----
target/i386/tcg/system/svm_helper.c  |  4 ++++
5 files changed, 24 insertions(+), 5 deletions(-)
[PATCH] target/i386/tcg: svm: implement GMET
Posted by Paolo Bonzini 5 days, 22 hours ago
GMET (Guest Mode Execution Trap) has two effects: it disables
the U bit check when the guest is in user mode, and enables
the SMEP check when the guest is in kernel mode.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target/i386/cpu.h                    |  2 ++
 target/i386/svm.h                    |  1 +
 target/i386/cpu.c                    |  2 +-
 target/i386/tcg/system/excp_helper.c | 20 ++++++++++++++++----
 target/i386/tcg/system/svm_helper.c  |  4 ++++
 5 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 0b539155c40..82b7d1a52e4 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -354,6 +354,7 @@ typedef enum X86Seg {
 #define PG_MODE_NXE      (1 << 2)
 #define PG_MODE_PSE      (1 << 3)
 #define PG_MODE_LA57     (1 << 4)
+#define PG_MODE_SVM_GMET (1 << 5)
 #define PG_MODE_SVM_MASK MAKE_64BIT_MASK(0, 15)
 
 /* Bits of CR4 that do not affect the NPT page format.  */
@@ -879,6 +880,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
 #define CPUID_SVM_AVIC            (1U << 13)
 #define CPUID_SVM_V_VMSAVE_VMLOAD (1U << 15)
 #define CPUID_SVM_VGIF            (1U << 16)
+#define CPUID_SVM_GMET            (1U << 17)
 #define CPUID_SVM_VNMI            (1U << 25)
 #define CPUID_SVM_SVME_ADDR_CHK   (1U << 28)
 
diff --git a/target/i386/svm.h b/target/i386/svm.h
index 1bd78447306..e05a66ecc43 100644
--- a/target/i386/svm.h
+++ b/target/i386/svm.h
@@ -140,6 +140,7 @@
 #define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
 
 #define SVM_NPT_ENABLED     (1 << 0)
+#define SVM_GMET_ENABLED    (1 << 3)
 
 #define SVM_NPTEXIT_GPA     (1ULL << 32)
 #define SVM_NPTEXIT_GPT     (1ULL << 33)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index d02f6f0653e..ec80649658c 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -960,7 +960,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
 #else
 #define CPUID_SVM_KERNEL_FEATURES 0
 #endif
-#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \
+#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | CPUID_SVM_GMET | \
           CPUID_SVM_SVME_ADDR_CHK | CPUID_SVM_KERNEL_FEATURES)
 
 #define TCG_KVM_FEATURES 0
diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c
index d7ea77c8558..bd99e8416f5 100644
--- a/target/i386/tcg/system/excp_helper.c
+++ b/target/i386/tcg/system/excp_helper.c
@@ -371,7 +371,9 @@ do_check_protect_pse36:
     ptep ^= PG_NX_MASK;
 
     /* can the page can be put in the TLB?  prot will tell us */
-    if (is_user && !(ptep & PG_USER_MASK)) {
+
+    /* GMET disables checks to the U bit other than the SMEP check below.  */
+    if (is_user && !(ptep & PG_USER_MASK) && !(pg_mode & PG_MODE_SVM_GMET)) {
         goto do_fault_protect;
     }
 
@@ -384,7 +386,7 @@ do_check_protect_pse36:
     }
     if (!(ptep & PG_NX_MASK) &&
         (is_user ||
-         !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) {
+         !((pg_mode & (PG_MODE_SMEP | PG_MODE_SVM_GMET)) && (ptep & PG_USER_MASK)))) {
         prot |= PAGE_EXEC;
     }
 
@@ -543,6 +545,17 @@ static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
     cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr);
 }
 
+static int cpu_mmu_index_svm(CPUX86State *env)
+{
+    unsigned pl = env->hflags & HF_CPL_MASK;
+    int mmu_index_32 = (env->nested_pg_mode & PG_MODE_LMA) ? 0 : 1;
+    int mmu_index_base =
+        pl < 3 && (env->nested_pg_mode & PG_MODE_SVM_GMET)
+        ? MMU_KNOSMAP64_IDX : MMU_USER64_IDX;
+
+    return mmu_index_base + mmu_index_32;
+}
+
 static bool get_physical_address(CPUX86State *env, vaddr addr,
                                  MMUAccessType access_type, int mmu_idx,
                                  TranslateResult *out, TranslateFault *err,
@@ -562,8 +575,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
         if (likely(use_stage2)) {
             in.cr3 = env->nested_cr3;
             in.pg_mode = env->nested_pg_mode;
-            in.mmu_idx =
-                env->nested_pg_mode & PG_MODE_LMA ? MMU_USER64_IDX : MMU_USER32_IDX;
+            in.mmu_idx = cpu_mmu_index_svm(env);
             in.ptw_idx = MMU_PHYS_IDX;
 
             if (!mmu_translate(env, &in, out, err, ra)) {
diff --git a/target/i386/tcg/system/svm_helper.c b/target/i386/tcg/system/svm_helper.c
index d5ffabc2f4d..14e46f00bb6 100644
--- a/target/i386/tcg/system/svm_helper.c
+++ b/target/i386/tcg/system/svm_helper.c
@@ -296,6 +296,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
         env->hflags2 |= HF2_NPT_MASK;
 
         env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
+        if ((nested_ctl & SVM_GMET_ENABLED) &&
+            (env->features[FEAT_SVM] & CPUID_SVM_GMET)) {
+            env->nested_pg_mode |= PG_MODE_SVM_GMET;
+        }
 
         tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
     }
-- 
2.53.0