diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_pr.c')
| -rw-r--r-- | arch/powerpc/kvm/book3s_pr.c | 907 | 
1 files changed, 606 insertions, 301 deletions
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 27db1e66595..8eef1e51907 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -40,14 +40,20 @@  #include <linux/sched.h>  #include <linux/vmalloc.h>  #include <linux/highmem.h> +#include <linux/module.h> +#include <linux/miscdevice.h> -#include "trace.h" +#include "book3s.h" + +#define CREATE_TRACE_POINTS +#include "trace_pr.h"  /* #define EXIT_DEBUG */  /* #define DEBUG_EXT */  static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,  			     ulong msr); +static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac);  /* Some compatibility defines */  #ifdef CONFIG_PPC_BOOK3S_32 @@ -56,38 +62,117 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,  #define HW_PAGE_SIZE PAGE_SIZE  #endif -void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)  {  #ifdef CONFIG_PPC_BOOK3S_64  	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);  	memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb)); -	memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu, -	       sizeof(get_paca()->shadow_vcpu));  	svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max; +	svcpu->in_use = 0;  	svcpu_put(svcpu);  #endif  	vcpu->cpu = smp_processor_id();  #ifdef CONFIG_PPC_BOOK3S_32 -	current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu; +	current->thread.kvm_shadow_vcpu = vcpu->arch.shadow_vcpu;  #endif  } -void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) +static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)  {  #ifdef CONFIG_PPC_BOOK3S_64  	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); +	if (svcpu->in_use) { +		kvmppc_copy_from_svcpu(vcpu, svcpu); +	}  	memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb)); -	memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, -	       sizeof(get_paca()->shadow_vcpu));  	to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;  	svcpu_put(svcpu);  #endif  	kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX); +	kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);  	vcpu->cpu = -1;  } -int kvmppc_core_check_requests(struct kvm_vcpu *vcpu) +/* Copy data needed by real-mode code from vcpu to shadow vcpu */ +void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu, +			  struct kvm_vcpu *vcpu) +{ +	svcpu->gpr[0] = vcpu->arch.gpr[0]; +	svcpu->gpr[1] = vcpu->arch.gpr[1]; +	svcpu->gpr[2] = vcpu->arch.gpr[2]; +	svcpu->gpr[3] = vcpu->arch.gpr[3]; +	svcpu->gpr[4] = vcpu->arch.gpr[4]; +	svcpu->gpr[5] = vcpu->arch.gpr[5]; +	svcpu->gpr[6] = vcpu->arch.gpr[6]; +	svcpu->gpr[7] = vcpu->arch.gpr[7]; +	svcpu->gpr[8] = vcpu->arch.gpr[8]; +	svcpu->gpr[9] = vcpu->arch.gpr[9]; +	svcpu->gpr[10] = vcpu->arch.gpr[10]; +	svcpu->gpr[11] = vcpu->arch.gpr[11]; +	svcpu->gpr[12] = vcpu->arch.gpr[12]; +	svcpu->gpr[13] = vcpu->arch.gpr[13]; +	svcpu->cr  = vcpu->arch.cr; +	svcpu->xer = vcpu->arch.xer; +	svcpu->ctr = vcpu->arch.ctr; +	svcpu->lr  = vcpu->arch.lr; +	svcpu->pc  = vcpu->arch.pc; +#ifdef CONFIG_PPC_BOOK3S_64 +	svcpu->shadow_fscr = vcpu->arch.shadow_fscr; +#endif +	svcpu->in_use = true; +} + +/* Copy data touched by real-mode code from shadow vcpu back to vcpu */ +void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu, +			    struct kvmppc_book3s_shadow_vcpu *svcpu) +{ +	/* +	 * vcpu_put would just call us again because in_use hasn't +	 * been updated yet. +	 */ +	preempt_disable(); + +	/* +	 * Maybe we were already preempted and synced the svcpu from +	 * our preempt notifiers. Don't bother touching this svcpu then. +	 */ +	if (!svcpu->in_use) +		goto out; + +	vcpu->arch.gpr[0] = svcpu->gpr[0]; +	vcpu->arch.gpr[1] = svcpu->gpr[1]; +	vcpu->arch.gpr[2] = svcpu->gpr[2]; +	vcpu->arch.gpr[3] = svcpu->gpr[3]; +	vcpu->arch.gpr[4] = svcpu->gpr[4]; +	vcpu->arch.gpr[5] = svcpu->gpr[5]; +	vcpu->arch.gpr[6] = svcpu->gpr[6]; +	vcpu->arch.gpr[7] = svcpu->gpr[7]; +	vcpu->arch.gpr[8] = svcpu->gpr[8]; +	vcpu->arch.gpr[9] = svcpu->gpr[9]; +	vcpu->arch.gpr[10] = svcpu->gpr[10]; +	vcpu->arch.gpr[11] = svcpu->gpr[11]; +	vcpu->arch.gpr[12] = svcpu->gpr[12]; +	vcpu->arch.gpr[13] = svcpu->gpr[13]; +	vcpu->arch.cr  = svcpu->cr; +	vcpu->arch.xer = svcpu->xer; +	vcpu->arch.ctr = svcpu->ctr; +	vcpu->arch.lr  = svcpu->lr; +	vcpu->arch.pc  = svcpu->pc; +	vcpu->arch.shadow_srr1 = svcpu->shadow_srr1; +	vcpu->arch.fault_dar   = svcpu->fault_dar; +	vcpu->arch.fault_dsisr = svcpu->fault_dsisr; +	vcpu->arch.last_inst   = svcpu->last_inst; +#ifdef CONFIG_PPC_BOOK3S_64 +	vcpu->arch.shadow_fscr = svcpu->shadow_fscr; +#endif +	svcpu->in_use = false; + +out: +	preempt_enable(); +} + +static int kvmppc_core_check_requests_pr(struct kvm_vcpu *vcpu)  {  	int r = 1; /* Indicate we want to get back into the guest */ @@ -100,58 +185,84 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)  }  /************* MMU Notifiers *************/ +static void do_kvm_unmap_hva(struct kvm *kvm, unsigned long start, +			     unsigned long end) +{ +	long i; +	struct kvm_vcpu *vcpu; +	struct kvm_memslots *slots; +	struct kvm_memory_slot *memslot; + +	slots = kvm_memslots(kvm); +	kvm_for_each_memslot(memslot, slots) { +		unsigned long hva_start, hva_end; +		gfn_t gfn, gfn_end; + +		hva_start = max(start, memslot->userspace_addr); +		hva_end = min(end, memslot->userspace_addr + +					(memslot->npages << PAGE_SHIFT)); +		if (hva_start >= hva_end) +			continue; +		/* +		 * {gfn(page) | page intersects with [hva_start, hva_end)} = +		 * {gfn, gfn+1, ..., gfn_end-1}. +		 */ +		gfn = hva_to_gfn_memslot(hva_start, memslot); +		gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); +		kvm_for_each_vcpu(i, vcpu, kvm) +			kvmppc_mmu_pte_pflush(vcpu, gfn << PAGE_SHIFT, +					      gfn_end << PAGE_SHIFT); +	} +} -int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) +static int kvm_unmap_hva_pr(struct kvm *kvm, unsigned long hva)  {  	trace_kvm_unmap_hva(hva); -	/* -	 * Flush all shadow tlb entries everywhere. This is slow, but -	 * we are 100% sure that we catch the to be unmapped page -	 */ -	kvm_flush_remote_tlbs(kvm); +	do_kvm_unmap_hva(kvm, hva, hva + PAGE_SIZE);  	return 0;  } -int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) +static int kvm_unmap_hva_range_pr(struct kvm *kvm, unsigned long start, +				  unsigned long end)  { -	/* kvm_unmap_hva flushes everything anyways */ -	kvm_unmap_hva(kvm, start); +	do_kvm_unmap_hva(kvm, start, end);  	return 0;  } -int kvm_age_hva(struct kvm *kvm, unsigned long hva) +static int kvm_age_hva_pr(struct kvm *kvm, unsigned long hva)  {  	/* XXX could be more clever ;) */  	return 0;  } -int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) +static int kvm_test_age_hva_pr(struct kvm *kvm, unsigned long hva)  {  	/* XXX could be more clever ;) */  	return 0;  } -void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) +static void kvm_set_spte_hva_pr(struct kvm *kvm, unsigned long hva, pte_t pte)  {  	/* The page will get remapped properly on its next fault */ -	kvm_unmap_hva(kvm, hva); +	do_kvm_unmap_hva(kvm, hva, hva + PAGE_SIZE);  }  /*****************************************/  static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)  { -	ulong smsr = vcpu->arch.shared->msr; +	ulong guest_msr = kvmppc_get_msr(vcpu); +	ulong smsr = guest_msr;  	/* Guest MSR values */ -	smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE; +	smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;  	/* Process MSR values */  	smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;  	/* External providers the guest reserved */ -	smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext); +	smsr |= (guest_msr & vcpu->arch.guest_owned_ext);  	/* 64-bit Process MSR values */  #ifdef CONFIG_PPC_BOOK3S_64  	smsr |= MSR_ISF | MSR_HV; @@ -159,16 +270,16 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)  	vcpu->arch.shadow_msr = smsr;  } -void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) +static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)  { -	ulong old_msr = vcpu->arch.shared->msr; +	ulong old_msr = kvmppc_get_msr(vcpu);  #ifdef EXIT_DEBUG  	printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);  #endif  	msr &= to_book3s(vcpu)->msr_mask; -	vcpu->arch.shared->msr = msr; +	kvmppc_set_msr_fast(vcpu, msr);  	kvmppc_recalc_shadow_msr(vcpu);  	if (msr & MSR_POW) { @@ -179,11 +290,11 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)  			/* Unset POW bit after we woke up */  			msr &= ~MSR_POW; -			vcpu->arch.shared->msr = msr; +			kvmppc_set_msr_fast(vcpu, msr);  		}  	} -	if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) != +	if ((kvmppc_get_msr(vcpu) & (MSR_PR|MSR_IR|MSR_DR)) !=  		   (old_msr & (MSR_PR|MSR_IR|MSR_DR))) {  		kvmppc_mmu_flush_segments(vcpu);  		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); @@ -215,11 +326,11 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)  	}  	/* Preload FPU if it's enabled */ -	if (vcpu->arch.shared->msr & MSR_FP) +	if (kvmppc_get_msr(vcpu) & MSR_FP)  		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);  } -void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) +void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)  {  	u32 host_pvr; @@ -256,6 +367,23 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)  	if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be"))  		to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1); +	/* +	 * If they're asking for POWER6 or later, set the flag +	 * indicating that we can do multiple large page sizes +	 * and 1TB segments. +	 * Also set the flag that indicates that tlbie has the large +	 * page bit in the RB operand instead of the instruction. +	 */ +	switch (PVR_VER(pvr)) { +	case PVR_POWER6: +	case PVR_POWER7: +	case PVR_POWER7p: +	case PVR_POWER8: +		vcpu->arch.hflags |= BOOK3S_HFLAG_MULTI_PGSIZE | +			BOOK3S_HFLAG_NEW_TLBIE; +		break; +	} +  #ifdef CONFIG_PPC_BOOK3S_32  	/* 32 bit Book3S always has 32 byte dcbz */  	vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; @@ -308,8 +436,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)  	/* patch dcbz into reserved instruction, so we trap */  	for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) -		if ((page[i] & 0xff0007ff) == INS_DCBZ) -			page[i] &= 0xfffffff7; +		if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ) +			page[i] &= cpu_to_be32(0xfffffff7);  	kunmap_atomic(page);  	put_page(hpage); @@ -319,7 +447,7 @@ static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)  {  	ulong mp_pa = vcpu->arch.magic_page_pa; -	if (!(vcpu->arch.shared->msr & MSR_SF)) +	if (!(kvmppc_get_msr(vcpu) & MSR_SF))  		mp_pa = (uint32_t)mp_pa;  	if (unlikely(mp_pa) && @@ -334,20 +462,23 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,  			    ulong eaddr, int vec)  {  	bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); +	bool iswrite = false;  	int r = RESUME_GUEST;  	int relocated;  	int page_found = 0;  	struct kvmppc_pte pte;  	bool is_mmio = false; -	bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false; -	bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false; +	bool dr = (kvmppc_get_msr(vcpu) & MSR_DR) ? true : false; +	bool ir = (kvmppc_get_msr(vcpu) & MSR_IR) ? true : false;  	u64 vsid;  	relocated = data ? dr : ir; +	if (data && (vcpu->arch.fault_dsisr & DSISR_ISSTORE)) +		iswrite = true;  	/* Resolve real address if translation turned on */  	if (relocated) { -		page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); +		page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data, iswrite);  	} else {  		pte.may_execute = true;  		pte.may_read = true; @@ -355,9 +486,10 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,  		pte.raddr = eaddr & KVM_PAM;  		pte.eaddr = eaddr;  		pte.vpage = eaddr >> 12; +		pte.page_size = MMU_PAGE_64K;  	} -	switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { +	switch (kvmppc_get_msr(vcpu) & (MSR_DR|MSR_IR)) {  	case 0:  		pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));  		break; @@ -365,7 +497,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,  	case MSR_IR:  		vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); -		if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR) +		if ((kvmppc_get_msr(vcpu) & (MSR_DR|MSR_IR)) == MSR_DR)  			pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));  		else  			pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12)); @@ -388,35 +520,42 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,  	if (page_found == -ENOENT) {  		/* Page not found in guest PTE entries */ -		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); -		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); -		vcpu->arch.shared->dsisr = svcpu->fault_dsisr; -		vcpu->arch.shared->msr |= -			(svcpu->shadow_srr1 & 0x00000000f8000000ULL); -		svcpu_put(svcpu); +		u64 ssrr1 = vcpu->arch.shadow_srr1; +		u64 msr = kvmppc_get_msr(vcpu); +		kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu)); +		kvmppc_set_dsisr(vcpu, vcpu->arch.fault_dsisr); +		kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));  		kvmppc_book3s_queue_irqprio(vcpu, vec);  	} else if (page_found == -EPERM) {  		/* Storage protection */ -		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); -		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); -		vcpu->arch.shared->dsisr = svcpu->fault_dsisr & ~DSISR_NOHPTE; -		vcpu->arch.shared->dsisr |= DSISR_PROTFAULT; -		vcpu->arch.shared->msr |= -			svcpu->shadow_srr1 & 0x00000000f8000000ULL; -		svcpu_put(svcpu); +		u32 dsisr = vcpu->arch.fault_dsisr; +		u64 ssrr1 = vcpu->arch.shadow_srr1; +		u64 msr = kvmppc_get_msr(vcpu); +		kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu)); +		dsisr = (dsisr & ~DSISR_NOHPTE) | DSISR_PROTFAULT; +		kvmppc_set_dsisr(vcpu, dsisr); +		kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));  		kvmppc_book3s_queue_irqprio(vcpu, vec);  	} else if (page_found == -EINVAL) {  		/* Page not found in guest SLB */ -		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); +		kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));  		kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);  	} else if (!is_mmio &&  		   kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { +		if (data && !(vcpu->arch.fault_dsisr & DSISR_NOHPTE)) { +			/* +			 * There is already a host HPTE there, presumably +			 * a read-only one for a page the guest thinks +			 * is writable, so get rid of it first. +			 */ +			kvmppc_mmu_unmap_page(vcpu, &pte); +		}  		/* The guest's PTE is not mapped yet. Map on the host */ -		kvmppc_mmu_map_page(vcpu, &pte); +		kvmppc_mmu_map_page(vcpu, &pte, iswrite);  		if (data)  			vcpu->stat.sp_storage++;  		else if (vcpu->arch.mmu.is_dcbz32(vcpu) && -			(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) +			 (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32)))  			kvmppc_patch_dcbz(vcpu, &pte);  	} else {  		/* MMIO */ @@ -440,12 +579,6 @@ static inline int get_fpr_index(int i)  void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)  {  	struct thread_struct *t = ¤t->thread; -	u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX -	u64 *vcpu_vsx = vcpu->arch.vsr; -#endif -	u64 *thread_fpr = (u64*)t->fpr; -	int i;  	/*  	 * VSX instructions can access FP and vector registers, so if @@ -466,28 +599,18 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)  		/*  		 * Note that on CPUs with VSX, giveup_fpu stores  		 * both the traditional FP registers and the added VSX -		 * registers into thread.fpr[]. +		 * registers into thread.fp_state.fpr[].  		 */ -		if (current->thread.regs->msr & MSR_FP) +		if (t->regs->msr & MSR_FP)  			giveup_fpu(current); -		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) -			vcpu_fpr[i] = thread_fpr[get_fpr_index(i)]; - -		vcpu->arch.fpscr = t->fpscr.val; - -#ifdef CONFIG_VSX -		if (cpu_has_feature(CPU_FTR_VSX)) -			for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++) -				vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1]; -#endif +		t->fp_save_area = NULL;  	}  #ifdef CONFIG_ALTIVEC  	if (msr & MSR_VEC) {  		if (current->thread.regs->msr & MSR_VEC)  			giveup_altivec(current); -		memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr)); -		vcpu->arch.vscr = t->vscr; +		t->vr_save_area = NULL;  	}  #endif @@ -495,6 +618,25 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)  	kvmppc_recalc_shadow_msr(vcpu);  } +/* Give up facility (TAR / EBB / DSCR) */ +static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac) +{ +#ifdef CONFIG_PPC_BOOK3S_64 +	if (!(vcpu->arch.shadow_fscr & (1ULL << fac))) { +		/* Facility not available to the guest, ignore giveup request*/ +		return; +	} + +	switch (fac) { +	case FSCR_TAR_LG: +		vcpu->arch.tar = mfspr(SPRN_TAR); +		mtspr(SPRN_TAR, current->thread.tar); +		vcpu->arch.shadow_fscr &= ~FSCR_TAR; +		break; +	} +#endif +} +  static int kvmppc_read_inst(struct kvm_vcpu *vcpu)  {  	ulong srr0 = kvmppc_get_pc(vcpu); @@ -503,11 +645,12 @@ static int kvmppc_read_inst(struct kvm_vcpu *vcpu)  	ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);  	if (ret == -ENOENT) { -		ulong msr = vcpu->arch.shared->msr; +		ulong msr = kvmppc_get_msr(vcpu);  		msr = kvmppc_set_field(msr, 33, 33, 1);  		msr = kvmppc_set_field(msr, 34, 36, 0); -		vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0); +		msr = kvmppc_set_field(msr, 42, 47, 0); +		kvmppc_set_msr_fast(vcpu, msr);  		kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);  		return EMULATE_AGAIN;  	} @@ -535,18 +678,12 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,  			     ulong msr)  {  	struct thread_struct *t = ¤t->thread; -	u64 *vcpu_fpr = vcpu->arch.fpr; -#ifdef CONFIG_VSX -	u64 *vcpu_vsx = vcpu->arch.vsr; -#endif -	u64 *thread_fpr = (u64*)t->fpr; -	int i;  	/* When we have paired singles, we emulate in software */  	if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)  		return RESUME_GUEST; -	if (!(vcpu->arch.shared->msr & msr)) { +	if (!(kvmppc_get_msr(vcpu) & msr)) {  		kvmppc_book3s_queue_irqprio(vcpu, exit_nr);  		return RESUME_GUEST;  	} @@ -578,27 +715,24 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,  #endif  	if (msr & MSR_FP) { -		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) -			thread_fpr[get_fpr_index(i)] = vcpu_fpr[i]; -#ifdef CONFIG_VSX -		for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++) -			thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i]; -#endif -		t->fpscr.val = vcpu->arch.fpscr; -		t->fpexc_mode = 0; -		kvmppc_load_up_fpu(); +		preempt_disable(); +		enable_kernel_fp(); +		load_fp_state(&vcpu->arch.fp); +		t->fp_save_area = &vcpu->arch.fp; +		preempt_enable();  	}  	if (msr & MSR_VEC) {  #ifdef CONFIG_ALTIVEC -		memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr)); -		t->vscr = vcpu->arch.vscr; -		t->vrsave = -1; -		kvmppc_load_up_altivec(); +		preempt_disable(); +		enable_kernel_altivec(); +		load_vr_state(&vcpu->arch.vr); +		t->vr_save_area = &vcpu->arch.vr; +		preempt_enable();  #endif  	} -	current->thread.regs->msr |= msr; +	t->regs->msr |= msr;  	vcpu->arch.guest_owned_ext |= msr;  	kvmppc_recalc_shadow_msr(vcpu); @@ -617,15 +751,93 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)  	if (!lost_ext)  		return; -	if (lost_ext & MSR_FP) -		kvmppc_load_up_fpu(); -	if (lost_ext & MSR_VEC) -		kvmppc_load_up_altivec(); +	if (lost_ext & MSR_FP) { +		preempt_disable(); +		enable_kernel_fp(); +		load_fp_state(&vcpu->arch.fp); +		preempt_enable(); +	} +#ifdef CONFIG_ALTIVEC +	if (lost_ext & MSR_VEC) { +		preempt_disable(); +		enable_kernel_altivec(); +		load_vr_state(&vcpu->arch.vr); +		preempt_enable(); +	} +#endif  	current->thread.regs->msr |= lost_ext;  } -int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, -                       unsigned int exit_nr) +#ifdef CONFIG_PPC_BOOK3S_64 + +static void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac) +{ +	/* Inject the Interrupt Cause field and trigger a guest interrupt */ +	vcpu->arch.fscr &= ~(0xffULL << 56); +	vcpu->arch.fscr |= (fac << 56); +	kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FAC_UNAVAIL); +} + +static void kvmppc_emulate_fac(struct kvm_vcpu *vcpu, ulong fac) +{ +	enum emulation_result er = EMULATE_FAIL; + +	if (!(kvmppc_get_msr(vcpu) & MSR_PR)) +		er = kvmppc_emulate_instruction(vcpu->run, vcpu); + +	if ((er != EMULATE_DONE) && (er != EMULATE_AGAIN)) { +		/* Couldn't emulate, trigger interrupt in guest */ +		kvmppc_trigger_fac_interrupt(vcpu, fac); +	} +} + +/* Enable facilities (TAR, EBB, DSCR) for the guest */ +static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac) +{ +	bool guest_fac_enabled; +	BUG_ON(!cpu_has_feature(CPU_FTR_ARCH_207S)); + +	/* +	 * Not every facility is enabled by FSCR bits, check whether the +	 * guest has this facility enabled at all. +	 */ +	switch (fac) { +	case FSCR_TAR_LG: +	case FSCR_EBB_LG: +		guest_fac_enabled = (vcpu->arch.fscr & (1ULL << fac)); +		break; +	case FSCR_TM_LG: +		guest_fac_enabled = kvmppc_get_msr(vcpu) & MSR_TM; +		break; +	default: +		guest_fac_enabled = false; +		break; +	} + +	if (!guest_fac_enabled) { +		/* Facility not enabled by the guest */ +		kvmppc_trigger_fac_interrupt(vcpu, fac); +		return RESUME_GUEST; +	} + +	switch (fac) { +	case FSCR_TAR_LG: +		/* TAR switching isn't lazy in Linux yet */ +		current->thread.tar = mfspr(SPRN_TAR); +		mtspr(SPRN_TAR, vcpu->arch.tar); +		vcpu->arch.shadow_fscr |= FSCR_TAR; +		break; +	default: +		kvmppc_emulate_fac(vcpu, fac); +		break; +	} + +	return RESUME_GUEST; +} +#endif + +int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, +			  unsigned int exit_nr)  {  	int r = RESUME_HOST;  	int s; @@ -643,25 +855,32 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  	switch (exit_nr) {  	case BOOK3S_INTERRUPT_INST_STORAGE:  	{ -		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); -		ulong shadow_srr1 = svcpu->shadow_srr1; +		ulong shadow_srr1 = vcpu->arch.shadow_srr1;  		vcpu->stat.pf_instruc++;  #ifdef CONFIG_PPC_BOOK3S_32  		/* We set segments as unused segments when invalidating them. So  		 * treat the respective fault as segment fault. */ -		if (svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] == SR_INVALID) { -			kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); -			r = RESUME_GUEST; +		{ +			struct kvmppc_book3s_shadow_vcpu *svcpu; +			u32 sr; + +			svcpu = svcpu_get(vcpu); +			sr = svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT];  			svcpu_put(svcpu); -			break; +			if (sr == SR_INVALID) { +				kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); +				r = RESUME_GUEST; +				break; +			}  		}  #endif -		svcpu_put(svcpu);  		/* only care about PTEG not found errors, but leave NX alone */  		if (shadow_srr1 & 0x40000000) { +			int idx = srcu_read_lock(&vcpu->kvm->srcu);  			r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr); +			srcu_read_unlock(&vcpu->kvm->srcu, idx);  			vcpu->stat.sp_instruc++;  		} else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&  			  (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { @@ -673,7 +892,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);  			r = RESUME_GUEST;  		} else { -			vcpu->arch.shared->msr |= shadow_srr1 & 0x58000000; +			u64 msr = kvmppc_get_msr(vcpu); +			msr |= shadow_srr1 & 0x58000000; +			kvmppc_set_msr_fast(vcpu, msr);  			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);  			r = RESUME_GUEST;  		} @@ -682,28 +903,39 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  	case BOOK3S_INTERRUPT_DATA_STORAGE:  	{  		ulong dar = kvmppc_get_fault_dar(vcpu); -		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); -		u32 fault_dsisr = svcpu->fault_dsisr; +		u32 fault_dsisr = vcpu->arch.fault_dsisr;  		vcpu->stat.pf_storage++;  #ifdef CONFIG_PPC_BOOK3S_32  		/* We set segments as unused segments when invalidating them. So  		 * treat the respective fault as segment fault. */ -		if ((svcpu->sr[dar >> SID_SHIFT]) == SR_INVALID) { -			kvmppc_mmu_map_segment(vcpu, dar); -			r = RESUME_GUEST; +		{ +			struct kvmppc_book3s_shadow_vcpu *svcpu; +			u32 sr; + +			svcpu = svcpu_get(vcpu); +			sr = svcpu->sr[dar >> SID_SHIFT];  			svcpu_put(svcpu); -			break; +			if (sr == SR_INVALID) { +				kvmppc_mmu_map_segment(vcpu, dar); +				r = RESUME_GUEST; +				break; +			}  		}  #endif -		svcpu_put(svcpu); -		/* The only case we need to handle is missing shadow PTEs */ -		if (fault_dsisr & DSISR_NOHPTE) { +		/* +		 * We need to handle missing shadow PTEs, and +		 * protection faults due to us mapping a page read-only +		 * when the guest thinks it is writable. +		 */ +		if (fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT)) { +			int idx = srcu_read_lock(&vcpu->kvm->srcu);  			r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); +			srcu_read_unlock(&vcpu->kvm->srcu, idx);  		} else { -			vcpu->arch.shared->dar = dar; -			vcpu->arch.shared->dsisr = fault_dsisr; +			kvmppc_set_dar(vcpu, dar); +			kvmppc_set_dsisr(vcpu, fault_dsisr);  			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);  			r = RESUME_GUEST;  		} @@ -711,7 +943,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  	}  	case BOOK3S_INTERRUPT_DATA_SEGMENT:  		if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) { -			vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); +			kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));  			kvmppc_book3s_queue_irqprio(vcpu,  				BOOK3S_INTERRUPT_DATA_SEGMENT);  		} @@ -727,6 +959,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  	/* We're good on these - the host merely wanted to get our attention */  	case BOOK3S_INTERRUPT_DECREMENTER:  	case BOOK3S_INTERRUPT_HV_DECREMENTER: +	case BOOK3S_INTERRUPT_DOORBELL:  		vcpu->stat.dec_exits++;  		r = RESUME_GUEST;  		break; @@ -743,15 +976,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,  	case BOOK3S_INTERRUPT_H_EMUL_ASSIST:  	{  		enum emulation_result er; -		struct kvmppc_book3s_shadow_vcpu *svcpu;  		ulong flags;  program_interrupt: -		svcpu = svcpu_get(vcpu); -		flags = svcpu->shadow_srr1 & 0x1f0000ull; -		svcpu_put(svcpu); +		flags = vcpu->arch.shadow_srr1 & 0x1f0000ull; -		if (vcpu->arch.shared->msr & MSR_PR) { +		if (kvmppc_get_msr(vcpu) & MSR_PR) {  #ifdef EXIT_DEBUG  			printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));  #endif @@ -793,12 +1023,12 @@ program_interrupt:  	case BOOK3S_INTERRUPT_SYSCALL:  		if (vcpu->arch.papr_enabled &&  		    (kvmppc_get_last_sc(vcpu) == 0x44000022) && -		    !(vcpu->arch.shared->msr & MSR_PR)) { +		    !(kvmppc_get_msr(vcpu) & MSR_PR)) {  			/* SC 1 papr hypercalls */  			ulong cmd = kvmppc_get_gpr(vcpu, 3);  			int i; -#ifdef CONFIG_KVM_BOOK3S_64_PR +#ifdef CONFIG_PPC_BOOK3S_64  			if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) {  				r = RESUME_GUEST;  				break; @@ -825,7 +1055,7 @@ program_interrupt:  				gprs[i] = kvmppc_get_gpr(vcpu, i);  			vcpu->arch.osi_needed = 1;  			r = RESUME_HOST_NV; -		} else if (!(vcpu->arch.shared->msr & MSR_PR) && +		} else if (!(kvmppc_get_msr(vcpu) & MSR_PR) &&  		    (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {  			/* KVM PV hypercalls */  			kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu)); @@ -866,14 +1096,26 @@ program_interrupt:  	}  	case BOOK3S_INTERRUPT_ALIGNMENT:  		if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { -			vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu, -				kvmppc_get_last_inst(vcpu)); -			vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu, -				kvmppc_get_last_inst(vcpu)); +			u32 last_inst = kvmppc_get_last_inst(vcpu); +			u32 dsisr; +			u64 dar; + +			dsisr = kvmppc_alignment_dsisr(vcpu, last_inst); +			dar = kvmppc_alignment_dar(vcpu, last_inst); + +			kvmppc_set_dsisr(vcpu, dsisr); +			kvmppc_set_dar(vcpu, dar); +  			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);  		}  		r = RESUME_GUEST;  		break; +#ifdef CONFIG_PPC_BOOK3S_64 +	case BOOK3S_INTERRUPT_FAC_UNAVAIL: +		kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56); +		r = RESUME_GUEST; +		break; +#endif  	case BOOK3S_INTERRUPT_MACHINE_CHECK:  	case BOOK3S_INTERRUPT_TRACE:  		kvmppc_book3s_queue_irqprio(vcpu, exit_nr); @@ -881,9 +1123,7 @@ program_interrupt:  		break;  	default:  	{ -		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); -		ulong shadow_srr1 = svcpu->shadow_srr1; -		svcpu_put(svcpu); +		ulong shadow_srr1 = vcpu->arch.shadow_srr1;  		/* Ugh - bork here! What did we get? */  		printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n",  			exit_nr, kvmppc_get_pc(vcpu), shadow_srr1); @@ -904,14 +1144,14 @@ program_interrupt:  		 * and if we really did time things so badly, then we just exit  		 * again due to a host external interrupt.  		 */ -		local_irq_disable();  		s = kvmppc_prepare_to_enter(vcpu); -		if (s <= 0) { -			local_irq_enable(); +		if (s <= 0)  			r = s; -		} else { +		else { +			/* interrupts now hard-disabled */  			kvmppc_fix_ee_before_entry();  		} +  		kvmppc_handle_lost_ext(vcpu);  	} @@ -920,8 +1160,8 @@ program_interrupt:  	return r;  } -int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, -                                  struct kvm_sregs *sregs) +static int kvm_arch_vcpu_ioctl_get_sregs_pr(struct kvm_vcpu *vcpu, +					    struct kvm_sregs *sregs)  {  	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);  	int i; @@ -936,7 +1176,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,  		}  	} else {  		for (i = 0; i < 16; i++) -			sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i]; +			sregs->u.s.ppc32.sr[i] = kvmppc_get_sr(vcpu, i);  		for (i = 0; i < 8; i++) {  			sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw; @@ -947,13 +1187,13 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,  	return 0;  } -int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, -                                  struct kvm_sregs *sregs) +static int kvm_arch_vcpu_ioctl_set_sregs_pr(struct kvm_vcpu *vcpu, +					    struct kvm_sregs *sregs)  {  	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);  	int i; -	kvmppc_set_pvr(vcpu, sregs->pvr); +	kvmppc_set_pvr_pr(vcpu, sregs->pvr);  	vcpu3s->sdr1 = sregs->u.s.sdr1;  	if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { @@ -983,7 +1223,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,  	return 0;  } -int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) +static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id, +				 union kvmppc_one_reg *val)  {  	int r = 0; @@ -991,19 +1232,15 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)  	case KVM_REG_PPC_HIOR:  		*val = get_reg_val(id, to_book3s(vcpu)->hior);  		break; -#ifdef CONFIG_VSX -	case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: { -		long int i = id - KVM_REG_PPC_VSR0; - -		if (!cpu_has_feature(CPU_FTR_VSX)) { -			r = -ENXIO; -			break; -		} -		val->vsxval[0] = vcpu->arch.fpr[i]; -		val->vsxval[1] = vcpu->arch.vsr[i]; +	case KVM_REG_PPC_LPCR: +		/* +		 * We are only interested in the LPCR_ILE bit +		 */ +		if (vcpu->arch.intr_msr & MSR_LE) +			*val = get_reg_val(id, LPCR_ILE); +		else +			*val = get_reg_val(id, 0);  		break; -	} -#endif /* CONFIG_VSX */  	default:  		r = -EINVAL;  		break; @@ -1012,7 +1249,16 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)  	return r;  } -int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) +static void kvmppc_set_lpcr_pr(struct kvm_vcpu *vcpu, u64 new_lpcr) +{ +	if (new_lpcr & LPCR_ILE) +		vcpu->arch.intr_msr |= MSR_LE; +	else +		vcpu->arch.intr_msr &= ~MSR_LE; +} + +static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id, +				 union kvmppc_one_reg *val)  {  	int r = 0; @@ -1021,19 +1267,9 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)  		to_book3s(vcpu)->hior = set_reg_val(id, *val);  		to_book3s(vcpu)->hior_explicit = true;  		break; -#ifdef CONFIG_VSX -	case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: { -		long int i = id - KVM_REG_PPC_VSR0; - -		if (!cpu_has_feature(CPU_FTR_VSX)) { -			r = -ENXIO; -			break; -		} -		vcpu->arch.fpr[i] = val->vsxval[0]; -		vcpu->arch.vsr[i] = val->vsxval[1]; +	case KVM_REG_PPC_LPCR: +		kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));  		break; -	} -#endif /* CONFIG_VSX */  	default:  		r = -EINVAL;  		break; @@ -1042,28 +1278,30 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)  	return r;  } -int kvmppc_core_check_processor_compat(void) -{ -	return 0; -} - -struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) +static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm, +						   unsigned int id)  {  	struct kvmppc_vcpu_book3s *vcpu_book3s;  	struct kvm_vcpu *vcpu;  	int err = -ENOMEM;  	unsigned long p; -	vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s)); -	if (!vcpu_book3s) +	vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); +	if (!vcpu)  		goto out; -	vcpu_book3s->shadow_vcpu = -		kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL); -	if (!vcpu_book3s->shadow_vcpu) +	vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s)); +	if (!vcpu_book3s)  		goto free_vcpu; +	vcpu->arch.book3s = vcpu_book3s; + +#ifdef CONFIG_KVM_BOOK3S_32_HANDLER +	vcpu->arch.shadow_vcpu = +		kzalloc(sizeof(*vcpu->arch.shadow_vcpu), GFP_KERNEL); +	if (!vcpu->arch.shadow_vcpu) +		goto free_vcpu3s; +#endif -	vcpu = &vcpu_book3s->vcpu;  	err = kvm_vcpu_init(vcpu, kvm, id);  	if (err)  		goto free_shadow_vcpu; @@ -1074,18 +1312,31 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)  		goto uninit_vcpu;  	/* the real shared page fills the last 4k of our page */  	vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096); -  #ifdef CONFIG_PPC_BOOK3S_64 -	/* default to book3s_64 (970fx) */ +	/* Always start the shared struct in native endian mode */ +#ifdef __BIG_ENDIAN__ +        vcpu->arch.shared_big_endian = true; +#else +        vcpu->arch.shared_big_endian = false; +#endif + +	/* +	 * Default to the same as the host if we're on sufficiently +	 * recent machine that we have 1TB segments; +	 * otherwise default to PPC970FX. +	 */  	vcpu->arch.pvr = 0x3C0301; +	if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) +		vcpu->arch.pvr = mfspr(SPRN_PVR); +	vcpu->arch.intr_msr = MSR_SF;  #else  	/* default to book3s_32 (750) */  	vcpu->arch.pvr = 0x84202;  #endif -	kvmppc_set_pvr(vcpu, vcpu->arch.pvr); +	kvmppc_set_pvr_pr(vcpu, vcpu->arch.pvr);  	vcpu->arch.slb_nr = 64; -	vcpu->arch.shadow_msr = MSR_USER64; +	vcpu->arch.shadow_msr = MSR_USER64 & ~MSR_LE;  	err = kvmppc_mmu_init(vcpu);  	if (err < 0) @@ -1096,39 +1347,36 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)  uninit_vcpu:  	kvm_vcpu_uninit(vcpu);  free_shadow_vcpu: -	kfree(vcpu_book3s->shadow_vcpu); -free_vcpu: +#ifdef CONFIG_KVM_BOOK3S_32_HANDLER +	kfree(vcpu->arch.shadow_vcpu); +free_vcpu3s: +#endif  	vfree(vcpu_book3s); +free_vcpu: +	kmem_cache_free(kvm_vcpu_cache, vcpu);  out:  	return ERR_PTR(err);  } -void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) +static void kvmppc_core_vcpu_free_pr(struct kvm_vcpu *vcpu)  {  	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);  	free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);  	kvm_vcpu_uninit(vcpu); -	kfree(vcpu_book3s->shadow_vcpu); +#ifdef CONFIG_KVM_BOOK3S_32_HANDLER +	kfree(vcpu->arch.shadow_vcpu); +#endif  	vfree(vcpu_book3s); +	kmem_cache_free(kvm_vcpu_cache, vcpu);  } -int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)  {  	int ret; -	double fpr[32][TS_FPRWIDTH]; -	unsigned int fpscr; -	int fpexc_mode;  #ifdef CONFIG_ALTIVEC -	vector128 vr[32]; -	vector128 vscr;  	unsigned long uninitialized_var(vrsave); -	int used_vr;  #endif -#ifdef CONFIG_VSX -	int used_vsr; -#endif -	ulong ext_msr;  	/* Check if we can run the vcpu at all */  	if (!vcpu->arch.sane) { @@ -1143,44 +1391,29 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)  	 * really did time things so badly, then we just exit again due to  	 * a host external interrupt.  	 */ -	local_irq_disable();  	ret = kvmppc_prepare_to_enter(vcpu); -	if (ret <= 0) { -		local_irq_enable(); +	if (ret <= 0)  		goto out; -	} +	/* interrupts now hard-disabled */ -	/* Save FPU state in stack */ +	/* Save FPU state in thread_struct */  	if (current->thread.regs->msr & MSR_FP)  		giveup_fpu(current); -	memcpy(fpr, current->thread.fpr, sizeof(current->thread.fpr)); -	fpscr = current->thread.fpscr.val; -	fpexc_mode = current->thread.fpexc_mode;  #ifdef CONFIG_ALTIVEC -	/* Save Altivec state in stack */ -	used_vr = current->thread.used_vr; -	if (used_vr) { -		if (current->thread.regs->msr & MSR_VEC) -			giveup_altivec(current); -		memcpy(vr, current->thread.vr, sizeof(current->thread.vr)); -		vscr = current->thread.vscr; -		vrsave = current->thread.vrsave; -	} +	/* Save Altivec state in thread_struct */ +	if (current->thread.regs->msr & MSR_VEC) +		giveup_altivec(current);  #endif  #ifdef CONFIG_VSX -	/* Save VSX state in stack */ -	used_vsr = current->thread.used_vsr; -	if (used_vsr && (current->thread.regs->msr & MSR_VSX)) +	/* Save VSX state in thread_struct */ +	if (current->thread.regs->msr & MSR_VSX)  		__giveup_vsx(current);  #endif -	/* Remember the MSR with disabled extensions */ -	ext_msr = current->thread.regs->msr; -  	/* Preload FPU if it's enabled */ -	if (vcpu->arch.shared->msr & MSR_FP) +	if (kvmppc_get_msr(vcpu) & MSR_FP)  		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);  	kvmppc_fix_ee_before_entry(); @@ -1193,26 +1426,8 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)  	/* Make sure we save the guest FPU/Altivec/VSX state */  	kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX); -	current->thread.regs->msr = ext_msr; - -	/* Restore FPU/VSX state from stack */ -	memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr)); -	current->thread.fpscr.val = fpscr; -	current->thread.fpexc_mode = fpexc_mode; - -#ifdef CONFIG_ALTIVEC -	/* Restore Altivec state from stack */ -	if (used_vr && current->thread.used_vr) { -		memcpy(current->thread.vr, vr, sizeof(current->thread.vr)); -		current->thread.vscr = vscr; -		current->thread.vrsave = vrsave; -	} -	current->thread.used_vr = used_vr; -#endif - -#ifdef CONFIG_VSX -	current->thread.used_vsr = used_vsr; -#endif +	/* Make sure we save the guest TAR/EBB/DSCR state */ +	kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);  out:  	vcpu->mode = OUTSIDE_GUEST_MODE; @@ -1222,8 +1437,8 @@ out:  /*   * Get (and clear) the dirty memory log for a memory slot.   */ -int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, -				      struct kvm_dirty_log *log) +static int kvm_vm_ioctl_get_dirty_log_pr(struct kvm *kvm, +					 struct kvm_dirty_log *log)  {  	struct kvm_memory_slot *memslot;  	struct kvm_vcpu *vcpu; @@ -1258,67 +1473,100 @@ out:  	return r;  } -#ifdef CONFIG_PPC64 -int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info) +static void kvmppc_core_flush_memslot_pr(struct kvm *kvm, +					 struct kvm_memory_slot *memslot)  { -	info->flags = KVM_PPC_1T_SEGMENTS; - -	/* SLB is always 64 entries */ -	info->slb_size = 64; - -	/* Standard 4k base page size segment */ -	info->sps[0].page_shift = 12; -	info->sps[0].slb_enc = 0; -	info->sps[0].enc[0].page_shift = 12; -	info->sps[0].enc[0].pte_enc = 0; - -	/* Standard 16M large page size segment */ -	info->sps[1].page_shift = 24; -	info->sps[1].slb_enc = SLB_VSID_L; -	info->sps[1].enc[0].page_shift = 24; -	info->sps[1].enc[0].pte_enc = 0; +	return; +} +static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm, +					struct kvm_memory_slot *memslot, +					struct kvm_userspace_memory_region *mem) +{  	return 0;  } -#endif /* CONFIG_PPC64 */ -void kvmppc_core_free_memslot(struct kvm_memory_slot *free, -			      struct kvm_memory_slot *dont) +static void kvmppc_core_commit_memory_region_pr(struct kvm *kvm, +				struct kvm_userspace_memory_region *mem, +				const struct kvm_memory_slot *old)  { +	return;  } -int kvmppc_core_create_memslot(struct kvm_memory_slot *slot, -			       unsigned long npages) +static void kvmppc_core_free_memslot_pr(struct kvm_memory_slot *free, +					struct kvm_memory_slot *dont)  { -	return 0; +	return;  } -int kvmppc_core_prepare_memory_region(struct kvm *kvm, -				      struct kvm_memory_slot *memslot, -				      struct kvm_userspace_memory_region *mem) +static int kvmppc_core_create_memslot_pr(struct kvm_memory_slot *slot, +					 unsigned long npages)  {  	return 0;  } -void kvmppc_core_commit_memory_region(struct kvm *kvm, -				struct kvm_userspace_memory_region *mem, -				const struct kvm_memory_slot *old) + +#ifdef CONFIG_PPC64 +static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm, +					 struct kvm_ppc_smmu_info *info)  { -} +	long int i; +	struct kvm_vcpu *vcpu; + +	info->flags = 0; + +	/* SLB is always 64 entries */ +	info->slb_size = 64; + +	/* Standard 4k base page size segment */ +	info->sps[0].page_shift = 12; +	info->sps[0].slb_enc = 0; +	info->sps[0].enc[0].page_shift = 12; +	info->sps[0].enc[0].pte_enc = 0; -void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot) +	/* +	 * 64k large page size. +	 * We only want to put this in if the CPUs we're emulating +	 * support it, but unfortunately we don't have a vcpu easily +	 * to hand here to test.  Just pick the first vcpu, and if +	 * that doesn't exist yet, report the minimum capability, +	 * i.e., no 64k pages. +	 * 1T segment support goes along with 64k pages. +	 */ +	i = 1; +	vcpu = kvm_get_vcpu(kvm, 0); +	if (vcpu && (vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE)) { +		info->flags = KVM_PPC_1T_SEGMENTS; +		info->sps[i].page_shift = 16; +		info->sps[i].slb_enc = SLB_VSID_L | SLB_VSID_LP_01; +		info->sps[i].enc[0].page_shift = 16; +		info->sps[i].enc[0].pte_enc = 1; +		++i; +	} + +	/* Standard 16M large page size segment */ +	info->sps[i].page_shift = 24; +	info->sps[i].slb_enc = SLB_VSID_L; +	info->sps[i].enc[0].page_shift = 24; +	info->sps[i].enc[0].pte_enc = 0; + +	return 0; +} +#else +static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm, +					 struct kvm_ppc_smmu_info *info)  { +	/* We should not get called */ +	BUG();  } +#endif /* CONFIG_PPC64 */  static unsigned int kvm_global_user_count = 0;  static DEFINE_SPINLOCK(kvm_global_user_count_lock); -int kvmppc_core_init_vm(struct kvm *kvm) +static int kvmppc_core_init_vm_pr(struct kvm *kvm)  { -#ifdef CONFIG_PPC64 -	INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables); -	INIT_LIST_HEAD(&kvm->arch.rtas_tokens); -#endif +	mutex_init(&kvm->arch.hpt_mutex);  	if (firmware_has_feature(FW_FEATURE_SET_MODE)) {  		spin_lock(&kvm_global_user_count_lock); @@ -1329,7 +1577,7 @@ int kvmppc_core_init_vm(struct kvm *kvm)  	return 0;  } -void kvmppc_core_destroy_vm(struct kvm *kvm) +static void kvmppc_core_destroy_vm_pr(struct kvm *kvm)  {  #ifdef CONFIG_PPC64  	WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables)); @@ -1344,26 +1592,83 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)  	}  } -static int kvmppc_book3s_init(void) +static int kvmppc_core_check_processor_compat_pr(void)  { -	int r; +	/* we are always compatible */ +	return 0; +} -	r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0, -		     THIS_MODULE); +static long kvm_arch_vm_ioctl_pr(struct file *filp, +				 unsigned int ioctl, unsigned long arg) +{ +	return -ENOTTY; +} -	if (r) +static struct kvmppc_ops kvm_ops_pr = { +	.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_pr, +	.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_pr, +	.get_one_reg = kvmppc_get_one_reg_pr, +	.set_one_reg = kvmppc_set_one_reg_pr, +	.vcpu_load   = kvmppc_core_vcpu_load_pr, +	.vcpu_put    = kvmppc_core_vcpu_put_pr, +	.set_msr     = kvmppc_set_msr_pr, +	.vcpu_run    = kvmppc_vcpu_run_pr, +	.vcpu_create = kvmppc_core_vcpu_create_pr, +	.vcpu_free   = kvmppc_core_vcpu_free_pr, +	.check_requests = kvmppc_core_check_requests_pr, +	.get_dirty_log = kvm_vm_ioctl_get_dirty_log_pr, +	.flush_memslot = kvmppc_core_flush_memslot_pr, +	.prepare_memory_region = kvmppc_core_prepare_memory_region_pr, +	.commit_memory_region = kvmppc_core_commit_memory_region_pr, +	.unmap_hva = kvm_unmap_hva_pr, +	.unmap_hva_range = kvm_unmap_hva_range_pr, +	.age_hva  = kvm_age_hva_pr, +	.test_age_hva = kvm_test_age_hva_pr, +	.set_spte_hva = kvm_set_spte_hva_pr, +	.mmu_destroy  = kvmppc_mmu_destroy_pr, +	.free_memslot = kvmppc_core_free_memslot_pr, +	.create_memslot = kvmppc_core_create_memslot_pr, +	.init_vm = kvmppc_core_init_vm_pr, +	.destroy_vm = kvmppc_core_destroy_vm_pr, +	.get_smmu_info = kvm_vm_ioctl_get_smmu_info_pr, +	.emulate_op = kvmppc_core_emulate_op_pr, +	.emulate_mtspr = kvmppc_core_emulate_mtspr_pr, +	.emulate_mfspr = kvmppc_core_emulate_mfspr_pr, +	.fast_vcpu_kick = kvm_vcpu_kick, +	.arch_vm_ioctl  = kvm_arch_vm_ioctl_pr, +}; + + +int kvmppc_book3s_init_pr(void) +{ +	int r; + +	r = kvmppc_core_check_processor_compat_pr(); +	if (r < 0)  		return r; -	r = kvmppc_mmu_hpte_sysinit(); +	kvm_ops_pr.owner = THIS_MODULE; +	kvmppc_pr_ops = &kvm_ops_pr; +	r = kvmppc_mmu_hpte_sysinit();  	return r;  } -static void kvmppc_book3s_exit(void) +void kvmppc_book3s_exit_pr(void)  { +	kvmppc_pr_ops = NULL;  	kvmppc_mmu_hpte_sysexit(); -	kvm_exit();  } -module_init(kvmppc_book3s_init); -module_exit(kvmppc_book3s_exit); +/* + * We only support separate modules for book3s 64 + */ +#ifdef CONFIG_PPC_BOOK3S_64 + +module_init(kvmppc_book3s_init_pr); +module_exit(kvmppc_book3s_exit_pr); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(KVM_MINOR); +MODULE_ALIAS("devname:kvm"); +#endif  | 
