[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH target-arm v1 6/9] target-arm: Implement PMSAv7 MPU
From: |
Peter Crosthwaite |
Subject: |
[Qemu-devel] [PATCH target-arm v1 6/9] target-arm: Implement PMSAv7 MPU |
Date: |
Mon, 1 Jun 2015 11:04:29 -0700 |
Unified MPU only. Uses ARM architecture major revision to switch
between PMSAv5 and v7 when ARM_FEATURE_MPU is set. PMSA v6 remains
unsupported and is asserted against.
The return code from get_phys_addr has to patched to handle the case
of a 0 FSR with error. Use -1 to indicate this condition.
Signed-off-by: Peter Crosthwaite <address@hidden>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 144 insertions(+), 10 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 9cb2e49..73e2619 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -559,6 +559,7 @@ void pmccntr_sync(CPUARMState *env);
#define SCTLR_DT (1U << 16) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWI (1U << 16) /* v8 onward */
#define SCTLR_HA (1U << 17)
+#define SCTLR_BR (1U << 17) /* PMSA only */
#define SCTLR_IT (1U << 18) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWE (1U << 18) /* v8 onward */
#define SCTLR_WXN (1U << 19)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 63859a4..09210d3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3323,13 +3323,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_one_arm_cp_reg(cpu, &rvbar);
}
if (arm_feature(env, ARM_FEATURE_MPU)) {
- /* These are the MPU registers prior to PMSAv6. Any new
- * PMSA core later than the ARM946 will require that we
- * implement the PMSAv6 or PMSAv7 registers, which are
- * completely different.
- */
- assert(!arm_feature(env, ARM_FEATURE_V6));
- define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ assert(arm_feature(env, ARM_FEATURE_V7));
+ define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
+ define_arm_cp_regs(cpu, pmsav7_cp_reginfo);
+ } else {
+ define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
+ }
} else {
define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
define_arm_cp_regs(cpu, vmsa_cp_reginfo);
@@ -5720,6 +5720,130 @@ do_fault:
return (1 << 9) | (fault_type << 2) | level;
}
+static inline void get_phys_addr_pmsav7_default(CPUARMState *env,
+ ARMMMUIdx mmu_idx,
+ int32_t address, int *prot)
+{
+ *prot = PAGE_READ | PAGE_WRITE;
+ switch (address) {
+ case 0xF0000000 ... 0xFFFFFFFF:
+ if (regime_sctlr(env, mmu_idx) & SCTLR_V) { /* hivecs execing is ok */
+ *prot |= PAGE_EXEC;
+ }
+ break;
+ case 0x00000000 ... 0x7FFFFFFF:
+ *prot |= PAGE_EXEC;
+ break;
+ }
+
+}
+
+static int get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
+ int access_type, ARMMMUIdx mmu_idx,
+ hwaddr *phys_ptr, int *prot)
+{
+ int n;
+ bool is_user = regime_is_user(env, mmu_idx);
+
+ *phys_ptr = address;
+ *prot = 0;
+
+ if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
+ get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
+ } else { /* MPU enabled */
+ for (n = 15; n >= 0; n--) { /* region search */
+ uint32_t base = env->cp15.c6_drbar[n];
+ uint32_t rsize = extract32(env->cp15.c6_drsr[n], 1, 5) + 1;
+ int snd;
+
+ if (!(env->cp15.c6_drsr[n] & 0x1)) {
+ continue;
+ }
+ if (rsize < 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "DRSR.Rsize field can not be
0");
+ }
+
+ if (address < base || address > base - 1 + (1ull << rsize)) {
+ continue;
+ }
+
+ if (rsize < 8) { /* no subregions for regions < 256 bytes */
+ break;
+ }
+
+ rsize -= 3; /* sub region size (power of 2) */
+ snd = (address - base) >> rsize & 0x7;
+ if (env->cp15.c6_drsr[n] & 1 << (snd + 8)) {
+ continue;
+ }
+ break;
+ }
+
+ if (n == -1) { /* no hits */
+ if (is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR)) {
+ /* background fault */
+ return -1;
+ } else {
+ get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
+ }
+ } else { /* a MPU hit! */
+ uint32_t ap = extract32(env->cp15.c6_dracr[n], 8, 3);
+
+ if (is_user) { /* User mode AP bit decoding */
+ switch (ap) {
+ case 0:
+ case 1:
+ case 5:
+ break; /* no access */
+ case 3:
+ *prot |= PAGE_WRITE;
+ /* fall through */
+ case 2:
+ case 6:
+ *prot |= PAGE_READ | PAGE_EXEC;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "Bad value for AP bits in "
+ "DRACR");
+ }
+ } else { /* Priv. mode AP bits decoding */
+ switch (ap) {
+ case 0:
+ break; /* no access */
+ case 1:
+ case 2:
+ case 3:
+ *prot |= PAGE_WRITE;
+ /* fall through */
+ case 5:
+ case 6:
+ *prot |= PAGE_READ | PAGE_EXEC;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "Bad value for AP bits in "
+ "DRACR");
+ }
+ }
+
+ /* execute never */
+ *prot &= env->cp15.c6_dracr[n] & 1 << 12 ? ~PAGE_EXEC : ~0;
+ }
+ }
+
+ switch (access_type) {
+ case 0:
+ return *prot & PAGE_READ ? 0 : 0x00D;
+ case 1:
+ return *prot & PAGE_WRITE ? 0 : 0x00D;
+ case 2:
+ return *prot & PAGE_EXEC ? 0 : 0x00D;
+ default:
+ abort(); /* should be unreachable */
+ return 0;
+ }
+
+}
+
static int get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot)
@@ -5795,13 +5919,14 @@ static int get_phys_addr_pmsav5(CPUARMState *env,
uint32_t address,
* MPU state on MPU based systems.
*
* Returns 0 if the translation was successful. Otherwise, phys_ptr, attrs,
- * prot and page_size may not be filled in, and the return value provides
+ * prot and page_size may or may-not be filled in, and the return value
provides
* information on why the translation aborted, in the format of a
* DFSR/IFSR fault register, with the following caveats:
* * we honour the short vs long DFSR format differences.
* * the WnR bit is never set (the caller must do this).
* * for MPU based systems we don't bother to return a full FSR format
* value.
+ * * -1 return value indicates a 0 FSR.
*
* @env: CPUARMState
* @address: virtual address to get physical address for
@@ -5857,8 +5982,14 @@ static inline int get_phys_addr(CPUARMState *env,
target_ulong address,
if (arm_feature(env, ARM_FEATURE_MPU)) {
*page_size = TARGET_PAGE_SIZE;
- return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
- phys_ptr, prot);
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ assert(arm_feature(env, ARM_FEATURE_V7));
+ return get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
+ phys_ptr, prot);
+ } else {
+ return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
+ phys_ptr, prot);
+ }
}
if (regime_using_lpae_format(env, mmu_idx)) {
@@ -5897,6 +6028,8 @@ int arm_tlb_fill(CPUState *cs, vaddr address,
tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
prot, mmu_idx, page_size);
return 0;
+ } else if (ret == -1) {
+ ret = 0;
}
return ret;
--
2.4.2.3.g2ffcb72
- Re: [Qemu-devel] [PATCH target-arm v1 3/9] target-arm/helper.c: define MPUIR register, (continued)
[Qemu-devel] [PATCH target-arm v1 4/9] target-arm: Add registers for PMSAv7, Peter Crosthwaite, 2015/06/01
[Qemu-devel] [PATCH target-arm v1 5/9] arm: helper: rename get_phys_addr_mpu, Peter Crosthwaite, 2015/06/01
[Qemu-devel] [PATCH target-arm v1 6/9] target-arm: Implement PMSAv7 MPU,
Peter Crosthwaite <=
[Qemu-devel] [PATCH target-arm v1 7/9] arm: r5: Implement dummy ATCM, BTCM and D-cache invalidate, Peter Crosthwaite, 2015/06/01
[Qemu-devel] [PATCH target-arm v1 8/9] arm: xlnx-zynqmp: Preface CPU variables with "A", Peter Crosthwaite, 2015/06/01