[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 16/30] target-arm: Split cpreg access checks out from
From: |
Peter Maydell |
Subject: |
[Qemu-devel] [PULL 16/30] target-arm: Split cpreg access checks out from read/write functions |
Date: |
Thu, 20 Feb 2014 11:17:20 +0000 |
Several of the system registers handled via the ARMCPRegInfo
mechanism have access trap control bits controlling whether the
registers are accessible to lower privilege levels. Replace
the existing mechanism (allowing the read and write functions
to return EXCP_UDEF if access is denied) with a dedicated
"check access rights" function pointer in the ARMCPRegInfo.
This will allow us to simplify some of the register definitions,
which no longer need read/write functions purely to handle
the access checks.
We take the opportunity to define the return value from the
access checking function in a way that allows us to set the
correct exception syndrome information for exceptions taken
to AArch64 (which may need to distinguish access failures due
to a configurable trap or enable from other kinds of access
failure).
This commit defines the new mechanism but does not move any
of the registers across to use it.
Signed-off-by: Peter Maydell <address@hidden>
Reviewed-by: Peter Crosthwaite <address@hidden>
---
target-arm/cpu.h | 29 +++++++++++++++++++++++++----
target-arm/helper.h | 1 +
target-arm/op_helper.c | 18 ++++++++++++++++++
target-arm/translate-a64.c | 11 +++++++++++
target-arm/translate.c | 11 +++++++++++
5 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ab57f55..cc3d0ac 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -811,14 +811,29 @@ static inline int arm_current_pl(CPUARMState *env)
typedef struct ARMCPRegInfo ARMCPRegInfo;
-/* Access functions for coprocessor registers. These should return
- * 0 on success, or one of the EXCP_* constants if access should cause
- * an exception (in which case *value is not written).
- */
+typedef enum CPAccessResult {
+ /* Access is permitted */
+ CP_ACCESS_OK = 0,
+ /* Access fails due to a configurable trap or enable which would
+ * result in a categorized exception syndrome giving information about
+ * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
+ * 0xc or 0x18).
+ */
+ CP_ACCESS_TRAP = 1,
+ /* Access fails and results in an exception syndrome 0x0 ("uncategorized").
+ * Note that this is not a catch-all case -- the set of cases which may
+ * result in this failure is specifically defined by the architecture.
+ */
+ CP_ACCESS_TRAP_UNCATEGORIZED = 2,
+} CPAccessResult;
+
+/* Access functions for coprocessor registers. These should always succeed. */
typedef int CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t *value);
typedef int CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t value);
+/* Access permission check functions for coprocessor registers. */
+typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo
*opaque);
/* Hook function for register reset */
typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
@@ -872,6 +887,12 @@ struct ARMCPRegInfo {
* 2. both readfn and writefn are specified
*/
ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
+ /* Function for making any access checks for this register in addition to
+ * those specified by the 'access' permissions bits. If NULL, no extra
+ * checks required. The access check is performed at runtime, not at
+ * translate time.
+ */
+ CPAccessFn *accessfn;
/* Function for handling reads of this register. If NULL, then reads
* will be done by loading from the offset into CPUARMState specified
* by fieldoffset.
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 7c60121..19bd620 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -57,6 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
DEF_HELPER_2(v7m_mrs, i32, env, i32)
+DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a918e5b..34c5e7f 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -273,6 +273,24 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t
regno, uint32_t val)
}
}
+void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
+{
+ const ARMCPRegInfo *ri = rip;
+ switch (ri->accessfn(env, ri)) {
+ case CP_ACCESS_OK:
+ return;
+ case CP_ACCESS_TRAP:
+ case CP_ACCESS_TRAP_UNCATEGORIZED:
+ /* These cases will eventually need to generate different
+ * syndrome information.
+ */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ raise_exception(env, EXCP_UDEF);
+}
+
void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
{
const ARMCPRegInfo *ri = rip;
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index f6500e5..e70d14f 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1193,6 +1193,17 @@ static void handle_sys(DisasContext *s, uint32_t insn,
bool isread,
return;
}
+ if (ri->accessfn) {
+ /* Emit code to perform further access permissions checks at
+ * runtime; this may result in an exception.
+ */
+ TCGv_ptr tmpptr;
+ gen_a64_set_pc_im(s->pc - 4);
+ tmpptr = tcg_const_ptr(ri);
+ gen_helper_access_check_cp_reg(cpu_env, tmpptr);
+ tcg_temp_free_ptr(tmpptr);
+ }
+
/* Handle special cases first */
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
case ARM_CP_NOP:
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6d822c6..0805053 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6837,6 +6837,17 @@ static int disas_coproc_insn(CPUARMState * env,
DisasContext *s, uint32_t insn)
return 1;
}
+ if (ri->accessfn) {
+ /* Emit code to perform further access permissions checks at
+ * runtime; this may result in an exception.
+ */
+ TCGv_ptr tmpptr;
+ gen_set_pc_im(s, s->pc);
+ tmpptr = tcg_const_ptr(ri);
+ gen_helper_access_check_cp_reg(cpu_env, tmpptr);
+ tcg_temp_free_ptr(tmpptr);
+ }
+
/* Handle special cases first */
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
case ARM_CP_NOP:
--
1.8.5
- [Qemu-devel] [PULL 00/30] target-arm queue, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 10/30] target-arm/kvm-consts.h: Define QEMU constants for known KVM CPUs, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 09/30] target-arm: A64: Implement remaining 3-same instructions, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 16/30] target-arm: Split cpreg access checks out from read/write functions,
Peter Maydell <=
- [Qemu-devel] [PULL 30/30] linux-user: AArch64: Fix exclusive store of the zero register, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 29/30] target-arm: A64: Implement unprivileged load/store, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 28/30] target-arm: A64: Implement narrowing three-reg-diff operations, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 27/30] target-arm: A64: Implement the wide 3-reg-different operations, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 07/30] target-arm: A64: Implement floating point pairwise insns, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 26/30] target-arm: A64: Add most remaining three-reg-diff widening ops, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 25/30] target-arm: A64: Add opcode comments to disas_simd_three_reg_diff, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 24/30] target-arm: A64: Implement store-exclusive for system mode, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 23/30] target-arm: Fix incorrect type for value argument to write_raw_cp_reg, Peter Maydell, 2014/02/20
- [Qemu-devel] [PULL 22/30] target-arm: Remove failure status return from read/write_raw_cp_reg, Peter Maydell, 2014/02/20