diff mbox

[Xen-devel,5/9] xen: arm: Handle CP15 register traps from userspace

Message ID 1410279788-27167-5-git-send-email-ian.campbell@citrix.com
State New
Headers show

Commit Message

Ian Campbell Sept. 9, 2014, 4:23 p.m. UTC
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@citrix.com>
---
 xen/arch/arm/traps.c |   32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

Comments

Julien Grall Sept. 9, 2014, 11:42 p.m. UTC | #1
Hi Ian,

On 09/09/14 09:23, Ian Campbell wrote:
> 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.

In the unlikely case it happens, I don't think it will harm Xen, but 
only the guest. So is the BUG_ON really necessary on these registers?

I think we should use BUG_ON when we know that it will harm the Xen and 
it's not possible to come back from the state.

Regards,
Ian Campbell Sept. 10, 2014, 9:48 a.m. UTC | #2
On Tue, 2014-09-09 at 16:42 -0700, Julien Grall wrote:
> Hi Ian,
> 
> On 09/09/14 09:23, Ian Campbell wrote:
> > 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.
> 
> In the unlikely case it happens, I don't think it will harm Xen, but 
> only the guest. So is the BUG_ON really necessary on these registers?
> 
> I think we should use BUG_ON when we know that it will harm the Xen and 
> it's not possible to come back from the state.

AIUI it would be a hardware bug to see these traps in Xen. I think a
BUG_ON is acceptable for such an occurrence.

Ian.
Julien Grall Sept. 10, 2014, 6:56 p.m. UTC | #3
On 10/09/14 02:48, Ian Campbell wrote:
> On Tue, 2014-09-09 at 16:42 -0700, Julien Grall wrote:
>> Hi Ian,
>>
>> On 09/09/14 09:23, Ian Campbell wrote:
>>> 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.
>>
>> In the unlikely case it happens, I don't think it will harm Xen, but
>> only the guest. So is the BUG_ON really necessary on these registers?
>>
>> I think we should use BUG_ON when we know that it will harm the Xen and
>> it's not possible to come back from the state.
>
> AIUI it would be a hardware bug to see these traps in Xen. I think a
> BUG_ON is acceptable for such an occurrence.

I would turn into an ASSERT to avoid checking it in non-debug build.

Regards,
Ian Campbell Sept. 18, 2014, 1:31 a.m. UTC | #4
On Wed, 2014-09-10 at 11:56 -0700, Julien Grall wrote:
> 
> On 10/09/14 02:48, Ian Campbell wrote:
> > On Tue, 2014-09-09 at 16:42 -0700, Julien Grall wrote:
> >> Hi Ian,
> >>
> >> On 09/09/14 09:23, Ian Campbell wrote:
> >>> 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.
> >>
> >> In the unlikely case it happens, I don't think it will harm Xen, but
> >> only the guest. So is the BUG_ON really necessary on these registers?
> >>
> >> I think we should use BUG_ON when we know that it will harm the Xen and
> >> it's not possible to come back from the state.
> >
> > AIUI it would be a hardware bug to see these traps in Xen. I think a
> > BUG_ON is acceptable for such an occurrence.
> 
> I would turn into an ASSERT to avoid checking it in non-debug build.

BUG_ON is what we normally use in these circumstances. If we did hit
this case we would want to stop, not carry on with hardware in a
potentially unknown/unpredictable state, even for a non-debug build.

Ian.
diff mbox

Patch

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 46ed21d..e7a2791 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1446,6 +1446,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,
@@ -1455,6 +1456,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,
@@ -1464,6 +1466,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,
@@ -1481,6 +1484,7 @@  static void do_cp15_32(struct cpu_user_regs *regs,
         goto undef_cp15_32;
 
     case HSR_CPREG32(ACTLR):
+        BUG_ON(psr_mode_is_user(regs));
         if ( cp32.read )
            *r = v->arch.actlr;
         break;
@@ -1493,6 +1497,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):
@@ -1504,12 +1520,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:
@@ -1908,8 +1931,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));
         do_cp15_32(regs, hsr);
         break;
     case HSR_EC_CP15_64: