|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 07/12] xen: arm: Handle CP15 register traps from userspace
Previously userspace access to PM* would have been incorrectly (but
benignly) implemented as RAZ/WI when running on a 32-bit kernel and
would cause a hypervisor exception (host crash) when running a 64-bit
kernel (this was already solved via the fix to XSA-102).
CLIDR, CCSIDR, DCCISW, ACTLR, PMINTENSET, PMINTENCLR are EL1 only,
attempts to access from EL0 will trap to EL1 not to us, hence BUG_ON
is appropriate now.
PMUSERENR is R/O at EL0 and we implement as RAZ/WI at EL1 as before.
The remaining PM* registers are accessible to EL0 only if
PMUSERENR_EL0.EN is set, since we emulate this as RAZ/WI the bit is
never set so we inject a trap on attempted access. We weren't
previously handling PMCCNTR.
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
xen/arch/arm/traps.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index c5ffcc5..e49ae79 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1565,6 +1565,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
switch ( hsr.bits & HSR_CP32_REGS_MASK )
{
case HSR_CPREG32(CLIDR):
+ BUG_ON(psr_mode_is_user(regs));
if ( !cp32.read )
{
dprintk(XENLOG_ERR,
@@ -1574,6 +1575,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
*r = READ_SYSREG32(CLIDR_EL1);
break;
case HSR_CPREG32(CCSIDR):
+ BUG_ON(psr_mode_is_user(regs));
if ( !cp32.read )
{
dprintk(XENLOG_ERR,
@@ -1583,6 +1585,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
*r = READ_SYSREG32(CCSIDR_EL1);
break;
case HSR_CPREG32(DCCISW):
+ BUG_ON(psr_mode_is_user(regs));
if ( cp32.read )
{
dprintk(XENLOG_ERR,
@@ -1601,6 +1604,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
goto undef_cp15_32;
break;
case HSR_CPREG32(ACTLR):
+ BUG_ON(psr_mode_is_user(regs));
if ( cp32.read )
*r = v->arch.actlr;
break;
@@ -1613,6 +1617,18 @@ static void do_cp15_32(struct cpu_user_regs *regs,
* always support PMCCNTR (the cyle counter): we just RAZ/WI for all
* PM register, which doesn't crash the kernel at least
*/
+ case HSR_CPREG32(PMUSERENR):
+ /* RO at EL0. RAZ/WI at EL1 */
+ if ( psr_mode_is_user(regs) && !hsr.cp32.read )
+ goto undef_cp15_32;
+ goto cp15_32_raz_wi;
+
+ case HSR_CPREG32(PMINTENSET):
+ case HSR_CPREG32(PMINTENCLR):
+ /* EL1 only */
+ BUG_ON(psr_mode_is_user(regs));
+ goto cp15_32_raz_wi;
+
case HSR_CPREG32(PMCR):
case HSR_CPREG32(PMCNTENSET):
case HSR_CPREG32(PMCNTENCLR):
@@ -1624,12 +1640,19 @@ static void do_cp15_32(struct cpu_user_regs *regs,
case HSR_CPREG32(PMCCNTR):
case HSR_CPREG32(PMXEVTYPER):
case HSR_CPREG32(PMXEVCNTR):
- case HSR_CPREG32(PMUSERENR):
- case HSR_CPREG32(PMINTENSET):
- case HSR_CPREG32(PMINTENCLR):
case HSR_CPREG32(PMOVSSET):
+ /*
+ * 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_cp15_32;
+ /* Fall thru */
+
+ cp15_32_raz_wi:
if ( cp32.read )
*r = 0;
+ /* else: write ignored */
break;
default:
@@ -2049,8 +2072,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs
*regs)
advance_pc(regs, hsr);
break;
case HSR_EC_CP15_32:
- if ( !is_32bit_domain(current->domain) )
- goto bad_trap;
+ BUG_ON(!psr_mode_is_32bit(regs->cpsr));
perfc_incr(trap_cp15_32);
do_cp15_32(regs, hsr);
break;
--
1.7.10.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |