Patchwork [07/15] target-arm: Implement privileged-execute-never (PXN)

login
register
mail settings
Submitter Peter Maydell
Date July 12, 2012, 1:36 p.m.
Message ID <1342100216-1832-8-git-send-email-peter.maydell@linaro.org>
Download mbox | patch
Permalink /patch/170660/
State New
Headers show

Comments

Peter Maydell - July 12, 2012, 1:36 p.m.
Implement the privileged-execute-never (PXN) translation table bit.
It is implementation-defined whether this is implemented, so we give
it its own ARM_FEATURE_ flag. LPAE requires PXN, so add also an
LPAE feature flag and the implication logic, as a placeholder
for actually implementing LPAE at a later date.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.c    |    4 ++++
 target-arm/cpu.h    |    2 ++
 target-arm/helper.c |   32 ++++++++++++++++++++------------
 3 files changed, 26 insertions(+), 12 deletions(-)

Patch

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index ae57953..526e725 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -192,6 +192,9 @@  void arm_cpu_realize(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_VFP3)) {
         set_feature(env, ARM_FEATURE_VFP);
     }
+    if (arm_feature(env, ARM_FEATURE_LPAE)) {
+        set_feature(env, ARM_FEATURE_PXN);
+    }
 
     register_cp_regs_for_features(cpu);
 }
@@ -532,6 +535,7 @@  static void cortex_a15_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V7MP);
     set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
     set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_feature(&cpu->env, ARM_FEATURE_LPAE);
     cpu->midr = 0x412fc0f1;
     cpu->reset_fpsid = 0x410430f0;
     cpu->mvfr0 = 0x10110222;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index aadfca0..82cad4b 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -386,6 +386,8 @@  enum arm_features {
     ARM_FEATURE_CACHE_DIRTY_REG, /* 1136/1176 cache dirty status register */
     ARM_FEATURE_CACHE_BLOCK_OPS, /* v6 optional cache block operations */
     ARM_FEATURE_MPIDR, /* has cp15 MPIDR */
+    ARM_FEATURE_PXN, /* has Privileged Execute Never bit */
+    ARM_FEATURE_LPAE, /* has Large Physical Address Extension */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 0015bee..e51b038 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1935,9 +1935,10 @@  static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
     uint32_t table;
     uint32_t desc;
     uint32_t xn;
+    uint32_t pxn = 0;
     int type;
     int ap;
-    int domain;
+    int domain = 0;
     int domain_prot;
     uint32_t phys_addr;
 
@@ -1946,27 +1947,27 @@  static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
     table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
-    if (type == 0) {
-        /* Section translation fault.  */
+    if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) {
+        /* Section translation fault, or attempt to use the encoding
+         * which is Reserved on implementations without PXN.
+         */
         code = 5;
-        domain = 0;
         goto do_fault;
-    } else if (type == 2 && (desc & (1 << 18))) {
-        /* Supersection.  */
-        domain = 0;
-    } else {
-        /* Section or page.  */
+    }
+    if ((type == 1) || !(desc & (1 << 18))) {
+        /* Page or Section.  */
         domain = (desc >> 5) & 0x0f;
     }
     domain_prot = (env->cp15.c3 >> (domain * 2)) & 3;
     if (domain_prot == 0 || domain_prot == 2) {
-        if (type == 2)
+        if (type != 1) {
             code = 9; /* Section domain fault.  */
-        else
+        } else {
             code = 11; /* Page domain fault.  */
+        }
         goto do_fault;
     }
-    if (type == 2) {
+    if (type != 1) {
         if (desc & (1 << 18)) {
             /* Supersection.  */
             phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
@@ -1978,8 +1979,12 @@  static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
         }
         ap = ((desc >> 10) & 3) | ((desc >> 13) & 4);
         xn = desc & (1 << 4);
+        pxn = desc & 1;
         code = 13;
     } else {
+        if (arm_feature(env, ARM_FEATURE_PXN)) {
+            pxn = (desc >> 2) & 1;
+        }
         /* Lookup l2 entry.  */
         table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
         desc = ldl_phys(table);
@@ -2007,6 +2012,9 @@  static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
     if (domain_prot == 3) {
         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
     } else {
+        if (pxn && !is_user) {
+            xn = 1;
+        }
         if (xn && access_type == 2)
             goto do_fault;