KVM: SVM: Provide an updated VMRUN invocation for SEV-ES guests
[linux-block.git] / arch / x86 / kvm / svm / svm.h
index 1d853fe4c778b56c09c87a2773e5e4bcab222cf7..a5067f776ce0c4e64a8822a57dc35998c0dbb9ed 100644 (file)
 
 #include <linux/kvm_types.h>
 #include <linux/kvm_host.h>
+#include <linux/bits.h>
 
 #include <asm/svm.h>
 
-static const u32 host_save_user_msrs[] = {
+#define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
+
+static const struct svm_host_save_msrs {
+       u32 index;              /* Index of the MSR */
+       bool sev_es_restored;   /* True if MSR is restored on SEV-ES VMEXIT */
+} host_save_user_msrs[] = {
 #ifdef CONFIG_X86_64
-       MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
-       MSR_FS_BASE,
+       { .index = MSR_STAR,                    .sev_es_restored = true },
+       { .index = MSR_LSTAR,                   .sev_es_restored = true },
+       { .index = MSR_CSTAR,                   .sev_es_restored = true },
+       { .index = MSR_SYSCALL_MASK,            .sev_es_restored = true },
+       { .index = MSR_KERNEL_GS_BASE,          .sev_es_restored = true },
+       { .index = MSR_FS_BASE,                 .sev_es_restored = true },
 #endif
-       MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-       MSR_TSC_AUX,
+       { .index = MSR_IA32_SYSENTER_CS,        .sev_es_restored = true },
+       { .index = MSR_IA32_SYSENTER_ESP,       .sev_es_restored = true },
+       { .index = MSR_IA32_SYSENTER_EIP,       .sev_es_restored = true },
+       { .index = MSR_TSC_AUX,                 .sev_es_restored = false },
 };
-
 #define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
 
-#define MAX_DIRECT_ACCESS_MSRS 15
+#define MAX_DIRECT_ACCESS_MSRS 18
 #define MSRPM_OFFSETS  16
 extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
 extern bool npt_enabled;
@@ -61,6 +72,7 @@ enum {
 
 struct kvm_sev_info {
        bool active;            /* SEV enabled guest */
+       bool es_active;         /* SEV-ES enabled guest */
        unsigned int asid;      /* ASID used for this guest */
        unsigned int handle;    /* SEV firmware handle */
        int fd;                 /* SEV device fd */
@@ -106,6 +118,7 @@ struct vcpu_svm {
        struct vmcb *vmcb;
        unsigned long vmcb_pa;
        struct svm_cpu_data *svm_data;
+       u32 asid;
        uint64_t asid_generation;
        uint64_t sysenter_esp;
        uint64_t sysenter_eip;
@@ -166,6 +179,17 @@ struct vcpu_svm {
                DECLARE_BITMAP(read, MAX_DIRECT_ACCESS_MSRS);
                DECLARE_BITMAP(write, MAX_DIRECT_ACCESS_MSRS);
        } shadow_msr_intercept;
+
+       /* SEV-ES support */
+       struct vmcb_save_area *vmsa;
+       struct ghcb *ghcb;
+       struct kvm_host_map ghcb_map;
+
+       /* SEV-ES scratch area support */
+       void *ghcb_sa;
+       u64 ghcb_sa_len;
+       bool ghcb_sa_sync;
+       bool ghcb_sa_free;
 };
 
 struct svm_cpu_data {
@@ -193,6 +217,28 @@ static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
        return container_of(kvm, struct kvm_svm, kvm);
 }
 
+static inline bool sev_guest(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev->active;
+#else
+       return false;
+#endif
+}
+
+static inline bool sev_es_guest(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev_guest(kvm) && sev->es_active;
+#else
+       return false;
+#endif
+}
+
 static inline void vmcb_mark_all_dirty(struct vmcb *vmcb)
 {
        vmcb->control.clean = 0;
@@ -244,21 +290,24 @@ static inline void set_dr_intercepts(struct vcpu_svm *svm)
 {
        struct vmcb *vmcb = get_host_vmcb(svm);
 
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ);
+       if (!sev_es_guest(svm->vcpu.kvm)) {
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE);
+       }
+
        vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE);
        vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
 
        recalc_intercepts(svm);
@@ -270,6 +319,12 @@ static inline void clr_dr_intercepts(struct vcpu_svm *svm)
 
        vmcb->control.intercepts[INTERCEPT_DR] = 0;
 
+       /* DR7 access must remain intercepted for an SEV-ES guest */
+       if (sev_es_guest(svm->vcpu.kvm)) {
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
+       }
+
        recalc_intercepts(svm);
 }
 
@@ -351,6 +406,10 @@ static inline bool gif_set(struct vcpu_svm *svm)
 #define MSR_CR3_LONG_MBZ_MASK                  0xfff0000000000000U
 #define MSR_INVALID                            0xffffffffU
 
+extern int sev;
+extern int sev_es;
+extern bool dump_invalid_vmcb;
+
 u32 svm_msrpm_offset(u32 msr);
 u32 *svm_vcpu_alloc_msrpm(void);
 void svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm);
