Subject: xen/arm: Don't let guess access to Debug and Performance Monitor registers
From: Julien Grall <[email-masked]>
Date: Tue, 15 Apr 2014 14:06:42 +0100

Debug and performance registers are not properly switched by Xen.

Trap them and inject an undefined instruction, except for those registers
which might be unconditionally accessed which we implement as RAZ/WI.

Signed-off-by: Julien Grall <[email-masked]>
Signed-off-by: Ian Campbell <[email-masked]>
---
 xen/arch/arm/traps.c            |   59 +++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/cpregs.h    |    2 ++
 xen/include/asm-arm/processor.h |   11 ++++++--
 xen/include/asm-arm/sysregs.h   |   43 ++++++++++++++++++++++++++++
 4 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 710e5cc..39c2468 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -74,6 +74,10 @@ void __cpuinit init_traps(void)
     /* Setup Hyp vector base */
     WRITE_SYSREG((vaddr_t)hyp_traps_vector, VBAR_EL2);
 
+    /* Trap Debug and Performance Monitor accesses */
+    WRITE_SYSREG(HDCR_TDRA|HDCR_TDOSA|HDCR_TDA|HDCR_TPM|HDCR_TPMCR,
+                 MDCR_EL2);
+
     /* Trap CP15 c15 used for implementation defined registers */
     WRITE_SYSREG(HSTR_T(15), HSTR_EL2);
 
@@ -1412,6 +1416,17 @@ static void do_cp15_64(struct cpu_user_regs *regs,
     advance_pc(regs, hsr);
 }
 
+static void do_cp14(struct cpu_user_regs *regs, union hsr hsr)
+{
+    if ( !check_conditional_instr(regs, hsr) )
+    {
+        advance_pc(regs, hsr);
+        return;
+    }
+
+    inject_undef32_exception(regs);
+}
+
 static void do_cp(struct cpu_user_regs *regs, union hsr hsr)
 {
     if ( !check_conditional_instr(regs, hsr) )
@@ -1427,9 +1442,46 @@ 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);
 
     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:
+    case HSR_SYSREG_PMCR_EL0:
+    case HSR_SYSREG_PMCNTENSET_EL0:
+    case HSR_SYSREG_PMCNTENCLR_EL0:
+    case HSR_SYSREG_PMOVSCLR_EL0:
+    case HSR_SYSREG_PMSWINC_EL0:
+    case HSR_SYSREG_PMSELR_EL0:
+    case HSR_SYSREG_PMCEID0_EL0:
+    case HSR_SYSREG_PMCEID1_EL0:
+    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):
+        if ( hsr.sysreg.read )
+            *x = 0;
+        /* else: write ignored */
+        break;
+
+    /* Write only, Write ignore registers: */
+    case HSR_SYSREG_OSLAR_EL1:
+        if ( hsr.sysreg.read )
+            goto bad_sysreg;
+        /* else: write ignored */
+        break;
     case HSR_SYSREG_CNTP_CTL_EL0:
     case HSR_SYSREG_CNTP_TVAL_EL0:
         if ( !vtimer_emulate(regs, hsr) )
@@ -1440,6 +1492,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
         }
         break;
     default:
