diff mbox series

target/i386: Added VGIF feature

Message ID 20210723112753.46047-1-laramglazier@gmail.com
State New
Headers show
Series target/i386: Added VGIF feature | expand

Commit Message

Lara Lazier July 23, 2021, 11:27 a.m. UTC
VGIF allows STGI and CLGI to execute in guest mode and control virtual
interrupts in guest mode.
When the VGIF feature is enabled then:
 * executing STGI in the guest sets bit 9 of the VMCB offset 60h.
 * executing CLGI in the guest clears bit 9 of the VMCB offset 60h.

Signed-off-by: Lara Lazier <laramglazier@gmail.com>
---
 target/i386/cpu.c                   |  3 ++-
 target/i386/svm.h                   |  6 +++++
 target/i386/tcg/sysemu/svm_helper.c | 36 +++++++++++++++++++++++++----
 3 files changed, 39 insertions(+), 6 deletions(-)

Comments

Paolo Bonzini July 23, 2021, 1:52 p.m. UTC | #1
On 23/07/21 13:27, Lara Lazier wrote:
> @@ -353,9 +358,12 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
>           tlb_flush(cs);
>           break;
>       }
> -
> -    env->hflags2 |= HF2_GIF_MASK;
> -
> +    if (virtual_gif_enabled(env, int_ctl)) {
> +        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
> +                        int_ctl |= V_GIF_MASK);
> +    } else {
> +        env->hflags2 |= HF2_GIF_MASK;
> +    }

This should not be changed, because it is setting the "real" GIF; vGIF 
hasn't taken effect yet.

The CLGI/VMRUN/STGI sequence is there to avoid delivering an interrupt 
while the processor state has been partly changed to whatever the guest 
wants.  VMRUN sets GIF so that it is possible for interrupts (or 
NMI/SMI) to cause a vmexit, but the vmexit immediately clears the GIF 
again so that it is only handled after the host executes STGI.

>       if (int_ctl & V_IRQ_MASK) {
>           CPUState *cs = env_cpu(env);
>   
> @@ -513,13 +521,31 @@ void helper_vmsave(CPUX86State *env, int aflag)
>   void helper_stgi(CPUX86State *env)
>   {
>       cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
> -    env->hflags2 |= HF2_GIF_MASK;
> +
> +    CPUState *cs = env_cpu(env);
> +    uint32_t int_ctl = x86_ldl_phys(cs,
> +                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
> +    if (virtual_gif_enabled(env, int_ctl) && likely(env->hflags & HF_GUEST_MASK)) {
> +        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
> +                        int_ctl |= V_GIF_MASK);

No need to use "|=", likewise for "&=" below.

Thanks,

Paolo

> +    } else {
> +        env->hflags2 |= HF2_GIF_MASK;
> +    }
>   }
>   
>   void helper_clgi(CPUX86State *env)
>   {
>       cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
> -    env->hflags2 &= ~HF2_GIF_MASK;
> +
> +    CPUState *cs = env_cpu(env);
> +    uint32_t int_ctl = x86_ldl_phys(cs,
> +                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
> +    if (virtual_gif_enabled(env, int_ctl) && likely(env->hflags & HF_GUEST_MASK)) {
> +        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
> +                        int_ctl &= ~V_GIF_MASK);
> +    } else {
> +        env->hflags2 &= ~HF2_GIF_MASK;
> +    }
>   }
>   
>   bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)
>
diff mbox series

Patch

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 48b55ebd0a..5e6d2b4294 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -631,7 +631,8 @@  void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
 #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
           CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
 #define TCG_EXT4_FEATURES 0
-#define TCG_SVM_FEATURES CPUID_SVM_NPT
+#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \
+          CPUID_SVM_SVME_ADDR_CHK)
 #define TCG_KVM_FEATURES 0
 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \
           CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
diff --git a/target/i386/svm.h b/target/i386/svm.h
index e54670ef12..dab2f90925 100644
--- a/target/i386/svm.h
+++ b/target/i386/svm.h
@@ -9,6 +9,12 @@ 
 #define V_IRQ_SHIFT 8
 #define V_IRQ_MASK (1 << V_IRQ_SHIFT)
 
+#define V_GIF_ENABLED_SHIFT 25
+#define V_GIF_ENABLED_MASK (1 << V_GIF_ENABLED_SHIFT)
+
+#define V_GIF_SHIFT 9
+#define V_GIF_MASK (1 << V_GIF_SHIFT)
+
 #define V_INTR_PRIO_SHIFT 16
 #define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
 
diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c
index 6118f6f587..ea85e3cae8 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -118,6 +118,11 @@  static inline void svm_vmrun_canonicalization(CPUX86State *env)
     env->tr.base = (long) ((uint32_t) env->tr.base);
 }
 
+static inline bool virtual_gif_enabled(CPUX86State *env, uint32_t int_ctl)
+{
+    return (int_ctl & V_GIF_ENABLED_MASK) && (env->features[FEAT_SVM] & CPUID_SVM_VGIF);
+}
+
 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
 {
     CPUState *cs = env_cpu(env);
@@ -353,9 +358,12 @@  void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
         tlb_flush(cs);
         break;
     }
-
-    env->hflags2 |= HF2_GIF_MASK;
-
+    if (virtual_gif_enabled(env, int_ctl)) {
+        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
+                        int_ctl |= V_GIF_MASK);
+    } else {
+        env->hflags2 |= HF2_GIF_MASK;
+    }
     if (int_ctl & V_IRQ_MASK) {
         CPUState *cs = env_cpu(env);
 
@@ -513,13 +521,31 @@  void helper_vmsave(CPUX86State *env, int aflag)
 void helper_stgi(CPUX86State *env)
 {
     cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
-    env->hflags2 |= HF2_GIF_MASK;
+
+    CPUState *cs = env_cpu(env);
+    uint32_t int_ctl = x86_ldl_phys(cs,
+                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    if (virtual_gif_enabled(env, int_ctl) && likely(env->hflags & HF_GUEST_MASK)) {
+        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
+                        int_ctl |= V_GIF_MASK);
+    } else {
+        env->hflags2 |= HF2_GIF_MASK;
+    }
 }
 
 void helper_clgi(CPUX86State *env)
 {
     cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
-    env->hflags2 &= ~HF2_GIF_MASK;
+
+    CPUState *cs = env_cpu(env);
+    uint32_t int_ctl = x86_ldl_phys(cs,
+                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    if (virtual_gif_enabled(env, int_ctl) && likely(env->hflags & HF_GUEST_MASK)) {
+        x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
+                        int_ctl &= ~V_GIF_MASK);
+    } else {
+        env->hflags2 &= ~HF2_GIF_MASK;
+    }
 }
 
 bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type)