FAILED: patch "[PATCH] KVM: x86: Use gpa_t for cr2/gpa to fix TDP support on 32-bit" failed to apply to 4.19-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 736c291c9f36b07f8889c61764c28edce20e715d Mon Sep 17 00:00:00 2001
From: Sean Christopherson <[email protected]>
Date: Fri, 6 Dec 2019 15:57:14 -0800
Subject: [PATCH] KVM: x86: Use gpa_t for cr2/gpa to fix TDP support on 32-bit
KVM
Convert a plethora of parameters and variables in the MMU and page fault flows from type gva_t to gpa_t to properly handle TDP on 32-bit KVM.
Thanks to PSE and PAE paging, 32-bit kernels can access 64-bit physical addresses. When TDP is enabled, the fault address is a guest physical address and thus can be a 64-bit value, even when both KVM and its guest are using 32-bit virtual addressing, e.g. VMX's VMCS.GUEST_PHYSICAL is a 64-bit field, not a natural width field.
Using a gva_t for the fault address means KVM will incorrectly drop the upper 32-bits of the GPA. Ditto for gva_to_gpa() when it is used to translate L2 GPAs to L1 GPAs.
Opportunistically rename variables and parameters to better reflect the dual address modes, e.g. use "cr2_or_gpa" for fault addresses and plain "addr" instead of "vaddr" when the address may be either a GVA or an L2 GPA. Similarly, use "gpa" in the nonpaging_page_fault() flows to avoid a confusing "gpa_t gva" declaration; this also sets the stage for a future patch to combing nonpaging_page_fault() and tdp_page_fault() with minimal churn.
Sprinkle in a few comments to document flows where an address is known to be a GVA and thus can be safely truncated to a 32-bit value. Add WARNs in kvm_handle_page_fault() and FNAME(gva_to_gpa_nested)() to help document such cases and detect bugs.
arch/x86/include/asm/kvm_host.h +4 -4
@@ -378,12 +378,12 @@ struct kvm_mmu {void (*set_cr3)(struct kvm_vcpu *vcpu,unsigned long root);unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);u64 (*get_pdptr)(struct kvm_vcpu *vcpu,int index); -int (*page_fault)(struct kvm_vcpu *vcpu,gva_t gva,u32 err, +int (*page_fault)(struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa,u32 err,bool prefault);void (*inject_page_fault)(struct kvm_vcpu *vcpu,struct x86_exception *fault); -gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu,gva_t gva,u32 access, -struct x86_exception *exception); +gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu,gpa_t gva_or_gpa, +u32 access,struct x86_exception *exception);gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu,gpa_t gpa,u32 access,struct x86_exception *exception); int (*sync_page)(struct kvm_vcpu *vcpu,
@@ -1473,7 +1473,7 @@ void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);int kvm_emulate_hypercall (struct kvm_vcpu *vcpu); -int kvm_mmu_page_fault (struct kvm_vcpu *vcpu,gva_t gva,u64 error_code, +int kvm_mmu_page_fault (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa,u64 error_code,void *insn,int insn_len);void kvm_mmu_invlpg (struct kvm_vcpu *vcpu,gva_t gva);void kvm_mmu_invpcid_gva (struct kvm_vcpu *vcpu,gva_t gva,unsigned long pcid);
arch/x86/kvm/mmu/mmu.c +40 -29
214 lines not on this page · raw message
arch/x86/kvm/mmu/paging_tmpl.h +16 -9
@@ -291,11 +291,11 @@ static inline unsigned FNAME(gpte_pkeys)(struct kvm_vcpu *vcpu, u64 gpte) }/* -* Fetch a guest pte for a guest virtual address +* Fetch a guest pte for a guest virtual address, or for an L2's GPA. */ static int FNAME (walk_addr_generic )(struct guest_walker *walker,struct kvm_vcpu *vcpu,struct kvm_mmu *mmu, -gva_t addr,u32 access) +gpa_t addr,u32 access) {int ret;pt_element_t pte;
@@ -496,7 +496,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, }static int FNAME (walk_addr )(struct guest_walker *walker, -struct kvm_vcpu *vcpu,gva_t addr,u32 access) +struct kvm_vcpu *vcpu,gpa_t addr,u32 access) {return FNAME (walk_addr_generic)(walker, vcpu, vcpu->arch.mmu, addr, access);
@@ -611,7 +611,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,* If the guest tries to write a write-protected page, we need to * emulate this operation, return 1 to indicate this case. */ -static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, +static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, struct guest_walker *gw, int write_fault, int hlevel, kvm_pfn_t pfn, bool map_writable, bool prefault,
@@ -765,7 +765,7 @@ FNAME(is_self_change_mapping)(struct kvm_vcpu *vcpu,* Returns: 1 if we need to emulate the instruction, 0 otherwise, or * a negative value on error. */ -static int FNAME (page_fault )(struct kvm_vcpu *vcpu,gva_t addr,u32 error_code, +static int FNAME (page_fault )(struct kvm_vcpu *vcpu,gpa_t addr,u32 error_code,bool prefault) {int write_fault = error_code &PFERR_WRITE_MASK ;
@@ -945,18 +945,19 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva, hpa_t root_hpa)spin_unlock (&vcpu->kvm->mmu_lock); } -static gpa_t FNAME (gva_to_gpa )(struct kvm_vcpu *vcpu,gva_t vaddr,u32 access, +/* Note, @addr is a GPA when gva_to_gpa() translates an L2 GPA to an L1 GPA. */ +static gpa_t FNAME (gva_to_gpa )(struct kvm_vcpu *vcpu,gpa_t addr,u32 access,struct x86_exception *exception) {struct guest_walker walker;gpa_t gpa =UNMAPPED_GVA ;int r; - r =FNAME (walk_addr)(&walker, vcpu, vaddr, access); + r =FNAME (walk_addr)(&walker, vcpu, addr, access);if (r) { gpa =gfn_to_gpa (walker.gfn); - gpa |= vaddr & ~PAGE_MASK ; + gpa |= addr & ~PAGE_MASK ; }else if (exception) *exception = walker.fault;
@@ -964,7 +965,8 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, }#if PTTYPE !=PTTYPE_EPT -static gpa_t FNAME (gva_to_gpa_nested )(struct kvm_vcpu *vcpu,gva_t vaddr, +/* Note, gva_to_gpa_nested() is only used to translate L2 GVAs. */ +static gpa_t FNAME (gva_to_gpa_nested )(struct kvm_vcpu *vcpu,gpa_t vaddr,u32 access,struct x86_exception *exception) {
@@ -972,6 +974,11 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,gpa_t gpa =UNMAPPED_GVA ;int r; +#ifndef CONFIG_X86_64 +/* A 64-bit GVA should be impossible on 32-bit KVM. */ +WARN_ON_ONCE (vaddr >>32 ); +#endif + r =FNAME (walk_addr_nested)(&walker, vcpu, vaddr, access);if (r) {
arch/x86/kvm/mmutrace.h +6 -6
@@ -249,13 +249,13 @@ TRACE_EVENT( TRACE_EVENT( fast_page_fault, - TP_PROTO(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, + TP_PROTO(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u32 error_code, u64 *sptep, u64 old_spte, bool retry), - TP_ARGS(vcpu, gva, error_code, sptep, old_spte, retry), + TP_ARGS(vcpu, cr2_or_gpa, error_code, sptep, old_spte, retry), TP_STRUCT__entry( __field(int, vcpu_id) - __field(gva_t, gva) + __field(gpa_t, cr2_or_gpa) __field(u32, error_code) __field(u64 *, sptep) __field(u64, old_spte)
@@ -265,7 +265,7 @@ TRACE_EVENT(TP_fast_assign ( __entry->vcpu_id = vcpu->vcpu_id; - __entry->gva = gva; + __entry->cr2_or_gpa = cr2_or_gpa; __entry->error_code = error_code; __entry->sptep = sptep; __entry->old_spte = old_spte;
@@ -273,9 +273,9 @@ TRACE_EVENT( __entry->retry = retry; ), -TP_printk ("vcpu %d gva %lx error_code %s sptep %p old %#llx" +TP_printk ("vcpu %d gva %llx error_code %s sptep %p old %#llx" " new %llx spurious %d fixed %d" , __entry->vcpu_id, - __entry->gva,__print_flags (__entry->error_code,"|" , + __entry->cr2_or_gpa,__print_flags (__entry->error_code,"|" , kvm_mmu_trace_pferr_flags), __entry->sptep, __entry->old_spte, __entry->new_spte, __spte_satisfied(old_spte), __spte_satisfied(new_spte)
arch/x86/kvm/x86.c +19 -21
@@ -6379,11 +6379,11 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type)return 1 ; } -static bool reexecute_instruction (struct kvm_vcpu *vcpu,gva_t cr2, +static bool reexecute_instruction (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa,bool write_fault_to_shadow_pgtable,int emulation_type) { -gpa_t gpa = cr2; +gpa_t gpa = cr2_or_gpa;kvm_pfn_t pfn;if (!(emulation_type &EMULTYPE_ALLOW_RETRY ))
@@ -6397,7 +6397,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2,* Write permission should be allowed since only * write access need to be emulated. */ - gpa =kvm_mmu_gva_to_gpa_write (vcpu, cr2,NULL ); + gpa =kvm_mmu_gva_to_gpa_write (vcpu, cr2_or_gpa,NULL );/* * If the mapping is invalid in guest, let cpu retry
@@ -6454,10 +6454,10 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2, }static bool retry_instruction (struct x86_emulate_ctxt *ctxt, -unsigned long cr2,int emulation_type) +gpa_t cr2_or_gpa,int emulation_type) {struct kvm_vcpu *vcpu =emul_to_vcpu (ctxt); -unsigned long last_retry_eip, last_retry_addr, gpa = cr2; +unsigned long last_retry_eip, last_retry_addr, gpa = cr2_or_gpa; last_retry_eip = vcpu->arch.last_retry_eip; last_retry_addr = vcpu->arch.last_retry_addr;
@@ -6486,14 +6486,14 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,if (x86_page_table_writing_insn (ctxt))return false; -if (ctxt->eip == last_retry_eip && last_retry_addr == cr2) +if (ctxt->eip == last_retry_eip && last_retry_addr == cr2_or_gpa)return false; vcpu->arch.last_retry_eip = ctxt->eip; - vcpu->arch.last_retry_addr = cr2; + vcpu->arch.last_retry_addr = cr2_or_gpa;if (!vcpu->arch.mmu->direct_map) - gpa =kvm_mmu_gva_to_gpa_write (vcpu, cr2,NULL ); + gpa =kvm_mmu_gva_to_gpa_write (vcpu, cr2_or_gpa,NULL );kvm_mmu_unprotect_page (vcpu->kvm,gpa_to_gfn (gpa));
@@ -6639,11 +6639,8 @@ static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)return false; } -int x86_emulate_instruction (struct kvm_vcpu *vcpu, -unsigned long cr2, -int emulation_type, -void *insn, -int insn_len) +int x86_emulate_instruction (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa, +int emulation_type,void *insn,int insn_len) {int r;struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
@@ -6689,8 +6686,9 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,kvm_queue_exception (vcpu,UD_VECTOR );return 1 ; } -if (reexecute_instruction (vcpu, cr2, write_fault_to_spt, - emulation_type)) +if (reexecute_instruction (vcpu, cr2_or_gpa, + write_fault_to_spt, + emulation_type))return 1 ;if (ctxt->have_exception) {/*
@@ -6724,7 +6722,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,return 1 ; } -if (retry_instruction (ctxt, cr2, emulation_type)) +if (retry_instruction (ctxt, cr2_or_gpa, emulation_type))return 1 ;/* this is needed for vmware backdoor interface to work since it
@@ -6736,7 +6734,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, restart:/* Save the faulting GPA (cr2) in the address field */ - ctxt->exception.address = cr2; + ctxt->exception.address = cr2_or_gpa; r =x86_emulate_insn (ctxt);
@@ -6744,7 +6742,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,return 1 ;if (r ==EMULATION_FAILED ) { -if (reexecute_instruction (vcpu, cr2, write_fault_to_spt, +if (reexecute_instruction (vcpu, cr2_or_gpa, write_fault_to_spt, emulation_type))return 1 ;
@@ -10025,7 +10023,7 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) work->arch.cr3 != vcpu->arch.mmu->get_cr3(vcpu)) return; - vcpu->arch.mmu->page_fault (vcpu, work->gva,0 , true); + vcpu->arch.mmu->page_fault (vcpu, work->cr2_or_gpa,0 , true); }static inline u32 kvm_async_pf_hash_fn (gfn_t gfn)
@@ -10138,7 +10136,7 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, {struct x86_exception fault; -trace_kvm_async_pf_not_present (work->arch.token, work->gva); +trace_kvm_async_pf_not_present (work->arch.token, work->cr2_or_gpa);kvm_add_async_pf_gfn (vcpu, work->arch.gfn); if (kvm_can_deliver_async_pf(vcpu) &&
@@ -10173,7 +10171,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, work->arch.token = ~0 ;/* broadcast wakeup */ else kvm_del_async_pf_gfn(vcpu, work->arch.gfn); -trace_kvm_async_pf_ready (work->arch.token, work->gva); +trace_kvm_async_pf_ready (work->arch.token, work->cr2_or_gpa);if (vcpu->arch.apf.msr_val &KVM_ASYNC_PF_ENABLED && !apf_get_user (vcpu, &val)) {
arch/x86/kvm/x86.h +1 -1
@@ -289,7 +289,7 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);bool kvm_mtrr_check_gfn_range_consistency (struct kvm_vcpu *vcpu,gfn_t gfn,int page_num);bool kvm_vector_hashing_enabled (void ); -int x86_emulate_instruction (struct kvm_vcpu *vcpu,unsigned long cr2, +int x86_emulate_instruction (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa,int emulation_type,void *insn,int insn_len);#define KVM_SUPPORTED_XCR0 (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
include/linux/kvm_host.h +3 -3
@@ -204,7 +204,7 @@ struct kvm_async_pf {struct list_head queue;struct kvm_vcpu *vcpu;struct mm_struct *mm; -gva_t gva; +gpa_t cr2_or_gpa;unsigned long addr;struct kvm_arch_async_pf arch;bool wakeup_all;
@@ -212,8 +212,8 @@ struct kvm_async_pf {void kvm_clear_async_pf_completion_queue (struct kvm_vcpu *vcpu);void kvm_check_async_pf_completion (struct kvm_vcpu *vcpu); -int kvm_setup_async_pf (struct kvm_vcpu *vcpu,gva_t gva,unsigned long hva, -struct kvm_arch_async_pf *arch); +int kvm_setup_async_pf (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa, +unsigned long hva,struct kvm_arch_async_pf *arch);int kvm_async_pf_wakeup_all (struct kvm_vcpu *vcpu);#endif
virt/kvm/async_pf.c +5 -5
@@ -64,7 +64,7 @@ static void async_pf_execute(struct work_struct *work)struct mm_struct *mm = apf->mm;struct kvm_vcpu *vcpu = apf->vcpu;unsigned long addr = apf->addr; -gva_t gva = apf->gva; +gpa_t cr2_or_gpa = apf->cr2_or_gpa;int locked =1 ;might_sleep ();
@@ -92,7 +92,7 @@ static void async_pf_execute(struct work_struct *work)* this point */ -trace_kvm_async_pf_completed (addr, gva); +trace_kvm_async_pf_completed (addr, cr2_or_gpa);if (swq_has_sleeper (&vcpu->wq))swake_up_one (&vcpu->wq);
@@ -165,8 +165,8 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) } } -int kvm_setup_async_pf (struct kvm_vcpu *vcpu,gva_t gva,unsigned long hva, -struct kvm_arch_async_pf *arch) +int kvm_setup_async_pf (struct kvm_vcpu *vcpu,gpa_t cr2_or_gpa, +unsigned long hva,struct kvm_arch_async_pf *arch) {struct kvm_async_pf *work;
@@ -185,7 +185,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva, work->wakeup_all = false; work->vcpu = vcpu; - work->gva = gva; + work->cr2_or_gpa = cr2_or_gpa; work->addr = hva; work->arch = *arch; work->mm = current->mm;