#define ARM_CPU_VIRQ 2
#define ARM_CPU_VFIQ 3
-#define NB_MMU_MODES 7
+#define NB_MMU_MODES 8
/* ARM-specific extra insn start words:
* 1: Conditional execution bits
* 2: Partial exception syndrome for data aborts
uint32_t cfsr[M_REG_NUM_BANKS]; /* Configurable Fault Status */
uint32_t hfsr; /* HardFault Status */
uint32_t dfsr; /* Debug Fault Status Register */
+ uint32_t sfsr; /* Secure Fault Status Register */
uint32_t mmfar[M_REG_NUM_BANKS]; /* MemManage Fault Address */
uint32_t bfar; /* BusFault Address */
+ uint32_t sfar; /* Secure Fault Address Register */
unsigned mpu_ctrl[M_REG_NUM_BANKS]; /* MPU_CTRL */
int exception;
uint32_t primask[M_REG_NUM_BANKS];
uint32_t faultmask[M_REG_NUM_BANKS];
+ uint32_t aircr; /* only holds r/w state if security extn implemented */
uint32_t secure; /* Is CPU in Secure state? (not guest visible) */
} v7m;
uint32_t mair1[M_REG_NUM_BANKS];
} pmsav8;
+ /* v8M SAU */
+ struct {
+ uint32_t *rbar;
+ uint32_t *rlar;
+ uint32_t rnr;
+ uint32_t ctrl;
+ } sau;
+
void *nvic;
const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */
bool has_mpu;
/* PMSAv7 MPU number of supported regions */
uint32_t pmsav7_dregion;
+ /* v8M SAU number of supported regions */
+ uint32_t sau_sregion;
/* PSCI conduit used to invoke PSCI methods
* 0 - disabled, 1 - smc, 2 - hvc
#define PSTATE_MODE_EL1t 4
#define PSTATE_MODE_EL0t 0
+/* Write a new value to v7m.exception, thus transitioning into or out
+ * of Handler mode; this may result in a change of active stack pointer.
+ */
+void write_v7m_exception(CPUARMState *env, uint32_t new_exc);
+
/* Map EL and handler into a PSTATE_MODE. */
static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
{
env->condexec_bits |= (val >> 8) & 0xfc;
}
if (mask & XPSR_EXCP) {
- env->v7m.exception = val & XPSR_EXCP;
+ /* Note that this only happens on exception exit */
+ write_v7m_exception(env, val & XPSR_EXCP);
}
}
FIELD(V7M_CCR, DC, 16, 1)
FIELD(V7M_CCR, IC, 17, 1)
+/* V7M AIRCR bits */
+FIELD(V7M_AIRCR, VECTRESET, 0, 1)
+FIELD(V7M_AIRCR, VECTCLRACTIVE, 1, 1)
+FIELD(V7M_AIRCR, SYSRESETREQ, 2, 1)
+FIELD(V7M_AIRCR, SYSRESETREQS, 3, 1)
+FIELD(V7M_AIRCR, PRIGROUP, 8, 3)
+FIELD(V7M_AIRCR, BFHFNMINS, 13, 1)
+FIELD(V7M_AIRCR, PRIS, 14, 1)
+FIELD(V7M_AIRCR, ENDIANNESS, 15, 1)
+FIELD(V7M_AIRCR, VECTKEY, 16, 16)
+
/* V7M CFSR bits for MMFSR */
FIELD(V7M_CFSR, IACCVIOL, 0, 1)
FIELD(V7M_CFSR, DACCVIOL, 1, 1)
FIELD(V7M_DFSR, VCATCH, 3, 1)
FIELD(V7M_DFSR, EXTERNAL, 4, 1)
+/* V7M SFSR bits */
+FIELD(V7M_SFSR, INVEP, 0, 1)
+FIELD(V7M_SFSR, INVIS, 1, 1)
+FIELD(V7M_SFSR, INVER, 2, 1)
+FIELD(V7M_SFSR, AUVIOL, 3, 1)
+FIELD(V7M_SFSR, INVTRAN, 4, 1)
+FIELD(V7M_SFSR, LSPERR, 5, 1)
+FIELD(V7M_SFSR, SFARVALID, 6, 1)
+FIELD(V7M_SFSR, LSERR, 7, 1)
+
/* v7M MPU_CTRL bits */
FIELD(V7M_MPU_CTRL, ENABLE, 0, 1)
FIELD(V7M_MPU_CTRL, HFNMIENA, 1, 1)
return true;
}
#endif
-void armv7m_nvic_set_pending(void *opaque, int irq);
-void armv7m_nvic_acknowledge_irq(void *opaque);
+/**
+ * armv7m_nvic_set_pending: mark the specified exception as pending
+ * @opaque: the NVIC
+ * @irq: the exception number to mark pending
+ * @secure: false for non-banked exceptions or for the nonsecure
+ * version of a banked exception, true for the secure version of a banked
+ * exception.
+ *
+ * Marks the specified exception as pending. Note that we will assert()
+ * if @secure is true and @irq does not specify one of the fixed set
+ * of architecturally banked exceptions.
+ */
+void armv7m_nvic_set_pending(void *opaque, int irq, bool secure);
+/**
+ * armv7m_nvic_acknowledge_irq: make highest priority pending exception active
+ * @opaque: the NVIC
+ *
+ * Move the current highest priority pending exception from the pending
+ * state to the active state, and update v7m.exception to indicate that
+ * it is the exception currently being handled.
+ *
+ * Returns: true if exception should be taken to Secure state, false for NS
+ */
+bool armv7m_nvic_acknowledge_irq(void *opaque);
/**
* armv7m_nvic_complete_irq: complete specified interrupt or exception
* @opaque: the NVIC
* @irq: the exception number to complete
+ * @secure: true if this exception was secure
*
* Returns: -1 if the irq was not active
* 1 if completing this irq brought us back to base (no active irqs)
* 0 if there is still an irq active after this one was completed
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
*/
-int armv7m_nvic_complete_irq(void *opaque, int irq);
+int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure);
/**
* armv7m_nvic_raw_execution_priority: return the raw execution priority
* @opaque: the NVIC
* (v8M ARM ARM I_PKLD.)
*/
int armv7m_nvic_raw_execution_priority(void *opaque);
+/**
+ * armv7m_nvic_neg_prio_requested: return true if the requested execution
+ * priority is negative for the specified security state.
+ * @opaque: the NVIC
+ * @secure: the security state to test
+ * This corresponds to the pseudocode IsReqExecPriNeg().
+ */
+#ifndef CONFIG_USER_ONLY
+bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure);
+#else
+static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
+{
+ return false;
+}
+#endif
/* Interface for defining coprocessor registers.
* Registers are defined in tables of arm_cp_reginfo structs
#define cpu_init(cpu_model) cpu_generic_init(TYPE_ARM_CPU, cpu_model)
+#define ARM_CPU_TYPE_SUFFIX "-" TYPE_ARM_CPU
+#define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
+
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
* They have the following different MMU indexes:
* User
* Privileged
- * Execution priority negative (this is like privileged, but the
- * MPU HFNMIENA bit means that it may have different access permission
- * check results to normal privileged code, so can't share a TLB).
+ * User, execution priority negative (ie the MPU HFNMIENA bit may apply)
+ * Privileged, execution priority negative (ditto)
* If the CPU supports the v8M Security Extension then there are also:
* Secure User
* Secure Privileged
- * Secure, execution priority negative
+ * Secure User, execution priority negative
+ * Secure Privileged, execution priority negative
*
* The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
* are not quite the same -- different CPU types (most notably M profile
* The constant names here are patterned after the general style of the names
* of the AT/ATS operations.
* The values used are carefully arranged to make mmu_idx => EL lookup easy.
+ * For M profile we arrange them to have a bit for priv, a bit for negpri
+ * and a bit for secure.
*/
#define ARM_MMU_IDX_A 0x10 /* A profile */
#define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */
#define ARM_MMU_IDX_M 0x40 /* M profile */
+/* meanings of the bits for M profile mmu idx values */
+#define ARM_MMU_IDX_M_PRIV 0x1
+#define ARM_MMU_IDX_M_NEGPRI 0x2
+#define ARM_MMU_IDX_M_S 0x4
+
#define ARM_MMU_IDX_TYPE_MASK (~0x7)
#define ARM_MMU_IDX_COREIDX_MASK 0x7
ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A,
ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M,
ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
- ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M,
- ARMMMUIdx_MSUser = 3 | ARM_MMU_IDX_M,
- ARMMMUIdx_MSPriv = 4 | ARM_MMU_IDX_M,
- ARMMMUIdx_MSNegPri = 5 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MUserNegPri = 2 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MPrivNegPri = 3 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MSUser = 4 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MSPriv = 5 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MSUserNegPri = 6 | ARM_MMU_IDX_M,
+ ARMMMUIdx_MSPrivNegPri = 7 | ARM_MMU_IDX_M,
/* Indexes below here don't have TLBs and are used only for AT system
* instructions or for the first stage of an S12 page table walk.
*/
ARMMMUIdxBit_S2NS = 1 << 6,
ARMMMUIdxBit_MUser = 1 << 0,
ARMMMUIdxBit_MPriv = 1 << 1,
- ARMMMUIdxBit_MNegPri = 1 << 2,
- ARMMMUIdxBit_MSUser = 1 << 3,
- ARMMMUIdxBit_MSPriv = 1 << 4,
- ARMMMUIdxBit_MSNegPri = 1 << 5,
+ ARMMMUIdxBit_MUserNegPri = 1 << 2,
+ ARMMMUIdxBit_MPrivNegPri = 1 << 3,
+ ARMMMUIdxBit_MSUser = 1 << 4,
+ ARMMMUIdxBit_MSPriv = 1 << 5,
+ ARMMMUIdxBit_MSUserNegPri = 1 << 6,
+ ARMMMUIdxBit_MSPrivNegPri = 1 << 7,
} ARMMMUIdxBit;
#define MMU_USER_IDX 0
case ARM_MMU_IDX_A:
return mmu_idx & 3;
case ARM_MMU_IDX_M:
- return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser)
- ? 0 : 1;
+ return mmu_idx & ARM_MMU_IDX_M_PRIV;
default:
g_assert_not_reached();
}
}
+/* Return the MMU index for a v7M CPU in the specified security and
+ * privilege state
+ */
+static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
+ bool secstate,
+ bool priv)
+{
+ ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
+
+ if (priv) {
+ mmu_idx |= ARM_MMU_IDX_M_PRIV;
+ }
+
+ if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
+ mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
+ }
+
+ if (secstate) {
+ mmu_idx |= ARM_MMU_IDX_M_S;
+ }
+
+ return mmu_idx;
+}
+
+/* Return the MMU index for a v7M CPU in the specified security state */
+static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env,
+ bool secstate)
+{
+ bool priv = arm_current_el(env) != 0;
+
+ return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
+}
+
/* Determine the current mmu_idx to use for normal loads/stores */
static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
{
int el = arm_current_el(env);
if (arm_feature(env, ARM_FEATURE_M)) {
- ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
-
- /* Execution priority is negative if FAULTMASK is set or
- * we're in a HardFault or NMI handler.
- */
- if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
- || env->v7m.faultmask[env->v7m.secure]) {
- mmu_idx = ARMMMUIdx_MNegPri;
- }
-
- if (env->v7m.secure) {
- mmu_idx += ARMMMUIdx_MSUser;
- }
+ ARMMMUIdx mmu_idx = arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
return arm_to_core_mmu_idx(mmu_idx);
}