diff options
Diffstat (limited to 'arch/arm64/kvm/sys_regs.c')
| -rw-r--r-- | arch/arm64/kvm/sys_regs.c | 122 | 
1 files changed, 53 insertions, 69 deletions
| diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 3d7c2df89946..c370b4014799 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -20,17 +20,20 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ -#include <linux/mm.h>  #include <linux/kvm_host.h> +#include <linux/mm.h>  #include <linux/uaccess.h> -#include <asm/kvm_arm.h> -#include <asm/kvm_host.h> -#include <asm/kvm_emulate.h> -#include <asm/kvm_coproc.h> -#include <asm/kvm_mmu.h> +  #include <asm/cacheflush.h>  #include <asm/cputype.h>  #include <asm/debug-monitors.h> +#include <asm/esr.h> +#include <asm/kvm_arm.h> +#include <asm/kvm_coproc.h> +#include <asm/kvm_emulate.h> +#include <asm/kvm_host.h> +#include <asm/kvm_mmu.h> +  #include <trace/events/kvm.h>  #include "sys_regs.h" @@ -69,68 +72,31 @@ static u32 get_ccsidr(u32 csselr)  	return ccsidr;  } -static void do_dc_cisw(u32 val) -{ -	asm volatile("dc cisw, %x0" : : "r" (val)); -	dsb(ish); -} - -static void do_dc_csw(u32 val) -{ -	asm volatile("dc csw, %x0" : : "r" (val)); -	dsb(ish); -} - -/* See note at ARM ARM B1.14.4 */ +/* + * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). + */  static bool access_dcsw(struct kvm_vcpu *vcpu,  			const struct sys_reg_params *p,  			const struct sys_reg_desc *r)  { -	unsigned long val; -	int cpu; -  	if (!p->is_write)  		return read_from_write_only(vcpu, p); -	cpu = get_cpu(); - -	cpumask_setall(&vcpu->arch.require_dcache_flush); -	cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush); - -	/* If we were already preempted, take the long way around */ -	if (cpu != vcpu->arch.last_pcpu) { -		flush_cache_all(); -		goto done; -	} - -	val = *vcpu_reg(vcpu, p->Rt); - -	switch (p->CRm) { -	case 6:			/* Upgrade DCISW to DCCISW, as per HCR.SWIO */ -	case 14:		/* DCCISW */ -		do_dc_cisw(val); -		break; - -	case 10:		/* DCCSW */ -		do_dc_csw(val); -		break; -	} - -done: -	put_cpu(); - +	kvm_set_way_flush(vcpu);  	return true;  }  /*   * Generic accessor for VM registers. Only called as long as HCR_TVM - * is set. + * is set. If the guest enables the MMU, we stop trapping the VM + * sys_regs and leave it in complete control of the caches.   */  static bool access_vm_reg(struct kvm_vcpu *vcpu,  			  const struct sys_reg_params *p,  			  const struct sys_reg_desc *r)  {  	unsigned long val; +	bool was_enabled = vcpu_has_cache_enabled(vcpu);  	BUG_ON(!p->is_write); @@ -143,24 +109,27 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,  		vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL;  	} +	kvm_toggle_cache(vcpu, was_enabled);  	return true;  }  /* - * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set.  If the - * guest enables the MMU, we stop trapping the VM sys_regs and leave - * it in complete control of the caches. + * Trap handler for the GICv3 SGI generation system register. + * Forward the request to the VGIC emulation. + * The cp15_64 code makes sure this automatically works + * for both AArch64 and AArch32 accesses.   */ -static bool access_sctlr(struct kvm_vcpu *vcpu, -			 const struct sys_reg_params *p, -			 const struct sys_reg_desc *r) +static bool access_gic_sgi(struct kvm_vcpu *vcpu, +			   const struct sys_reg_params *p, +			   const struct sys_reg_desc *r)  { -	access_vm_reg(vcpu, p, r); +	u64 val; -	if (vcpu_has_cache_enabled(vcpu)) {	/* MMU+Caches enabled? */ -		vcpu->arch.hcr_el2 &= ~HCR_TVM; -		stage2_flush_vm(vcpu->kvm); -	} +	if (!p->is_write) +		return read_from_write_only(vcpu, p); + +	val = *vcpu_reg(vcpu, p->Rt); +	vgic_v3_dispatch_sgi(vcpu, val);  	return true;  } @@ -252,10 +221,19 @@ static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)  { +	u64 mpidr; +  	/* -	 * Simply map the vcpu_id into the Aff0 field of the MPIDR. +	 * Map the vcpu_id into the first three affinity level fields of +	 * the MPIDR. We limit the number of VCPUs in level 0 due to a +	 * limitation to 16 CPUs in that level in the ICC_SGIxR registers +	 * of the GICv3 to be able to address each CPU directly when +	 * sending IPIs.  	 */ -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1UL << 31) | (vcpu->vcpu_id & 0xff); +	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); +	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); +	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); +	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;  }  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */ @@ -377,7 +355,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {  	  NULL, reset_mpidr, MPIDR_EL1 },  	/* SCTLR_EL1 */  	{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000), -	  access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 }, +	  access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },  	/* CPACR_EL1 */  	{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),  	  NULL, reset_val, CPACR_EL1, 0 }, @@ -425,6 +403,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {  	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),  	  NULL, reset_val, VBAR_EL1, 0 }, +	/* ICC_SGI1R_EL1 */ +	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1011), Op2(0b101), +	  access_gic_sgi },  	/* ICC_SRE_EL1 */  	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101),  	  trap_raz_wi }, @@ -657,7 +638,9 @@ static const struct sys_reg_desc cp14_64_regs[] = {   * register).   */  static const struct sys_reg_desc cp15_regs[] = { -	{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR }, +	{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, + +	{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, c1_SCTLR },  	{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },  	{ Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },  	{ Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR }, @@ -704,6 +687,7 @@ static const struct sys_reg_desc cp15_regs[] = {  static const struct sys_reg_desc cp15_64_regs[] = {  	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 }, +	{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi },  	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },  }; @@ -815,12 +799,12 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,  	int cp;  	switch(hsr_ec) { -	case ESR_EL2_EC_CP15_32: -	case ESR_EL2_EC_CP15_64: +	case ESR_ELx_EC_CP15_32: +	case ESR_ELx_EC_CP15_64:  		cp = 15;  		break; -	case ESR_EL2_EC_CP14_MR: -	case ESR_EL2_EC_CP14_64: +	case ESR_ELx_EC_CP14_MR: +	case ESR_ELx_EC_CP14_64:  		cp = 14;  		break;  	default: |