KVM updates for the 2.6.34 merge window (batch 3/4)
cover KVM updates for the 2.6.34 merge window (batch 3/4)
This is the first of four batches of patches for the 2.6.34 merge window. KVM changes for this cycle include:
- rdtscp support
- powerpc server-class updates
- much improved large-guest scaling (now up to 64 vcpus)
- improved guest fpu handling
- initial Hyper-V emulation
- better swapping with EPT
- 1GB pages on Intel
- x86 emulator fixes
as well as the usual assortment of random fixes and improvements.
Avi Kivity (13):
KVM: export <asm/hyperv.h>
KVM: Allow kvm_load_guest_fpu() even when !vcpu->fpu_active
KVM: Drop kvm_{load,put}_guest_fpu() exports
KVM: Activate fpu on clts
KVM: Add a helper for checking if the guest is in protected mode
KVM: Move cr0/cr4/efer related helpers to x86.h
KVM: Rename vcpu->shadow_efer to efer
KVM: Optimize kvm_read_cr[04]_bits()
KVM: trace guest fpu loads and unloads
KVM: VMX: Pass cr0.mp through to the guest when the fpu is active
KVM: Fix msr trace
KVM: Trace failed msr reads and writes
KVM: VMX: Wire up .fpu_activate() callback
Gleb Natapov (3):
KVM: fix Hyper-V hypercall warnings and wrong mask value
KVM: x86: fix checking of cr0 validity
KVM: mark segments accessed on HW task switch
Gui Jianfeng (1):
KVM: VMX: Remove redundant check in
vm_need_virtualize_apic_accesses()
Jan Kiszka (5):
KVM: VMX: Fix exceptions of mov to dr
KVM: VMX: Fix emulation of DR4 and DR5
KVM: VMX: Clean up DR6 emulation
KVM: SVM: Clean up and enhance mov dr emulation
KVM: SVM: Trap all debug register accesses
Joe Perches (1):
KVM: ia64: Fix string literal continuation lines
Joerg Roedel (1):
KVM: Introduce kvm_host_page_size
Julia Lawall (1):
KVM: VMX: Remove redundant test in vmx_set_efer()
Liu Yu (3):
KVM: PPC E500: Add register l1csr0 emulation
KVM: PPC: Add PVR/PIR init for E500
KVM: PPC E500: fix tlbcfg emulation
Marcelo Tosatti (1):
KVM: fix cleanup_srcu_struct on vm destruction
Rik van Riel (1):
KVM: VMX: emulate accessed bit for EPT
Sheng Yang (2):
KVM: VMX: Remove emulation failure report
KVM: Fix kvm_coalesced_mmio_ring duplicate allocation
Takuya Yoshikawa (4):
KVM: x86: Use macros for x86_emulate_ops to avoid future mistakes
KVM: fix load_guest_segment_descriptor() to return X86EMUL_*
KVM: fix kvm_fix_hypercall() to return X86EMUL_*
KVM: Remove redundant reading of rax on OUT instructions
Wei Yongjun (1):
KVM: MMU: Remove some useless code from alloc_mmu_pages()
Zhai, Edwin (1):
KVM: enable PCI multiple-segments for pass-through device
arch/ia64/kvm/kvm-ia64.c | 1 + arch/ia64/kvm/mmio.c | 4 +- arch/ia64/kvm/vcpu.c | 4 +- arch/powerpc/include/asm/kvm_e500.h | 3 + arch/powerpc/kvm/e500.c | 6 ++ arch/powerpc/kvm/e500_emulate.c | 26 +++------ arch/powerpc/kvm/e500_tlb.c | 6 ++ arch/powerpc/kvm/powerpc.c | 1 + arch/s390/kvm/kvm-s390.c | 1 + arch/x86/include/asm/Kbuild | 1 + arch/x86/include/asm/kvm_host.h | 8 +- arch/x86/kvm/emulate.c | 75 ++++++++++++----------- arch/x86/kvm/kvm_cache_regs.h | 11 +++- arch/x86/kvm/mmu.c | 38 ++++------- arch/x86/kvm/mmu.h | 24 ------- arch/x86/kvm/svm.c | 111 +++++++++++++++++++--------------- arch/x86/kvm/trace.h | 27 +++++---- arch/x86/kvm/vmx.c | 114 +++++++++++++++++++---------------- arch/x86/kvm/x86.c | 107 ++++++++++++++------------------- arch/x86/kvm/x86.h | 30 +++++++++ include/linux/kvm.h | 4 +- include/linux/kvm_host.h | 2 + include/trace/events/kvm.h | 19 ++++++ virt/kvm/assigned-dev.c | 4 +- virt/kvm/iommu.c | 9 ++- virt/kvm/kvm_main.c | 43 ++++++++------ 26 files changed, 373 insertions(+), 306 deletions(-)
PATCH 1/38 KVM: export <asm/hyperv.h>
Needed by <asm/kvm_para.h>.
--- arch/x86/include/asm/Kbuild | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/include/asm/Kbuild +1 -0
@@ -11,6 +11,7 @@ header-y += sigcontext32.h header-y += ucontext.h header-y += processor-flags.h header-y += hw_breakpoint.h +header-y += hyperv.h unifdef-y += e820.h unifdef-y += ist.h
Signature · 1 line
1.6.5.3
PATCH 2/38 KVM: VMX: Remove emulation failure report
In reply to Avi KivityFrom: Sheng Yang <[email protected]>
As Avi noted:
Quoted 4 lines
There are two problems with the kernel failure report. First, it doesn't report enough data - registers, surrounding instructions, etc. that are needed to explain what is going on. Second, it can flood dmesg, which is a pretty bad thing to do.
So we remove the emulation failure report in handle_invalid_guest_state(), and would inspected the guest using userspace tool in the future.
--- arch/x86/kvm/vmx.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
arch/x86/kvm/vmx.c +0 -1
@@ -3449,7 +3449,6 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) }if (err !=EMULATE_DONE ) { -kvm_report_emulation_failure (vcpu,"emulation failure" ); vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ; vcpu->run->internal.ndata =0 ;
Signature · 1 line
1.6.5.3
PATCH 3/38 KVM: fix Hyper-V hypercall warnings and wrong mask value
In reply to Avi KivityFrom: Gleb Natapov <[email protected]>
Fix compilation warnings and wrong mask value.
--- arch/x86/kvm/x86.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
arch/x86/kvm/x86.c +6 -6
@@ -3806,12 +3806,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) longmode =is_long_mode (vcpu) && cs_l ==1 ;if (!longmode) { - param = (kvm_register_read (vcpu,VCPU_REGS_RDX ) <<32 ) | - (kvm_register_read (vcpu,VCPU_REGS_RAX ) &0xffffff ); - ingpa = (kvm_register_read (vcpu,VCPU_REGS_RBX ) <<32 ) | - (kvm_register_read (vcpu,VCPU_REGS_RCX ) &0xffffff ); - outgpa = (kvm_register_read (vcpu,VCPU_REGS_RDI ) <<32 ) | - (kvm_register_read (vcpu,VCPU_REGS_RSI ) &0xffffff ); + param = ((u64 )kvm_register_read (vcpu,VCPU_REGS_RDX ) <<32 ) | + (kvm_register_read (vcpu,VCPU_REGS_RAX ) &0xffffffff ); + ingpa = ((u64 )kvm_register_read (vcpu,VCPU_REGS_RBX ) <<32 ) | + (kvm_register_read (vcpu,VCPU_REGS_RCX ) &0xffffffff ); + outgpa = ((u64 )kvm_register_read (vcpu,VCPU_REGS_RDI ) <<32 ) | + (kvm_register_read (vcpu,VCPU_REGS_RSI ) &0xffffffff ); }#ifdef CONFIG_X86_64 else {
Signature · 1 line
1.6.5.3
PATCH 4/38 KVM: fix cleanup_srcu_struct on vm destruction
In reply to Avi KivityFrom: Marcelo Tosatti <[email protected]>
cleanup_srcu_struct on VM destruction remains broken:
BUG: unable to handle kernel paging request at ffffffffffffffff IP: [<ffffffff802533d2>] srcu_read_lock+0x16/0x21 RIP: 0010:[<ffffffff802533d2>] [<ffffffff802533d2>] srcu_read_lock+0x16/0x21 Call Trace: [<ffffffffa05354c4>] kvm_arch_vcpu_uninit+0x1b/0x48 [kvm] [<ffffffffa05339c6>] kvm_vcpu_uninit+0x9/0x15 [kvm] [<ffffffffa0569f7d>] vmx_free_vcpu+0x7f/0x8f [kvm_intel] [<ffffffffa05357b5>] kvm_arch_destroy_vm+0x78/0x111 [kvm] [<ffffffffa053315b>] kvm_put_kvm+0xd4/0xfe [kvm]
Move it to kvm_arch_destroy_vm.
--- arch/ia64/kvm/kvm-ia64.c | 1 + arch/powerpc/kvm/powerpc.c | 1 + arch/s390/kvm/kvm-s390.c | 1 + arch/x86/kvm/x86.c | 1 + virt/kvm/kvm_main.c | 1 - 5 files changed, 4 insertions(+), 1 deletions(-)
arch/ia64/kvm/kvm-ia64.c +1 -0
@@ -1404,6 +1404,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)kfree (kvm->arch.vioapic);kvm_release_vm_pages (kvm);kvm_free_physmem (kvm); +cleanup_srcu_struct (&kvm->srcu);free_kvm (kvm); }
arch/powerpc/kvm/powerpc.c +1 -0
@@ -137,6 +137,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) {kvmppc_free_vcpus (kvm);kvm_free_physmem (kvm); +cleanup_srcu_struct (&kvm->srcu);kfree (kvm); }
arch/s390/kvm/kvm-s390.c +1 -0
@@ -241,6 +241,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)kvm_free_physmem (kvm);free_page ((unsigned long )(kvm->arch.sca));debug_unregister (kvm->arch.dbf); +cleanup_srcu_struct (&kvm->srcu);kfree (kvm); }
arch/x86/kvm/x86.c +1 -0
@@ -5547,6 +5547,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)put_page (kvm->arch.apic_access_page);if (kvm->arch.ept_identity_pagetable)put_page (kvm->arch.ept_identity_pagetable); +cleanup_srcu_struct (&kvm->srcu);kfree (kvm->arch.aliases);kfree (kvm); }
virt/kvm/kvm_main.c +0 -1
@@ -506,7 +506,6 @@ static void kvm_destroy_vm(struct kvm *kvm)#else kvm_arch_flush_shadow (kvm);#endif -cleanup_srcu_struct (&kvm->srcu);kvm_arch_destroy_vm (kvm);hardware_disable_all ();mmdrop (mm);
Signature · 1 line
1.6.5.3
PATCH 5/38 KVM: x86: Use macros for x86_emulate_ops to avoid future mistakes
In reply to Avi KivityFrom: Takuya Yoshikawa <[email protected]>
The return values from x86_emulate_ops are defined in kvm_emulate.h as macros X86EMUL_*.
But in emulate.c, we are comparing the return values from these ops with 0 to check if they're X86EMUL_CONTINUE or not: X86EMUL_CONTINUE is defined as 0 now.
To avoid possible mistakes in the future, this patch substitutes "X86EMUL_CONTINUE" for "0" that are being compared with the return values from x86_emulate_ops.
We think that there are more places we should use these macros, but the meanings of rc values in x86_emulate_insn() were not so clear at a glance. If we use proper macros in this function, we would be able to follow the flow of each emulation more easily and, maybe, more securely.
--- arch/x86/kvm/emulate.c | 65 ++++++++++++++++++++++++++--------------------- 1 files changed, 36 insertions(+), 29 deletions(-)
arch/x86/kvm/emulate.c +36 -29
@@ -1196,7 +1196,7 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt, rc = ops->read_emulated (register_address (c,ss_base (ctxt), c->regs[VCPU_REGS_RSP ]), dest, len, ctxt->vcpu); -if (rc !=0 ) +if (rc !=X86EMUL_CONTINUE )return rc;register_address_increment (c, &c->regs[VCPU_REGS_RSP ], len);
@@ -1370,7 +1370,7 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,int rc; rc = ops->read_emulated (memop, &old,8 , ctxt->vcpu); -if (rc !=0 ) +if (rc !=X86EMUL_CONTINUE )return rc; if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) ||
@@ -1385,7 +1385,7 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt, (u32 ) c->regs[VCPU_REGS_RBX ]; rc = ops->cmpxchg_emulated (memop, &old, &new,8 , ctxt->vcpu); -if (rc !=0 ) +if (rc !=X86EMUL_CONTINUE )return rc; ctxt->eflags |=EFLG_ZF ; }
@@ -1451,7 +1451,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, &c->dst.val, c->dst.bytes, ctxt->vcpu); -if (rc !=0 ) +if (rc !=X86EMUL_CONTINUE )return rc;break ;case OP_NONE :
@@ -1749,7 +1749,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) &c->src.val, c->src.bytes, ctxt->vcpu); -if (rc !=0 ) +if (rc !=X86EMUL_CONTINUE ) goto done; c->src.orig_val = c->src.val; }
@@ -1768,12 +1768,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) c->dst.ptr = (void *)c->dst.ptr + (c->src.val & mask) /8 ; } -if (!(c->d & Mov) && -/* optimisation - avoid slow emulated read */ - ((rc = ops->read_emulated ((unsigned long )c->dst.ptr, - &c->dst.val, - c->dst.bytes, ctxt->vcpu)) !=0 )) - goto done; +if (!(c->d & Mov)) { +/* optimisation - avoid slow emulated read */ + rc = ops->read_emulated ((unsigned long )c->dst.ptr, + &c->dst.val, + c->dst.bytes, + ctxt->vcpu); +if (rc !=X86EMUL_CONTINUE ) + goto done; + } } c->dst.orig_val = c->dst.val;
@@ -2039,11 +2042,12 @@ special_insn: c->dst.ptr = (unsigned long *)register_address (c,es_base (ctxt), c->regs[VCPU_REGS_RDI ]); -if ((rc = ops->read_emulated (register_address (c, -seg_override_base (ctxt, c), - c->regs[VCPU_REGS_RSI ]), + rc = ops->read_emulated (register_address (c, +seg_override_base (ctxt, c), + c->regs[VCPU_REGS_RSI ]), &c->dst.val, - c->dst.bytes, ctxt->vcpu)) !=0 ) + c->dst.bytes, ctxt->vcpu); +if (rc !=X86EMUL_CONTINUE ) goto done; register_address_increment(c, &c->regs[VCPU_REGS_RSI], (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
@@ -2058,10 +2062,11 @@ special_insn: c->src.ptr = (unsigned long *)register_address (c,seg_override_base (ctxt, c), c->regs[VCPU_REGS_RSI ]); -if ((rc = ops->read_emulated ((unsigned long )c->src.ptr, - &c->src.val, - c->src.bytes, - ctxt->vcpu)) !=0 ) + rc = ops->read_emulated ((unsigned long )c->src.ptr, + &c->src.val, + c->src.bytes, + ctxt->vcpu); +if (rc !=X86EMUL_CONTINUE ) goto done; c->dst.type =OP_NONE ;/* Disable writeback. */
@@ -2069,10 +2074,11 @@ special_insn: c->dst.ptr = (unsigned long *)register_address (c,es_base (ctxt), c->regs[VCPU_REGS_RDI ]); -if ((rc = ops->read_emulated ((unsigned long )c->dst.ptr, - &c->dst.val, - c->dst.bytes, - ctxt->vcpu)) !=0 ) + rc = ops->read_emulated ((unsigned long )c->dst.ptr, + &c->dst.val, + c->dst.bytes, + ctxt->vcpu); +if (rc !=X86EMUL_CONTINUE ) goto done;DPRINTF ("cmps: mem1=0x%p mem2=0x%p\n" , c->src.ptr, c->dst.ptr);
@@ -2102,12 +2108,13 @@ special_insn: c->dst.type =OP_REG ; c->dst.bytes = (c->d & ByteOp) ?1 : c->op_bytes; c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX ]; -if ((rc = ops->read_emulated (register_address (c, -seg_override_base (ctxt, c), - c->regs[VCPU_REGS_RSI ]), - &c->dst.val, - c->dst.bytes, - ctxt->vcpu)) !=0 ) + rc = ops->read_emulated (register_address (c, +seg_override_base (ctxt, c), + c->regs[VCPU_REGS_RSI ]), + &c->dst.val, + c->dst.bytes, + ctxt->vcpu); +if (rc !=X86EMUL_CONTINUE ) goto done; register_address_increment(c, &c->regs[VCPU_REGS_RSI], (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
Signature · 1 line
1.6.5.3
PATCH 6/38 KVM: VMX: Fix exceptions of mov to dr
In reply to Avi KivityFrom: Jan Kiszka <[email protected]>
Injecting GP without an error code is a bad idea (causes unhandled guest exits). Moreover, we must not skip the instruction if we injected an exception.
--- arch/x86/kvm/vmx.c | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-)
arch/x86/kvm/vmx.c +8 -5
@@ -3045,6 +3045,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)unsigned long val;int dr, reg; +/* Do not handle if the CPL > 0, will trigger GP on re-entry */ if (!kvm_require_cpl (vcpu,0 ))return 1 ; dr =vmcs_readl (GUEST_DR7 );
@@ -3099,20 +3100,22 @@ static int handle_dr(struct kvm_vcpu *vcpu) vcpu->arch.eff_db[dr] = val;break ; case 4 ... 5: -if (kvm_read_cr4_bits (vcpu,X86_CR4_DE )) +if (kvm_read_cr4_bits (vcpu,X86_CR4_DE )) {kvm_queue_exception (vcpu,UD_VECTOR ); +return 1 ; + }break ;case 6 :if (val &0xffffffff00000000ULL ) { -kvm_queue_exception (vcpu,GP_VECTOR ); -break ; +kvm_inject_gp (vcpu,0 ); +return 1 ; } vcpu->arch.dr6 = (val &DR6_VOLATILE ) |DR6_FIXED_1 ;break ;case 7 :if (val &0xffffffff00000000ULL ) { -kvm_queue_exception (vcpu,GP_VECTOR ); -break ; +kvm_inject_gp (vcpu,0 ); +return 1 ; } vcpu->arch.dr7 = (val &DR7_VOLATILE ) |DR7_FIXED_1 ;if (!(vcpu->guest_debug &KVM_GUESTDBG_USE_HW_BP )) {
Signature · 1 line
1.6.5.3
PATCH 7/38 KVM: VMX: Fix emulation of DR4 and DR5
In reply to Avi KivityFrom: Jan Kiszka <[email protected]>
Make sure DR4 and DR5 are aliased to DR6 and DR7, respectively, if CR4.DE is not set.
--- arch/x86/kvm/vmx.c | 35 ++++++++++++++++++++++++++--------- 1 files changed, 26 insertions(+), 9 deletions(-)
arch/x86/kvm/vmx.c +26 -9
@@ -3039,6 +3039,15 @@ static int handle_cr(struct kvm_vcpu *vcpu)return 0 ; } +static int check_dr_alias (struct kvm_vcpu *vcpu) +{ +if (kvm_read_cr4_bits (vcpu,X86_CR4_DE )) { +kvm_queue_exception (vcpu,UD_VECTOR ); +return -1 ; + } +return 0 ; +} +static int handle_dr (struct kvm_vcpu *vcpu) {unsigned long exit_qualification;
@@ -3081,14 +3090,20 @@ static int handle_dr(struct kvm_vcpu *vcpu) case 0 ... 3: val = vcpu->arch.db[dr];break ; +case 4 : +if (check_dr_alias (vcpu) <0 ) +return 1 ; +/* fall through */ case 6 : val = vcpu->arch.dr6;break ; -case 7 : +case 5 : +if (check_dr_alias (vcpu) <0 ) +return 1 ; +/* fall through */ +default :/* 7 */ val = vcpu->arch.dr7;break ; -default : - val =0 ; }kvm_register_write (vcpu, reg, val); }else {
@@ -3099,12 +3114,10 @@ static int handle_dr(struct kvm_vcpu *vcpu)if (!(vcpu->guest_debug &KVM_GUESTDBG_USE_HW_BP )) vcpu->arch.eff_db[dr] = val;break ; - case 4 ... 5: -if (kvm_read_cr4_bits (vcpu,X86_CR4_DE )) { -kvm_queue_exception (vcpu,UD_VECTOR ); +case 4 : +if (check_dr_alias (vcpu) <0 )return 1 ; - } -break ; +/* fall through */ case 6 :if (val &0xffffffff00000000ULL ) {kvm_inject_gp (vcpu,0 );
@@ -3112,7 +3125,11 @@ static int handle_dr(struct kvm_vcpu *vcpu) } vcpu->arch.dr6 = (val &DR6_VOLATILE ) |DR6_FIXED_1 ;break ; -case 7 : +case 5 : +if (check_dr_alias (vcpu) <0 ) +return 1 ; +/* fall through */ +default :/* 7 */ if (val &0xffffffff00000000ULL ) {kvm_inject_gp (vcpu,0 );return 1 ;
Signature · 1 line
1.6.5.3
PATCH 8/38 KVM: VMX: Clean up DR6 emulation
In reply to Avi KivityFrom: Jan Kiszka <[email protected]>
As we trap all debug register accesses, we do not need to switch real DR6 at all. Clean up update_exception_bitmap at this chance, too.
--- arch/x86/kvm/vmx.c | 23 ++++++----------------- 1 files changed, 6 insertions(+), 17 deletions(-)
arch/x86/kvm/vmx.c +6 -17
@@ -579,17 +579,12 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) {u32 eb; - eb = (1u <<PF_VECTOR ) | (1u <<UD_VECTOR ) | (1u <<MC_VECTOR ) - | (1u <<NM_VECTOR ); -/* -* Unconditionally intercept #DB so we can maintain dr6 without -* reading it every exit. -*/ - eb |=1u <<DB_VECTOR ; -if (vcpu->guest_debug &KVM_GUESTDBG_ENABLE ) { -if (vcpu->guest_debug &KVM_GUESTDBG_USE_SW_BP ) - eb |=1u <<BP_VECTOR ; - } + eb = (1u <<PF_VECTOR ) | (1u <<UD_VECTOR ) | (1u <<MC_VECTOR ) | + (1u <<NM_VECTOR ) | (1u <<DB_VECTOR ); +if ((vcpu->guest_debug & + (KVM_GUESTDBG_ENABLE |KVM_GUESTDBG_USE_SW_BP )) == + (KVM_GUESTDBG_ENABLE |KVM_GUESTDBG_USE_SW_BP )) + eb |=1u <<BP_VECTOR ;if (to_vmx (vcpu)->rmode.vm86_active) eb = ~0 ;if (enable_ept)
@@ -3777,9 +3772,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)*/ vmcs_writel (HOST_CR0 ,read_cr0 ()); -if (vcpu->arch.switch_db_regs) -set_debugreg (vcpu->arch.dr6,6 ); - asm(/* Store host registers */ "push %%"R"dx; push %%"R"bp;"
@@ -3880,9 +3872,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) | (1 << VCPU_EXREG_PDPTR)); vcpu->arch.regs_dirty =0 ; -if (vcpu->arch.switch_db_regs) -get_debugreg (vcpu->arch.dr6,6 ); - vmx->idt_vectoring_info =vmcs_read32 (IDT_VECTORING_INFO_FIELD );if (vmx->rmode.irq.pending)fixup_rmode_irq (vmx);
Signature · 1 line
1.6.5.3
PATCH 9/38 KVM: SVM: Clean up and enhance mov dr emulation
In reply to Avi KivityFrom: Jan Kiszka <[email protected]>
Enhance mov dr instruction emulation used by SVM so that it properly handles dr4/5: alias to dr6/7 if cr4.de is cleared. Otherwise return EMULATE_FAIL which will let our only possible caller in that scenario, ud_interception, re-inject UD.
We do not need to inject faults, SVM does this for us (exceptions take precedence over instruction interceptions). For the same reason, the value overflow checks can be removed.
--- arch/x86/include/asm/kvm_host.h | 5 +-- arch/x86/kvm/svm.c | 64 +++++++++++++++++--------------------- arch/x86/kvm/x86.c | 19 +---------- 3 files changed, 33 insertions(+), 55 deletions(-)
arch/x86/include/asm/kvm_host.h +2 -3
@@ -506,9 +506,8 @@ struct kvm_x86_ops {void (*set_idt)(struct kvm_vcpu *vcpu,struct descriptor_table *dt);void (*get_gdt)(struct kvm_vcpu *vcpu,struct descriptor_table *dt);void (*set_gdt)(struct kvm_vcpu *vcpu,struct descriptor_table *dt); -unsigned long (*get_dr)(struct kvm_vcpu *vcpu,int dr); -void (*set_dr)(struct kvm_vcpu *vcpu,int dr,unsigned long value, -int *exception); +int (*get_dr)(struct kvm_vcpu *vcpu,int dr,unsigned long *dest); +int (*set_dr)(struct kvm_vcpu *vcpu,int dr,unsigned long value);void (*cache_reg)(struct kvm_vcpu *vcpu,enum kvm_reg reg);unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);void (*set_rflags)(struct kvm_vcpu *vcpu,unsigned long rflags);
arch/x86/kvm/svm.c +29 -35
105 lines not on this page · raw message
arch/x86/kvm/x86.c +2 -17
@@ -3270,29 +3270,14 @@ int emulate_clts(struct kvm_vcpu *vcpu)int emulator_get_dr (struct x86_emulate_ctxt *ctxt,int dr,unsigned long *dest) { -struct kvm_vcpu *vcpu = ctxt->vcpu; - -switch (dr) { - case 0 ... 3: - *dest = kvm_x86_ops->get_dr (vcpu, dr); -return X86EMUL_CONTINUE ; -default : -pr_unimpl (vcpu,"%s: unexpected dr %u\n" , __func__, dr); -return X86EMUL_UNHANDLEABLE ; - } +return kvm_x86_ops->get_dr (ctxt->vcpu, dr, dest); }int emulator_set_dr (struct x86_emulate_ctxt *ctxt,int dr,unsigned long value) {unsigned long mask = (ctxt->mode ==X86EMUL_MODE_PROT64 ) ? ~0ULL : ~0U ; -int exception; - kvm_x86_ops->set_dr (ctxt->vcpu, dr, value & mask, &exception); -if (exception) { -/* FIXME: better handling */ -return X86EMUL_UNHANDLEABLE ; - } -return X86EMUL_CONTINUE ; +return kvm_x86_ops->set_dr (ctxt->vcpu, dr, value & mask); }void kvm_report_emulation_failure (struct kvm_vcpu *vcpu,const char *context)
Signature · 1 line
1.6.5.3
PATCH 10/38 KVM: SVM: Trap all debug register accesses
In reply to Avi KivityFrom: Jan Kiszka <[email protected]>
To enable proper debug register emulation under all conditions, trap access to all DR0..7. This may be optimized later on.
--- arch/x86/kvm/svm.c | 14 +++++++++++++- 1 files changed, 13 insertions(+), 1 deletions(-)
arch/x86/kvm/svm.c +13 -1
@@ -554,13 +554,19 @@ static void init_vmcb(struct vcpu_svm *svm) control->intercept_dr_read =INTERCEPT_DR0_MASK |INTERCEPT_DR1_MASK |INTERCEPT_DR2_MASK | -INTERCEPT_DR3_MASK ; +INTERCEPT_DR3_MASK | +INTERCEPT_DR4_MASK | +INTERCEPT_DR5_MASK | +INTERCEPT_DR6_MASK | +INTERCEPT_DR7_MASK ; control->intercept_dr_write =INTERCEPT_DR0_MASK |INTERCEPT_DR1_MASK |INTERCEPT_DR2_MASK |INTERCEPT_DR3_MASK | +INTERCEPT_DR4_MASK |INTERCEPT_DR5_MASK | +INTERCEPT_DR6_MASK |INTERCEPT_DR7_MASK ; control->intercept_exceptions = (1 << PF_VECTOR) |
@@ -2319,11 +2325,17 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_DR1] = emulate_on_interception, [SVM_EXIT_READ_DR2] = emulate_on_interception, [SVM_EXIT_READ_DR3] = emulate_on_interception, + [SVM_EXIT_READ_DR4] = emulate_on_interception, + [SVM_EXIT_READ_DR5] = emulate_on_interception, + [SVM_EXIT_READ_DR6] = emulate_on_interception, + [SVM_EXIT_READ_DR7] = emulate_on_interception, [SVM_EXIT_WRITE_DR0] = emulate_on_interception, [SVM_EXIT_WRITE_DR1] = emulate_on_interception, [SVM_EXIT_WRITE_DR2] = emulate_on_interception, [SVM_EXIT_WRITE_DR3] = emulate_on_interception, + [SVM_EXIT_WRITE_DR4] = emulate_on_interception, [SVM_EXIT_WRITE_DR5] = emulate_on_interception, + [SVM_EXIT_WRITE_DR6] = emulate_on_interception, [SVM_EXIT_WRITE_DR7] = emulate_on_interception, [SVM_EXIT_EXCP_BASE + DB_VECTOR] = db_interception, [SVM_EXIT_EXCP_BASE + BP_VECTOR] = bp_interception,
Signature · 1 line
1.6.5.3
PATCH 11/38 KVM: Fix kvm_coalesced_mmio_ring duplicate allocation
In reply to Avi KivityFrom: Sheng Yang <[email protected]>
The commit 0953ca73 "KVM: Simplify coalesced mmio initialization" allocate kvm_coalesced_mmio_ring in the kvm_coalesced_mmio_init(), but didn't discard the original allocation...
--- virt/kvm/kvm_main.c | 17 ----------------- 1 files changed, 0 insertions(+), 17 deletions(-)
virt/kvm/kvm_main.c +0 -17
@@ -371,9 +371,6 @@ static struct kvm *kvm_create_vm(void) {int r =0 , i;struct kvm *kvm =kvm_arch_create_vm (); -#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET -struct page *page; -#endif if (IS_ERR (kvm)) goto out;
@@ -402,23 +399,9 @@ static struct kvm *kvm_create_vm(void) } } -#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET - page =alloc_page (GFP_KERNEL | __GFP_ZERO); -if (!page) { -cleanup_srcu_struct (&kvm->srcu); - goto out_err; - } - - kvm->coalesced_mmio_ring = - (struct kvm_coalesced_mmio_ring *)page_address (page); -#endif - r =kvm_init_mmu_notifier (kvm);if (r) {cleanup_srcu_struct (&kvm->srcu); -#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET -put_page (page); -#endif goto out_err; }
Signature · 1 line
1.6.5.3
PATCH 12/38 KVM: x86: fix checking of cr0 validity
In reply to Avi KivityFrom: Gleb Natapov <[email protected]>
Move to/from Control Registers chapter of Intel SDM says. "Reserved bits in CR0 remain clear after any load of those registers; attempts to set them have no impact". Control Register chapter says "Bits 63:32 of CR0 are reserved and must be written with zeros. Writing a nonzero value to any of the upper 32 bits results in a general-protection exception, #GP(0)."
This patch tries to implement this twisted logic.
--- arch/x86/kvm/x86.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
arch/x86/kvm/x86.c +5 -1
@@ -430,12 +430,16 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { cr0 |=X86_CR0_ET ; -if (cr0 &CR0_RESERVED_BITS ) { +#ifdef CONFIG_X86_64 +if (cr0 &0xffffffff00000000UL ) {printk (KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n" , cr0,kvm_read_cr0 (vcpu));kvm_inject_gp (vcpu,0 );return ; } +#endif + + cr0 &= ~CR0_RESERVED_BITS ;if ((cr0 &X86_CR0_NW ) && !(cr0 &X86_CR0_CD )) {printk (KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n" );
Signature · 1 line
1.6.5.3
PATCH 13/38 KVM: Allow kvm_load_guest_fpu() even when !vcpu->fpu_active
In reply to Avi KivityThis allows accessing the guest fpu from the instruction emulator, as well as being symmetric with kvm_put_guest_fpu().
--- arch/x86/kvm/x86.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +3 -2
@@ -4239,7 +4239,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)preempt_disable (); kvm_x86_ops->prepare_guest_switch (vcpu); -kvm_load_guest_fpu (vcpu); +if (vcpu->fpu_active) +kvm_load_guest_fpu (vcpu);local_irq_disable ();
@@ -5285,7 +5286,7 @@ EXPORT_SYMBOL_GPL(fx_init);void kvm_load_guest_fpu (struct kvm_vcpu *vcpu) { -if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) +if (vcpu->guest_fpu_loaded)return ; vcpu->guest_fpu_loaded =1 ;
Signature · 1 line
1.6.5.3
PATCH 14/38 KVM: Drop kvm_{load,put}_guest_fpu() exports
In reply to Avi KivityNot used anymore.
--- arch/x86/kvm/x86.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +0 -2
@@ -5293,7 +5293,6 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)kvm_fx_save (&vcpu->arch.host_fx_image);kvm_fx_restore (&vcpu->arch.guest_fx_image); } -EXPORT_SYMBOL_GPL (kvm_load_guest_fpu);void kvm_put_guest_fpu (struct kvm_vcpu *vcpu) {
@@ -5306,7 +5305,6 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) ++vcpu->stat.fpu_reload;set_bit (KVM_REQ_DEACTIVATE_FPU , &vcpu->requests); } -EXPORT_SYMBOL_GPL (kvm_put_guest_fpu);void kvm_arch_vcpu_free (struct kvm_vcpu *vcpu) {
Signature · 1 line
1.6.5.3
PATCH 15/38 KVM: Activate fpu on clts
In reply to Avi KivityAssume that if the guest executes clts, it knows what it's doing, and load the guest fpu to prevent an #NM exception.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm.c | 8 +++++++- arch/x86/kvm/vmx.c | 1 + arch/x86/kvm/x86.c | 1 + 4 files changed, 10 insertions(+), 1 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -511,6 +511,7 @@ struct kvm_x86_ops {void (*cache_reg)(struct kvm_vcpu *vcpu,enum kvm_reg reg);unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);void (*set_rflags)(struct kvm_vcpu *vcpu,unsigned long rflags); +void (*fpu_activate)(struct kvm_vcpu *vcpu);void (*fpu_deactivate)(struct kvm_vcpu *vcpu);void (*tlb_flush)(struct kvm_vcpu *vcpu);
arch/x86/kvm/svm.c +7 -1
@@ -1259,12 +1259,17 @@ static int ud_interception(struct vcpu_svm *svm)return 1 ; } -static int nm_interception (struct vcpu_svm *svm) +static void svm_fpu_activate (struct kvm_vcpu *vcpu) { +struct vcpu_svm *svm =to_svm (vcpu); svm->vmcb->control.intercept_exceptions &= ~(1 <<NM_VECTOR ); svm->vcpu.fpu_active =1 ;update_cr0_intercept (svm); +} +static int nm_interception (struct vcpu_svm *svm) +{ +svm_fpu_activate (&svm->vcpu);return 1 ; }
@@ -2977,6 +2982,7 @@ static struct kvm_x86_ops svm_x86_ops = { .cache_reg = svm_cache_reg, .get_rflags = svm_get_rflags, .set_rflags = svm_set_rflags, + .fpu_activate = svm_fpu_activate, .fpu_deactivate = svm_fpu_deactivate, .tlb_flush = svm_flush_tlb,
arch/x86/kvm/vmx.c +1 -0
@@ -3002,6 +3002,7 @@ static int handle_cr(struct kvm_vcpu *vcpu)vmx_set_cr0 (vcpu,kvm_read_cr0_bits (vcpu, ~X86_CR0_TS ));trace_kvm_cr_write (0 ,kvm_read_cr0 (vcpu));skip_emulated_instruction (vcpu); +vmx_fpu_activate (vcpu);return 1 ;case 1 :/*mov from cr*/ switch (cr) {
arch/x86/kvm/x86.c +1 -0
@@ -3269,6 +3269,7 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)int emulate_clts (struct kvm_vcpu *vcpu) { kvm_x86_ops->set_cr0 (vcpu,kvm_read_cr0_bits (vcpu, ~X86_CR0_TS )); + kvm_x86_ops->fpu_activate (vcpu);return X86EMUL_CONTINUE ; }
Signature · 1 line
1.6.5.3
PATCH 16/38 KVM: Add a helper for checking if the guest is in protected mode
In reply to Avi Kivity--- arch/x86/kvm/emulate.c | 9 ++++----- arch/x86/kvm/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 7 +++---- arch/x86/kvm/x86.h | 6 ++++++ 4 files changed, 15 insertions(+), 11 deletions(-)
arch/x86/kvm/emulate.c +4 -5
@@ -32,6 +32,7 @@#include <linux/module.h> #include <asm/kvm_emulate.h> +#include "x86.h" #include "mmu.h" /* for is_long_mode() */ /*
@@ -1515,7 +1516,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)/* syscall is not available in real mode */ if (c->lock_prefix || ctxt->mode ==X86EMUL_MODE_REAL - || !kvm_read_cr0_bits (ctxt->vcpu,X86_CR0_PE )) + || !is_protmode (ctxt->vcpu))return -1 ;setup_syscalls_segments (ctxt, &cs, &ss);
@@ -1568,8 +1569,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)return -1 ;/* inject #GP if in real mode or paging is disabled */ -if (ctxt->mode ==X86EMUL_MODE_REAL || - !kvm_read_cr0_bits (ctxt->vcpu,X86_CR0_PE )) { +if (ctxt->mode ==X86EMUL_MODE_REAL || !is_protmode (ctxt->vcpu)) {kvm_inject_gp (ctxt->vcpu,0 );return -1 ; }
@@ -1634,8 +1634,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)return -1 ;/* inject #GP if in real mode or paging is disabled */ -if (ctxt->mode ==X86EMUL_MODE_REAL - || !kvm_read_cr0_bits (ctxt->vcpu,X86_CR0_PE )) { +if (ctxt->mode ==X86EMUL_MODE_REAL || !is_protmode (ctxt->vcpu)) {kvm_inject_gp (ctxt->vcpu,0 );return -1 ; }
arch/x86/kvm/vmx.c +2 -2
@@ -1845,7 +1845,7 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,static int vmx_get_cpl (struct kvm_vcpu *vcpu) { -if (!kvm_read_cr0_bits (vcpu,X86_CR0_PE ))/* if real mode */ +if (!is_protmode (vcpu))return 0 ;if (vmx_get_rflags (vcpu) &X86_EFLAGS_VM )/* if virtual 8086 */
@@ -2100,7 +2100,7 @@ static bool cs_ss_rpl_check(struct kvm_vcpu *vcpu)static bool guest_state_valid (struct kvm_vcpu *vcpu) {/* real mode guest state checks */ -if (!kvm_read_cr0_bits (vcpu,X86_CR0_PE )) { +if (!is_protmode (vcpu)) {if (!rmode_segment_valid (vcpu,VCPU_SREG_CS ))return false;if (!rmode_segment_valid (vcpu,VCPU_SREG_SS ))
arch/x86/kvm/x86.c +3 -4
@@ -3786,8 +3786,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)* hypercall generates UD from non zero cpl and real mode * per HYPER-V spec */ -if (kvm_x86_ops->get_cpl (vcpu) !=0 || - !kvm_read_cr0_bits (vcpu,X86_CR0_PE )) { +if (kvm_x86_ops->get_cpl (vcpu) !=0 || !is_protmode (vcpu)) {kvm_queue_exception (vcpu,UD_VECTOR );return 0 ; }
@@ -4751,7 +4750,7 @@ int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, {struct kvm_segment kvm_seg; -if (is_vm86_segment (vcpu, seg) || !(kvm_read_cr0_bits (vcpu,X86_CR0_PE ))) +if (is_vm86_segment (vcpu, seg) || !is_protmode (vcpu))return kvm_load_realmode_segment (vcpu, selector, seg);if (load_segment_descriptor_to_kvm_desct (vcpu, selector, &kvm_seg))return 1 ;
@@ -5103,7 +5102,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,/* Older userspace won't unhalt the vcpu on reset. */ if (kvm_vcpu_is_bsp (vcpu) &&kvm_rip_read (vcpu) ==0xfff0 && sregs->cs.selector ==0xf000 && sregs->cs.base ==0xffff0000 && - !(kvm_read_cr0_bits (vcpu,X86_CR0_PE ))) + !is_protmode (vcpu)) vcpu->arch.mp_state =KVM_MP_STATE_RUNNABLE ;vcpu_put (vcpu);
arch/x86/kvm/x86.h +6 -0
@@ -2,6 +2,7 @@#define ARCH_X86_KVM_X86_H #include <linux/kvm_host.h> +#include "kvm_cache_regs.h" static inline void kvm_clear_exception_queue (struct kvm_vcpu *vcpu) {
@@ -35,4 +36,9 @@ static inline bool kvm_exception_is_soft(unsigned int nr)struct kvm_cpuid_entry2 *kvm_find_cpuid_entry (struct kvm_vcpu *vcpu,u32 function,u32 index); +static inline bool is_protmode (struct kvm_vcpu *vcpu) +{ +return kvm_read_cr0_bits (vcpu,X86_CR0_PE ); +} +#endif
Signature · 1 line
1.6.5.3
PATCH 17/38 KVM: Move cr0/cr4/efer related helpers to x86.h
In reply to Avi KivityThey have more general scope than the mmu.
--- arch/x86/kvm/emulate.c | 1 - arch/x86/kvm/mmu.c | 1 + arch/x86/kvm/mmu.h | 24 ------------------------ arch/x86/kvm/x86.h | 24 ++++++++++++++++++++++++ 4 files changed, 25 insertions(+), 25 deletions(-)
arch/x86/kvm/emulate.c +0 -1
@@ -33,7 +33,6 @@#include <asm/kvm_emulate.h> #include "x86.h" -#include "mmu.h" /* for is_long_mode() */ /* * Opcode effective-address decode tables.
arch/x86/kvm/mmu.c +1 -0
@@ -18,6 +18,7 @@*/ #include "mmu.h" +#include "x86.h" #include "kvm_cache_regs.h" #include <linux/kvm_host.h>
arch/x86/kvm/mmu.h +0 -24
@@ -58,30 +58,6 @@ static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)return kvm_mmu_load (vcpu); } -static inline int is_long_mode (struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_X86_64 -return vcpu->arch.shadow_efer &EFER_LMA ; -#else -return 0 ; -#endif -} - -static inline int is_pae (struct kvm_vcpu *vcpu) -{ -return kvm_read_cr4_bits (vcpu,X86_CR4_PAE ); -} - -static inline int is_pse (struct kvm_vcpu *vcpu) -{ -return kvm_read_cr4_bits (vcpu,X86_CR4_PSE ); -} - -static inline int is_paging (struct kvm_vcpu *vcpu) -{ -return kvm_read_cr0_bits (vcpu,X86_CR0_PG ); -} -static inline int is_present_gpte (unsigned long pte) {return pte &PT_PRESENT_MASK ;
arch/x86/kvm/x86.h +24 -0
@@ -41,4 +41,28 @@ static inline bool is_protmode(struct kvm_vcpu *vcpu) return kvm_read_cr0_bits(vcpu, X86_CR0_PE); } +static inline int is_long_mode (struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_X86_64 +return vcpu->arch.shadow_efer &EFER_LMA ; +#else +return 0 ; +#endif +} + +static inline int is_pae (struct kvm_vcpu *vcpu) +{ +return kvm_read_cr4_bits (vcpu,X86_CR4_PAE ); +} + +static inline int is_pse (struct kvm_vcpu *vcpu) +{ +return kvm_read_cr4_bits (vcpu,X86_CR4_PSE ); +} + +static inline int is_paging (struct kvm_vcpu *vcpu) +{ +return kvm_read_cr0_bits (vcpu,X86_CR0_PG ); +} +#endif
Signature · 1 line
1.6.5.3
PATCH 18/38 KVM: Rename vcpu->shadow_efer to efer
In reply to Avi KivityNone of the other registers have the shadow_ prefix.
--- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu.c | 2 +- arch/x86/kvm/svm.c | 12 ++++++------ arch/x86/kvm/vmx.c | 14 +++++++------- arch/x86/kvm/x86.c | 14 +++++++------- arch/x86/kvm/x86.h | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -1
@@ -277,7 +277,7 @@ struct kvm_vcpu_arch {unsigned long cr8;u32 hflags;u64 pdptrs[4 ];/* pae */ -u64 shadow_efer; +u64 efer;u64 apic_base;struct kvm_lapic *apic;/* kernel irqchip context */ int32_t apic_arb_prio;
arch/x86/kvm/mmu.c +1 -1
@@ -237,7 +237,7 @@ static int is_cpuid_PSE36(void)static int is_nx (struct kvm_vcpu *vcpu) { -return vcpu->arch.shadow_efer &EFER_NX ; +return vcpu->arch.efer &EFER_NX ; }static int is_shadow_present_pte (u64 pte)
arch/x86/kvm/svm.c +6 -6
@@ -231,7 +231,7 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) efer &= ~EFER_LME ;to_svm (vcpu)->vmcb->save.efer = efer |EFER_SVME ; - vcpu->arch.shadow_efer = efer; + vcpu->arch.efer = efer; } static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
@@ -996,14 +996,14 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)struct vcpu_svm *svm =to_svm (vcpu);#ifdef CONFIG_X86_64 -if (vcpu->arch.shadow_efer &EFER_LME ) { +if (vcpu->arch.efer &EFER_LME ) {if (!is_paging (vcpu) && (cr0 &X86_CR0_PG )) { - vcpu->arch.shadow_efer |=EFER_LMA ; + vcpu->arch.efer |=EFER_LMA ; svm->vmcb->save.efer |=EFER_LMA |EFER_LME ; }if (is_paging (vcpu) && !(cr0 &X86_CR0_PG )) { - vcpu->arch.shadow_efer &= ~EFER_LMA ; + vcpu->arch.efer &= ~EFER_LMA ; svm->vmcb->save.efer &= ~(EFER_LMA |EFER_LME ); } }
@@ -1361,7 +1361,7 @@ static int vmmcall_interception(struct vcpu_svm *svm)static int nested_svm_check_permissions (struct vcpu_svm *svm) { -if (!(svm->vcpu.arch.shadow_efer &EFER_SVME ) +if (!(svm->vcpu.arch.efer &EFER_SVME ) || !is_paging (&svm->vcpu)) {kvm_queue_exception (&svm->vcpu,UD_VECTOR );return 1 ;
@@ -1764,7 +1764,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) hsave->save.ds = vmcb->save.ds; hsave->save.gdtr = vmcb->save.gdtr; hsave->save.idtr = vmcb->save.idtr; - hsave->save.efer = svm->vcpu.arch.shadow_efer; + hsave->save.efer = svm->vcpu.arch.efer; hsave->save.cr0 =kvm_read_cr0 (&svm->vcpu); hsave->save.cr4 = svm->vcpu.arch.cr4; hsave->save.rflags = vmcb->save.rflags;
arch/x86/kvm/vmx.c +7 -7
@@ -613,7 +613,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)u64 guest_efer;u64 ignore_bits; - guest_efer = vmx->vcpu.arch.shadow_efer; + guest_efer = vmx->vcpu.arch.efer;/* * NX is emulated; LMA and LME handled by hardware; SCE meaninless
@@ -955,7 +955,7 @@ static void setup_msrs(struct vcpu_vmx *vmx)* if efer.sce is enabled. */ index =__find_msr_index (vmx,MSR_K6_STAR ); -if ((index >=0 ) && (vmx->vcpu.arch.shadow_efer &EFER_SCE )) +if ((index >=0 ) && (vmx->vcpu.arch.efer &EFER_SCE )) move_msr_up(vmx, index, save_nmsrs++); }#endif
@@ -1600,7 +1600,7 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)* of this msr depends on is_long_mode(). */ vmx_load_host_state (to_vmx (vcpu)); - vcpu->arch.shadow_efer = efer; + vcpu->arch.efer = efer;if (!msr)return ;if (efer &EFER_LMA ) {
@@ -1632,13 +1632,13 @@ static void enter_lmode(struct kvm_vcpu *vcpu) (guest_tr_ar & ~AR_TYPE_MASK ) | AR_TYPE_BUSY_64_TSS); } - vcpu->arch.shadow_efer |=EFER_LMA ; -vmx_set_efer (vcpu, vcpu->arch.shadow_efer); + vcpu->arch.efer |=EFER_LMA ; +vmx_set_efer (vcpu, vcpu->arch.efer); }static void exit_lmode (struct kvm_vcpu *vcpu) { - vcpu->arch.shadow_efer &= ~EFER_LMA ; + vcpu->arch.efer &= ~EFER_LMA ;vmcs_write32 (VM_ENTRY_CONTROLS , vmcs_read32(VM_ENTRY_CONTROLS)
@@ -1745,7 +1745,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)enter_rmode (vcpu);#ifdef CONFIG_X86_64 -if (vcpu->arch.shadow_efer &EFER_LME ) { +if (vcpu->arch.efer &EFER_LME ) {if (!is_paging (vcpu) && (cr0 &X86_CR0_PG ))enter_lmode (vcpu);if (is_paging (vcpu) && !(cr0 &X86_CR0_PG ))
arch/x86/kvm/x86.c +7 -7
@@ -456,7 +456,7 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)if (!is_paging (vcpu) && (cr0 &X86_CR0_PG )) {#ifdef CONFIG_X86_64 -if ((vcpu->arch.shadow_efer &EFER_LME )) { +if ((vcpu->arch.efer &EFER_LME )) {int cs_db, cs_l;if (!is_pae (vcpu)) {
@@ -655,7 +655,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) }if (is_paging (vcpu) - && (vcpu->arch.shadow_efer &EFER_LME ) != (efer &EFER_LME )) { + && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) {printk (KERN_DEBUG "set_efer: #GP, change LME while paging\n" );kvm_inject_gp (vcpu,0 );return ;
@@ -686,9 +686,9 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) kvm_x86_ops->set_efer (vcpu, efer); efer &= ~EFER_LMA ; - efer |= vcpu->arch.shadow_efer &EFER_LMA ; + efer |= vcpu->arch.efer &EFER_LMA ; - vcpu->arch.shadow_efer = efer; + vcpu->arch.efer = efer; vcpu->arch.mmu.base_role.nxe = (efer &EFER_NX ) && !tdp_enabled;kvm_mmu_reset_context (vcpu);
@@ -1426,7 +1426,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) data |= (((uint64_t )4ULL ) <<40 );break ;case MSR_EFER : - data = vcpu->arch.shadow_efer; + data = vcpu->arch.efer;break ;case MSR_KVM_WALL_CLOCK : data = vcpu->kvm->arch.wall_clock;
@@ -4569,7 +4569,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, sregs->cr3 = vcpu->arch.cr3; sregs->cr4 =kvm_read_cr4 (vcpu); sregs->cr8 =kvm_get_cr8 (vcpu); - sregs->efer = vcpu->arch.shadow_efer; + sregs->efer = vcpu->arch.efer; sregs->apic_base =kvm_get_apic_base (vcpu);memset (sregs->interrupt_bitmap,0 ,sizeof sregs->interrupt_bitmap);
@@ -5059,7 +5059,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,kvm_set_cr8 (vcpu, sregs->cr8); - mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer; + mmu_reset_needed |= vcpu->arch.efer != sregs->efer; kvm_x86_ops->set_efer (vcpu, sregs->efer);kvm_set_apic_base (vcpu, sregs->apic_base);
arch/x86/kvm/x86.h +1 -1
@@ -44,7 +44,7 @@ static inline bool is_protmode(struct kvm_vcpu *vcpu)static inline int is_long_mode (struct kvm_vcpu *vcpu) {#ifdef CONFIG_X86_64 -return vcpu->arch.shadow_efer &EFER_LMA ; +return vcpu->arch.efer &EFER_LMA ;#else return 0 ;#endif
Signature · 1 line
1.6.5.3
PATCH 19/38 KVM: Optimize kvm_read_cr[04]_bits()
In reply to Avi Kivity'mask' is always a constant, so we can check whether it includes a bit that might be owned by the guest very cheaply, and avoid the decache call. Saves a few hundred bytes of module text.
--- arch/x86/kvm/kvm_cache_regs.h | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/kvm/kvm_cache_regs.h +9 -2
@@ -1,6 +1,11 @@#ifndef ASM_KVM_CACHE_REGS_H #define ASM_KVM_CACHE_REGS_H +#define KVM_POSSIBLE_CR0_GUEST_BITS X86_CR0_TS +#define KVM_POSSIBLE_CR4_GUEST_BITS \ + (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR \ + | X86_CR4_OSXMMEXCPT | X86_CR4_PGE) +static inline unsigned long kvm_register_read (struct kvm_vcpu *vcpu,enum kvm_reg reg) {
@@ -40,7 +45,8 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)static inline ulong kvm_read_cr0_bits (struct kvm_vcpu *vcpu,ulong mask) { -if (mask & vcpu->arch.cr0_guest_owned_bits) +ulong tmask = mask &KVM_POSSIBLE_CR0_GUEST_BITS ; +if (tmask & vcpu->arch.cr0_guest_owned_bits) kvm_x86_ops->decache_cr0_guest_bits (vcpu);return vcpu->arch.cr0 & mask; }
@@ -52,7 +58,8 @@ static inline ulong kvm_read_cr0(struct kvm_vcpu *vcpu)static inline ulong kvm_read_cr4_bits (struct kvm_vcpu *vcpu,ulong mask) { -if (mask & vcpu->arch.cr4_guest_owned_bits) +ulong tmask = mask &KVM_POSSIBLE_CR4_GUEST_BITS ; +if (tmask & vcpu->arch.cr4_guest_owned_bits) kvm_x86_ops->decache_cr4_guest_bits (vcpu);return vcpu->arch.cr4 & mask; }
Signature · 1 line
1.6.5.3
PATCH 20/38 KVM: trace guest fpu loads and unloads
In reply to Avi Kivity--- arch/x86/kvm/x86.c | 2 ++ include/trace/events/kvm.h | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
arch/x86/kvm/x86.c +2 -0
@@ -5292,6 +5292,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) vcpu->guest_fpu_loaded =1 ;kvm_fx_save (&vcpu->arch.host_fx_image);kvm_fx_restore (&vcpu->arch.guest_fx_image); +trace_kvm_fpu (1 ); }void kvm_put_guest_fpu (struct kvm_vcpu *vcpu)
@@ -5304,6 +5305,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)kvm_fx_restore (&vcpu->arch.host_fx_image); ++vcpu->stat.fpu_reload;set_bit (KVM_REQ_DEACTIVATE_FPU , &vcpu->requests); +trace_kvm_fpu (0 ); }void kvm_arch_vcpu_free (struct kvm_vcpu *vcpu)
include/trace/events/kvm.h +19 -0
@@ -145,6 +145,25 @@ TRACE_EVENT(kvm_mmio, __entry->len, __entry->gpa, __entry->val) ); +#define kvm_fpu_load_symbol \ + {0, "unload"}, \ + {1, "load"} + +TRACE_EVENT (kvm_fpu, + TP_PROTO(int load), +TP_ARGS (load), + +TP_STRUCT__entry ( +__field ( u32, load ) + ), + +TP_fast_assign ( + __entry->load = load; + ), + +TP_printk ("%s" ,__print_symbolic (__entry->load, kvm_fpu_load_symbol)) +); +#endif /* _TRACE_KVM_MAIN_H */ /* This part must be outside protection */
Signature · 1 line
1.6.5.3
PATCH 21/38 KVM: MMU: Remove some useless code from alloc_mmu_pages()
In reply to Avi KivityFrom: Wei Yongjun <[email protected]>
If we fail to alloc page for vcpu->arch.mmu.pae_root, call to free_mmu_pages() is unnecessary, which just do free the page malloc for vcpu->arch.mmu.pae_root.
--- arch/x86/kvm/mmu.c | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-)
arch/x86/kvm/mmu.c +2 -5
@@ -2843,16 +2843,13 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)*/ page =alloc_page (GFP_KERNEL | __GFP_DMA32);if (!page) - goto error_1; +return -ENOMEM ; + vcpu->arch.mmu.pae_root =page_address (page);for (i =0 ; i <4 ; ++i) vcpu->arch.mmu.pae_root[i] =INVALID_PAGE ;return 0 ; - -error_1: -free_mmu_pages (vcpu); -return -ENOMEM ; }int kvm_mmu_create (struct kvm_vcpu *vcpu)
Signature · 1 line
1.6.5.3
PATCH 22/38 KVM: PPC E500: Add register l1csr0 emulation
In reply to Avi KivityFrom: Liu Yu <[email protected]>
Latest kernel start to access l1csr0 to contron L1. We just tell guest no operation is on going.
--- arch/powerpc/include/asm/kvm_e500.h | 1 + arch/powerpc/kvm/e500_emulate.c | 6 ++++++ 2 files changed, 7 insertions(+), 0 deletions(-)
arch/powerpc/include/asm/kvm_e500.h +1 -0
@@ -52,6 +52,7 @@ struct kvmppc_vcpu_e500 {u32 mas5;u32 mas6;u32 mas7; +u32 l1csr0;u32 l1csr1;u32 hid0;u32 hid1;
arch/powerpc/kvm/e500_emulate.c +6 -0
@@ -99,6 +99,10 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) vcpu_e500->mas6 = spr_val;break ;case SPRN_MAS7 : vcpu_e500->mas7 = spr_val;break ; +case SPRN_L1CSR0 : + vcpu_e500->l1csr0 = spr_val; + vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI |L1CSR0_CLFC ); +break ;case SPRN_L1CSR1 : vcpu_e500->l1csr1 = spr_val;break ;case SPRN_HID0 :
@@ -179,6 +183,8 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)break ; } +case SPRN_L1CSR0 : +kvmppc_set_gpr (vcpu, rt, vcpu_e500->l1csr0);break ;case SPRN_L1CSR1 :kvmppc_set_gpr (vcpu, rt, vcpu_e500->l1csr1);break ;case SPRN_HID0 :
Signature · 1 line
1.6.5.3
PATCH 23/38 KVM: PPC: Add PVR/PIR init for E500
In reply to Avi KivityFrom: Liu Yu <[email protected]>
commit 513579e3a391a3874c478a8493080822069976e8 change the way we emulate PVR/PIR,
which left PVR/PIR uninitialized on E500, and make guest puzzled.
--- arch/powerpc/kvm/e500.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
arch/powerpc/kvm/e500.c +6 -0
@@ -60,6 +60,12 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)kvmppc_e500_tlb_setup (vcpu_e500); +/* Registers init */ + vcpu->arch.pvr =mfspr (SPRN_PVR ); + +/* Since booke kvm only support one core, update all vcpus' PIR to 0 */ + vcpu->vcpu_id =0 ; +return 0 ; }
Signature · 1 line
1.6.5.3
PATCH 24/38 KVM: PPC E500: fix tlbcfg emulation
In reply to Avi KivityFrom: Liu Yu <[email protected]>
commit 55fb1027c1cf9797dbdeab48180da530e81b1c39 doesn't update tlbcfg correctly. Fix it.
And since guest OS likes 'fixed' hardware, initialize tlbcfg everytime when guest access is useless. So move this part to init code.
--- arch/powerpc/include/asm/kvm_e500.h | 2 ++ arch/powerpc/kvm/e500_emulate.c | 20 ++------------------ arch/powerpc/kvm/e500_tlb.c | 6 ++++++ 3 files changed, 10 insertions(+), 18 deletions(-)
arch/powerpc/include/asm/kvm_e500.h +2 -0
@@ -56,6 +56,8 @@ struct kvmppc_vcpu_e500 {u32 l1csr1;u32 hid0;u32 hid1; +u32 tlb0cfg; +u32 tlb1cfg;struct kvm_vcpu vcpu; };
arch/powerpc/kvm/e500_emulate.c +2 -18
@@ -164,25 +164,9 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)kvmppc_set_gpr (vcpu, rt, vcpu_e500->mas7);break ;case SPRN_TLB0CFG : - { -ulong tmp =SPRN_TLB0CFG ; - - tmp &= ~0xfffUL ; - tmp |= vcpu_e500->guest_tlb_size[0 ]; -kvmppc_set_gpr (vcpu, rt, tmp); -break ; - } - +kvmppc_set_gpr (vcpu, rt, vcpu_e500->tlb0cfg);break ;case SPRN_TLB1CFG : - { -ulong tmp =SPRN_TLB1CFG ; - - tmp &= ~0xfffUL ; - tmp |= vcpu_e500->guest_tlb_size[1 ]; -kvmppc_set_gpr (vcpu, rt, tmp); -break ; - } - +kvmppc_set_gpr (vcpu, rt, vcpu_e500->tlb1cfg);break ;case SPRN_L1CSR0 :kvmppc_set_gpr (vcpu, rt, vcpu_e500->l1csr0);break ;case SPRN_L1CSR1 :
arch/powerpc/kvm/e500_tlb.c +6 -0
@@ -728,6 +728,12 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)if (vcpu_e500->shadow_pages[1 ] ==NULL ) goto err_out_page0; +/* Init TLB configuration register */ + vcpu_e500->tlb0cfg =mfspr (SPRN_TLB0CFG ) & ~0xfffUL ; + vcpu_e500->tlb0cfg |= vcpu_e500->guest_tlb_size[0 ]; + vcpu_e500->tlb1cfg =mfspr (SPRN_TLB1CFG ) & ~0xfffUL ; + vcpu_e500->tlb1cfg |= vcpu_e500->guest_tlb_size[1 ]; +return 0 ; err_out_page0:
Signature · 1 line
1.6.5.3
PATCH 25/38 KVM: VMX: Pass cr0.mp through to the guest when the fpu is active
In reply to Avi KivityWhen cr0.mp is clear, the guest doesn't expect a #NM in response to a WAIT instruction. Because we always keep cr0.mp set, it will get a #NM, and potentially be confused.
Fix by keeping cr0.mp set only when the fpu is inactive, and passing it through when inactive.
--- arch/x86/kvm/vmx.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)
arch/x86/kvm/vmx.c +9 -6
@@ -66,7 +66,7 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);#define KVM_GUEST_CR0_MASK \ (KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST \ - (X86_CR0_WP | X86_CR0_NE | X86_CR0_MP) + (X86_CR0_WP | X86_CR0_NE)#define KVM_VM_CR0_ALWAYS_ON \ (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)#define KVM_CR4_GUEST_OWNED_BITS \
@@ -791,12 +791,15 @@ static void vmx_vcpu_put(struct kvm_vcpu *vcpu)static void vmx_fpu_activate (struct kvm_vcpu *vcpu) { +ulong cr0; +if (vcpu->fpu_active)return ; vcpu->fpu_active =1 ; -vmcs_clear_bits (GUEST_CR0 ,X86_CR0_TS ); -if (kvm_read_cr0_bits (vcpu,X86_CR0_TS )) -vmcs_set_bits (GUEST_CR0 ,X86_CR0_TS ); + cr0 =vmcs_readl (GUEST_CR0 ); + cr0 &= ~(X86_CR0_TS |X86_CR0_MP ); + cr0 |=kvm_read_cr0_bits (vcpu,X86_CR0_TS |X86_CR0_MP ); +vmcs_writel (GUEST_CR0 , cr0);update_exception_bitmap (vcpu); vcpu->arch.cr0_guest_owned_bits =X86_CR0_TS ;vmcs_writel (CR0_GUEST_HOST_MASK , ~vcpu->arch.cr0_guest_owned_bits);
@@ -807,7 +810,7 @@ static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu);static void vmx_fpu_deactivate (struct kvm_vcpu *vcpu) {vmx_decache_cr0_guest_bits (vcpu); -vmcs_set_bits (GUEST_CR0 ,X86_CR0_TS ); +vmcs_set_bits (GUEST_CR0 ,X86_CR0_TS |X86_CR0_MP );update_exception_bitmap (vcpu); vcpu->arch.cr0_guest_owned_bits =0 ;vmcs_writel (CR0_GUEST_HOST_MASK , ~vcpu->arch.cr0_guest_owned_bits);
@@ -1757,7 +1760,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)ept_update_paging_mode_cr0 (&hw_cr0, cr0, vcpu);if (!vcpu->fpu_active) - hw_cr0 |=X86_CR0_TS ; + hw_cr0 |=X86_CR0_TS |X86_CR0_MP ;vmcs_writel (CR0_READ_SHADOW , cr0);vmcs_writel (GUEST_CR0 , hw_cr0);
Signature · 1 line
1.6.5.3
PATCH 26/38 KVM: mark segments accessed on HW task switch
In reply to Avi KivityFrom: Gleb Natapov <[email protected]>
On HW task switch newly loaded segments should me marked as accessed.
--- arch/x86/kvm/x86.c | 22 +++++++++------------- 1 files changed, 9 insertions(+), 13 deletions(-)
arch/x86/kvm/x86.c +9 -13
@@ -4697,18 +4697,6 @@ static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)return kvm_seg.selector; } -static int load_segment_descriptor_to_kvm_desct (struct kvm_vcpu *vcpu, -u16 selector, -struct kvm_segment *kvm_seg) -{ -struct desc_struct seg_desc; - -if (load_guest_segment_descriptor (vcpu, selector, &seg_desc)) -return 1 ; -seg_desct_to_kvm_desct (&seg_desc, selector, kvm_seg); -return 0 ; -} -static int kvm_load_realmode_segment (struct kvm_vcpu *vcpu,u16 selector,int seg) {struct kvm_segment segvar = {
@@ -4749,11 +4737,14 @@ int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int type_bits, int seg) {struct kvm_segment kvm_seg; +struct desc_struct seg_desc;if (is_vm86_segment (vcpu, seg) || !is_protmode (vcpu))return kvm_load_realmode_segment (vcpu, selector, seg); -if (load_segment_descriptor_to_kvm_desct (vcpu, selector, &kvm_seg)) + +if (load_guest_segment_descriptor (vcpu, selector, &seg_desc))return 1 ; +seg_desct_to_kvm_desct (&seg_desc, selector, &kvm_seg);kvm_check_segment_descriptor (vcpu, seg, selector); kvm_seg.type |= type_bits;
@@ -4764,6 +4755,11 @@ int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, kvm_seg.unusable =1 ;kvm_set_segment (vcpu, &kvm_seg, seg); +if (selector && !kvm_seg.unusable && kvm_seg.s) { +/* mark segment as accessed */ + seg_desc.type |=1 ; +save_guest_segment_descriptor (vcpu, selector, &seg_desc); + }return 0 ; }
Signature · 1 line
1.6.5.3
PATCH 27/38 KVM: Fix msr trace
In reply to Avi Kivity- data is 64 bits wide, not unsigned long
- rw is confusingly named
--- arch/x86/kvm/trace.h | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-)
arch/x86/kvm/trace.h +8 -8
@@ -246,23 +246,23 @@ TRACE_EVENT(kvm_page_fault,* Tracepoint for guest MSR access. */ TRACE_EVENT (kvm_msr, - TP_PROTO(unsigned int rw, unsigned int ecx, unsigned long data), -TP_ARGS (rw, ecx, data), + TP_PROTO(unsigned write, u32 ecx, u64 data), +TP_ARGS (write, ecx, data),TP_STRUCT__entry ( - __field( unsigned int, rw ) - __field( unsigned int, ecx ) - __field( unsigned long, data ) + __field( unsigned, write ) + __field( u32, ecx ) +__field ( u64, data ) ),TP_fast_assign ( - __entry->rw = rw; + __entry->write = write; __entry->ecx = ecx; __entry->data = data; ), -TP_printk ("msr_%s %x = 0x%lx" , - __entry->rw ?"write" :"read" , +TP_printk ("msr_%s %x = 0x%llx" , + __entry->write ?"write" :"read" , __entry->ecx, __entry->data) );
Signature · 1 line
1.6.5.3
PATCH 28/38 KVM: Trace failed msr reads and writes
In reply to Avi KivityRecord failed msrs reads and writes, and the fact that they failed as well.
--- arch/x86/kvm/svm.c | 13 ++++++++----- arch/x86/kvm/trace.h | 17 +++++++++++------ arch/x86/kvm/vmx.c | 5 +++-- 3 files changed, 22 insertions(+), 13 deletions(-)
arch/x86/kvm/svm.c +8 -5
@@ -2177,9 +2177,10 @@ static int rdmsr_interception(struct vcpu_svm *svm)u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX ];u64 data; -if (svm_get_msr (&svm->vcpu, ecx, &data)) +if (svm_get_msr (&svm->vcpu, ecx, &data)) { +trace_kvm_msr_read_ex (ecx);kvm_inject_gp (&svm->vcpu,0 ); -else { + }else {trace_kvm_msr_read (ecx, data); svm->vcpu.arch.regs[VCPU_REGS_RAX ] = data &0xffffffff ;
@@ -2271,13 +2272,15 @@ static int wrmsr_interception(struct vcpu_svm *svm)u64 data = (svm->vcpu.arch.regs[VCPU_REGS_RAX ] &-1u ) | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX ] &-1u ) <<32 ); -trace_kvm_msr_write (ecx, data); svm->next_rip =kvm_rip_read (&svm->vcpu) +2 ; -if (svm_set_msr (&svm->vcpu, ecx, data)) +if (svm_set_msr (&svm->vcpu, ecx, data)) { +trace_kvm_msr_write_ex (ecx, data);kvm_inject_gp (&svm->vcpu,0 ); -else + }else { +trace_kvm_msr_write (ecx, data);skip_emulated_instruction (&svm->vcpu); + }return 1 ; }
arch/x86/kvm/trace.h +11 -6
@@ -246,28 +246,33 @@ TRACE_EVENT(kvm_page_fault,* Tracepoint for guest MSR access. */ TRACE_EVENT (kvm_msr, - TP_PROTO(unsigned write, u32 ecx, u64 data), -TP_ARGS (write, ecx, data), + TP_PROTO(unsigned write, u32 ecx, u64 data, bool exception), +TP_ARGS (write, ecx, data, exception),TP_STRUCT__entry ( __field( unsigned, write ) __field( u32, ecx ) __field( u64, data ) +__field ( u8, exception ) ),TP_fast_assign ( __entry->write = write; __entry->ecx = ecx; __entry->data = data; + __entry->exception = exception; ), -TP_printk ("msr_%s %x = 0x%llx" , +TP_printk ("msr_%s %x = 0x%llx%s" , __entry->write ?"write" :"read" , - __entry->ecx, __entry->data) + __entry->ecx, __entry->data, + __entry->exception ?" (#GP)" :"" ) ); -#define trace_kvm_msr_read (ecx, data) trace_kvm_msr(0, ecx, data) -#define trace_kvm_msr_write (ecx, data) trace_kvm_msr(1, ecx, data) +#define trace_kvm_msr_read (ecx, data) trace_kvm_msr(0, ecx, data, false) +#define trace_kvm_msr_write (ecx, data) trace_kvm_msr(1, ecx, data, false) +#define trace_kvm_msr_read_ex (ecx) trace_kvm_msr(0, ecx, 0, true) +#define trace_kvm_msr_write_ex (ecx, data) trace_kvm_msr(1, ecx, data, true)/* * Tracepoint for guest CR access.
arch/x86/kvm/vmx.c +3 -2
@@ -3158,6 +3158,7 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu)u64 data;if (vmx_get_msr (vcpu, ecx, &data)) { +trace_kvm_msr_read_ex (ecx);kvm_inject_gp (vcpu,0 );return 1 ; }
@@ -3177,13 +3178,13 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu)u64 data = (vcpu->arch.regs[VCPU_REGS_RAX ] &-1u ) | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX ] &-1u ) <<32 ); -trace_kvm_msr_write (ecx, data); -if (vmx_set_msr (vcpu, ecx, data) !=0 ) { +trace_kvm_msr_write_ex (ecx, data);kvm_inject_gp (vcpu,0 );return 1 ; } +trace_kvm_msr_write (ecx, data);skip_emulated_instruction (vcpu);return 1 ; }
Signature · 1 line
1.6.5.3
PATCH 29/38 KVM: VMX: Remove redundant check in vm_need_virtualize_apic_accesses()
In reply to Avi KivityFrom: Gui Jianfeng <[email protected]>
flexpriority_enabled implies cpu_has_vmx_virtualize_apic_accesses() returning true, so we don't need this check here.
--- arch/x86/kvm/vmx.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-)
arch/x86/kvm/vmx.c +1 -3
@@ -358,9 +358,7 @@ static inline int cpu_has_vmx_ple(void)static inline int vm_need_virtualize_apic_accesses (struct kvm *kvm) { -return flexpriority_enabled && - (cpu_has_vmx_virtualize_apic_accesses ()) && - (irqchip_in_kernel (kvm)); +return flexpriority_enabled &&irqchip_in_kernel (kvm); }static inline int cpu_has_vmx_vpid (void )
Signature · 1 line
1.6.5.3
PATCH 30/38 KVM: enable PCI multiple-segments for pass-through device
In reply to Avi KivityFrom: Zhai, Edwin <[email protected]>
Enable optional parameter (default 0) - PCI segment (or domain) besides BDF, when assigning PCI device to guest.
--- arch/x86/kvm/x86.c | 1 + include/linux/kvm.h | 4 +++- include/linux/kvm_host.h | 1 + virt/kvm/assigned-dev.c | 4 +++- virt/kvm/iommu.c | 9 ++++++--- 5 files changed, 14 insertions(+), 5 deletions(-)
arch/x86/kvm/x86.c +1 -0
@@ -1569,6 +1569,7 @@ int kvm_dev_ioctl_check_extension(long ext)case KVM_CAP_HYPERV :case KVM_CAP_HYPERV_VAPIC :case KVM_CAP_HYPERV_SPIN : +case KVM_CAP_PCI_SEGMENT : r =1 ;break ;case KVM_CAP_COALESCED_MMIO :
include/linux/kvm.h +3 -1
@@ -500,6 +500,7 @@ struct kvm_ioeventfd {#define KVM_CAP_HYPERV 44#define KVM_CAP_HYPERV_VAPIC 45#define KVM_CAP_HYPERV_SPIN 46 +#define KVM_CAP_PCI_SEGMENT 47#ifdef KVM_CAP_IRQ_ROUTING
@@ -694,8 +695,9 @@ struct kvm_assigned_pci_dev {__u32 busnr;__u32 devfn;__u32 flags; +__u32 segnr;union { -__u32 reserved[12 ]; +__u32 reserved[11 ]; }; };
include/linux/kvm_host.h +1 -0
@@ -400,6 +400,7 @@ struct kvm_assigned_dev_kernel {struct work_struct interrupt_work;struct list_head list;int assigned_dev_id; +int host_segnr;int host_busnr;int host_devfn;unsigned int entries_nr;
virt/kvm/assigned-dev.c +3 -1
@@ -526,7 +526,8 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, r = -ENOMEM ; goto out; } - dev =pci_get_bus_and_slot (assigned_dev->busnr, + dev =pci_get_domain_bus_and_slot (assigned_dev->segnr, + assigned_dev->busnr, assigned_dev->devfn);if (!dev) {printk (KERN_INFO "%s: host device not found\n" , __func__);
@@ -548,6 +549,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,pci_reset_function (dev); match->assigned_dev_id = assigned_dev->assigned_dev_id; + match->host_segnr = assigned_dev->segnr; match->host_busnr = assigned_dev->busnr; match->host_devfn = assigned_dev->devfn; match->flags = assigned_dev->flags;
virt/kvm/iommu.c +6 -3
@@ -106,7 +106,8 @@ int kvm_assign_device(struct kvm *kvm, r =iommu_attach_device (domain, &pdev->dev);if (r) { -printk (KERN_ERR "assign device %x:%x.%x failed" , +printk (KERN_ERR "assign device %x:%x:%x.%x failed" , +pci_domain_nr (pdev->bus), pdev->bus->number,PCI_SLOT (pdev->devfn),PCI_FUNC (pdev->devfn));
@@ -127,7 +128,8 @@ int kvm_assign_device(struct kvm *kvm, goto out_unmap; } -printk (KERN_DEBUG "assign device: host bdf = %x:%x:%x\n" , +printk (KERN_DEBUG "assign device %x:%x:%x.%x\n" , + assigned_dev->host_segnr, assigned_dev->host_busnr,PCI_SLOT (assigned_dev->host_devfn),PCI_FUNC (assigned_dev->host_devfn));
@@ -154,7 +156,8 @@ int kvm_deassign_device(struct kvm *kvm,iommu_detach_device (domain, &pdev->dev); -printk (KERN_DEBUG "deassign device: host bdf = %x:%x:%x\n" , +printk (KERN_DEBUG "deassign device %x:%x:%x.%x\n" , + assigned_dev->host_segnr, assigned_dev->host_busnr,PCI_SLOT (assigned_dev->host_devfn),PCI_FUNC (assigned_dev->host_devfn));
Signature · 1 line
1.6.5.3
PATCH 31/38 KVM: fix load_guest_segment_descriptor() to return X86EMUL_*
In reply to Avi KivityFrom: Takuya Yoshikawa <[email protected]>
This patch fixes load_guest_segment_descriptor() to return X86EMUL_PROPAGATE_FAULT when it tries to access the descriptor table beyond the limit of it: suggested by Marcelo.
I have checked current callers of this helper function,
- kvm_load_segment_descriptor()
- kvm_task_switch()
and confirmed that this patch will change nothing in the upper layers if we do not change the handling of this return value from load_guest_segment_descriptor().
Next step: Although fixing the kvm_task_switch() to handle the propagated faults properly seems difficult, and maybe not worth it because TSS is not used commonly these days, we can fix kvm_load_segment_descriptor(). By doing so, the injected #GP becomes possible to be handled by the guest. The only problem for this is how to differentiate this fault from the page faults generated by kvm_read_guest_virt(). We may have to split this function to achive this goal.
--- arch/x86/kvm/x86.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kvm/x86.c +1 -1
@@ -4663,7 +4663,7 @@ static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,if (dtable.limit < index *8 +7 ) {kvm_queue_exception_e (vcpu,GP_VECTOR , selector &0xfffc ); -return 1 ; +return X86EMUL_PROPAGATE_FAULT ; }return kvm_read_guest_virt (dtable.base + index*8 , seg_desc,sizeof (*seg_desc), vcpu); }
Signature · 1 line
1.6.5.3
PATCH 32/38 KVM: fix kvm_fix_hypercall() to return X86EMUL_*
In reply to Avi KivityFrom: Takuya Yoshikawa <[email protected]>
This patch fixes kvm_fix_hypercall() to propagate X86EMUL_* info generated by emulator_write_emulated() to its callers:
suggested by Marcelo.
The effect of this is x86_emulate_insn() will begin to handle the page faults which occur in emulator_write_emulated():
this should be OK because emulator_write_emulated_onepage() always injects page fault when emulator_write_emulated() returns X86EMUL_PROPAGATE_FAULT.
--- arch/x86/kvm/x86.c | 7 +------ 1 files changed, 1 insertions(+), 6 deletions(-)
arch/x86/kvm/x86.c +1 -6
@@ -3888,10 +3888,8 @@ EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);int kvm_fix_hypercall (struct kvm_vcpu *vcpu) {char instruction[3 ]; -int ret =0 ;unsigned long rip =kvm_rip_read (vcpu); -/* * Blow out the MMU to ensure that no other VCPU has an active mapping * to ensure that the updated hypercall appears atomically across all
@@ -3900,11 +3898,8 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)kvm_mmu_zap_all (vcpu->kvm); kvm_x86_ops->patch_hypercall (vcpu, instruction); -if (emulator_write_emulated (rip, instruction,3 , vcpu) - !=X86EMUL_CONTINUE ) - ret = -EFAULT ; -return ret; +return emulator_write_emulated (rip, instruction,3 , vcpu); }static u64 mk_cr_64 (u64 curr_cr,u32 new_val)
Signature · 1 line
1.6.5.3
PATCH 33/38 KVM: VMX: Wire up .fpu_activate() callback
In reply to Avi Kivity--- arch/x86/kvm/vmx.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/kvm/vmx.c +1 -0
@@ -4137,6 +4137,7 @@ static struct kvm_x86_ops vmx_x86_ops = { .cache_reg = vmx_cache_reg, .get_rflags = vmx_get_rflags, .set_rflags = vmx_set_rflags, + .fpu_activate = vmx_fpu_activate, .fpu_deactivate = vmx_fpu_deactivate, .tlb_flush = vmx_flush_tlb,
Signature · 1 line
1.6.5.3
PATCH 34/38 KVM: ia64: Fix string literal continuation lines
In reply to Avi KivityFrom: Joe Perches <[email protected]>
String constants that are continued on subsequent lines with \
are not good.
--- arch/ia64/kvm/mmio.c | 4 ++-- arch/ia64/kvm/vcpu.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
arch/ia64/kvm/mmio.c +2 -2
@@ -316,8 +316,8 @@ void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma)return ; }else { inst_type =-1 ; -panic_vm (vcpu,"Unsupported MMIO access instruction! \ -Bunld[0]=0x%lx, Bundle[1]=0x%lx\n" , +panic_vm (vcpu,"Unsupported MMIO access instruction! " +"Bunld[0]=0x%lx, Bundle[1]=0x%lx\n" , bundle.i64[0 ], bundle.i64[1 ]); }
arch/ia64/kvm/vcpu.c +2 -2
@@ -1639,8 +1639,8 @@ void vcpu_set_psr(struct kvm_vcpu *vcpu, unsigned long val)* Otherwise panic */ if (val & (IA64_PSR_PK |IA64_PSR_IS |IA64_PSR_VM )) -panic_vm (vcpu,"Only support guests with vpsr.pk =0 \ -& vpsr.is=0\n" ); +panic_vm (vcpu,"Only support guests with vpsr.pk =0 " +"& vpsr.is=0\n" );/* * For those IA64_PSR bits: id/da/dd/ss/ed/ia
Signature · 1 line
1.6.5.3
PATCH 35/38 KVM: VMX: Remove redundant test in vmx_set_efer()
In reply to Avi KivityFrom: Julia Lawall <[email protected]>
msr was tested above, so the second test is not needed.
A simplified version of the semantic match that finds this problem is as
follows: (http://coccinelle.lip6.fr/)
// <smpl>
@r@
expression *x;
expression e;
identifier l;
@@
if (x == NULL || ...) {
... when forall
return ...; }
... when != goto l;
when != x = e
when != &x*x == NULL
// </smpl>
--- arch/x86/kvm/vmx.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx.c +0 -2
@@ -1602,8 +1602,6 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)*/ vmx_load_host_state (to_vmx (vcpu)); vcpu->arch.efer = efer; -if (!msr) -return ;if (efer &EFER_LMA ) { vmcs_write32(VM_ENTRY_CONTROLS, vmcs_read32(VM_ENTRY_CONTROLS) |
Signature · 1 line
1.6.5.3
PATCH 36/38 KVM: Introduce kvm_host_page_size
In reply to Avi KivityFrom: Joerg Roedel <[email protected]>
This patch introduces a generic function to find out the host page size for a given gfn. This function is needed by the kvm iommu code. This patch also simplifies the x86 host_mapping_level function.
--- arch/x86/kvm/mmu.c | 18 ++---------------- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 16 deletions(-)
arch/x86/kvm/mmu.c +2 -16
@@ -468,24 +468,10 @@ static int has_wrprotected_page(struct kvm *kvm,static int host_mapping_level (struct kvm *kvm,gfn_t gfn) { -unsigned long page_size =PAGE_SIZE ; -struct vm_area_struct *vma; -unsigned long addr; +unsigned long page_size;int i, ret =0 ; - addr =gfn_to_hva (kvm, gfn); -if (kvm_is_error_hva (addr)) -return PT_PAGE_TABLE_LEVEL ; - -down_read (¤t->mm->mmap_sem); - vma =find_vma (current->mm, addr); -if (!vma) - goto out; - - page_size =vma_kernel_pagesize (vma); - -out: -up_read (¤t->mm->mmap_sem); + page_size =kvm_host_page_size (kvm, gfn);for (i =PT_PAGE_TABLE_LEVEL ; i < (PT_PAGE_TABLE_LEVEL +KVM_NR_PAGE_SIZES ); ++i) {
include/linux/kvm_host.h +1 -0
@@ -300,6 +300,7 @@ int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);int kvm_clear_guest (struct kvm *kvm,gpa_t gpa,unsigned long len);struct kvm_memory_slot *gfn_to_memslot (struct kvm *kvm,gfn_t gfn);int kvm_is_visible_gfn (struct kvm *kvm,gfn_t gfn); +unsigned long kvm_host_page_size (struct kvm *kvm,gfn_t gfn);void mark_page_dirty (struct kvm *kvm,gfn_t gfn);void kvm_vcpu_block (struct kvm_vcpu *vcpu);
virt/kvm/kvm_main.c +25 -0
@@ -45,6 +45,7 @@#include <linux/spinlock.h> #include <linux/compat.h> #include <linux/srcu.h> +#include <linux/hugetlb.h> #include <asm/processor.h> #include <asm/io.h>
@@ -867,6 +868,30 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) }EXPORT_SYMBOL_GPL (kvm_is_visible_gfn); +unsigned long kvm_host_page_size (struct kvm *kvm,gfn_t gfn) +{ +struct vm_area_struct *vma; +unsigned long addr, size; + + size =PAGE_SIZE ; + + addr =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (addr)) +return PAGE_SIZE ; + +down_read (¤t->mm->mmap_sem); + vma =find_vma (current->mm, addr); +if (!vma) + goto out; + + size =vma_kernel_pagesize (vma); + +out: +up_read (¤t->mm->mmap_sem); + +return size; +} +int memslot_id (struct kvm *kvm,gfn_t gfn) {int i;
Signature · 1 line
1.6.5.3
PATCH 37/38 KVM: VMX: emulate accessed bit for EPT
In reply to Avi KivityFrom: Rik van Riel <[email protected]>
Currently KVM pretends that pages with EPT mappings never got accessed. This has some side effects in the VM, like swapping out actively used guest pages and needlessly breaking up actively used hugepages.
We can avoid those very costly side effects by emulating the accessed bit for EPT PTEs, which should only be slightly costly because pages pass through page_referenced infrequently.
TLB flushing is taken care of by kvm_mmu_notifier_clear_flush_young().
This seems to help prevent KVM guests from being swapped out when they should not on my system.
--- arch/x86/kvm/mmu.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-)
arch/x86/kvm/mmu.c +8 -2
@@ -838,9 +838,15 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,u64 *spte;int young =0 ; -/* always return old for EPT */ +/* +* Emulate the accessed bit for EPT, by checking if this page has +* an EPT mapping, and clearing it if it does. On the next access, +* a new EPT mapping will be established. +* This has some overhead, but not as much as the cost of swapping +* out actively used pages or breaking up actively used hugepages. +*/ if (!shadow_accessed_mask) -return 0 ; +return kvm_unmap_rmapp (kvm, rmapp, data); spte =rmap_next (kvm, rmapp,NULL );while (spte) {
Signature · 1 line
1.6.5.3
PATCH 38/38 KVM: Remove redundant reading of rax on OUT instructions
In reply to Avi KivityFrom: Takuya Yoshikawa <[email protected]>
kvm_emulate_pio() and complete_pio() both read out the RAX register value and copy it to a place into which the value read out from the port will be copied later.
This patch removes this redundancy.
/*** snippet from arch/x86/kvm/x86.c ***/
int complete_pio(struct kvm_vcpu *vcpu)
{
...
if (!io->string) {
if (io->in) {
val = kvm_register_read(vcpu, VCPU_REGS_RAX);
memcpy(&val, vcpu->arch.pio_data, io->size);
kvm_register_write(vcpu, VCPU_REGS_RAX, val);
}
...--- arch/x86/kvm/x86.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +4 -2
@@ -3551,8 +3551,10 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)trace_kvm_pio (vcpu->run->io.direction ==KVM_EXIT_IO_OUT , port, size,1 ); - val =kvm_register_read (vcpu,VCPU_REGS_RAX ); -memcpy (vcpu->arch.pio_data, &val,4 ); +if (!vcpu->arch.pio.in) { + val =kvm_register_read (vcpu,VCPU_REGS_RAX ); +memcpy (vcpu->arch.pio_data, &val,4 ); + }if (!kernel_pio (vcpu, vcpu->arch.pio_data)) {complete_pio (vcpu);
Signature · 1 line
1.6.5.3