aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2012-07-12 10:59:05 +0000
committerPeter Maydell <peter.maydell@linaro.org>2012-07-12 10:59:54 +0000
commitde9b05b807918d40db9e26ddd6a54ad2978ac5b7 (patch)
treec9518ecd83f855a85dc9ae6099ca0ffa65379512
parent3cc0cd61f4adfecf2c0de392fe61a7e323e496ba (diff)
target-arm: Implement privileged-execute-never (PXN)
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>
-rw-r--r--target-arm/cpu.c4
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c32
3 files changed, 26 insertions, 12 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index ae5795337f..526e7254f2 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 aadfca0a26..82cad4b975 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 0015bee977..e51b038944 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;