diff options
Diffstat (limited to 'arch/powerpc/kvm/powerpc.c')
| -rw-r--r-- | arch/powerpc/kvm/powerpc.c | 756 | 
1 files changed, 659 insertions, 97 deletions
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 38f756f2505..61c738ab128 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -21,26 +21,130 @@  #include <linux/errno.h>  #include <linux/err.h>  #include <linux/kvm_host.h> -#include <linux/module.h>  #include <linux/vmalloc.h>  #include <linux/hrtimer.h>  #include <linux/fs.h>  #include <linux/slab.h> +#include <linux/file.h> +#include <linux/module.h>  #include <asm/cputable.h>  #include <asm/uaccess.h>  #include <asm/kvm_ppc.h>  #include <asm/tlbflush.h> +#include <asm/cputhreads.h> +#include <asm/irqflags.h>  #include "timing.h" +#include "irq.h"  #include "../mm/mmu_decl.h"  #define CREATE_TRACE_POINTS  #include "trace.h" +struct kvmppc_ops *kvmppc_hv_ops; +EXPORT_SYMBOL_GPL(kvmppc_hv_ops); +struct kvmppc_ops *kvmppc_pr_ops; +EXPORT_SYMBOL_GPL(kvmppc_pr_ops); + +  int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)  { -	return !(v->arch.shared->msr & MSR_WE) || -	       !!(v->arch.pending_exceptions); +	return !!(v->arch.pending_exceptions) || +	       v->requests; +} + +int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) +{ +	return 1; +} + +/* + * Common checks before entering the guest world.  Call with interrupts + * disabled. + * + * returns: + * + * == 1 if we're ready to go into guest state + * <= 0 if we need to go back to the host with return value + */ +int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) +{ +	int r; + +	WARN_ON(irqs_disabled()); +	hard_irq_disable(); + +	while (true) { +		if (need_resched()) { +			local_irq_enable(); +			cond_resched(); +			hard_irq_disable(); +			continue; +		} + +		if (signal_pending(current)) { +			kvmppc_account_exit(vcpu, SIGNAL_EXITS); +			vcpu->run->exit_reason = KVM_EXIT_INTR; +			r = -EINTR; +			break; +		} + +		vcpu->mode = IN_GUEST_MODE; + +		/* +		 * Reading vcpu->requests must happen after setting vcpu->mode, +		 * so we don't miss a request because the requester sees +		 * OUTSIDE_GUEST_MODE and assumes we'll be checking requests +		 * before next entering the guest (and thus doesn't IPI). +		 */ +		smp_mb(); + +		if (vcpu->requests) { +			/* Make sure we process requests preemptable */ +			local_irq_enable(); +			trace_kvm_check_requests(vcpu); +			r = kvmppc_core_check_requests(vcpu); +			hard_irq_disable(); +			if (r > 0) +				continue; +			break; +		} + +		if (kvmppc_core_prepare_to_enter(vcpu)) { +			/* interrupts got enabled in between, so we +			   are back at square 1 */ +			continue; +		} + +		kvm_guest_enter(); +		return 1; +	} + +	/* return to host */ +	local_irq_enable(); +	return r; +} +EXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter); + +#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) +static void kvmppc_swab_shared(struct kvm_vcpu *vcpu) +{ +	struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared; +	int i; + +	shared->sprg0 = swab64(shared->sprg0); +	shared->sprg1 = swab64(shared->sprg1); +	shared->sprg2 = swab64(shared->sprg2); +	shared->sprg3 = swab64(shared->sprg3); +	shared->srr0 = swab64(shared->srr0); +	shared->srr1 = swab64(shared->srr1); +	shared->dar = swab64(shared->dar); +	shared->msr = swab64(shared->msr); +	shared->dsisr = swab32(shared->dsisr); +	shared->int_pending = swab32(shared->int_pending); +	for (i = 0; i < ARRAY_SIZE(shared->sr); i++) +		shared->sr[i] = swab32(shared->sr[i]);  } +#endif  int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)  { @@ -52,7 +156,7 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)  	unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);  	unsigned long r2 = 0; -	if (!(vcpu->arch.shared->msr & MSR_SF)) { +	if (!(kvmppc_get_msr(vcpu) & MSR_SF)) {  		/* 32 bit mode */  		param1 &= 0xffffffff;  		param2 &= 0xffffffff; @@ -61,26 +165,52 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)  	}  	switch (nr) { -	case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE: +	case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):  	{ -		vcpu->arch.magic_page_pa = param1; -		vcpu->arch.magic_page_ea = param2; +#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) +		/* Book3S can be little endian, find it out here */ +		int shared_big_endian = true; +		if (vcpu->arch.intr_msr & MSR_LE) +			shared_big_endian = false; +		if (shared_big_endian != vcpu->arch.shared_big_endian) +			kvmppc_swab_shared(vcpu); +		vcpu->arch.shared_big_endian = shared_big_endian; +#endif + +		if (!(param2 & MAGIC_PAGE_FLAG_NOT_MAPPED_NX)) { +			/* +			 * Older versions of the Linux magic page code had +			 * a bug where they would map their trampoline code +			 * NX. If that's the case, remove !PR NX capability. +			 */ +			vcpu->arch.disable_kernel_nx = true; +			kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); +		} + +		vcpu->arch.magic_page_pa = param1 & ~0xfffULL; +		vcpu->arch.magic_page_ea = param2 & ~0xfffULL; -		r2 = KVM_MAGIC_FEAT_SR; +		r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7; -		r = HC_EV_SUCCESS; +		r = EV_SUCCESS;  		break;  	} -	case HC_VENDOR_KVM | KVM_HC_FEATURES: -		r = HC_EV_SUCCESS; -#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */ +	case KVM_HCALL_TOKEN(KVM_HC_FEATURES): +		r = EV_SUCCESS; +#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2) +		/* XXX Missing magic page on 44x */  		r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);  #endif  		/* Second return value is in r4 */  		break; +	case EV_HCALL_TOKEN(EV_IDLE): +		r = EV_SUCCESS; +		kvm_vcpu_block(vcpu); +		clear_bit(KVM_REQ_UNHALT, &vcpu->requests); +		break;  	default: -		r = HC_EV_UNIMPLEMENTED; +		r = EV_UNIMPLEMENTED;  		break;  	} @@ -88,6 +218,36 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)  	return r;  } +EXPORT_SYMBOL_GPL(kvmppc_kvm_pv); + +int kvmppc_sanity_check(struct kvm_vcpu *vcpu) +{ +	int r = false; + +	/* We have to know what CPU to virtualize */ +	if (!vcpu->arch.pvr) +		goto out; + +	/* PAPR only works with book3s_64 */ +	if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled) +		goto out; + +	/* HV KVM can only do PAPR mode for now */ +	if (!vcpu->arch.papr_enabled && is_kvmppc_hv_enabled(vcpu->kvm)) +		goto out; + +#ifdef CONFIG_KVM_BOOKE_HV +	if (!cpu_has_feature(CPU_FTR_EMB_HV)) +		goto out; +#endif + +	r = true; + +out: +	vcpu->arch.sane = r; +	return r ? 0 : -EINVAL; +} +EXPORT_SYMBOL_GPL(kvmppc_sanity_check);  int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)  { @@ -116,11 +276,13 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)  		r = RESUME_HOST;  		break;  	default: -		BUG(); +		WARN_ON(1); +		r = RESUME_GUEST;  	}  	return r;  } +EXPORT_SYMBOL_GPL(kvmppc_emulate_mmio);  int kvm_arch_hardware_enable(void *garbage)  { @@ -145,18 +307,40 @@ void kvm_arch_check_processor_compat(void *rtn)  	*(int *)rtn = kvmppc_core_check_processor_compat();  } -struct kvm *kvm_arch_create_vm(void) +int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)  { -	struct kvm *kvm; - -	kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); -	if (!kvm) -		return ERR_PTR(-ENOMEM); - -	return kvm; +	struct kvmppc_ops *kvm_ops = NULL; +	/* +	 * if we have both HV and PR enabled, default is HV +	 */ +	if (type == 0) { +		if (kvmppc_hv_ops) +			kvm_ops = kvmppc_hv_ops; +		else +			kvm_ops = kvmppc_pr_ops; +		if (!kvm_ops) +			goto err_out; +	} else	if (type == KVM_VM_PPC_HV) { +		if (!kvmppc_hv_ops) +			goto err_out; +		kvm_ops = kvmppc_hv_ops; +	} else if (type == KVM_VM_PPC_PR) { +		if (!kvmppc_pr_ops) +			goto err_out; +		kvm_ops = kvmppc_pr_ops; +	} else +		goto err_out; + +	if (kvm_ops->owner && !try_module_get(kvm_ops->owner)) +		return -ENOENT; + +	kvm->arch.kvm_ops = kvm_ops; +	return kvmppc_core_init_vm(kvm); +err_out: +	return -EINVAL;  } -static void kvmppc_free_vcpus(struct kvm *kvm) +void kvm_arch_destroy_vm(struct kvm *kvm)  {  	unsigned int i;  	struct kvm_vcpu *vcpu; @@ -169,38 +353,127 @@ static void kvmppc_free_vcpus(struct kvm *kvm)  		kvm->vcpus[i] = NULL;  	atomic_set(&kvm->online_vcpus, 0); + +	kvmppc_core_destroy_vm(kvm); +  	mutex_unlock(&kvm->lock); -} -void kvm_arch_sync_events(struct kvm *kvm) -{ +	/* drop the module reference */ +	module_put(kvm->arch.kvm_ops->owner);  } -void kvm_arch_destroy_vm(struct kvm *kvm) +void kvm_arch_sync_events(struct kvm *kvm)  { -	kvmppc_free_vcpus(kvm); -	kvm_free_physmem(kvm); -	cleanup_srcu_struct(&kvm->srcu); -	kfree(kvm);  }  int kvm_dev_ioctl_check_extension(long ext)  {  	int r; +	/* FIXME!! +	 * Should some of this be vm ioctl ? is it possible now ? +	 */ +	int hv_enabled = kvmppc_hv_ops ? 1 : 0;  	switch (ext) { +#ifdef CONFIG_BOOKE +	case KVM_CAP_PPC_BOOKE_SREGS: +	case KVM_CAP_PPC_BOOKE_WATCHDOG: +	case KVM_CAP_PPC_EPR: +#else  	case KVM_CAP_PPC_SEGSTATE: -	case KVM_CAP_PPC_PAIRED_SINGLES: +	case KVM_CAP_PPC_HIOR: +	case KVM_CAP_PPC_PAPR: +#endif  	case KVM_CAP_PPC_UNSET_IRQ:  	case KVM_CAP_PPC_IRQ_LEVEL:  	case KVM_CAP_ENABLE_CAP: +	case KVM_CAP_ONE_REG: +	case KVM_CAP_IOEVENTFD: +	case KVM_CAP_DEVICE_CTRL: +		r = 1; +		break; +	case KVM_CAP_PPC_PAIRED_SINGLES:  	case KVM_CAP_PPC_OSI:  	case KVM_CAP_PPC_GET_PVINFO: -		r = 1; +#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) +	case KVM_CAP_SW_TLB: +#endif +		/* We support this only for PR */ +		r = !hv_enabled;  		break; +#ifdef CONFIG_KVM_MMIO  	case KVM_CAP_COALESCED_MMIO:  		r = KVM_COALESCED_MMIO_PAGE_OFFSET;  		break; +#endif +#ifdef CONFIG_KVM_MPIC +	case KVM_CAP_IRQ_MPIC: +		r = 1; +		break; +#endif + +#ifdef CONFIG_PPC_BOOK3S_64 +	case KVM_CAP_SPAPR_TCE: +	case KVM_CAP_PPC_ALLOC_HTAB: +	case KVM_CAP_PPC_RTAS: +	case KVM_CAP_PPC_FIXUP_HCALL: +#ifdef CONFIG_KVM_XICS +	case KVM_CAP_IRQ_XICS: +#endif +		r = 1; +		break; +#endif /* CONFIG_PPC_BOOK3S_64 */ +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +	case KVM_CAP_PPC_SMT: +		if (hv_enabled) +			r = threads_per_subcore; +		else +			r = 0; +		break; +	case KVM_CAP_PPC_RMA: +		r = hv_enabled; +		/* PPC970 requires an RMA */ +		if (r && cpu_has_feature(CPU_FTR_ARCH_201)) +			r = 2; +		break; +#endif +	case KVM_CAP_SYNC_MMU: +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +		if (hv_enabled) +			r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0; +		else +			r = 0; +#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) +		r = 1; +#else +		r = 0; +#endif +		break; +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE +	case KVM_CAP_PPC_HTAB_FD: +		r = hv_enabled; +		break; +#endif +	case KVM_CAP_NR_VCPUS: +		/* +		 * Recommending a number of CPUs is somewhat arbitrary; we +		 * return the number of present CPUs for -HV (since a host +		 * will have secondary threads "offline"), and for other KVM +		 * implementations just count online CPUs. +		 */ +		if (hv_enabled) +			r = num_present_cpus(); +		else +			r = num_online_cpus(); +		break; +	case KVM_CAP_MAX_VCPUS: +		r = KVM_MAX_VCPUS; +		break; +#ifdef CONFIG_PPC_BOOK3S_64 +	case KVM_CAP_PPC_GET_SMMU_INFO: +		r = 1; +		break; +#endif  	default:  		r = 0;  		break; @@ -215,37 +488,64 @@ long kvm_arch_dev_ioctl(struct file *filp,  	return -EINVAL;  } +void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free, +			   struct kvm_memory_slot *dont) +{ +	kvmppc_core_free_memslot(kvm, free, dont); +} + +int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, +			    unsigned long npages) +{ +	return kvmppc_core_create_memslot(kvm, slot, npages); +} + +void kvm_arch_memslots_updated(struct kvm *kvm) +{ +} +  int kvm_arch_prepare_memory_region(struct kvm *kvm, -                                   struct kvm_memory_slot *memslot, -                                   struct kvm_memory_slot old, -                                   struct kvm_userspace_memory_region *mem, -                                   int user_alloc) +				   struct kvm_memory_slot *memslot, +				   struct kvm_userspace_memory_region *mem, +				   enum kvm_mr_change change)  { -	return 0; +	return kvmppc_core_prepare_memory_region(kvm, memslot, mem);  }  void kvm_arch_commit_memory_region(struct kvm *kvm, -               struct kvm_userspace_memory_region *mem, -               struct kvm_memory_slot old, -               int user_alloc) +				   struct kvm_userspace_memory_region *mem, +				   const struct kvm_memory_slot *old, +				   enum kvm_mr_change change)  { -       return; +	kvmppc_core_commit_memory_region(kvm, mem, old);  } +void kvm_arch_flush_shadow_all(struct kvm *kvm) +{ +} -void kvm_arch_flush_shadow(struct kvm *kvm) +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, +				   struct kvm_memory_slot *slot)  { +	kvmppc_core_flush_memslot(kvm, slot);  }  struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)  {  	struct kvm_vcpu *vcpu;  	vcpu = kvmppc_core_vcpu_create(kvm, id); -	if (!IS_ERR(vcpu)) +	if (!IS_ERR(vcpu)) { +		vcpu->arch.wqp = &vcpu->wq;  		kvmppc_create_vcpu_debugfs(vcpu, id); +	}  	return vcpu;  } +int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) +{ +	return 0; +} +  void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)  {  	/* Make sure we're not using the vcpu anymore */ @@ -253,6 +553,16 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)  	tasklet_kill(&vcpu->arch.tasklet);  	kvmppc_remove_vcpu_debugfs(vcpu); + +	switch (vcpu->arch.irq_type) { +	case KVMPPC_IRQ_MPIC: +		kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); +		break; +	case KVMPPC_IRQ_XICS: +		kvmppc_xics_free_icp(vcpu); +		break; +	} +  	kvmppc_core_vcpu_free(vcpu);  } @@ -266,18 +576,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)  	return kvmppc_core_pending_dec(vcpu);  } -static void kvmppc_decrementer_func(unsigned long data) -{ -	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; - -	kvmppc_core_queue_dec(vcpu); - -	if (waitqueue_active(&vcpu->wq)) { -		wake_up_interruptible(&vcpu->wq); -		vcpu->stat.halt_wakeup++; -	} -} -  /*   * low level hrtimer wake routine. Because this runs in hardirq context   * we schedule a tasklet to do the real work. @@ -294,32 +592,47 @@ enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer)  int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)  { +	int ret; +  	hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);  	tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu);  	vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; +	vcpu->arch.dec_expires = ~(u64)0; -	return 0; +#ifdef CONFIG_KVM_EXIT_TIMING +	mutex_init(&vcpu->arch.exit_timing_lock); +#endif +	ret = kvmppc_subarch_vcpu_init(vcpu); +	return ret;  }  void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)  {  	kvmppc_mmu_destroy(vcpu); +	kvmppc_subarch_vcpu_uninit(vcpu);  }  void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)  { +#ifdef CONFIG_BOOKE +	/* +	 * vrsave (formerly usprg0) isn't used by Linux, but may +	 * be used by the guest. +	 * +	 * On non-booke this is associated with Altivec and +	 * is handled by code in book3s.c. +	 */ +	mtspr(SPRN_VRSAVE, vcpu->arch.vrsave); +#endif  	kvmppc_core_vcpu_load(vcpu, cpu);  }  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)  {  	kvmppc_core_vcpu_put(vcpu); -} - -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, -                                        struct kvm_guest_debug *dbg) -{ -	return -EINVAL; +#ifdef CONFIG_BOOKE +	vcpu->arch.vrsave = mfspr(SPRN_VRSAVE); +#endif  }  static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, @@ -372,20 +685,20 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,  	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); -	switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) { -	case KVM_REG_GPR: +	switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) { +	case KVM_MMIO_REG_GPR:  		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);  		break; -	case KVM_REG_FPR: -		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; +	case KVM_MMIO_REG_FPR: +		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;  		break;  #ifdef CONFIG_PPC_BOOK3S -	case KVM_REG_QPR: -		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; +	case KVM_MMIO_REG_QPR: +		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;  		break; -	case KVM_REG_FQPR: -		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; -		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; +	case KVM_MMIO_REG_FQPR: +		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; +		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;  		break;  #endif  	default: @@ -394,8 +707,20 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,  }  int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, -                       unsigned int rt, unsigned int bytes, int is_bigendian) +		       unsigned int rt, unsigned int bytes, +		       int is_default_endian)  { +	int idx, ret; +	int is_bigendian; + +	if (kvmppc_need_byteswap(vcpu)) { +		/* Default endianness is "little endian". */ +		is_bigendian = !is_default_endian; +	} else { +		/* Default endianness is "big endian". */ +		is_bigendian = is_default_endian; +	} +  	if (bytes > sizeof(run->mmio.data)) {  		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,  		       run->mmio.len); @@ -411,25 +736,50 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,  	vcpu->mmio_is_write = 0;  	vcpu->arch.mmio_sign_extend = 0; +	idx = srcu_read_lock(&vcpu->kvm->srcu); + +	ret = kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, +			      bytes, &run->mmio.data); + +	srcu_read_unlock(&vcpu->kvm->srcu, idx); + +	if (!ret) { +		kvmppc_complete_mmio_load(vcpu, run); +		vcpu->mmio_needed = 0; +		return EMULATE_DONE; +	} +  	return EMULATE_DO_MMIO;  } +EXPORT_SYMBOL_GPL(kvmppc_handle_load);  /* Same as above, but sign extends */  int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, -                        unsigned int rt, unsigned int bytes, int is_bigendian) +			unsigned int rt, unsigned int bytes, +			int is_default_endian)  {  	int r; -	r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian);  	vcpu->arch.mmio_sign_extend = 1; +	r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian);  	return r;  }  int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, -                        u64 val, unsigned int bytes, int is_bigendian) +			u64 val, unsigned int bytes, int is_default_endian)  {  	void *data = run->mmio.data; +	int idx, ret; +	int is_bigendian; + +	if (kvmppc_need_byteswap(vcpu)) { +		/* Default endianness is "little endian". */ +		is_bigendian = !is_default_endian; +	} else { +		/* Default endianness is "big endian". */ +		is_bigendian = is_default_endian; +	}  	if (bytes > sizeof(run->mmio.data)) {  		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -459,8 +809,21 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,  		}  	} +	idx = srcu_read_lock(&vcpu->kvm->srcu); + +	ret = kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, +			       bytes, &run->mmio.data); + +	srcu_read_unlock(&vcpu->kvm->srcu, idx); + +	if (!ret) { +		vcpu->mmio_needed = 0; +		return EMULATE_DONE; +	} +  	return EMULATE_DO_MMIO;  } +EXPORT_SYMBOL_GPL(kvmppc_handle_store);  int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)  { @@ -485,15 +848,21 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)  		for (i = 0; i < 32; i++)  			kvmppc_set_gpr(vcpu, i, gprs[i]);  		vcpu->arch.osi_needed = 0; -	} +	} else if (vcpu->arch.hcall_needed) { +		int i; -	kvmppc_core_deliver_interrupts(vcpu); +		kvmppc_set_gpr(vcpu, 3, run->papr_hcall.ret); +		for (i = 0; i < 9; ++i) +			kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]); +		vcpu->arch.hcall_needed = 0; +#ifdef CONFIG_BOOKE +	} else if (vcpu->arch.epr_needed) { +		kvmppc_set_epr(vcpu, run->epr.epr); +		vcpu->arch.epr_needed = 0; +#endif +	} -	local_irq_disable(); -	kvm_guest_enter(); -	r = __kvmppc_vcpu_run(run, vcpu); -	kvm_guest_exit(); -	local_irq_enable(); +	r = kvmppc_vcpu_run(run, vcpu);  	if (vcpu->sigset_active)  		sigprocmask(SIG_SETMASK, &sigsaved, NULL); @@ -503,16 +872,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)  int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)  { -	if (irq->irq == KVM_INTERRUPT_UNSET) -		kvmppc_core_dequeue_external(vcpu, irq); -	else -		kvmppc_core_queue_external(vcpu, irq); - -	if (waitqueue_active(&vcpu->wq)) { -		wake_up_interruptible(&vcpu->wq); -		vcpu->stat.halt_wakeup++; +	if (irq->irq == KVM_INTERRUPT_UNSET) { +		kvmppc_core_dequeue_external(vcpu); +		return 0;  	} +	kvmppc_core_queue_external(vcpu, irq); + +	kvm_vcpu_kick(vcpu); +  	return 0;  } @@ -529,11 +897,82 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,  		r = 0;  		vcpu->arch.osi_enabled = true;  		break; +	case KVM_CAP_PPC_PAPR: +		r = 0; +		vcpu->arch.papr_enabled = true; +		break; +	case KVM_CAP_PPC_EPR: +		r = 0; +		if (cap->args[0]) +			vcpu->arch.epr_flags |= KVMPPC_EPR_USER; +		else +			vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; +		break; +#ifdef CONFIG_BOOKE +	case KVM_CAP_PPC_BOOKE_WATCHDOG: +		r = 0; +		vcpu->arch.watchdog_enabled = true; +		break; +#endif +#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) +	case KVM_CAP_SW_TLB: { +		struct kvm_config_tlb cfg; +		void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0]; + +		r = -EFAULT; +		if (copy_from_user(&cfg, user_ptr, sizeof(cfg))) +			break; + +		r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg); +		break; +	} +#endif +#ifdef CONFIG_KVM_MPIC +	case KVM_CAP_IRQ_MPIC: { +		struct fd f; +		struct kvm_device *dev; + +		r = -EBADF; +		f = fdget(cap->args[0]); +		if (!f.file) +			break; + +		r = -EPERM; +		dev = kvm_device_from_filp(f.file); +		if (dev) +			r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); + +		fdput(f); +		break; +	} +#endif +#ifdef CONFIG_KVM_XICS +	case KVM_CAP_IRQ_XICS: { +		struct fd f; +		struct kvm_device *dev; + +		r = -EBADF; +		f = fdget(cap->args[0]); +		if (!f.file) +			break; + +		r = -EPERM; +		dev = kvm_device_from_filp(f.file); +		if (dev) +			r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); + +		fdput(f); +		break; +	} +#endif /* CONFIG_KVM_XICS */  	default:  		r = -EINVAL;  		break;  	} +	if (!r) +		r = kvmppc_sanity_check(vcpu); +  	return r;  } @@ -575,6 +1014,31 @@ long kvm_arch_vcpu_ioctl(struct file *filp,  		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);  		break;  	} + +	case KVM_SET_ONE_REG: +	case KVM_GET_ONE_REG: +	{ +		struct kvm_one_reg reg; +		r = -EFAULT; +		if (copy_from_user(®, argp, sizeof(reg))) +			goto out; +		if (ioctl == KVM_SET_ONE_REG) +			r = kvm_vcpu_ioctl_set_one_reg(vcpu, ®); +		else +			r = kvm_vcpu_ioctl_get_one_reg(vcpu, ®); +		break; +	} + +#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) +	case KVM_DIRTY_TLB: { +		struct kvm_dirty_tlb dirty; +		r = -EFAULT; +		if (copy_from_user(&dirty, argp, sizeof(dirty))) +			goto out; +		r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty); +		break; +	} +#endif  	default:  		r = -EINVAL;  	} @@ -583,11 +1047,23 @@ out:  	return r;  } +int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) +{ +	return VM_FAULT_SIGBUS; +} +  static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)  { +	u32 inst_nop = 0x60000000; +#ifdef CONFIG_KVM_BOOKE_HV +	u32 inst_sc1 = 0x44000022; +	pvinfo->hcall[0] = cpu_to_be32(inst_sc1); +	pvinfo->hcall[1] = cpu_to_be32(inst_nop); +	pvinfo->hcall[2] = cpu_to_be32(inst_nop); +	pvinfo->hcall[3] = cpu_to_be32(inst_nop); +#else  	u32 inst_lis = 0x3c000000;  	u32 inst_ori = 0x60000000; -	u32 inst_nop = 0x60000000;  	u32 inst_sc = 0x44000002;  	u32 inst_imm_mask = 0xffff; @@ -600,17 +1076,33 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)  	 *    sc  	 *    nop  	 */ -	pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask); -	pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask); -	pvinfo->hcall[2] = inst_sc; -	pvinfo->hcall[3] = inst_nop; +	pvinfo->hcall[0] = cpu_to_be32(inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask)); +	pvinfo->hcall[1] = cpu_to_be32(inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask)); +	pvinfo->hcall[2] = cpu_to_be32(inst_sc); +	pvinfo->hcall[3] = cpu_to_be32(inst_nop); +#endif + +	pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;  	return 0;  } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, +			  bool line_status) +{ +	if (!irqchip_in_kernel(kvm)) +		return -ENXIO; + +	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, +					irq_event->irq, irq_event->level, +					line_status); +	return 0; +} +  long kvm_arch_vm_ioctl(struct file *filp,                         unsigned int ioctl, unsigned long arg)  { +	struct kvm *kvm __maybe_unused = filp->private_data;  	void __user *argp = (void __user *)arg;  	long r; @@ -626,14 +1118,83 @@ long kvm_arch_vm_ioctl(struct file *filp,  		break;  	} +#ifdef CONFIG_PPC_BOOK3S_64 +	case KVM_CREATE_SPAPR_TCE: { +		struct kvm_create_spapr_tce create_tce; + +		r = -EFAULT; +		if (copy_from_user(&create_tce, argp, sizeof(create_tce))) +			goto out; +		r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce); +		goto out; +	} +	case KVM_PPC_GET_SMMU_INFO: { +		struct kvm_ppc_smmu_info info; +		struct kvm *kvm = filp->private_data; + +		memset(&info, 0, sizeof(info)); +		r = kvm->arch.kvm_ops->get_smmu_info(kvm, &info); +		if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) +			r = -EFAULT; +		break; +	} +	case KVM_PPC_RTAS_DEFINE_TOKEN: { +		struct kvm *kvm = filp->private_data; + +		r = kvm_vm_ioctl_rtas_define_token(kvm, argp); +		break; +	} +	default: { +		struct kvm *kvm = filp->private_data; +		r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg); +	} +#else /* CONFIG_PPC_BOOK3S_64 */  	default:  		r = -ENOTTY; +#endif  	} -  out:  	return r;  } +static unsigned long lpid_inuse[BITS_TO_LONGS(KVMPPC_NR_LPIDS)]; +static unsigned long nr_lpids; + +long kvmppc_alloc_lpid(void) +{ +	long lpid; + +	do { +		lpid = find_first_zero_bit(lpid_inuse, KVMPPC_NR_LPIDS); +		if (lpid >= nr_lpids) { +			pr_err("%s: No LPIDs free\n", __func__); +			return -ENOMEM; +		} +	} while (test_and_set_bit(lpid, lpid_inuse)); + +	return lpid; +} +EXPORT_SYMBOL_GPL(kvmppc_alloc_lpid); + +void kvmppc_claim_lpid(long lpid) +{ +	set_bit(lpid, lpid_inuse); +} +EXPORT_SYMBOL_GPL(kvmppc_claim_lpid); + +void kvmppc_free_lpid(long lpid) +{ +	clear_bit(lpid, lpid_inuse); +} +EXPORT_SYMBOL_GPL(kvmppc_free_lpid); + +void kvmppc_init_lpid(unsigned long nr_lpids_param) +{ +	nr_lpids = min_t(unsigned long, KVMPPC_NR_LPIDS, nr_lpids_param); +	memset(lpid_inuse, 0, sizeof(lpid_inuse)); +} +EXPORT_SYMBOL_GPL(kvmppc_init_lpid); +  int kvm_arch_init(void *opaque)  {  	return 0; @@ -641,4 +1202,5 @@ int kvm_arch_init(void *opaque)  void kvm_arch_exit(void)  { +  }  | 
