Accesses using guest-physical addresses may cause SPP-induced VM exits due to an SPPT misconfiguration or an SPPT miss. The basic VM exit reason code reported for SPP-induced VM exits is 66.
An SPPT misconfiguration VM exit occurs when, in the course of translating a guest-physical address, the logical processor encounters a leaf EPT paging-structure entry mapping a 4KB page for which the sub-page write permission control bit is set and during the SPPT lookup an SPPT paging-structure entry contains an unsupported value. An SPPT miss VM exit occurs when, in the course of translation a guest-physical address, the logical processor encounters a leaf EPT paging-structure entry for which the sub-page write permission control bit is set and during the SPPT lookup there is no SPPT misconfiguration but any level of SPPT paging-structure entries are not-present. SPPT misconfigurations and SPPT misses can occur only due to an attempt to write memory with a guest-physical address. Signed-off-by: Zhang Yi <yi.z.zh...@linux.intel.com> Signed-off-by: He Chen <he.c...@linux.intel.com> --- arch/x86/include/asm/vmx.h | 7 +++++++ arch/x86/include/uapi/asm/vmx.h | 2 ++ arch/x86/kvm/vmx.c | 45 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index bd4ec8a..ee24eb2 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -539,6 +539,13 @@ struct vmx_msr_entry { #define EPT_VIOLATION_GVA_TRANSLATED (1 << EPT_VIOLATION_GVA_TRANSLATED_BIT) /* + * Exit Qualifications for SPPT-Induced VM Exits + */ +#define SPPT_INDUCED_EXIT_TYPE_BIT 11 +#define SPPT_INDUCED_EXIT_TYPE (1 << SPPT_INDUCED_EXIT_TYPE_BIT) +#define SPPT_INTR_INFO_UNBLOCK_NMI INTR_INFO_UNBLOCK_NMI + +/* * VM-instruction error numbers */ enum vm_instruction_error_number { diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index f0b0c90..ac67622 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -85,6 +85,7 @@ #define EXIT_REASON_PML_FULL 62 #define EXIT_REASON_XSAVES 63 #define EXIT_REASON_XRSTORS 64 +#define EXIT_REASON_SPP 66 #define VMX_EXIT_REASONS \ { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ @@ -141,6 +142,7 @@ { EXIT_REASON_ENCLS, "ENCLS" }, \ { EXIT_REASON_RDSEED, "RDSEED" }, \ { EXIT_REASON_PML_FULL, "PML_FULL" }, \ + { EXIT_REASON_SPP, "SPP" }, \ { EXIT_REASON_XSAVES, "XSAVES" }, \ { EXIT_REASON_XRSTORS, "XRSTORS" } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e96b4c7..6634098 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9698,6 +9698,50 @@ static int handle_invpcid(struct kvm_vcpu *vcpu) } } +static int handle_spp(struct kvm_vcpu *vcpu) +{ + unsigned long exit_qualification; + + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + + /* + * SPP VM exit happened while executing iret from NMI, + * "blocked by NMI" bit has to be set before next VM entry. + * There are errata that may cause this bit to not be set: + * AAK134, BY25. + */ + if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && + (exit_qualification & SPPT_INTR_INFO_UNBLOCK_NMI)) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + + pr_debug("SPP: SPP exit_qualification=%lx\n", exit_qualification); + + vcpu->arch.exit_qualification = exit_qualification; + + if (exit_qualification & SPPT_INDUCED_EXIT_TYPE) { + /* + * SPPT Miss + * We don't set SPP write access for the corresponding + * GPA, if we haven't setup, we need to construct + * SPP table here. + */ + pr_debug("SPP: %s: SPPT Miss!!!\n", __func__); + return 1; + } + + /* + * SPPT Misconfig + * This is probably possible that your sppt table + * set as a incorrect format + */ + WARN_ON(1); + vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; + vcpu->run->hw.hardware_exit_reason = EXIT_REASON_SPP; + pr_alert("SPP: %s: SPPT Misconfiguration!!!\n", __func__); + return 0; +} + static int handle_pml_full(struct kvm_vcpu *vcpu) { unsigned long exit_qualification; @@ -9910,6 +9954,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_INVVPID] = handle_invvpid, [EXIT_REASON_RDRAND] = handle_invalid_op, [EXIT_REASON_RDSEED] = handle_invalid_op, + [EXIT_REASON_SPP] = handle_spp, [EXIT_REASON_XSAVES] = handle_xsaves, [EXIT_REASON_XRSTORS] = handle_xrstors, [EXIT_REASON_PML_FULL] = handle_pml_full, -- 2.7.4