@@ -1726,11 +1726,40 @@ static void do_sysreg(struct cpu_user_regs *regs,
switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
{
/* RAZ/WI registers: */
+
/* - Debug */
case HSR_SYSREG_MDSCR_EL1:
/* - Perf monitors */
case HSR_SYSREG_PMINTENSET_EL1:
case HSR_SYSREG_PMINTENCLR_EL1:
+ /* - Breakpoints */
+ HSR_SYSREG_DBG_CASES(DBGBVR):
+ HSR_SYSREG_DBG_CASES(DBGBCR):
+ /* - Watchpoints */
+ HSR_SYSREG_DBG_CASES(DBGWVR):
+ HSR_SYSREG_DBG_CASES(DBGWCR):
+ /* - Double Lock Register */
+ case HSR_SYSREG_OSDLR_EL1:
+ /* EL1 only */
+ BUG_ON(psr_mode_is_user(regs));
+ goto sysreg_raz_wi;
+
+ case HSR_SYSREG_PMUSERENR_EL0:
+ /* RO at EL0. RAZ/WI at EL1 */
+ if ( psr_mode_is_user(regs) && !hsr.sysreg.read )
+ goto undef_sysreg;
+ goto sysreg_raz_wi;
+
+ case HSR_SYSREG_MDCCSR_EL0:
+ /*
+ * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that
+ * register as RAZ/WI above. So RO at both EL0 and EL1.
+ */
+ if ( !hsr.sysreg.read )
+ goto undef_sysreg;
+
+ *x = 0;
+ break;
case HSR_SYSREG_PMCR_EL0:
case HSR_SYSREG_PMCNTENSET_EL0:
case HSR_SYSREG_PMCNTENCLR_EL0:
@@ -1742,16 +1771,16 @@ static void do_sysreg(struct cpu_user_regs *regs,
case HSR_SYSREG_PMCCNTR_EL0:
case HSR_SYSREG_PMXEVTYPER_EL0:
case HSR_SYSREG_PMXEVCNTR_EL0:
- case HSR_SYSREG_PMUSERENR_EL0:
case HSR_SYSREG_PMOVSSET_EL0:
- /* - Breakpoints */
- HSR_SYSREG_DBG_CASES(DBGBVR):
- HSR_SYSREG_DBG_CASES(DBGBCR):
- /* - Watchpoints */
- HSR_SYSREG_DBG_CASES(DBGWVR):
- HSR_SYSREG_DBG_CASES(DBGWCR):
- /* - Double Lock Register */
- case HSR_SYSREG_OSDLR_EL1:
+ /*
+ * Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
+ * emulate that register as 0 above.
+ */
+ if ( psr_mode_is_user(regs) )
+ goto undef_sysreg;
+ /* Fall thru */
+
+ sysreg_raz_wi:
if ( hsr.sysreg.read )
*x = 0;
/* else: write ignored */
@@ -1759,8 +1788,9 @@ static void do_sysreg(struct cpu_user_regs *regs,
/* Write only, Write ignore registers: */
case HSR_SYSREG_OSLAR_EL1:
+ BUG_ON(psr_mode_is_user(regs));
if ( hsr.sysreg.read )
- goto bad_sysreg;
+ goto undef_sysreg;
/* else: write ignored */
break;
case HSR_SYSREG_CNTP_CTL_EL0:
@@ -1768,7 +1798,6 @@ static void do_sysreg(struct cpu_user_regs *regs,
case HSR_SYSREG_CNTPCT_EL0:
goto undef_sysreg;
default:
- bad_sysreg:
{
#ifndef NDEBUG
struct hsr_sysreg sysreg = hsr.sysreg;
@@ -1999,8 +2028,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
inject_undef64_exception(regs, hsr.len);
break;
case HSR_EC_SYSREG:
- if ( is_32bit_domain(current->domain) )
- goto bad_trap;
+ BUG_ON(psr_mode_is_32bit(regs->cpsr));
do_sysreg(regs, hsr);
break;
#endif
@@ -43,6 +43,7 @@
#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)
+#define HSR_SYSREG_MDCCSR_EL0 HSR_SYSREG(2,3,c0,c1,0)
#define HSR_SYSREG_DBGBVRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,4)
#define HSR_SYSREG_DBGBCRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,5)
Previously we implemented all registers as RAZ/WI even if they shouldn't be accessible to userspace. Accesses to the *_EL1 registers from EL0 are trapped to EL1 by the hardware, so add a BUG_ON. Likewise accesses from 32-bit EL1 cannot happen. PMUSERENR_EL0 and MDCCSR_EL0 are R/O to EL0. Other PM*_EL0 registers are accessible at EL0 only if PMUSERENR_EL0.EN is set, since we emulate that as RAZ/WI we know that bit cannot be set. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 54 +++++++++++++++++++++++++++++++---------- xen/include/asm-arm/sysregs.h | 1 + 2 files changed, 42 insertions(+), 13 deletions(-)