On 05/19/2013 12:52 PM, Jun Nakajima wrote:
> Add code to detect EPT misconfiguration and inject it to L1 VMM. Also,
> it injects more correct exit qualification upon EPT violation to L1
> VMM.  Now L1 can correctly go to ept_misconfig handler (instead of
> wrongly going to fast_page_fault), it will try to handle mmio page
> fault, if failed, it is a real EPT misconfiguration.
> 
> Signed-off-by: Jun Nakajima <jun.nakaj...@intel.com>
> Signed-off-by: Xinhao Xu <xinhao...@intel.com>
> ---
>  arch/x86/include/asm/kvm_host.h |  4 +++
>  arch/x86/kvm/mmu.c              |  5 ---
>  arch/x86/kvm/mmu.h              |  5 +++
>  arch/x86/kvm/paging_tmpl.h      | 26 ++++++++++++++
>  arch/x86/kvm/vmx.c              | 79 
> +++++++++++++++++++++++++++++++++++++++--
>  5 files changed, 111 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 3741c65..1d03202 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -262,6 +262,8 @@ struct kvm_mmu {
>       void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
>       void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
>                          u64 *spte, const void *pte);
> +     bool (*check_tdp_pte)(u64 pte, int level);
> +
>       hpa_t root_hpa;
>       int root_level;
>       int shadow_root_level;
> @@ -503,6 +505,8 @@ struct kvm_vcpu_arch {
>        * instruction.
>        */
>       bool write_fault_to_shadow_pgtable;
> +
> +     unsigned long exit_qualification; /* set at EPT violation at this point 
> */
>  };
> 
>  struct kvm_lpage_info {
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index 93d6abf..3a3b11f 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -233,11 +233,6 @@ static bool set_mmio_spte(u64 *sptep, gfn_t gfn, pfn_t 
> pfn, unsigned access)
>       return false;
>  }
> 
> -static inline u64 rsvd_bits(int s, int e)
> -{
> -     return ((1ULL << (e - s + 1)) - 1) << s;
> -}
> -
>  void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
>               u64 dirty_mask, u64 nx_mask, u64 x_mask)
>  {
> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> index 8fc94dd..559e2e0 100644
> --- a/arch/x86/kvm/mmu.h
> +++ b/arch/x86/kvm/mmu.h
> @@ -88,6 +88,11 @@ static inline bool is_write_protection(struct kvm_vcpu 
> *vcpu)
>       return kvm_read_cr0_bits(vcpu, X86_CR0_WP);
>  }
> 
> +static inline u64 rsvd_bits(int s, int e)
> +{
> +     return ((1ULL << (e - s + 1)) - 1) << s;
> +}
> +
>  /*
>   * Will a fault with a given page-fault error code (pfec) cause a permission
>   * fault with the given access (in ACC_* format)?
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index 2432d49..067b1f8 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -126,10 +126,14 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, 
> struct kvm_mmu *mmu,
> 
>  static bool FNAME(is_rsvd_bits_set)(struct kvm_mmu *mmu, u64 gpte, int level)
>  {
> +#if PTTYPE == PTTYPE_EPT
> +     return (mmu->check_tdp_pte(gpte, level));
> +#else
>       int bit7;
> 
>       bit7 = (gpte >> 7) & 1;
>       return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0;
> +#endif
>  }

It is better that set mmu->check_tdp_pte = is_rsvd_bits_set for the
current modes, then this part can be moved to mmu.c

> 
>  static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu,
> @@ -352,6 +356,28 @@ error:
>       walker->fault.vector = PF_VECTOR;
>       walker->fault.error_code_valid = true;
>       walker->fault.error_code = errcode;
> +
> +#if PTTYPE == PTTYPE_EPT
> +     /*
> +      * Use PFERR_RSVD_MASK in erorr_code to to tell if EPT
> +      * misconfiguration requires to be injected. The detection is
> +      * done by is_rsvd_bits_set() above.
> +      *
> +      * We set up the value of exit_qualification to inject:
> +      * [2:0] -- Derive from [2:0] of real exit_qualification at EPT 
> violation
> +      * [5:3] -- Calculated by the page walk of the guest EPT page tables
> +      * [7:8] -- Clear to 0.
> +      *
> +      * The other bits are set to 0.
> +      */
> +     if (!(errcode & PFERR_RSVD_MASK)) {
> +             unsigned long exit_qualification = 
> vcpu->arch.exit_qualification;
> +
> +             pte_access = pt_access & pte;
> +             vcpu->arch.exit_qualification = ((pte_access & 0x7) << 3) |
> +                     (exit_qualification & 0x7);
> +     }
> +#endif

This specified operations can be move to nested_ept_inject_page_fault()?

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to