Kernel updates for PowerPC KVM
Subsystems (3)
PATCH 1/1 Kernel updates for PowerPC KVM
Hi Avi, these patches have been tested in PowerPC trees for a while. Some of these reorganize the PowerPC KVM code to make implementations on other cores possible, but does cause a little code churn. There are also some performance optimization for 440 from Christian, and a few bugfixes thrown in too.
Please apply.
-Hollis
PATCH 1/1 kvm: ppc: adjust vcpu types to support 64-bit cores
However, some of these fields could be split into separate per-core structures in the future.
arch/powerpc/include/asm/kvm_host.h +25 -25
@@ -84,32 +84,32 @@ struct kvm_vcpu_arch {u32 host_msr;u64 fpr[32 ]; -u32 gpr[32 ]; +ulong gpr[32 ]; -u32 pc; +ulong pc;u32 cr; -u32 ctr; -u32 lr; -u32 xer; +ulong ctr; +ulong lr; +ulong xer; -u32 msr; +ulong msr;u32 mmucr; -u32 sprg0; -u32 sprg1; -u32 sprg2; -u32 sprg3; -u32 sprg4; -u32 sprg5; -u32 sprg6; -u32 sprg7; -u32 srr0; -u32 srr1; -u32 csrr0; -u32 csrr1; -u32 dsrr0; -u32 dsrr1; -u32 dear; -u32 esr; +ulong sprg0; +ulong sprg1; +ulong sprg2; +ulong sprg3; +ulong sprg4; +ulong sprg5; +ulong sprg6; +ulong sprg7; +ulong srr0; +ulong srr1; +ulong csrr0; +ulong csrr1; +ulong dsrr0; +ulong dsrr1; +ulong dear; +ulong esr;u32 dec;u32 decar;u32 tbl;
@@ -117,7 +117,7 @@ struct kvm_vcpu_arch {u32 tcr;u32 tsr;u32 ivor[16 ]; -u32 ivpr; +ulong ivpr;u32 pir;u32 shadow_pid;
@@ -131,8 +131,8 @@ struct kvm_vcpu_arch {u32 dbcr1;u32 last_inst; -u32 fault_dear; -u32 fault_esr; +ulong fault_dear; +ulong fault_esr;gpa_t paddr_accessed;u8 io_gpr;/* GPR used as IO source/target */
arch/powerpc/kvm/booke.c +5 -5
@@ -120,14 +120,14 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *v {int i; -printk ("pc: %08x msr: %08x\n" , vcpu->arch.pc, vcpu->arch.msr); -printk ("lr: %08x ctr: %08x\n" , vcpu->arch.lr, vcpu->arch.ctr); -printk ("srr0: %08x srr1: %08x\n" , vcpu->arch.srr0, vcpu->arch.srr1); +printk ("pc: %08lx msr: %08lx\n" , vcpu->arch.pc, vcpu->arch.msr); +printk ("lr: %08lx ctr: %08lx\n" , vcpu->arch.lr, vcpu->arch.ctr); +printk ("srr0: %08lx srr1: %08lx\n" , vcpu->arch.srr0, vcpu->arch.srr1);printk ("exceptions: %08lx\n" , vcpu->arch.pending_exceptions);for (i =0 ; i <32 ; i +=4 ) { - printk("gpr%02d: %08x %08x %08x %08x\n", i, + printk("gpr%02d: %08lx %08lx %08lx %08lx\n", i, vcpu->arch.gpr[i], vcpu->arch.gpr[i+1], vcpu->arch.gpr[i+2],
@@ -305,7 +305,7 @@ int kvmppc_handle_exit(struct kvm_run *rbreak ;case EMULATE_FAIL :/* XXX Deliver Program interrupt to guest. */ -printk (KERN_CRIT "%s: emulation at %x failed (%08x)\n" , +printk (KERN_CRIT "%s: emulation at %lx failed (%08x)\n" , __func__, vcpu->arch.pc, vcpu->arch.last_inst);/* For debugging, encode the failing instruction and * report it to userspace. */
arch/powerpc/kvm/emulate.c +1 -1
@@ -380,7 +380,7 @@ int kvmppc_emulate_instruction(struct kv } } -KVMTRACE_3D (PPC_INSTR , vcpu, inst, vcpu->arch.pc, emulated, entryexit); +KVMTRACE_3D (PPC_INSTR , vcpu, inst, (int )vcpu->arch.pc, emulated, entryexit);if (advance) vcpu->arch.pc +=4 ;/* Advance past emulated instruction. */
arch/powerpc/kvm/powerpc.c +2 -2
@@ -249,14 +249,14 @@ static void kvmppc_complete_dcr_load(strstatic void kvmppc_complete_dcr_load (struct kvm_vcpu *vcpu,struct kvm_run *run) { -u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr]; +ulong *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr]; *gpr = run->dcr.data; }static void kvmppc_complete_mmio_load (struct kvm_vcpu *vcpu,struct kvm_run *run) { -u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr]; +ulong *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr];if (run->mmio.len >sizeof (*gpr)) {printk (KERN_ERR "bad MMIO length: %d\n" , run->mmio.len);
PATCH 1/1 kvm: ppc: Move the last bits of 44x code out of booke.c
In reply to Hollis BlanchardNeeded to port to other Book E processors.
arch/powerpc/include/asm/kvm_ppc.h +3 -0
@@ -62,7 +62,10 @@ extern void kvmppc_mmu_switch_pid(struct/* Core-specific hooks */ +extern int kvmppc_core_vcpu_setup (struct kvm_vcpu *vcpu);extern int kvmppc_core_check_processor_compat (void ); +extern int kvmppc_core_vcpu_translate (struct kvm_vcpu *vcpu, +struct kvm_translation *tr);extern void kvmppc_core_vcpu_load (struct kvm_vcpu *vcpu,int cpu);extern void kvmppc_core_vcpu_put (struct kvm_vcpu *vcpu);
arch/powerpc/kvm/44x.c +53 -0
56 lines not on this page · raw message
arch/powerpc/kvm/booke.c +2 -44
67 lines not on this page · raw message
PATCH 1/1 kvm: ppc: create struct kvm_vcpu_44x and introduce container_of() accessor
In reply to Hollis BlanchardThis patch doesn't yet move all 44x-specific data into the new structure, but is the first step down that path. In the future we may also want to create a struct kvm_vcpu_booke.
Based on patch from Liu Yu <[email protected]>.
arch/powerpc/include/asm/kvm_44x.h new file +47 -0
@@ -0,0 +1,47 @@ +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2, as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Copyright IBM Corp. 2008 +* +* Authors: Hollis Blanchard <[email protected]> +*/ + +#ifndef __ASM_44X_H__ +#define __ASM_44X_H__ + +#include <linux/kvm_host.h> + +/* XXX Can't include mmu-44x.h because it redefines struct mm_context. */ +#define PPC44x_TLB_SIZE 64 + +struct kvmppc_vcpu_44x { +/* Unmodified copy of the guest's TLB. */ +struct kvmppc_44x_tlbe guest_tlb[PPC44x_TLB_SIZE]; +/* TLB that's actually used when the guest is running. */ +struct kvmppc_44x_tlbe shadow_tlb[PPC44x_TLB_SIZE]; +/* Pages which are referenced in the shadow TLB. */ +struct page *shadow_pages[PPC44x_TLB_SIZE]; + +/* Track which TLB entries we've modified in the current exit. */ +u8 shadow_tlb_mod[PPC44x_TLB_SIZE]; + +struct kvm_vcpu vcpu; +}; + +static inline struct kvmppc_vcpu_44x *to_44x (struct kvm_vcpu *vcpu) +{ + return container_of(vcpu, struct kvmppc_vcpu_44x, vcpu); +} + +#endif /* __ASM_44X_H__ */
arch/powerpc/include/asm/kvm_host.h +0 -13
@@ -74,20 +74,7 @@ struct kvm_arch {struct kvm_arch { }; -/* XXX Can't include mmu-44x.h because it redefines struct mm_context. */ -#define PPC44x_TLB_SIZE 64 -struct kvm_vcpu_arch { -/* Unmodified copy of the guest's TLB. */ -struct kvmppc_44x_tlbe guest_tlb[PPC44x_TLB_SIZE]; -/* TLB that's actually used when the guest is running. */ -struct kvmppc_44x_tlbe shadow_tlb[PPC44x_TLB_SIZE]; -/* Pages which are referenced in the shadow TLB. */ -struct page *shadow_pages[PPC44x_TLB_SIZE]; - -/* Track which TLB entries we've modified in the current exit. */ -u8 shadow_tlb_mod[PPC44x_TLB_SIZE]; -u32 host_stack;u32 host_pid;u32 host_dbcr0;
arch/powerpc/include/asm/kvm_ppc.h +7 -0
@@ -62,6 +62,9 @@ extern void kvmppc_mmu_switch_pid(struct/* Core-specific hooks */ +extern struct kvm_vcpu *kvmppc_core_vcpu_create (struct kvm *kvm, +unsigned int id); +extern void kvmppc_core_vcpu_free (struct kvm_vcpu *vcpu);extern int kvmppc_core_vcpu_setup (struct kvm_vcpu *vcpu);extern int kvmppc_core_check_processor_compat (void ); extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
@@ -85,4 +88,8 @@ extern int kvmppc_core_emulate_mtspr(strextern int kvmppc_core_emulate_mtspr (struct kvm_vcpu *vcpu,int sprn,int rs);extern int kvmppc_core_emulate_mfspr (struct kvm_vcpu *vcpu,int sprn,int rt); + +extern int kvmppc_booke_init (void ); +extern void kvmppc_booke_exit (void ); +#endif /* __POWERPC_KVM_PPC_H__ */
arch/powerpc/kernel/asm-offsets.c +9 -5
@@ -23,9 +23,6 @@#include <linux/mm.h> #include <linux/suspend.h> #include <linux/hrtimer.h> -#ifdef CONFIG_KVM -#include <linux/kvm_host.h> -#endif #ifdef CONFIG_PPC64 #include <linux/time.h> #include <linux/hardirq.h>
@@ -50,6 +47,9 @@#endif #ifdef CONFIG_PPC_ISERIES #include <asm/iseries/alpaca.h> +#endif +#ifdef CONFIG_KVM +#include <asm/kvm_44x.h> #endif #if defined(CONFIG_BOOKE ) || defined(CONFIG_40x)
@@ -357,10 +357,14 @@ int main(void)#ifdef CONFIG_KVM DEFINE (TLBE_BYTES ,sizeof (struct kvmppc_44x_tlbe )); +DEFINE (VCPU_TO_44X , offsetof(struct kvmppc_vcpu_44x , vcpu)); +DEFINE (VCPU44x_SHADOW_TLB, + offsetof(struct kvmppc_vcpu_44x , shadow_tlb)); +DEFINE (VCPU44x_SHADOW_MOD, + offsetof(struct kvmppc_vcpu_44x , shadow_tlb_mod)); + DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); - DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb)); - DEFINE(VCPU_SHADOW_MOD, offsetof(struct kvm_vcpu, arch.shadow_tlb_mod)); DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
arch/powerpc/kvm/44x.c +60 -2
92 lines not on this page · raw message
arch/powerpc/kvm/44x_tlb.c +24 -13
@@ -24,6 +24,7 @@#include <linux/highmem.h> #include <asm/mmu-44x.h> #include <asm/kvm_ppc.h> +#include <asm/kvm_44x.h> #include "44x_tlb.h"
@@ -43,7 +44,7 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *v "nr", "tid", "word0", "word1", "word2");for (i =0 ; i < PPC44x_TLB_SIZE; i++) { - tlbe = &vcpu->arch.guest_tlb[i]; + tlbe = &vcpu_44x->guest_tlb[i];if (tlbe->word0 & PPC44x_TLB_VALID) printk(" G%2d | %02X | %08X | %08X | %08X |\n", i, tlbe->tid, tlbe->word0, tlbe->word1,
@@ -51,7 +52,7 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *v }for (i =0 ; i < PPC44x_TLB_SIZE; i++) { - tlbe = &vcpu->arch.shadow_tlb[i]; + tlbe = &vcpu_44x->shadow_tlb[i];if (tlbe->word0 & PPC44x_TLB_VALID) printk(" S%2d | %02X | %08X | %08X | %08X |\n", i, tlbe->tid, tlbe->word0, tlbe->word1,
@@ -82,11 +83,12 @@ int kvmppc_44x_tlb_index(struct kvm_vcpuint kvmppc_44x_tlb_index (struct kvm_vcpu *vcpu,gva_t eaddr,unsigned int pid,unsigned int as) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);int i;/* XXX Replace loop with fancy data structures. */ for (i =0 ; i < PPC44x_TLB_SIZE; i++) { -struct kvmppc_44x_tlbe *tlbe = &vcpu->arch.guest_tlb[i]; +struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[i];unsigned int tid;if (eaddr <get_tlb_eaddr (tlbe))
@@ -114,25 +116,27 @@ struct kvmppc_44x_tlbe *kvmppc_44x_itlb_struct kvmppc_44x_tlbe *kvmppc_44x_itlb_search (struct kvm_vcpu *vcpu,gva_t eaddr) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);unsigned int as = !!(vcpu->arch.msr &MSR_IS );unsigned int index; index =kvmppc_44x_tlb_index (vcpu, eaddr, vcpu->arch.pid, as);if (index ==-1 )return NULL ; -return &vcpu->arch.guest_tlb[index]; +return &vcpu_44x->guest_tlb[index]; }struct kvmppc_44x_tlbe *kvmppc_44x_dtlb_search (struct kvm_vcpu *vcpu,gva_t eaddr) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);unsigned int as = !!(vcpu->arch.msr &MSR_DS );unsigned int index; index =kvmppc_44x_tlb_index (vcpu, eaddr, vcpu->arch.pid, as);if (index ==-1 )return NULL ; -return &vcpu->arch.guest_tlb[index]; +return &vcpu_44x->guest_tlb[index]; }static int kvmppc_44x_tlbe_is_writable (struct kvmppc_44x_tlbe *tlbe)
@@ -143,8 +147,9 @@ static void kvmppc_44x_shadow_release(ststatic void kvmppc_44x_shadow_release (struct kvm_vcpu *vcpu,unsigned int index) { -struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[index]; -struct page *page = vcpu->arch.shadow_pages[index]; +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu); +struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[index]; +struct page *page = vcpu_44x->shadow_pages[index];if (get_tlb_v (stlbe)) {if (kvmppc_44x_tlbe_is_writable (stlbe))
@@ -156,7 +161,9 @@ static void kvmppc_44x_shadow_release(stvoid kvmppc_tlbe_set_modified (struct kvm_vcpu *vcpu,unsigned int i) { - vcpu->arch.shadow_tlb_mod[i] =1 ; +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu); + + vcpu_44x->shadow_tlb_mod[i] =1 ; }/* Caller must ensure that the specified guest TLB entry is safe to insert into
@@ -164,6 +171,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpvoid kvmppc_mmu_map (struct kvm_vcpu *vcpu,u64 gvaddr,gfn_t gfn,u64 asid,u32 flags) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);struct page *new_page;struct kvmppc_44x_tlbe *stlbe;hpa_t hpaddr;
@@ -174,7 +182,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcp victim = kvmppc_tlb_44x_pos++;if (kvmppc_tlb_44x_pos > tlb_44x_hwater) kvmppc_tlb_44x_pos =0 ; - stlbe = &vcpu->arch.shadow_tlb[victim]; + stlbe = &vcpu_44x->shadow_tlb[victim];/* Get reference to new page. */ new_page =gfn_to_page (vcpu->kvm, gfn);
@@ -188,7 +196,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcp/* Drop reference to old page. */ kvmppc_44x_shadow_release (vcpu, victim); - vcpu->arch.shadow_pages[victim] = new_page; + vcpu_44x->shadow_pages[victim] = new_page;/* XXX Make sure (va, size) doesn't overlap any other * entries. 440x6 user manual says the result would be
@@ -216,12 +224,13 @@ static void kvmppc_mmu_invalidate(structstatic void kvmppc_mmu_invalidate (struct kvm_vcpu *vcpu,gva_t eaddr,gva_t eend,u32 asid) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);unsigned int pid = !(asid &0xff );int i;/* XXX Replace loop with fancy data structures. */ for (i =0 ; i <= tlb_44x_hwater; i++) { -struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[i]; +struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];unsigned int tid;if (!get_tlb_v (stlbe))
@@ -251,12 +260,13 @@ static void kvmppc_mmu_invalidate(struct* switching address spaces. */ void kvmppc_mmu_priv_switch (struct kvm_vcpu *vcpu,int usermode) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);int i;if (vcpu->arch.swap_pid) {/* XXX Replace loop with fancy data structures. */ for (i =0 ; i <= tlb_44x_hwater; i++) { -struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[i]; +struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];/* Future optimization: clear only userspace mappings. */ kvmppc_44x_shadow_release (vcpu, i);
@@ -295,6 +305,7 @@ static int tlbe_is_host_safe(const strucint kvmppc_44x_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws) { +struct kvmppc_vcpu_44x *vcpu_44x =to_44x (vcpu);u64 eaddr;u64 raddr;u64 asid;
@@ -309,7 +320,7 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpreturn EMULATE_FAIL ; } - tlbe = &vcpu->arch.guest_tlb[index]; + tlbe = &vcpu_44x->guest_tlb[index];/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ if (tlbe->word0 & PPC44x_TLB_VALID) {
arch/powerpc/kvm/booke.c +3 -6
@@ -573,7 +573,7 @@ int kvm_arch_vcpu_ioctl_translate(structreturn kvmppc_core_vcpu_translate (vcpu, tr); } -static int kvmppc_booke_init (void ) +int kvmppc_booke_init (void ) {unsigned long ivor[16 ];unsigned long max_ivor =0 ;
@@ -618,14 +618,11 @@ static int kvmppc_booke_init(void)flush_icache_range (kvmppc_booke_handlers, kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); -return kvm_init (NULL ,sizeof (struct kvm_vcpu ),THIS_MODULE ); +return 0 ; } -static void __exit kvmppc_booke_exit(void) +void __exit kvmppc_booke_exit(void) {free_pages (kvmppc_booke_handlers,VCPU_SIZE_ORDER );kvm_exit (); } - -module_init (kvmppc_booke_init) -module_exit (kvmppc_booke_exit)
arch/powerpc/kvm/booke_interrupts.S +3 -3
@@ -349,8 +349,8 @@ lightweight_exit: lis r5, tlb_44x_hwater@ha lwz r5, tlb_44x_hwater@l(r5) mtctr r5 - addi r9, r4, VCPU_SHADOW_TLB - addi r5, r4, VCPU_SHADOW_MOD + addi r9, r4, -VCPU_TO_44X + VCPU44x_SHADOW_TLB + addi r5, r4, -VCPU_TO_44X + VCPU44x_SHADOW_MOD li r3, 0 1: lbzx r7, r3, r5
@@ -377,7 +377,7 @@ 3: /* Clear bitmap of modified TLB entries */ li r5, PPC44x_TLB_SIZE>>2 mtctr r5 - addi r5, r4, VCPU_SHADOW_MOD - 4 + addi r5, r4, -VCPU_TO_44X + VCPU44x_SHADOW_MOD - 4 li r6, 0 1: stwu r6, 4(r5)
arch/powerpc/kvm/powerpc.c +2 -21
@@ -170,31 +170,12 @@ void kvm_arch_flush_shadow(struct kvm *kstruct kvm_vcpu *kvm_arch_vcpu_create (struct kvm *kvm,unsigned int id) { -struct kvm_vcpu *vcpu; -int err; - - vcpu =kmem_cache_zalloc (kvm_vcpu_cache,GFP_KERNEL ); -if (!vcpu) { - err = -ENOMEM ; - goto out; - } - - err =kvm_vcpu_init (vcpu, kvm, id); -if (err) - goto free_vcpu; - -return vcpu; - -free_vcpu: -kmem_cache_free (kvm_vcpu_cache, vcpu); -out: -return ERR_PTR (err); +return kvmppc_core_vcpu_create (kvm, id); }void kvm_arch_vcpu_free (struct kvm_vcpu *vcpu) { -kvm_vcpu_uninit (vcpu); -kmem_cache_free (kvm_vcpu_cache, vcpu); +kvmppc_core_vcpu_free (vcpu); }void kvm_arch_vcpu_destroy (struct kvm_vcpu *vcpu)
PATCH 1/1 kvm: ppc: optimize kvm stat handling
In reply to Hollis BlanchardCurrently we use an unnecessary if&switch to detect some cases. To be honest we don't need the ligh_exits counter anyway, because we can calculate it out of others. Sum_exits can also be calculated, so we can remove that too.
MMIO, DCR and INTR can be counted on other places without these additional control structures (The INTR case was never hit anyway).
The handling of BOOKE_INTERRUPT_EXTERNAL/BOOKE_INTERRUPT_DECREMENTER is similar, but we can avoid the additional if when copying 3 lines of code. I thought about a goto there to prevent duplicate lines, but rewriting three lines should be better style than a goto cross switch/case statements (its also not enough code to justify a new inline function).
arch/powerpc/kvm/booke.c +9 -23
@@ -38,11 +38,9 @@ unsigned long kvmppc_booke_handlers;#define VCPU_STAT (x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPUstruct kvm_stats_debugfs_item debugfs_entries[] = { - {"exits" ,VCPU_STAT (sum_exits) }, {"mmio" ,VCPU_STAT (mmio_exits) }, {"dcr" ,VCPU_STAT (dcr_exits) }, {"sig" ,VCPU_STAT (signal_exits) }, - {"light" ,VCPU_STAT (light_exits) }, {"itlb_r" ,VCPU_STAT (itlb_real_miss_exits) }, {"itlb_v" ,VCPU_STAT (itlb_virt_miss_exits) }, {"dtlb_r" ,VCPU_STAT (dtlb_real_miss_exits) },
@@ -263,6 +261,12 @@ int kvmppc_handle_exit(struct kvm_run *rbreak ;case BOOKE_INTERRUPT_EXTERNAL : + vcpu->stat.ext_intr_exits++; +if (need_resched ()) +cond_resched (); + r =RESUME_GUEST ; +break ; +case BOOKE_INTERRUPT_DECREMENTER :/* Since we switched IVPR back to the host's value, the host * handled this interrupt the moment we enabled interrupts.
@@ -272,12 +276,9 @@ int kvmppc_handle_exit(struct kvm_run *r* we do reschedule the host will fault over it. Perhaps we * should politely restore the host's entries to minimize * misses before ceding control. */ + vcpu->stat.dec_exits++;if (need_resched ())cond_resched (); -if (exit_nr ==BOOKE_INTERRUPT_DECREMENTER ) - vcpu->stat.dec_exits++; -else - vcpu->stat.ext_intr_exits++; r =RESUME_GUEST ;break ;
@@ -301,6 +302,7 @@ int kvmppc_handle_exit(struct kvm_run *rbreak ;case EMULATE_DO_DCR : run->exit_reason =KVM_EXIT_DCR ; + vcpu->stat.dcr_exits++; r =RESUME_HOST ;break ;case EMULATE_FAIL :
@@ -379,6 +381,7 @@ int kvmppc_handle_exit(struct kvm_run *r/* Guest has mapped and accessed a page which is not * actually RAM. */ r =kvmppc_emulate_mmio (run, vcpu); + vcpu->stat.mmio_exits++; }break ;
@@ -445,8 +448,6 @@ int kvmppc_handle_exit(struct kvm_run *rkvmppc_core_deliver_interrupts (vcpu); -/* Do some exit accounting. */ - vcpu->stat.sum_exits++;if (!(r &RESUME_HOST )) {/* To avoid clobbering exit_reason, only check for signals if * we aren't already exiting to userspace for some other
@@ -454,22 +455,7 @@ int kvmppc_handle_exit(struct kvm_run *rif (signal_pending (current)) { run->exit_reason =KVM_EXIT_INTR ; r = (-EINTR <<2 ) |RESUME_HOST | (r &RESUME_FLAG_NV ); - vcpu->stat.signal_exits++; - }else { - vcpu->stat.light_exits++; - } - }else { -switch (run->exit_reason) { -case KVM_EXIT_MMIO : - vcpu->stat.mmio_exits++; -break ; -case KVM_EXIT_DCR : - vcpu->stat.dcr_exits++; -break ; -case KVM_EXIT_INTR : - vcpu->stat.signal_exits++; -break ; } }
PATCH 1/1 kvm: ppc: optimize find first bit
In reply to Hollis BlanchardSince we use a unsigned long here anyway we can use the optimized __ffs.
arch/powerpc/kvm/booke.c +1 -1
@@ -222,7 +222,7 @@ void kvmppc_core_deliver_interrupts(struunsigned int exception;unsigned int priority; - priority =find_first_bit (pending,BITS_PER_BYTE *sizeof (*pending)); + priority =__ffs (*pending);while (priority <=BOOKE_MAX_INTERRUPT ) { exception = priority_exception[priority];if (kvmppc_can_deliver_interrupt (vcpu, exception)) {
PATCH 1/1 kvmppc: fix set regs to take care of msr change
In reply to Hollis BlanchardWhen changing some msr bits e.g. problem state we need to take special care of that. We call the function in our mtmsr emulation (not needed for wrtee[i]), but we don't call kvmppc_set_msr if we change msr via set_regs ioctl.
It's a corner case we never hit so far, but I assume it should be kvmppc_set_msr in our arch set regs function (I found it because it is also a corner case when using pv support which would miss the update otherwise).
arch/powerpc/kvm/booke.c +1 -1
@@ -528,7 +528,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct vcpu->arch.ctr = regs->ctr; vcpu->arch.lr = regs->lr; vcpu->arch.xer = regs->xer; - vcpu->arch.msr = regs->msr; +kvmppc_set_msr (vcpu, regs->msr); vcpu->arch.srr0 = regs->srr0; vcpu->arch.srr1 = regs->srr1; vcpu->arch.sprg0 = regs->sprg0;
PATCH 1/1 kvm: ppc: improve trap emulation
In reply to Hollis Blanchardset ESR[PTR] when emulating a guest trap. This allows Linux guests to properly handle WARN_ON() (i.e. detect that it's a non-fatal trap).
Also remove debugging printk in trap emulation.
arch/powerpc/kvm/emulate.c +2 -2
@@ -74,8 +74,8 @@ int kvmppc_emulate_instruction(struct kvint advance =1 ;switch (get_op (inst)) { -case 3 :/* trap */ -printk ("trap!\n" ); +case 3 :/* trap */ + vcpu->arch.esr |=ESR_PTR ;kvmppc_core_queue_program (vcpu); advance =0 ;break ;
PATCH 1/1 KVM: ppc: refactor instruction emulation into generic and core-specific pieces
In reply to Hollis BlanchardCores provide 3 emulation hooks, implemented for example in the new 4xx_emulate.c:kvmppc_core_emulate_opkvmppc_core_emulate_mtsprkvmppc_core_emulate_mfspr
Strictly speaking the last two aren't necessary, but provide for more informative error reporting ("unknown SPR").
Long term I'd like to have instruction decoding autogenerated from tables of opcodes, and that way we could aggregate universal, Book E, and core-specific instructions more easily and without redundant switch statements.
arch/powerpc/include/asm/kvm_ppc.h +6 -23
@@ -53,34 +53,12 @@ extern int kvmppc_emulate_instruction(stextern int kvmppc_emulate_instruction (struct kvm_run *run,struct kvm_vcpu *vcpu);extern int kvmppc_emulate_mmio (struct kvm_run *run,struct kvm_vcpu *vcpu); -extern int kvmppc_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws); -extern int kvmppc_emul_tlbsx (struct kvm_vcpu *vcpu,u8 rt,u8 ra,u8 rb,u8 rc); +extern void kvmppc_emulate_dec (struct kvm_vcpu *vcpu);extern void kvmppc_mmu_map (struct kvm_vcpu *vcpu,u64 gvaddr,gfn_t gfn,u64 asid,u32 flags);extern void kvmppc_mmu_priv_switch (struct kvm_vcpu *vcpu,int usermode);extern void kvmppc_mmu_switch_pid (struct kvm_vcpu *vcpu,u32 pid); - -/* Helper function for "full" MSR writes. No need to call this if only EE is -* changing. */ -static inline void kvmppc_set_msr (struct kvm_vcpu *vcpu,u32 new_msr) -{ -if ((new_msr &MSR_PR ) != (vcpu->arch.msr &MSR_PR )) -kvmppc_mmu_priv_switch (vcpu, new_msr &MSR_PR ); - - vcpu->arch.msr = new_msr; - -if (vcpu->arch.msr &MSR_WE ) -kvm_vcpu_block (vcpu); -} - -static inline void kvmppc_set_pid (struct kvm_vcpu *vcpu,u32 new_pid) -{ -if (vcpu->arch.pid != new_pid) { - vcpu->arch.pid = new_pid; - vcpu->arch.swap_pid =1 ; - } -}/* Core-specific hooks */
@@ -99,4 +77,9 @@ extern void kvmppc_core_queue_external(sextern void kvmppc_core_queue_external (struct kvm_vcpu *vcpu,struct kvm_interrupt *irq); +extern int kvmppc_core_emulate_op (struct kvm_run *run,struct kvm_vcpu *vcpu, +unsigned int op,int *advance); +extern int kvmppc_core_emulate_mtspr (struct kvm_vcpu *vcpu,int sprn,int rs); +extern int kvmppc_core_emulate_mfspr (struct kvm_vcpu *vcpu,int sprn,int rt); +#endif /* __POWERPC_KVM_PPC_H__ */
arch/powerpc/kvm/44x_emulate.c new file +335 -0
335 lines not on this page · raw message
arch/powerpc/kvm/44x_tlb.c +2 -2
@@ -293,7 +293,7 @@ static int tlbe_is_host_safe(const strucreturn 1 ; } -int kvmppc_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws) +int kvmppc_44x_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws) {u64 eaddr;u64 raddr;
@@ -355,7 +355,7 @@ int kvmppc_emul_tlbwe(struct kvm_vcpu *vreturn EMULATE_DONE ; } -int kvmppc_emul_tlbsx (struct kvm_vcpu *vcpu,u8 rt,u8 ra,u8 rb,u8 rc) +int kvmppc_44x_emul_tlbsx (struct kvm_vcpu *vcpu,u8 rt,u8 ra,u8 rb,u8 rc) {u32 ea;int index;
arch/powerpc/kvm/44x_tlb.h +4 -0
@@ -30,6 +30,10 @@ extern struct kvmppc_44x_tlbe *kvmppc_44extern struct kvmppc_44x_tlbe *kvmppc_44x_itlb_search (struct kvm_vcpu *vcpu,gva_t eaddr);extern void kvmppc_tlbe_set_modified (struct kvm_vcpu *vcpu,unsigned int i); + +extern int kvmppc_44x_emul_tlbsx (struct kvm_vcpu *vcpu,u8 rt,u8 ra,u8 rb, +u8 rc); +extern int kvmppc_44x_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws);/* TLB helper functions */ static inline unsigned int get_tlb_size (const struct kvmppc_44x_tlbe *tlbe)
arch/powerpc/kvm/Makefile +6 -1
@@ -13,5 +13,10 @@ obj-$(CONFIG_KVM) += kvm.o AFLAGS_booke_interrupts.o := -I$(obj) -kvm-440-objs := booke.o booke_interrupts.o 44x.o 44x_tlb.o +kvm-440-objs := \ + booke.o \ + booke_interrupts.o \ + 44x.o \ + 44x_tlb.o \ + 44x_emulate.o obj-$(CONFIG_KVM_440) += kvm-440.o
arch/powerpc/kvm/booke.c +1 -0
@@ -29,6 +29,7 @@#include <asm/kvm_ppc.h> #include <asm/cacheflush.h> +#include "booke.h" #include "44x_tlb.h" unsigned long kvmppc_booke_handlers;
arch/powerpc/kvm/booke.h new file +39 -0
@@ -0,0 +1,39 @@ +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License, version 2, as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Copyright IBM Corp. 2008 +* +* Authors: Hollis Blanchard <[email protected]> +*/ + +#ifndef __KVM_BOOKE_H__ +#define __KVM_BOOKE_H__ + +#include <linux/types.h> +#include <linux/kvm_host.h> + +/* Helper function for "full" MSR writes. No need to call this if only EE is +* changing. */ +static inline void kvmppc_set_msr (struct kvm_vcpu *vcpu,u32 new_msr) +{ +if ((new_msr &MSR_PR ) != (vcpu->arch.msr &MSR_PR )) +kvmppc_mmu_priv_switch (vcpu, new_msr &MSR_PR ); + + vcpu->arch.msr = new_msr; + +if (vcpu->arch.msr &MSR_WE ) +kvm_vcpu_block (vcpu); +} + +#endif /* __KVM_BOOKE_H__ */
arch/powerpc/kvm/emulate.c +22 -250
392 lines not on this page · raw message
PATCH 1/1 kvm: ppc: optimize irq delivery path
In reply to Hollis BlanchardIn kvmppc_deliver_interrupt is just one case left in the switch and it is a rare one (less than 8%) when looking at the exit numbers. Therefore we can at least drop the switch/case and if an if. I inserted an unlikely too, but that's open for discussion.
In kvmppc_can_deliver_interrupt all frequent cases are in the default case. I know compilers are smart but we can make it easier for them. By writing down all options and removing the default case combined with the fact that ithe values are constants 0..15 should allow the compiler to write an easy jump table.
Modifying kvmppc_can_deliver_interrupt pointed me to the fact that gcc seems to be unable to reduce priority_exception[x] to a build time constant. Therefore I changed the usage of the translation arrays in the interrupt delivery path completely. It is now using priority without translation to irq on the full irq delivery path.
To be able to do that ivpr regs are stored by their priority now.
Additionally the decision made in kvmppc_can_deliver_interrupt is already sufficient to get the value of interrupt_msr_mask[x]. Therefore we can replace the 16x4byte array used here with a single 4byte variable (might still be one miss, but the chance to find this in cache should be better than the right entry of the whole array).
arch/powerpc/include/asm/kvm_ppc.h +0 -3
@@ -35,9 +35,6 @@ enum emulation_result {EMULATE_DO_DCR ,/* kvm_run filled with DCR request */ EMULATE_FAIL, /* can't emulate this instruction */ }; - -extern const unsigned char exception_priority[]; -extern const unsigned char priority_exception[];extern int __kvmppc_vcpu_run (struct kvm_run *kvm_run,struct kvm_vcpu *vcpu);extern char kvmppc_handlers_start[];
arch/powerpc/kvm/44x_emulate.c +67 -33
143 lines not on this page · raw message
arch/powerpc/kvm/booke.c +58 -123
280 lines not on this page · raw message
arch/powerpc/kvm/booke.h +18 -0
@@ -23,6 +23,24 @@#include <linux/types.h> #include <linux/kvm_host.h> +/* interrupt priortity ordering */ +#define BOOKE_IRQPRIO_DATA_STORAGE 0 +#define BOOKE_IRQPRIO_INST_STORAGE 1 +#define BOOKE_IRQPRIO_ALIGNMENT 2 +#define BOOKE_IRQPRIO_PROGRAM 3 +#define BOOKE_IRQPRIO_FP_UNAVAIL 4 +#define BOOKE_IRQPRIO_SYSCALL 5 +#define BOOKE_IRQPRIO_AP_UNAVAIL 6 +#define BOOKE_IRQPRIO_DTLB_MISS 7 +#define BOOKE_IRQPRIO_ITLB_MISS 8 +#define BOOKE_IRQPRIO_MACHINE_CHECK 9 +#define BOOKE_IRQPRIO_DEBUG 10 +#define BOOKE_IRQPRIO_CRITICAL 11 +#define BOOKE_IRQPRIO_WATCHDOG 12 +#define BOOKE_IRQPRIO_EXTERNAL 13 +#define BOOKE_IRQPRIO_FIT 14 +#define BOOKE_IRQPRIO_DECREMENTER 15 +/* Helper function for "full" MSR writes. No need to call this if only EE is * changing. */ static inline void kvmppc_set_msr (struct kvm_vcpu *vcpu,u32 new_msr)
Quoted 7 lines · Hollis Blanchard
Hi Avi, these patches have been tested in PowerPC trees for a while. Some of these reorganize the PowerPC KVM code to make implementations on other cores possible, but does cause a little code churn. There are also some performance optimization for 440 from Christian, and a few bugfixes thrown in too.
Please apply.
Patches won't apply. Are you sure they are against kvm.git?
Patch 1 says
arch/powerpc/include/asm/kvm_ppc.h
Quoted 5 lines
arch/powerpc/include/asm/kvm_ppc.h +1
-2-extern int kvmppc_emul_tlbwe (struct kvm_vcpu *vcpu,u8 ra,u8 rs,u8 ws); -extern int kvmppc_emul_tlbsx (struct kvm_vcpu *vcpu,u8 rt,u8 ra,u8 rb,u8 rc); +extern void kvmppc_emulate_dec (struct kvm_vcpu *vcpu)
But kvmppc_emul_tlbwe lives in arch/powerpc/kvm/emulate.c.
Signature · 1 line
error compiling committee.c: too many arguments to function