diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv.c')
| -rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 271 | 
1 files changed, 228 insertions, 43 deletions
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 7a12edbb61e7..27cced9c7249 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -35,6 +35,7 @@  #include <asm/reg.h>  #include <asm/cputable.h> +#include <asm/cache.h>  #include <asm/cacheflush.h>  #include <asm/tlbflush.h>  #include <asm/uaccess.h> @@ -67,6 +68,15 @@  /* Used as a "null" value for timebase values */  #define TB_NIL	(~(u64)0) +static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1); + +#if defined(CONFIG_PPC_64K_PAGES) +#define MPP_BUFFER_ORDER	0 +#elif defined(CONFIG_PPC_4K_PAGES) +#define MPP_BUFFER_ORDER	3 +#endif + +  static void kvmppc_end_cede(struct kvm_vcpu *vcpu);  static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); @@ -270,7 +280,7 @@ struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id)  static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa)  {  	vpa->__old_status |= LPPACA_OLD_SHARED_PROC; -	vpa->yield_count = 1; +	vpa->yield_count = cpu_to_be32(1);  }  static int set_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *v, @@ -293,8 +303,8 @@ static int set_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *v,  struct reg_vpa {  	u32 dummy;  	union { -		u16 hword; -		u32 word; +		__be16 hword; +		__be32 word;  	} length;  }; @@ -333,9 +343,9 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,  		if (va == NULL)  			return H_PARAMETER;  		if (subfunc == H_VPA_REG_VPA) -			len = ((struct reg_vpa *)va)->length.hword; +			len = be16_to_cpu(((struct reg_vpa *)va)->length.hword);  		else -			len = ((struct reg_vpa *)va)->length.word; +			len = be32_to_cpu(((struct reg_vpa *)va)->length.word);  		kvmppc_unpin_guest_page(kvm, va, vpa, false);  		/* Check length */ @@ -540,21 +550,63 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,  		return;  	memset(dt, 0, sizeof(struct dtl_entry));  	dt->dispatch_reason = 7; -	dt->processor_id = vc->pcpu + vcpu->arch.ptid; -	dt->timebase = now + vc->tb_offset; -	dt->enqueue_to_dispatch_time = stolen; -	dt->srr0 = kvmppc_get_pc(vcpu); -	dt->srr1 = vcpu->arch.shregs.msr; +	dt->processor_id = cpu_to_be16(vc->pcpu + vcpu->arch.ptid); +	dt->timebase = cpu_to_be64(now + vc->tb_offset); +	dt->enqueue_to_dispatch_time = cpu_to_be32(stolen); +	dt->srr0 = cpu_to_be64(kvmppc_get_pc(vcpu)); +	dt->srr1 = cpu_to_be64(vcpu->arch.shregs.msr);  	++dt;  	if (dt == vcpu->arch.dtl.pinned_end)  		dt = vcpu->arch.dtl.pinned_addr;  	vcpu->arch.dtl_ptr = dt;  	/* order writing *dt vs. writing vpa->dtl_idx */  	smp_wmb(); -	vpa->dtl_idx = ++vcpu->arch.dtl_index; +	vpa->dtl_idx = cpu_to_be64(++vcpu->arch.dtl_index);  	vcpu->arch.dtl.dirty = true;  } +static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu) +{ +	if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207) +		return true; +	if ((!vcpu->arch.vcore->arch_compat) && +	    cpu_has_feature(CPU_FTR_ARCH_207S)) +		return true; +	return false; +} + +static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, +			     unsigned long resource, unsigned long value1, +			     unsigned long value2) +{ +	switch (resource) { +	case H_SET_MODE_RESOURCE_SET_CIABR: +		if (!kvmppc_power8_compatible(vcpu)) +			return H_P2; +		if (value2) +			return H_P4; +		if (mflags) +			return H_UNSUPPORTED_FLAG_START; +		/* Guests can't breakpoint the hypervisor */ +		if ((value1 & CIABR_PRIV) == CIABR_PRIV_HYPER) +			return H_P3; +		vcpu->arch.ciabr  = value1; +		return H_SUCCESS; +	case H_SET_MODE_RESOURCE_SET_DAWR: +		if (!kvmppc_power8_compatible(vcpu)) +			return H_P2; +		if (mflags) +			return H_UNSUPPORTED_FLAG_START; +		if (value2 & DABRX_HYP) +			return H_P4; +		vcpu->arch.dawr  = value1; +		vcpu->arch.dawrx = value2; +		return H_SUCCESS; +	default: +		return H_TOO_HARD; +	} +} +  int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)  {  	unsigned long req = kvmppc_get_gpr(vcpu, 3); @@ -562,6 +614,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)  	struct kvm_vcpu *tvcpu;  	int idx, rc; +	if (req <= MAX_HCALL_OPCODE && +	    !test_bit(req/4, vcpu->kvm->arch.enabled_hcalls)) +		return RESUME_HOST; +  	switch (req) {  	case H_ENTER:  		idx = srcu_read_lock(&vcpu->kvm->srcu); @@ -620,7 +676,14 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)  		/* Send the error out to userspace via KVM_RUN */  		return rc; - +	case H_SET_MODE: +		ret = kvmppc_h_set_mode(vcpu, kvmppc_get_gpr(vcpu, 4), +					kvmppc_get_gpr(vcpu, 5), +					kvmppc_get_gpr(vcpu, 6), +					kvmppc_get_gpr(vcpu, 7)); +		if (ret == H_TOO_HARD) +			return RESUME_HOST; +		break;  	case H_XIRR:  	case H_CPPR:  	case H_EOI: @@ -639,6 +702,29 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)  	return RESUME_GUEST;  } +static int kvmppc_hcall_impl_hv(unsigned long cmd) +{ +	switch (cmd) { +	case H_CEDE: +	case H_PROD: +	case H_CONFER: +	case H_REGISTER_VPA: +	case H_SET_MODE: +#ifdef CONFIG_KVM_XICS +	case H_XIRR: +	case H_CPPR: +	case H_EOI: +	case H_IPI: +	case H_IPOLL: +	case H_XIRR_X: +#endif +		return 1; +	} + +	/* See if it's in the real-mode table */ +	return kvmppc_hcall_impl_hv_realmode(cmd); +} +  static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,  				 struct task_struct *tsk)  { @@ -785,7 +871,8 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,  	return 0;  } -static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr) +static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr, +		bool preserve_top32)  {  	struct kvmppc_vcore *vc = vcpu->arch.vcore;  	u64 mask; @@ -820,6 +907,10 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr)  	mask = LPCR_DPFD | LPCR_ILE | LPCR_TC;  	if (cpu_has_feature(CPU_FTR_ARCH_207S))  		mask |= LPCR_AIL; + +	/* Broken 32-bit version of LPCR must not clear top bits */ +	if (preserve_top32) +		mask &= 0xFFFFFFFF;  	vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);  	spin_unlock(&vc->lock);  } @@ -894,12 +985,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,  	case KVM_REG_PPC_CIABR:  		*val = get_reg_val(id, vcpu->arch.ciabr);  		break; -	case KVM_REG_PPC_IC: -		*val = get_reg_val(id, vcpu->arch.ic); -		break; -	case KVM_REG_PPC_VTB: -		*val = get_reg_val(id, vcpu->arch.vtb); -		break;  	case KVM_REG_PPC_CSIGR:  		*val = get_reg_val(id, vcpu->arch.csigr);  		break; @@ -939,6 +1024,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,  		*val = get_reg_val(id, vcpu->arch.vcore->tb_offset);  		break;  	case KVM_REG_PPC_LPCR: +	case KVM_REG_PPC_LPCR_64:  		*val = get_reg_val(id, vcpu->arch.vcore->lpcr);  		break;  	case KVM_REG_PPC_PPR: @@ -1094,12 +1180,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,  		if ((vcpu->arch.ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER)  			vcpu->arch.ciabr &= ~CIABR_PRIV;	/* disable */  		break; -	case KVM_REG_PPC_IC: -		vcpu->arch.ic = set_reg_val(id, *val); -		break; -	case KVM_REG_PPC_VTB: -		vcpu->arch.vtb = set_reg_val(id, *val); -		break;  	case KVM_REG_PPC_CSIGR:  		vcpu->arch.csigr = set_reg_val(id, *val);  		break; @@ -1150,7 +1230,10 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,  			ALIGN(set_reg_val(id, *val), 1UL << 24);  		break;  	case KVM_REG_PPC_LPCR: -		kvmppc_set_lpcr(vcpu, set_reg_val(id, *val)); +		kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), true); +		break; +	case KVM_REG_PPC_LPCR_64: +		kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), false);  		break;  	case KVM_REG_PPC_PPR:  		vcpu->arch.ppr = set_reg_val(id, *val); @@ -1228,6 +1311,33 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,  	return r;  } +static struct kvmppc_vcore *kvmppc_vcore_create(struct kvm *kvm, int core) +{ +	struct kvmppc_vcore *vcore; + +	vcore = kzalloc(sizeof(struct kvmppc_vcore), GFP_KERNEL); + +	if (vcore == NULL) +		return NULL; + +	INIT_LIST_HEAD(&vcore->runnable_threads); +	spin_lock_init(&vcore->lock); +	init_waitqueue_head(&vcore->wq); +	vcore->preempt_tb = TB_NIL; +	vcore->lpcr = kvm->arch.lpcr; +	vcore->first_vcpuid = core * threads_per_subcore; +	vcore->kvm = kvm; + +	vcore->mpp_buffer_is_valid = false; + +	if (cpu_has_feature(CPU_FTR_ARCH_207S)) +		vcore->mpp_buffer = (void *)__get_free_pages( +			GFP_KERNEL|__GFP_ZERO, +			MPP_BUFFER_ORDER); + +	return vcore; +} +  static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,  						   unsigned int id)  { @@ -1279,16 +1389,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,  	mutex_lock(&kvm->lock);  	vcore = kvm->arch.vcores[core];  	if (!vcore) { -		vcore = kzalloc(sizeof(struct kvmppc_vcore), GFP_KERNEL); -		if (vcore) { -			INIT_LIST_HEAD(&vcore->runnable_threads); -			spin_lock_init(&vcore->lock); -			init_waitqueue_head(&vcore->wq); -			vcore->preempt_tb = TB_NIL; -			vcore->lpcr = kvm->arch.lpcr; -			vcore->first_vcpuid = core * threads_per_subcore; -			vcore->kvm = kvm; -		} +		vcore = kvmppc_vcore_create(kvm, core);  		kvm->arch.vcores[core] = vcore;  		kvm->arch.online_vcores++;  	} @@ -1500,6 +1601,33 @@ static int on_primary_thread(void)  	return 1;  } +static void kvmppc_start_saving_l2_cache(struct kvmppc_vcore *vc) +{ +	phys_addr_t phy_addr, mpp_addr; + +	phy_addr = (phys_addr_t)virt_to_phys(vc->mpp_buffer); +	mpp_addr = phy_addr & PPC_MPPE_ADDRESS_MASK; + +	mtspr(SPRN_MPPR, mpp_addr | PPC_MPPR_FETCH_ABORT); +	logmpp(mpp_addr | PPC_LOGMPP_LOG_L2); + +	vc->mpp_buffer_is_valid = true; +} + +static void kvmppc_start_restoring_l2_cache(const struct kvmppc_vcore *vc) +{ +	phys_addr_t phy_addr, mpp_addr; + +	phy_addr = virt_to_phys(vc->mpp_buffer); +	mpp_addr = phy_addr & PPC_MPPE_ADDRESS_MASK; + +	/* We must abort any in-progress save operations to ensure +	 * the table is valid so that prefetch engine knows when to +	 * stop prefetching. */ +	logmpp(mpp_addr | PPC_LOGMPP_LOG_ABORT); +	mtspr(SPRN_MPPR, mpp_addr | PPC_MPPR_FETCH_WHOLE_TABLE); +} +  /*   * Run a set of guest threads on a physical core.   * Called with vc->lock held. @@ -1577,9 +1705,16 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)  	srcu_idx = srcu_read_lock(&vc->kvm->srcu); +	if (vc->mpp_buffer_is_valid) +		kvmppc_start_restoring_l2_cache(vc); +  	__kvmppc_vcore_entry();  	spin_lock(&vc->lock); + +	if (vc->mpp_buffer) +		kvmppc_start_saving_l2_cache(vc); +  	/* disable sending of IPIs on virtual external irqs */  	list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)  		vcpu->cpu = -1; @@ -1929,12 +2064,6 @@ static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,  	(*sps)->page_shift = def->shift;  	(*sps)->slb_enc = def->sllp;  	(*sps)->enc[0].page_shift = def->shift; -	/* -	 * Only return base page encoding. We don't want to return -	 * all the supporting pte_enc, because our H_ENTER doesn't -	 * support MPSS yet. Once they do, we can start passing all -	 * support pte_enc here -	 */  	(*sps)->enc[0].pte_enc = def->penc[linux_psize];  	/*  	 * Add 16MB MPSS support if host supports it @@ -2281,6 +2410,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)  	 */  	cpumask_setall(&kvm->arch.need_tlb_flush); +	/* Start out with the default set of hcalls enabled */ +	memcpy(kvm->arch.enabled_hcalls, default_enabled_hcalls, +	       sizeof(kvm->arch.enabled_hcalls)); +  	kvm->arch.rma = NULL;  	kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); @@ -2323,8 +2456,14 @@ static void kvmppc_free_vcores(struct kvm *kvm)  {  	long int i; -	for (i = 0; i < KVM_MAX_VCORES; ++i) +	for (i = 0; i < KVM_MAX_VCORES; ++i) { +		if (kvm->arch.vcores[i] && kvm->arch.vcores[i]->mpp_buffer) { +			struct kvmppc_vcore *vc = kvm->arch.vcores[i]; +			free_pages((unsigned long)vc->mpp_buffer, +				   MPP_BUFFER_ORDER); +		}  		kfree(kvm->arch.vcores[i]); +	}  	kvm->arch.online_vcores = 0;  } @@ -2419,6 +2558,49 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp,  	return r;  } +/* + * List of hcall numbers to enable by default. + * For compatibility with old userspace, we enable by default + * all hcalls that were implemented before the hcall-enabling + * facility was added.  Note this list should not include H_RTAS. + */ +static unsigned int default_hcall_list[] = { +	H_REMOVE, +	H_ENTER, +	H_READ, +	H_PROTECT, +	H_BULK_REMOVE, +	H_GET_TCE, +	H_PUT_TCE, +	H_SET_DABR, +	H_SET_XDABR, +	H_CEDE, +	H_PROD, +	H_CONFER, +	H_REGISTER_VPA, +#ifdef CONFIG_KVM_XICS +	H_EOI, +	H_CPPR, +	H_IPI, +	H_IPOLL, +	H_XIRR, +	H_XIRR_X, +#endif +	0 +}; + +static void init_default_hcalls(void) +{ +	int i; +	unsigned int hcall; + +	for (i = 0; default_hcall_list[i]; ++i) { +		hcall = default_hcall_list[i]; +		WARN_ON(!kvmppc_hcall_impl_hv(hcall)); +		__set_bit(hcall / 4, default_enabled_hcalls); +	} +} +  static struct kvmppc_ops kvm_ops_hv = {  	.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,  	.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv, @@ -2451,6 +2633,7 @@ static struct kvmppc_ops kvm_ops_hv = {  	.emulate_mfspr = kvmppc_core_emulate_mfspr_hv,  	.fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv,  	.arch_vm_ioctl  = kvm_arch_vm_ioctl_hv, +	.hcall_implemented = kvmppc_hcall_impl_hv,  };  static int kvmppc_book3s_init_hv(void) @@ -2466,6 +2649,8 @@ static int kvmppc_book3s_init_hv(void)  	kvm_ops_hv.owner = THIS_MODULE;  	kvmppc_hv_ops = &kvm_ops_hv; +	init_default_hcalls(); +  	r = kvmppc_mmu_hv_init();  	return r;  }  | 