+ bad_sysreg:
         {
             struct hsr_sysreg sysreg = hsr.sysreg;
 #ifndef NDEBUG
@@ -1614,6 +1667,12 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
             goto bad_trap;
         do_cp15_64(regs, hsr);
         break;
+    case HSR_EC_CP14_32:
+    case HSR_EC_CP14_DBG:
+        if ( !is_pv32_domain(current->domain) )
+            goto bad_trap;
+        do_cp14(regs, hsr);
+        break;
     case HSR_EC_CP:
         if ( !is_pv32_domain(current->domain) )
             goto bad_trap;
diff --git a/xen/include/asm-arm/cpregs.h b/xen/include/asm-arm/cpregs.h
index e9a8094..bf8133e 100644
--- a/xen/include/asm-arm/cpregs.h
+++ b/xen/include/asm-arm/cpregs.h
@@ -115,6 +115,7 @@
 #define NSACR           p15,0,c1,c1,2   /* Non-Secure Access Control Register */
 #define HSCTLR          p15,4,c1,c0,0   /* Hyp. System Control Register */
 #define HCR             p15,4,c1,c1,0   /* Hyp. Configuration Register */
+#define HDCR            p15,4,c1,c1,1   /* Hyp. Debug Configuration Register */
 #define HCPTR           p15,4,c1,c1,2   /* Hyp. Coprocessor Trap Register */
 #define HSTR            p15,4,c1,c1,3   /* Hyp. System Trap Register */
 
@@ -287,6 +288,7 @@
 #define ID_PFR0_EL1             ID_PFR0
 #define ID_PFR1_EL1             ID_PFR1
 #define IFSR32_EL2              IFSR
+#define MDCR_EL2                HDCR
 #define MIDR_EL1                MIDR
 #define MPIDR_EL1               MPIDR
 #define PAR_EL1                 PAR
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 750864a..9267c1b 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -92,12 +92,19 @@
 /* HSTR Hyp. System Trap Register */
 #define HSTR_T(x)       ((_AC(1,U)<<(x)))       /* Trap Cp15 c<x> */
 
+/* HDCR Hyp. Debug Configuration Register */
+#define HDCR_TDRA       (_AC(1,U)<<11)          /* Trap Debug ROM access */
+#define HDCR_TDOSA      (_AC(1,U)<<10)          /* Trap Debug-OS-related register access */
+#define HDCR_TDA        (_AC(1,U)<<9)           /* Trap Debug Access */
+#define HDCR_TPM        (_AC(1,U)<<6)           /* Trap Performance Monitors accesses */
+#define HDCR_TPMCR      (_AC(1,U)<<5)           /* Trap PMCR accesses */
+
 #define HSR_EC_UNKNOWN              0x00
 #define HSR_EC_WFI_WFE              0x01
 #define HSR_EC_CP15_32              0x03
 #define HSR_EC_CP15_64              0x04
-#define HSR_EC_CP14_32              0x05
-#define HSR_EC_CP14_DBG             0x06
+#define HSR_EC_CP14_32              0x05        /* Trapped MCR or MRC access to CP14 */
+#define HSR_EC_CP14_DBG             0x06        /* Trapped LDC/STC access to CP14 (only for debug registers) */
 #define HSR_EC_CP                   0x07        /* HCPTR-trapped access to CP0-CP13 */
 #define HSR_EC_CP10                 0x08
 #define HSR_EC_JAZELLE              0x09
diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
index 0cee0e9..4a4de34 100644
--- a/xen/include/asm-arm/sysregs.h
+++ b/xen/include/asm-arm/sysregs.h
@@ -40,6 +40,31 @@
     ((__HSR_SYSREG_##crm) << HSR_SYSREG_CRM_SHIFT) | \
     ((__HSR_SYSREG_##op2) << HSR_SYSREG_OP2_SHIFT)
 
+#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_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)
+#define HSR_SYSREG_DBGWVRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,6)
+#define HSR_SYSREG_DBGWCRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,7)
+
+#define HSR_SYSREG_DBG_CASES(REG) case HSR_SYSREG_##REG##n_EL1(0):  \
+                                  case HSR_SYSREG_##REG##n_EL1(1):  \
+                                  case HSR_SYSREG_##REG##n_EL1(2):  \
+                                  case HSR_SYSREG_##REG##n_EL1(3):  \
+                                  case HSR_SYSREG_##REG##n_EL1(4):  \
+                                  case HSR_SYSREG_##REG##n_EL1(5):  \
+                                  case HSR_SYSREG_##REG##n_EL1(6):  \
+                                  case HSR_SYSREG_##REG##n_EL1(7):  \
+                                  case HSR_SYSREG_##REG##n_EL1(8):  \
+                                  case HSR_SYSREG_##REG##n_EL1(9):  \
+                                  case HSR_SYSREG_##REG##n_EL1(10): \
+                                  case HSR_SYSREG_##REG##n_EL1(11): \
+                                  case HSR_SYSREG_##REG##n_EL1(12): \
+                                  case HSR_SYSREG_##REG##n_EL1(13): \
+                                  case HSR_SYSREG_##REG##n_EL1(14): \
+                                  case HSR_SYSREG_##REG##n_EL1(15)
+
 #define HSR_SYSREG_SCTLR_EL1      HSR_SYSREG(3,0,c1, c0,0)
 #define HSR_SYSREG_TTBR0_EL1      HSR_SYSREG(3,0,c2, c0,0)
 #define HSR_SYSREG_TTBR1_EL1      HSR_SYSREG(3,0,c2, c0,1)
@@ -48,10 +73,28 @@
 #define HSR_SYSREG_AFSR1_EL1      HSR_SYSREG(3,0,c5, c1,1)
 #define HSR_SYSREG_ESR_EL1        HSR_SYSREG(3,0,c5, c2,0)
 #define HSR_SYSREG_FAR_EL1        HSR_SYSREG(3,0,c6, c0,0)
+#define HSR_SYSREG_PMINTENSET_EL1 HSR_SYSREG(3,0,c9,c14,1)
+#define HSR_SYSREG_PMINTENCLR_EL1 HSR_SYSREG(3,0,c9,c14,2)
 #define HSR_SYSREG_MAIR_EL1       HSR_SYSREG(3,0,c10,c2,0)
 #define HSR_SYSREG_AMAIR_EL1      HSR_SYSREG(3,0,c10,c3,0)
 #define HSR_SYSREG_CONTEXTIDR_EL1 HSR_SYSREG(3,0,c13,c0,1)
 
+#define HSR_SYSREG_PMCR_EL0       HSR_SYSREG(3,3,c9,c12,0)
+#define HSR_SYSREG_PMCNTENSET_EL0 HSR_SYSREG(3,3,c9,c12,1)
+#define HSR_SYSREG_PMCNTENCLR_EL0 HSR_SYSREG(3,3,c9,c12,2)
+#define HSR_SYSREG_PMOVSCLR_EL0   HSR_SYSREG(3,3,c9,c12,3)
+#define HSR_SYSREG_PMSWINC_EL0    HSR_SYSREG(3,3,c9,c12,4)
+#define HSR_SYSREG_PMSELR_EL0     HSR_SYSREG(3,3,c9,c12,5)
+#define HSR_SYSREG_PMCEID0_EL0    HSR_SYSREG(3,3,c9,c12,6)
+#define HSR_SYSREG_PMCEID1_EL0    HSR_SYSREG(3,3,c9,c12,7)
+
+#define HSR_SYSREG_PMCCNTR_EL0    HSR_SYSREG(3,3,c9,c13,0)
+#define HSR_SYSREG_PMXEVTYPER_EL0 HSR_SYSREG(3,3,c9,c13,1)
+#define HSR_SYSREG_PMXEVCNTR_EL0  HSR_SYSREG(3,3,c9,c13,2)
+
+#define HSR_SYSREG_PMUSERENR_EL0  HSR_SYSREG(3,3,c9,c14,0)
+#define HSR_SYSREG_PMOVSSET_EL0   HSR_SYSREG(3,3,c9,c14,3)
+
 #define HSR_SYSREG_CNTPCT_EL0     HSR_SYSREG(3,3,c14,c0,0)
 #define HSR_SYSREG_CNTP_CTL_EL0   HSR_SYSREG(3,3,c14,c2,1)
 #define HSR_SYSREG_CNTP_TVAL_EL0  HSR_SYSREG(3,3,c14,c2,0)
-- 
1.7.10.4