@@ -358,13 +417,16 @@ void svm_vcpu_free_msrpm(u32 *msrpm);
 
 int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer);
 void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
 void svm_flush_tlb(struct kvm_vcpu *vcpu);
 void disable_nmi_singlestep(struct vcpu_svm *svm);
 bool svm_smi_blocked(struct kvm_vcpu *vcpu);
 bool svm_nmi_blocked(struct kvm_vcpu *vcpu);
 bool svm_interrupt_blocked(struct kvm_vcpu *vcpu);
 void svm_set_gif(struct vcpu_svm *svm, bool value);
+int svm_invoke_exit_handler(struct vcpu_svm *svm, u64 exit_code);
+void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
+                         int read, int write);
 
 /* nested.c */
 
@@ -470,18 +532,42 @@ void svm_vcpu_unblocking(struct kvm_vcpu *vcpu);
 
 /* sev.c */
 
-extern unsigned int max_sev_asid;
+#define GHCB_VERSION_MAX               1ULL
+#define GHCB_VERSION_MIN               1ULL
+
+#define GHCB_MSR_INFO_POS              0
+#define GHCB_MSR_INFO_MASK             (BIT_ULL(12) - 1)
+
+#define GHCB_MSR_SEV_INFO_RESP         0x001
+#define GHCB_MSR_SEV_INFO_REQ          0x002
+#define GHCB_MSR_VER_MAX_POS           48
+#define GHCB_MSR_VER_MAX_MASK          0xffff
+#define GHCB_MSR_VER_MIN_POS           32
+#define GHCB_MSR_VER_MIN_MASK          0xffff
+#define GHCB_MSR_CBIT_POS              24
+#define GHCB_MSR_CBIT_MASK             0xff
+#define GHCB_MSR_SEV_INFO(_max, _min, _cbit)                           \
+       ((((_max) & GHCB_MSR_VER_MAX_MASK) << GHCB_MSR_VER_MAX_POS) |   \
+        (((_min) & GHCB_MSR_VER_MIN_MASK) << GHCB_MSR_VER_MIN_POS) |   \
+        (((_cbit) & GHCB_MSR_CBIT_MASK) << GHCB_MSR_CBIT_POS) |        \
+        GHCB_MSR_SEV_INFO_RESP)
+
+#define GHCB_MSR_CPUID_REQ             0x004
+#define GHCB_MSR_CPUID_RESP            0x005
+#define GHCB_MSR_CPUID_FUNC_POS                32
+#define GHCB_MSR_CPUID_FUNC_MASK       0xffffffff
+#define GHCB_MSR_CPUID_VALUE_POS       32
+#define GHCB_MSR_CPUID_VALUE_MASK      0xffffffff
+#define GHCB_MSR_CPUID_REG_POS         30
+#define GHCB_MSR_CPUID_REG_MASK                0x3
+
+#define GHCB_MSR_TERM_REQ              0x100
+#define GHCB_MSR_TERM_REASON_SET_POS   12
+#define GHCB_MSR_TERM_REASON_SET_MASK  0xf
+#define GHCB_MSR_TERM_REASON_POS       16
+#define GHCB_MSR_TERM_REASON_MASK      0xff
 
-static inline bool sev_guest(struct kvm *kvm)
-{
-#ifdef CONFIG_KVM_AMD_SEV
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       return sev->active;
-#else
-       return false;
-#endif
-}
+extern unsigned int max_sev_asid;
 
 static inline bool svm_sev_enabled(void)
 {
@@ -495,7 +581,19 @@ int svm_register_enc_region(struct kvm *kvm,
 int svm_unregister_enc_region(struct kvm *kvm,
                              struct kvm_enc_region *range);
 void pre_sev_run(struct vcpu_svm *svm, int cpu);
-int __init sev_hardware_setup(void);
+void __init sev_hardware_setup(void);
 void sev_hardware_teardown(void);
+void sev_free_vcpu(struct kvm_vcpu *vcpu);
+int sev_handle_vmgexit(struct vcpu_svm *svm);
+int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
+void sev_es_init_vmcb(struct vcpu_svm *svm);
+void sev_es_create_vcpu(struct vcpu_svm *svm);
+void sev_es_vcpu_load(struct vcpu_svm *svm, int cpu);
+void sev_es_vcpu_put(struct vcpu_svm *svm);
+
+/* vmenter.S */
+
+void __svm_sev_es_vcpu_run(unsigned long vmcb_pa);
+void __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs);
 
 #endif