]> git.proxmox.com Git - pve-kernel.git/blobdiff - patches/kernel/0015-KVM-x86-emulator-smm-preserve-interrupt-shadow-in-SM.patch
rebase patches on top of Ubuntu-6.1.0-12.12
[pve-kernel.git] / patches / kernel / 0015-KVM-x86-emulator-smm-preserve-interrupt-shadow-in-SM.patch
diff --git a/patches/kernel/0015-KVM-x86-emulator-smm-preserve-interrupt-shadow-in-SM.patch b/patches/kernel/0015-KVM-x86-emulator-smm-preserve-interrupt-shadow-in-SM.patch
new file mode 100644 (file)
index 0000000..7248b78
--- /dev/null
@@ -0,0 +1,180 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <mlevitsk@redhat.com>
+Date: Wed, 3 Aug 2022 18:50:11 +0300
+Subject: [PATCH] KVM: x86: emulator/smm: preserve interrupt shadow in SMRAM
+
+When #SMI is asserted, the CPU can be in interrupt shadow
+due to sti or mov ss.
+
+It is not mandatory in  Intel/AMD prm to have the #SMI
+blocked during the shadow, and on top of
+that, since neither SVM nor VMX has true support for SMI
+window, waiting for one instruction would mean single stepping
+the guest.
+
+Instead, allow #SMI in this case, but both reset the interrupt
+window and stash its value in SMRAM to restore it on exit
+from SMM.
+
+This fixes rare failures seen mostly on windows guests on VMX,
+when #SMI falls on the sti instruction which mainfest in
+VM entry failure due to EFLAGS.IF not being set, but STI interrupt
+window still being set in the VMCS.
+
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ arch/x86/kvm/emulate.c     | 17 ++++++++++++++---
+ arch/x86/kvm/kvm_emulate.h | 10 ++++++----
+ arch/x86/kvm/x86.c         | 12 ++++++++++++
+ 3 files changed, 32 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
+index 03f9e5aa036e..bb008a5be539 100644
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -2435,7 +2435,7 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt,
+                            const struct kvm_smram_state_32 *smstate)
+ {
+       struct desc_ptr dt;
+-      int i;
++      int i, r;
+       ctxt->eflags =  smstate->eflags | X86_EFLAGS_FIXED;
+       ctxt->_eip =  smstate->eip;
+@@ -2470,8 +2470,16 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt,
+       ctxt->ops->set_smbase(ctxt, smstate->smbase);
+-      return rsm_enter_protected_mode(ctxt, smstate->cr0,
+-                                      smstate->cr3, smstate->cr4);
++      r = rsm_enter_protected_mode(ctxt, smstate->cr0,
++                                   smstate->cr3, smstate->cr4);
++
++      if (r != X86EMUL_CONTINUE)
++              return r;
++
++      ctxt->ops->set_int_shadow(ctxt, 0);
++      ctxt->interruptibility = (u8)smstate->int_shadow;
++
++      return X86EMUL_CONTINUE;
+ }
+ #ifdef CONFIG_X86_64
+@@ -2520,6 +2528,9 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt,
+       rsm_load_seg_64(ctxt, &smstate->fs, VCPU_SREG_FS);
+       rsm_load_seg_64(ctxt, &smstate->gs, VCPU_SREG_GS);
++      ctxt->ops->set_int_shadow(ctxt, 0);
++      ctxt->interruptibility = (u8)smstate->int_shadow;
++
+       return X86EMUL_CONTINUE;
+ }
+ #endif
+diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
+index 76c0b8e7890b..a7313add0f2a 100644
+--- a/arch/x86/kvm/kvm_emulate.h
++++ b/arch/x86/kvm/kvm_emulate.h
+@@ -234,6 +234,7 @@ struct x86_emulate_ops {
+       bool (*guest_has_rdpid)(struct x86_emulate_ctxt *ctxt);
+       void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked);
++      void (*set_int_shadow)(struct x86_emulate_ctxt *ctxt, u8 shadow);
+       unsigned (*get_hflags)(struct x86_emulate_ctxt *ctxt);
+       void (*exiting_smm)(struct x86_emulate_ctxt *ctxt);
+@@ -518,7 +519,8 @@ struct kvm_smram_state_32 {
+       u32 reserved1[62];
+       u32 smbase;
+       u32 smm_revision;
+-      u32 reserved2[5];
++      u32 reserved2[4];
++      u32 int_shadow; /* KVM extension */
+       u32 cr4; /* CR4 is not present in Intel/AMD SMRAM image */
+       u32 reserved3[5];
+@@ -566,6 +568,7 @@ static inline void __check_smram32_offsets(void)
+       __CHECK_SMRAM32_OFFSET(smbase,          0xFEF8);
+       __CHECK_SMRAM32_OFFSET(smm_revision,    0xFEFC);
+       __CHECK_SMRAM32_OFFSET(reserved2,       0xFF00);
++      __CHECK_SMRAM32_OFFSET(int_shadow,      0xFF10);
+       __CHECK_SMRAM32_OFFSET(cr4,             0xFF14);
+       __CHECK_SMRAM32_OFFSET(reserved3,       0xFF18);
+       __CHECK_SMRAM32_OFFSET(ds,              0xFF2C);
+@@ -625,7 +628,7 @@ struct kvm_smram_state_64 {
+       u64 io_restart_rsi;
+       u64 io_restart_rdi;
+       u32 io_restart_dword;
+-      u32 reserved1;
++      u32 int_shadow;
+       u8 io_inst_restart;
+       u8 auto_hlt_restart;
+       u8 reserved2[6];
+@@ -663,7 +666,6 @@ struct kvm_smram_state_64 {
+       u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */
+ };
+-
+ static inline void __check_smram64_offsets(void)
+ {
+ #define __CHECK_SMRAM64_OFFSET(field, offset) \
+@@ -684,7 +686,7 @@ static inline void __check_smram64_offsets(void)
+       __CHECK_SMRAM64_OFFSET(io_restart_rsi,          0xFEB0);
+       __CHECK_SMRAM64_OFFSET(io_restart_rdi,          0xFEB8);
+       __CHECK_SMRAM64_OFFSET(io_restart_dword,        0xFEC0);
+-      __CHECK_SMRAM64_OFFSET(reserved1,               0xFEC4);
++      __CHECK_SMRAM64_OFFSET(int_shadow,              0xFEC4);
+       __CHECK_SMRAM64_OFFSET(io_inst_restart,         0xFEC8);
+       __CHECK_SMRAM64_OFFSET(auto_hlt_restart,        0xFEC9);
+       __CHECK_SMRAM64_OFFSET(reserved2,               0xFECA);
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index 7a4d86f9bdcd..609829ec1d13 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -8173,6 +8173,11 @@ static void emulator_set_nmi_mask(struct x86_emulate_ctxt *ctxt, bool masked)
+       static_call(kvm_x86_set_nmi_mask)(emul_to_vcpu(ctxt), masked);
+ }
++static void emulator_set_int_shadow(struct x86_emulate_ctxt *ctxt, u8 shadow)
++{
++       static_call(kvm_x86_set_interrupt_shadow)(emul_to_vcpu(ctxt), shadow);
++}
++
+ static unsigned emulator_get_hflags(struct x86_emulate_ctxt *ctxt)
+ {
+       return emul_to_vcpu(ctxt)->arch.hflags;
+@@ -8253,6 +8258,7 @@ static const struct x86_emulate_ops emulate_ops = {
+       .guest_has_fxsr      = emulator_guest_has_fxsr,
+       .guest_has_rdpid     = emulator_guest_has_rdpid,
+       .set_nmi_mask        = emulator_set_nmi_mask,
++      .set_int_shadow      = emulator_set_int_shadow,
+       .get_hflags          = emulator_get_hflags,
+       .exiting_smm         = emulator_exiting_smm,
+       .leave_smm           = emulator_leave_smm,
+@@ -10170,6 +10176,8 @@ static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, struct kvm_smram_stat
+       smram->cr4 = kvm_read_cr4(vcpu);
+       smram->smm_revision = 0x00020000;
+       smram->smbase = vcpu->arch.smbase;
++
++      smram->int_shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu);
+ }
+ #ifdef CONFIG_X86_64
+@@ -10218,6 +10226,8 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, struct kvm_smram_stat
+       enter_smm_save_seg_64(vcpu, &smram->ds, VCPU_SREG_DS);
+       enter_smm_save_seg_64(vcpu, &smram->fs, VCPU_SREG_FS);
+       enter_smm_save_seg_64(vcpu, &smram->gs, VCPU_SREG_GS);
++
++      smram->int_shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu);
+ }
+ #endif
+@@ -10254,6 +10264,8 @@ static void enter_smm(struct kvm_vcpu *vcpu)
+       kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
+       kvm_rip_write(vcpu, 0x8000);
++      static_call(kvm_x86_set_interrupt_shadow)(vcpu, 0);
++
+       cr0 = vcpu->arch.cr0 & ~(X86_CR0_PE | X86_CR0_EM | X86_CR0_TS | X86_CR0_PG);
+       static_call(kvm_x86_set_cr0)(vcpu, cr0);
+       vcpu->arch.cr0 = cr0;