From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ian Campbell Subject: [PATCH v4 08/15] xen: arm: don't pretend to handle cache maintenance by set/way Date: Fri, 27 Mar 2015 14:33:37 +0000 Message-ID: <1427466824-31967-8-git-send-email-ian.campbell@citrix.com> References: <1427466798.13935.158.camel@citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1427466798.13935.158.camel@citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: julien.grall@linaro.org, tim@xen.org, Ian Campbell , stefano.stabellini@eu.citrix.com List-Id: xen-devel@lists.xenproject.org We set HCR_EL2.TSW but only (sort of) handle 32-bit access to DCCISW but not the other two registers, nor any 64-bit access. Add handlers for all of these. The existing handling of DCCISW was to simply propagate the action to the host level. This can't really work on an SMP system (due to speculation from other cores) and is even worse under virtualisation (imagine a VCPU changing PCPU half way through a set/way loop). Since set/way operations are not really usable under any hypervisor don't even try, instead for writes log a guest debug message and inject an under exception. These registers are all WO, so continue to kill the guest on read from EL1. For accesses from EL0 just silently inject undef. In do_sysreg promote the sysreg variable to the top level and use throughout. Signed-off-by: Ian Campbell --- v4: New patch --- xen/arch/arm/traps.c | 57 +++++++++++++++++++++++++++++++++-------- xen/include/asm-arm/sysregs.h | 4 +++ xen/include/public/arch-arm.h | 5 ++++ 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index f35b7c3..10eb3e6 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -1564,19 +1564,28 @@ static void do_cp15_32(struct cpu_user_regs *regs, switch ( hsr.bits & HSR_CP32_REGS_MASK ) { + case HSR_CPREG32(DCISW): + case HSR_CPREG32(DCCSW): case HSR_CPREG32(DCCISW): + if ( psr_mode_is_user(regs) ) + goto undef_cp15_32; + + gdprintk(XENLOG_ERR, + "Unhandled set/way operation " + "p15, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister", " + "rn = %"PRIx32"\n", + cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, + regs->pc, *r); + if ( cp32.read ) { dprintk(XENLOG_ERR, - "attempt to read from write-only register DCCISW\n"); + "attempt to read from write-only register\n"); domain_crash_synchronous(); } -#ifdef CONFIG_ARM_32 - WRITE_CP32(*r, DCCISW); -#else - asm volatile("dc cisw, %0;" : : "r" (*r) : "memory"); -#endif - break; + + goto undef_cp15_32; + case HSR_CPREG32(CNTP_CTL): case HSR_CPREG32(CNTP_TVAL): if ( !vtimer_emulate(regs, hsr) ) @@ -1781,10 +1790,37 @@ static void do_cp(struct cpu_user_regs *regs, union hsr hsr) static void do_sysreg(struct cpu_user_regs *regs, union hsr hsr) { - register_t *x = select_user_reg(regs, hsr.sysreg.reg); + struct hsr_sysreg sysreg = hsr.sysreg; + register_t *x = select_user_reg(regs, sysreg.reg); switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) { + + /* Set/way registers */ + case HSR_SYSREG_DCISW: + case HSR_SYSREG_DCCSW: + case HSR_SYSREG_DCCISW: + if ( psr_mode_is_user(regs) ) + goto undef_sysreg; + + gdprintk(XENLOG_ERR, + "Unhandled set/way operation " + "%d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister", " + "xn = %"PRIx64"\n", + sysreg.op0, sysreg.op1, + sysreg.crn, sysreg.crm, + sysreg.op2, + sysreg.read ? "=>" : "<=", + sysreg.reg, regs->pc, *x); + if ( sysreg.read ) + { + dprintk(XENLOG_ERR, + "attempt to read from write-only register\n"); + domain_crash_synchronous(); + } + + goto undef_sysreg; + /* RAZ/WI registers: */ /* - Debug */ case HSR_SYSREG_MDSCR_EL1: @@ -1812,14 +1848,14 @@ static void do_sysreg(struct cpu_user_regs *regs, HSR_SYSREG_DBG_CASES(DBGWCR): /* - Double Lock Register */ case HSR_SYSREG_OSDLR_EL1: - if ( hsr.sysreg.read ) + if ( sysreg.read ) *x = 0; /* else: write ignored */ break; /* Write only, Write ignore registers: */ case HSR_SYSREG_OSLAR_EL1: - if ( hsr.sysreg.read ) + if ( sysreg.read ) goto bad_sysreg; /* else: write ignored */ break; @@ -1847,7 +1883,6 @@ static void do_sysreg(struct cpu_user_regs *regs, bad_sysreg: { #ifndef NDEBUG - struct hsr_sysreg sysreg = hsr.sysreg; gdprintk(XENLOG_ERR, "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h index df8e070..2e256cc 100644 --- a/xen/include/asm-arm/sysregs.h +++ b/xen/include/asm-arm/sysregs.h @@ -40,6 +40,10 @@ ((__HSR_SYSREG_##crm) << HSR_SYSREG_CRM_SHIFT) | \ ((__HSR_SYSREG_##op2) << HSR_SYSREG_OP2_SHIFT) +#define HSR_SYSREG_DCISW HSR_SYSREG(1,0,c7,c6,2) +#define HSR_SYSREG_DCCSW HSR_SYSREG(1,0,c7,c10,2) +#define HSR_SYSREG_DCCISW HSR_SYSREG(1,0,c7,c14,2) + #define HSR_SYSREG_MDSCR_EL1 HSR_SYSREG(2,0,c0,c2,2) #define HSR_SYSREG_OSLAR_EL1 HSR_SYSREG(2,0,c1,c0,4) #define HSR_SYSREG_OSDLR_EL1 HSR_SYSREG(2,0,c1,c3,4) diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index c2dcb66..cf3d6cc 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -161,6 +161,11 @@ * * - The device tree Xen compatible node is fully described under Linux * at Documentation/devicetree/bindings/arm/xen.txt. + * + * - Cache maintenaince operations by set/way ("dc isw|cisw|csw" and + * the equivalent cp15 registers) are not available when running + * under Xen and will result in an undefined instruction exception + * delivered to the guest. */ #define XEN_HYPERCALL_TAG 0XEA1 -- 1.7.10.4