* [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
@ 2014-05-13 16:15 Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
` (23 more replies)
0 siblings, 24 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Fabian Aggeler, peter.maydell
Hi,
This is a rework of the Samsung patches sent last year to add Security
Extensions. The patches have been changed based on the discussion on
the mailing list. Other changes became necessary because of Aarch64
support which got added in the meantime. This patchset makes it possible
to run a kernel in the secure world and then switch to non-secure
on CPUs that implement Security Extensions. It works for EL3 in Aarch32
state, but may add _EL3 registers where necessary to reflect the mapping
of secure instances of cp registers to _EL3 registers.
Banking of cp registers has been changed from active mass-swapping to
the mechanism discussed on the mailing list, where every Aarch32 cp
register goes into the hashtable twice. A ns-bit is added to the key
of the register which is used when accessing a cp register to get the
correct instance.
Magic numbers have been changed to bitshifted constants or macros to make
the code easier to read.
The whole patchset now uses the term Security Extensions instead of
TrustZone as this is the term which is used in the ARM ARM.
I am happy for any feedback, especially for the banking of course. It should
not be too hard to combine these changes with the recent effort towards EL3
in A64.
Thanks,
Fabian
Fabian Aggeler (12):
target-arm: add arm_is_secure() function
target-arm: add NSACR support
target-arm: Split TLB for secure state and EL3 in Aarch64
target-arm: add banked coprocessor register type and macros
target-arm: Restrict EL3 to Aarch32 state
target-arm: Use arm_current_sctlr to access SCTLR
target-arm: Use raw_write/raw_read whenever possible
target-arm: Convert banked coprocessor registers
target-arm: maintain common bits of banked CP registers
target-arm: add MVBAR support
target-arm: implement IRQ/FIQ routing to Monitor mode
target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI
Sergey Fedorov (8):
target-arm: move SCR into Security Extensions register list
target-arm: adjust TTBCR for Security Extension feature
target-arm: reject switching to monitor mode from non-secure state
target-arm: adjust arm_current_pl() for Security Extensions
target-arm: add non-secure Translation Block flag
target-arm: implement CPACR register logic
target-arm: add SDER definition
target-arm: implement SMC instruction
Svetlana Fedoseeva (3):
target-arm: add new CPU feature for Security Extensions
target-arm: preserve RAO/WI bits of ARMv7 SCTLR
target-arm: add CPU Monitor mode
hw/arm/pxa2xx.c | 2 +-
linux-user/main.c | 2 +-
target-arm/cpu-qom.h | 1 +
target-arm/cpu.c | 8 +-
target-arm/cpu.h | 271 ++++++++++++++++++++++---
target-arm/helper-a64.c | 3 +-
target-arm/helper.c | 489 ++++++++++++++++++++++++++++++++++++---------
target-arm/machine.c | 6 +-
target-arm/op_helper.c | 2 +-
target-arm/translate-a64.c | 9 +-
target-arm/translate.c | 342 ++++++++++++++++++-------------
target-arm/translate.h | 4 +
12 files changed, 866 insertions(+), 273 deletions(-)
--
1.8.3.2
^ permalink raw reply [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-21 14:46 ` Peter Maydell
2014-05-21 14:51 ` Peter Maydell
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list Fabian Aggeler
` (22 subsequent siblings)
23 siblings, 2 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel
Cc: edgar.iglesias, Sergey Fedorov, Svetlana Fedoseeva,
Fabian Aggeler, peter.maydell
From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Define Security Extensions CPU feature. Set that feature for relevant CPUs.
Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.c | 4 ++++
target-arm/cpu.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index c0ddc3e..b0d4a9b 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -527,6 +527,7 @@ static void arm1176_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
+ set_feature(&cpu->env, ARM_FEATURE_SECURITY_EXTENSIONS);
cpu->midr = 0x410fb767;
cpu->reset_fpsid = 0x410120b5;
cpu->mvfr0 = 0x11111111;
@@ -613,6 +614,7 @@ static void cortex_a8_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+ set_feature(&cpu->env, ARM_FEATURE_SECURITY_EXTENSIONS);
cpu->midr = 0x410fc080;
cpu->reset_fpsid = 0x410330c0;
cpu->mvfr0 = 0x11110222;
@@ -679,6 +681,7 @@ static void cortex_a9_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_SECURITY_EXTENSIONS);
/* Note that A9 supports the MP extensions even for
* A9UP and single-core A9MP (which are both different
* and valid configurations; we don't model A9UP).
@@ -746,6 +749,7 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
set_feature(&cpu->env, ARM_FEATURE_LPAE);
+ set_feature(&cpu->env, ARM_FEATURE_SECURITY_EXTENSIONS);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
cpu->midr = 0x412fc0f1;
cpu->reset_fpsid = 0x410430f0;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c83f249..5eba825 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -631,6 +631,7 @@ enum arm_features {
ARM_FEATURE_CBAR, /* has cp15 CBAR */
ARM_FEATURE_CRC, /* ARMv8 CRC instructions */
ARM_FEATURE_CBAR_RO, /* has cp15 CBAR and it is read-only */
+ ARM_FEATURE_SECURITY_EXTENSIONS, /* has Security Extensions */
};
static inline int arm_feature(CPUARMState *env, int feature)
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 14:19 ` Greg Bellows
2014-05-21 14:57 ` Peter Maydell
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature Fabian Aggeler
` (21 subsequent siblings)
23 siblings, 2 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
Define a new ARM CP register info list for the Security Extension feature.
Register that list only for ARM cores with Security Extension support.
Moving SCR into Security Extension register group.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3be917c..7898f40 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -768,9 +768,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.access = PL1_RW, .writefn = vbar_write,
.fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
.resetvalue = 0 },
- { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
@@ -2087,6 +2084,15 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush(CPU(cpu), 1);
}
+static const ARMCPRegInfo tz_cp_reginfo[] = {
+#ifndef CONFIG_USER_ONLY
+ { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
+ .resetvalue = 0, },
+#endif
+ REGINFO_SENTINEL
+};
+
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
@@ -2364,6 +2370,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_LPAE)) {
define_arm_cp_regs(cpu, lpae_cp_reginfo);
}
+ if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
+ define_arm_cp_regs(cpu, tz_cp_reginfo);
+ }
/* Slightly awkwardly, the OMAP and StrongARM cores need all of
* cp15 crn=0 to be writes-ignored, whereas for other cores they should
* be read-only (ie write causes UNDEF exception).
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-21 16:06 ` Peter Maydell
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR Fabian Aggeler
` (20 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
TTBCR has additional fields PD0 and PD1 when using Short-descriptor
translation table format on a CPU with Security Extension support.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 7898f40..9c3269f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1388,6 +1388,11 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
if (arm_feature(env, ARM_FEATURE_LPAE) && (value & (1 << 31))) {
value &= ~((7 << 19) | (3 << 14) | (0xf << 3));
+ } else if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
+ /* In an implementation that includes the Security Extensions
+ * TTBCR has additional fields PD0 [4] and PD1 [5].
+ */
+ value &= (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
} else {
value &= 7;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (2 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 5:43 ` Sergey Fedorov
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 05/23] target-arm: add CPU Monitor mode Fabian Aggeler
` (19 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel
Cc: edgar.iglesias, Sergey Fedorov, Svetlana Fedoseeva,
Fabian Aggeler, peter.maydell
From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9c3269f..2b57ad9 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2083,6 +2083,11 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
ARMCPU *cpu = arm_env_get_cpu(env);
+ if (arm_feature(env, ARM_FEATURE_V7)) {
+ value |= SCTLR_XP | SCTLR_U | SCTLR_nTWE | SCTLR_nTWI | SCTLR_L
+ | SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
+ }
+
env->cp15.c1_sys = value;
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 05/23] target-arm: add CPU Monitor mode
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (3 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function Fabian Aggeler
` (18 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel
Cc: edgar.iglesias, Sergey Fedorov, Svetlana Fedoseeva,
Fabian Aggeler, peter.maydell
From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Define CPU monitor mode. Adjust core registers banking. Adjust CPU VM
state info. Provide CPU mode name for monitor mode.
Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 7 ++++---
target-arm/helper.c | 2 ++
target-arm/machine.c | 6 +++---
target-arm/translate.c | 2 +-
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 5eba825..a56d3d6 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -143,9 +143,9 @@ typedef struct CPUARMState {
uint32_t spsr;
/* Banked registers. */
- uint64_t banked_spsr[6];
- uint32_t banked_r13[6];
- uint32_t banked_r14[6];
+ uint64_t banked_spsr[7];
+ uint32_t banked_r13[7];
+ uint32_t banked_r14[7];
/* These hold r8-r12. */
uint32_t usr_regs[5];
@@ -563,6 +563,7 @@ enum arm_cpu_mode {
ARM_CPU_MODE_FIQ = 0x11,
ARM_CPU_MODE_IRQ = 0x12,
ARM_CPU_MODE_SVC = 0x13,
+ ARM_CPU_MODE_MON = 0x16,
ARM_CPU_MODE_ABT = 0x17,
ARM_CPU_MODE_UND = 0x1b,
ARM_CPU_MODE_SYS = 0x1f
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2b57ad9..c1388eb 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3095,6 +3095,8 @@ int bank_number(int mode)
return 4;
case ARM_CPU_MODE_FIQ:
return 5;
+ case ARM_CPU_MODE_MON:
+ return 6;
}
hw_error("bank number requested for bad CPSR mode value 0x%x\n", mode);
}
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 810ba27..6c4f7b7 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -238,9 +238,9 @@ const VMStateDescription vmstate_arm_cpu = {
.offset = 0,
},
VMSTATE_UINT32(env.spsr, ARMCPU),
- VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
- VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
- VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
+ VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 7),
+ VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 7),
+ VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 7),
VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
VMSTATE_UINT64(env.elr_el1, ARMCPU),
diff --git a/target-arm/translate.c b/target-arm/translate.c
index a4d920b..46553fa 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -11047,7 +11047,7 @@ void gen_intermediate_code_pc(CPUARMState *env, TranslationBlock *tb)
}
static const char *cpu_mode_names[16] = {
- "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
+ "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
"???", "???", "???", "und", "???", "???", "???", "sys"
};
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (4 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 05/23] target-arm: add CPU Monitor mode Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 5:53 ` Sergey Fedorov
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 07/23] target-arm: reject switching to monitor mode from non-secure state Fabian Aggeler
` (17 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
arm_is_secure() function allows to determine CPU security state
if the CPU implements Security Extensions.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a56d3d6..6ea0432 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -640,6 +640,21 @@ static inline int arm_feature(CPUARMState *env, int feature)
return (env->features & (1ULL << feature)) != 0;
}
+/* Return true if the processor is in secure state */
+static inline bool arm_is_secure(CPUARMState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
+ return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
+ !(env->cp15.c1_scr & 1);
+ } else {
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
/* Return true if the specified exception level is running in AArch64 state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 07/23] target-arm: reject switching to monitor mode from non-secure state
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (5 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 08/23] target-arm: adjust arm_current_pl() for Security Extensions Fabian Aggeler
` (16 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index c1388eb..cf1f88c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2903,6 +2903,8 @@ static int bad_mode_switch(CPUARMState *env, int mode)
case ARM_CPU_MODE_IRQ:
case ARM_CPU_MODE_FIQ:
return 0;
+ case ARM_CPU_MODE_MON:
+ return !arm_is_secure(env);
default:
return 1;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 08/23] target-arm: adjust arm_current_pl() for Security Extensions
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (6 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 07/23] target-arm: reject switching to monitor mode from non-secure state Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 09/23] target-arm: add non-secure Translation Block flag Fabian Aggeler
` (15 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
Make arm_current_pl() return PL3 for secure PL1 and monitor mode.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 6ea0432..717b2e7 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -853,9 +853,12 @@ static inline int arm_current_pl(CPUARMState *env)
if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR) {
return 0;
+ } else if (arm_is_secure(env)) {
+ /* Secure PL1 and monitor mode are mapped to PL3 */
+ return 3;
}
- /* We don't currently implement the Virtualization or TrustZone
- * extensions, so PL2 and PL3 don't exist for us.
+ /* We currently do not implement the Virtualization extensions, so PL2 does
+ * not exist for us.
*/
return 1;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 09/23] target-arm: add non-secure Translation Block flag
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (7 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 08/23] target-arm: adjust arm_current_pl() for Security Extensions Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic Fabian Aggeler
` (14 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
This patch is based on idea found in patch at
git://github.com/jowinter/qemu-trustzone.git
f3d955c6c0ed8c46bc0eb10b634201032a651dd2 by
Johannes Winter <johannes.winter@iaik.tugraz.at>.
This flag prevents from executing TCG code generated for other CPU
secure state. It also allows to generate different TCG code depending on
CPU secure state.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 7 +++++++
target-arm/translate.c | 3 +++
target-arm/translate.h | 1 +
3 files changed, 11 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 717b2e7..f86a101 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1133,6 +1133,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
#define ARM_TBFLAG_BSWAP_CODE_MASK (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
#define ARM_TBFLAG_CPACR_FPEN_SHIFT 17
#define ARM_TBFLAG_CPACR_FPEN_MASK (1 << ARM_TBFLAG_CPACR_FPEN_SHIFT)
+#define ARM_TBFLAG_NS_SHIFT 18
+#define ARM_TBFLAG_NS_MASK (1 << ARM_TBFLAG_NS_SHIFT)
/* Bit usage when in AArch64 state */
#define ARM_TBFLAG_AA64_EL_SHIFT 0
@@ -1163,6 +1165,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
(((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT)
#define ARM_TBFLAG_AA64_FPEN(F) \
(((F) & ARM_TBFLAG_AA64_FPEN_MASK) >> ARM_TBFLAG_AA64_FPEN_SHIFT)
+#define ARM_TBFLAG_NS(F) \
+ (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT)
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -1192,6 +1196,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
if (privmode) {
*flags |= ARM_TBFLAG_PRIV_MASK;
}
+ if (!arm_is_secure(env)) {
+ *flags |= ARM_TBFLAG_NS_MASK;
+ }
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
|| arm_el_is_aa64(env, 1)) {
*flags |= ARM_TBFLAG_VFPEN_MASK;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 46553fa..87d0918 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -53,8 +53,10 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
+#define IS_NS(s) 1
#else
#define IS_USER(s) (s->user)
+#define IS_NS(s) (s->ns)
#endif
TCGv_ptr cpu_env;
@@ -10783,6 +10785,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
#if !defined(CONFIG_USER_ONLY)
dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
+ dc->ns = ARM_TBFLAG_NS(tb->flags);
#endif
dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags);
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 34328f4..5732738 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -19,6 +19,7 @@ typedef struct DisasContext {
int bswap_code;
#if !defined(CONFIG_USER_ONLY)
int user;
+ int ns;
#endif
bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
bool vfp_enabled; /* FP enabled via FPSCR.EN */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (8 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 09/23] target-arm: add non-secure Translation Block flag Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 6:06 ` Sergey Fedorov
2014-05-14 13:09 ` Peter Crosthwaite
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 11/23] target-arm: add NSACR support Fabian Aggeler
` (13 subsequent siblings)
23 siblings, 2 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
CPACR register allows to control access rights to coprocessor 0-13
interfaces. Bits corresponding to unimplemented coprocessors should be
RAZ/WI. QEMU implements only VFP coprocessor on ARMv6+ targets. So only
cp10 & cp11 bits are writable.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 6 ++++++
target-arm/translate.c | 26 +++++++++++++++++++++++---
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cf1f88c..4e82259 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -477,6 +477,12 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ uint32_t mask = 0;
+
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
+ }
+ value &= mask;
if (env->cp15.c1_coproc != value) {
env->cp15.c1_coproc = value;
/* ??? Is this safe when called from within a TB? */
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 87d0918..c815fb3 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6866,9 +6866,29 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
const ARMCPRegInfo *ri;
cpnum = (insn >> 8) & 0xf;
- if (arm_feature(env, ARM_FEATURE_XSCALE)
- && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
- return 1;
+ if (cpnum < 14) {
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ if (~env->cp15.c15_cpar & (1 << cpnum)) {
+ return 1;
+ }
+ } else {
+ /* Bits [20:21] of CPACR control access to cp10
+ * Bits [23:22] of CPACR control access to cp11 */
+ switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
+ case 0: /* access denied */
+ return 1;
+ case 1: /* privileged mode access only */
+ if (IS_USER(s)) {
+ return 1;
+ }
+ break;
+ case 2: /* reserved */
+ return 1;
+ case 3: /* privileged and user mode access */
+ break;
+ }
+ }
+ }
/* First check for coprocessor space used for actual instructions */
switch (cpnum) {
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 11/23] target-arm: add NSACR support
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (9 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 12/23] target-arm: add SDER definition Fabian Aggeler
` (12 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
NSACR allows to control non-secure access to coprocessor interfaces 0-13
and CPACR bits.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 29 +++++++++++++++++++++++++++++
target-arm/translate.c | 7 +++++++
3 files changed, 37 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f86a101..fb72cfa 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -173,6 +173,7 @@ typedef struct CPUARMState {
uint64_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
+ uint32_t c1_nsacr; /* Non-secure access control register. */
uint64_t ttbr0_el1; /* MMU translation table base 0. */
uint64_t ttbr1_el1; /* MMU translation table base 1. */
uint64_t c2_control; /* MMU translation table base control. */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4e82259..2c600ef 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -483,6 +483,23 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
}
value &= mask;
+ /* In an implementation that includes Security Extensions access to CPACR
+ * can be restricted by NSACR.
+ */
+ if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)
+ && !arm_is_secure(env)) {
+ int cpnum;
+ mask = 0;
+ for (cpnum = 0; cpnum < 14; ++cpnum) {
+ if (env->cp15.c1_nsacr & (1 << cpnum)) {
+ /* Bits [20:21] of CPACR control access to cp10
+ * Bits [23:22] of CPACR control access to cp11 */
+ mask |= (3 << (cpnum * 2));
+ }
+ }
+ value &= mask;
+ value |= env->cp15.c1_coproc & ~mask;
+ }
if (env->cp15.c1_coproc != value) {
env->cp15.c1_coproc = value;
/* ??? Is this safe when called from within a TB? */
@@ -2100,11 +2117,23 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush(CPU(cpu), 1);
}
+#ifndef CONFIG_USER_ONLY
+
+static void nsacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ env->cp15.c1_nsacr = value & 0x3fff;
+}
+#endif
+
static const ARMCPRegInfo tz_cp_reginfo[] = {
#ifndef CONFIG_USER_ONLY
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
.resetvalue = 0, },
+ { .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 2,
+ .access = PL3_RW | PL1_R, .resetvalue = 0, .writefn = nsacr_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_nsacr) },
#endif
REGINFO_SENTINEL
};
diff --git a/target-arm/translate.c b/target-arm/translate.c
index c815fb3..4ebd9f7 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6872,6 +6872,13 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
return 1;
}
} else {
+ /* If Security Extensions are implemented NSACR controls non-secure
+ * access to cp10/cp11 (Bits [11:10]) */
+ if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && IS_NS(s)
+ && (~env->cp15.c1_nsacr & (1 << cpnum))) {
+ return 1;
+ }
+
/* Bits [20:21] of CPACR control access to cp10
* Bits [23:22] of CPACR control access to cp11 */
switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 12/23] target-arm: add SDER definition
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (10 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 11/23] target-arm: add NSACR support Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64 Fabian Aggeler
` (11 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index fb72cfa..76c9e90 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -173,6 +173,7 @@ typedef struct CPUARMState {
uint64_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
+ uint32_t c1_sder; /* Secure debug enable register. */
uint32_t c1_nsacr; /* Non-secure access control register. */
uint64_t ttbr0_el1; /* MMU translation table base 0. */
uint64_t ttbr1_el1; /* MMU translation table base 1. */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2c600ef..00dc4af 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2131,6 +2131,9 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
.resetvalue = 0, },
+ { .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
{ .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 2,
.access = PL3_RW | PL1_R, .resetvalue = 0, .writefn = nsacr_write,
.fieldoffset = offsetof(CPUARMState, cp15.c1_nsacr) },
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (11 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 12/23] target-arm: add SDER definition Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 6:15 ` Sergey Fedorov
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
` (10 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
This patch is based on ideas found in a patch at
git://github.com/jowinter/qemu-trustzone.git
a9ad01767c4b25e14700b5682a412f4fd8146ee8 by
Johannes Winter <johannes.winter@iaik.tugraz.at>.
Each world (secure and non-secure) has its own MMU state. Providing
a separate TLB for each state prevents flushing it on each transition
from secure to non-secure world and vice versa.
For EL3 in Aarch64 state another MMU state is introduced since
EL3 will be able to configure its own translation regime.
Do not use IS_USER() macro anymore as MMU index in translation
code. Use new MEM_INDEX() and MEM_INDEX_USER() macros instead.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 42 +++++++-
target-arm/helper.c | 2 +-
target-arm/translate-a64.c | 9 +-
target-arm/translate.c | 247 +++++++++++++++++++++++----------------------
target-arm/translate.h | 1 +
5 files changed, 176 insertions(+), 125 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 76c9e90..a970d55 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -91,7 +91,7 @@ typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
struct arm_boot_info;
-#define NB_MMU_MODES 2
+#define NB_MMU_MODES 5
/* We currently assume float and double are IEEE single and double
precision respectively.
@@ -1104,10 +1104,43 @@ static inline CPUARMState *cpu_init(const char *cpu_model)
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
#define MMU_MODE1_SUFFIX _user
-#define MMU_USER_IDX 1
+#define MMU_MODE2_SUFFIX _secure_kernel
+#define MMU_MODE3_SUFFIX _secure_user
+#define MMU_MODE4_SUFFIX _el3
+#define MMU_USER_BIT 1
+#define MMU_SECURE_BIT (1 << 1)
+#define MMU_EL3_BIT (1 << 2)
+#define MMU_KERN_IDX (0)
+#define MMU_USER_IDX (MMU_USER_BIT)
+#define MMU_SECURE_KERN_IDX (MMU_SECURE_BIT | MMU_KERN_IDX)
+#define MMU_SECURE_USER_IDX (MMU_SECURE_BIT | MMU_USER_IDX)
static inline int cpu_mmu_index (CPUARMState *env)
{
- return arm_current_pl(env) ? 0 : 1;
+ int mmu_index = 0;
+ int current_pl;
+ /* Security Extensions introduce two separate virtual MMUs for each CPU,
+ * one each for secure and non-secure world. If EL3 is in Aarch64 state it
+ * gets its own MMU which it can configure through the SCTLR_EL3 register.*/
+
+ current_pl = arm_current_pl(env);
+ if (current_pl == 3 && arm_el_is_aa64(env, 3)) {
+ /* Bit 3: 1 for EL3 in Aarch64 state */
+ return 1 << 3;
+ } else {
+ /* Bit 0: 0 for PL1/2/3, 1 for PL0
+ * Bit 1: 0 for non-secure, 1 for secure
+ */
+ if (arm_is_secure(env)) {
+ mmu_index |= MMU_SECURE_BIT;
+ }
+
+ if (current_pl == 0) {
+ mmu_index |= MMU_USER_BIT;
+ }
+
+ return mmu_index;
+ }
+
}
#include "exec/cpu-all.h"
@@ -1182,6 +1215,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
*flags |= ARM_TBFLAG_AA64_FPEN_MASK;
}
+ if (!arm_is_secure(env)) {
+ *flags |= ARM_TBFLAG_NS_MASK;
+ }
} else {
int privmode;
*pc = env->regs[15];
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 00dc4af..9326ef8 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -4079,7 +4079,7 @@ int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
uint32_t syn;
bool same_el = (arm_current_pl(env) != 0);
- is_user = mmu_idx == MMU_USER_IDX;
+ is_user = mmu_idx & MMU_USER_BIT;
ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,
&page_size);
if (ret == 0) {
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index b62db4d..1b4c932 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -167,7 +167,13 @@ static int get_mem_index(DisasContext *s)
#ifdef CONFIG_USER_ONLY
return 1;
#else
- return s->user;
+ /* EL3 in Aarch64 state has its own MMU */
+ if (s->current_pl == 3) {
+ return MMU_EL3_BIT;
+ } else {
+ return (s->user ? MMU_USER_BIT : 0) |
+ (s->ns ? 0 : MMU_SECURE_BIT);
+ }
#endif
}
@@ -10661,6 +10667,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
dc->condexec_cond = 0;
#if !defined(CONFIG_USER_ONLY)
dc->user = (ARM_TBFLAG_AA64_EL(tb->flags) == 0);
+ dc->ns = ARM_TBFLAG_NS(tb->flags);
#endif
dc->cpacr_fpen = ARM_TBFLAG_AA64_FPEN(tb->flags);
dc->vec_len = 0;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 4ebd9f7..bbd4c77 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -54,9 +54,13 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#define IS_NS(s) 1
+#define MEM_INDEX(s) MMU_USER_IDX
+#define MEM_INDEX_USER(S) MMU_USER_IDX
#else
#define IS_USER(s) (s->user)
#define IS_NS(s) (s->ns)
+#define MEM_INDEX(s) (s->mem_idx)
+#define MEM_INDEX_USER(S) (MEM_INDEX(s) | MMU_USER_BIT)
#endif
TCGv_ptr cpu_env;
@@ -1167,18 +1171,18 @@ VFP_GEN_FIX(ulto, )
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
{
if (dp) {
- gen_aa32_ld64(cpu_F0d, addr, IS_USER(s));
+ gen_aa32_ld64(cpu_F0d, addr, MEM_INDEX(s));
} else {
- gen_aa32_ld32u(cpu_F0s, addr, IS_USER(s));
+ gen_aa32_ld32u(cpu_F0s, addr, MEM_INDEX(s));
}
}
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
{
if (dp) {
- gen_aa32_st64(cpu_F0d, addr, IS_USER(s));
+ gen_aa32_st64(cpu_F0d, addr, MEM_INDEX(s));
} else {
- gen_aa32_st32(cpu_F0s, addr, IS_USER(s));
+ gen_aa32_st32(cpu_F0s, addr, MEM_INDEX(s));
}
}
@@ -1516,24 +1520,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
if (insn & ARM_CP_RW_BIT) {
if ((insn >> 28) == 0xf) { /* WLDRW wCx */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
iwmmxt_store_creg(wrd, tmp);
} else {
i = 1;
if (insn & (1 << 8)) {
if (insn & (1 << 22)) { /* WLDRD */
- gen_aa32_ld64(cpu_M0, addr, IS_USER(s));
+ gen_aa32_ld64(cpu_M0, addr, MEM_INDEX(s));
i = 0;
} else { /* WLDRW wRd */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
}
} else {
tmp = tcg_temp_new_i32();
if (insn & (1 << 22)) { /* WLDRH */
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
} else { /* WLDRB */
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
}
}
if (i) {
@@ -1545,24 +1549,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
} else {
if ((insn >> 28) == 0xf) { /* WSTRW wCx */
tmp = iwmmxt_load_creg(wrd);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
} else {
gen_op_iwmmxt_movq_M0_wRn(wrd);
tmp = tcg_temp_new_i32();
if (insn & (1 << 8)) {
if (insn & (1 << 22)) { /* WSTRD */
- gen_aa32_st64(cpu_M0, addr, IS_USER(s));
+ gen_aa32_st64(cpu_M0, addr, MEM_INDEX(s));
} else { /* WSTRW wRd */
tcg_gen_trunc_i64_i32(tmp, cpu_M0);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
}
} else {
if (insn & (1 << 22)) { /* WSTRH */
tcg_gen_trunc_i64_i32(tmp, cpu_M0);
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
} else { /* WSTRB */
tcg_gen_trunc_i64_i32(tmp, cpu_M0);
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
}
}
}
@@ -2627,15 +2631,15 @@ static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
TCGv_i32 tmp = tcg_temp_new_i32();
switch (size) {
case 0:
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
gen_neon_dup_u8(tmp, 0);
break;
case 1:
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
gen_neon_dup_low16(tmp);
break;
case 2:
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
default: /* Avoid compiler warnings. */
abort();
@@ -4306,11 +4310,11 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
if (size == 3) {
tmp64 = tcg_temp_new_i64();
if (load) {
- gen_aa32_ld64(tmp64, addr, IS_USER(s));
+ gen_aa32_ld64(tmp64, addr, MEM_INDEX(s));
neon_store_reg64(tmp64, rd);
} else {
neon_load_reg64(tmp64, rd);
- gen_aa32_st64(tmp64, addr, IS_USER(s));
+ gen_aa32_st64(tmp64, addr, MEM_INDEX(s));
}
tcg_temp_free_i64(tmp64);
tcg_gen_addi_i32(addr, addr, stride);
@@ -4319,21 +4323,21 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
if (size == 2) {
if (load) {
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
neon_store_reg(rd, pass, tmp);
} else {
tmp = neon_load_reg(rd, pass);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_gen_addi_i32(addr, addr, stride);
} else if (size == 1) {
if (load) {
tmp = tcg_temp_new_i32();
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
tcg_gen_addi_i32(addr, addr, stride);
tmp2 = tcg_temp_new_i32();
- gen_aa32_ld16u(tmp2, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp2, addr, MEM_INDEX(s));
tcg_gen_addi_i32(addr, addr, stride);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp, tmp, tmp2);
@@ -4343,10 +4347,10 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tmp = neon_load_reg(rd, pass);
tmp2 = tcg_temp_new_i32();
tcg_gen_shri_i32(tmp2, tmp, 16);
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
tcg_gen_addi_i32(addr, addr, stride);
- gen_aa32_st16(tmp2, addr, IS_USER(s));
+ gen_aa32_st16(tmp2, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp2);
tcg_gen_addi_i32(addr, addr, stride);
}
@@ -4355,7 +4359,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
TCGV_UNUSED_I32(tmp2);
for (n = 0; n < 4; n++) {
tmp = tcg_temp_new_i32();
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
tcg_gen_addi_i32(addr, addr, stride);
if (n == 0) {
tmp2 = tmp;
@@ -4375,7 +4379,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
} else {
tcg_gen_shri_i32(tmp, tmp2, n * 8);
}
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
tcg_gen_addi_i32(addr, addr, stride);
}
@@ -4499,13 +4503,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tmp = tcg_temp_new_i32();
switch (size) {
case 0:
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 1:
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 2:
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
default: /* Avoid compiler warnings. */
abort();
@@ -4523,13 +4527,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tcg_gen_shri_i32(tmp, tmp, shift);
switch (size) {
case 0:
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
break;
case 1:
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
break;
case 2:
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
break;
}
tcg_temp_free_i32(tmp);
@@ -7202,14 +7206,14 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
switch (size) {
case 0:
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 1:
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 2:
case 3:
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -7220,7 +7224,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
TCGv_i32 tmp3 = tcg_temp_new_i32();
tcg_gen_addi_i32(tmp2, addr, 4);
- gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
+ gen_aa32_ld32u(tmp3, tmp2, MEM_INDEX(s));
tcg_temp_free_i32(tmp2);
tcg_gen_concat_i32_i64(cpu_exclusive_val, tmp, tmp3);
store_reg(s, rt2, tmp3);
@@ -7271,14 +7275,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
tmp = tcg_temp_new_i32();
switch (size) {
case 0:
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 1:
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 2:
case 3:
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -7289,7 +7293,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
TCGv_i32 tmp2 = tcg_temp_new_i32();
TCGv_i32 tmp3 = tcg_temp_new_i32();
tcg_gen_addi_i32(tmp2, addr, 4);
- gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
+ gen_aa32_ld32u(tmp3, tmp2, MEM_INDEX(s));
tcg_temp_free_i32(tmp2);
tcg_gen_concat_i32_i64(val64, tmp, tmp3);
tcg_temp_free_i32(tmp3);
@@ -7304,14 +7308,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
tmp = load_reg(s, rt);
switch (size) {
case 0:
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
break;
case 1:
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
break;
case 2:
case 3:
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -7320,7 +7324,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
if (size == 3) {
tcg_gen_addi_i32(addr, addr, 4);
tmp = load_reg(s, rt2);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_gen_movi_i32(cpu_R[rd], 0);
@@ -7367,11 +7371,11 @@ static void gen_srs(DisasContext *s,
}
tcg_gen_addi_i32(addr, addr, offset);
tmp = load_reg(s, 14);
- gen_aa32_st32(tmp, addr, 0);
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
tmp = load_cpu_field(spsr);
tcg_gen_addi_i32(addr, addr, 4);
- gen_aa32_st32(tmp, addr, 0);
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
if (writeback) {
switch (amode) {
@@ -7524,10 +7528,10 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tcg_gen_addi_i32(addr, addr, offset);
/* Load PC into tmp and CPSR into tmp2. */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, 0);
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
tcg_gen_addi_i32(addr, addr, 4);
tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp2, addr, 0);
+ gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
if (insn & (1 << 21)) {
/* Base writeback. */
switch (i) {
@@ -8116,13 +8120,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tmp = tcg_temp_new_i32();
switch (op1) {
case 0: /* lda */
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
case 2: /* ldab */
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 3: /* ldah */
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -8133,13 +8137,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tmp = load_reg(s, rm);
switch (op1) {
case 0: /* stl */
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
break;
case 2: /* stlb */
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
break;
case 3: /* stlh */
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -8194,11 +8198,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tmp = load_reg(s, rm);
tmp2 = tcg_temp_new_i32();
if (insn & (1 << 22)) {
- gen_aa32_ld8u(tmp2, addr, IS_USER(s));
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp2, addr, MEM_INDEX(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
} else {
- gen_aa32_ld32u(tmp2, addr, IS_USER(s));
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
}
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(addr);
@@ -8220,14 +8224,14 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
tmp = tcg_temp_new_i32();
switch(sh) {
case 1:
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 2:
- gen_aa32_ld8s(tmp, addr, IS_USER(s));
+ gen_aa32_ld8s(tmp, addr, MEM_INDEX(s));
break;
default:
case 3:
- gen_aa32_ld16s(tmp, addr, IS_USER(s));
+ gen_aa32_ld16s(tmp, addr, MEM_INDEX(s));
break;
}
load = 1;
@@ -8237,21 +8241,21 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
if (sh & 1) {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
tcg_gen_addi_i32(addr, addr, 4);
tmp = load_reg(s, rd + 1);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
load = 0;
} else {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
tcg_gen_addi_i32(addr, addr, 4);
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
rd++;
load = 1;
}
@@ -8259,7 +8263,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
} else {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
load = 0;
}
@@ -8597,7 +8601,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
tmp2 = load_reg(s, rn);
- i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
+ i = (insn & 0x01200000) == 0x00200000 ?
+ MEM_INDEX_USER(s) : MEM_INDEX(s);
if (insn & (1 << 24))
gen_add_data_offset(s, insn, tmp2);
if (insn & (1 << 20)) {
@@ -8681,7 +8686,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
if (insn & (1 << 20)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
if (user) {
tmp2 = tcg_const_i32(i);
gen_helper_set_user_reg(cpu_env, tmp2, tmp);
@@ -8708,7 +8713,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
} else {
tmp = load_reg(s, i);
}
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
j++;
@@ -8974,20 +8979,20 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
if (insn & (1 << 20)) {
/* ldrd */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, rs, tmp);
tcg_gen_addi_i32(addr, addr, 4);
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
} else {
/* strd */
tmp = load_reg(s, rs);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
tcg_gen_addi_i32(addr, addr, 4);
tmp = load_reg(s, rd);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
if (insn & (1 << 21)) {
@@ -9025,11 +9030,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tcg_gen_add_i32(addr, addr, tmp);
tcg_temp_free_i32(tmp);
tmp = tcg_temp_new_i32();
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
} else { /* tbb */
tcg_temp_free_i32(tmp);
tmp = tcg_temp_new_i32();
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
}
tcg_temp_free_i32(addr);
tcg_gen_shli_i32(tmp, tmp, 1);
@@ -9066,13 +9071,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = tcg_temp_new_i32();
switch (op) {
case 0: /* ldab */
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 1: /* ldah */
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 2: /* lda */
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -9082,13 +9087,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = load_reg(s, rs);
switch (op) {
case 0: /* stlb */
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
break;
case 1: /* stlh */
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
break;
case 2: /* stl */
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
break;
default:
abort();
@@ -9116,10 +9121,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tcg_gen_addi_i32(addr, addr, -8);
/* Load PC into tmp and CPSR into tmp2. */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, 0);
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
tcg_gen_addi_i32(addr, addr, 4);
tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp2, addr, 0);
+ gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
if (insn & (1 << 21)) {
/* Base writeback. */
if (insn & (1 << 24)) {
@@ -9158,7 +9163,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
if (insn & (1 << 20)) {
/* Load. */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
if (i == 15) {
gen_bx(s, tmp);
} else if (i == rn) {
@@ -9170,7 +9175,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
} else {
/* Store. */
tmp = load_reg(s, i);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_gen_addi_i32(addr, addr, 4);
@@ -9870,7 +9875,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
{
int postinc = 0;
int writeback = 0;
- int user;
+ int mem_idx;
if ((insn & 0x01100000) == 0x01000000) {
if (disas_neon_ls_insn(env, s, insn))
goto illegal_op;
@@ -9914,7 +9919,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
return 1;
}
}
- user = IS_USER(s);
+ mem_idx = MEM_INDEX(s);
if (rn == 15) {
addr = tcg_temp_new_i32();
/* PC relative. */
@@ -9951,7 +9956,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
break;
case 0xe: /* User privilege. */
tcg_gen_addi_i32(addr, addr, imm);
- user = 1;
+ mem_idx = MEM_INDEX_USER(s);
break;
case 0x9: /* Post-decrement. */
imm = -imm;
@@ -9978,19 +9983,19 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = tcg_temp_new_i32();
switch (op) {
case 0:
- gen_aa32_ld8u(tmp, addr, user);
+ gen_aa32_ld8u(tmp, addr, mem_idx);
break;
case 4:
- gen_aa32_ld8s(tmp, addr, user);
+ gen_aa32_ld8s(tmp, addr, mem_idx);
break;
case 1:
- gen_aa32_ld16u(tmp, addr, user);
+ gen_aa32_ld16u(tmp, addr, mem_idx);
break;
case 5:
- gen_aa32_ld16s(tmp, addr, user);
+ gen_aa32_ld16s(tmp, addr, mem_idx);
break;
case 2:
- gen_aa32_ld32u(tmp, addr, user);
+ gen_aa32_ld32u(tmp, addr, mem_idx);
break;
default:
tcg_temp_free_i32(tmp);
@@ -10007,13 +10012,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = load_reg(s, rs);
switch (op) {
case 0:
- gen_aa32_st8(tmp, addr, user);
+ gen_aa32_st8(tmp, addr, mem_idx);
break;
case 1:
- gen_aa32_st16(tmp, addr, user);
+ gen_aa32_st16(tmp, addr, mem_idx);
break;
case 2:
- gen_aa32_st32(tmp, addr, user);
+ gen_aa32_st32(tmp, addr, mem_idx);
break;
default:
tcg_temp_free_i32(tmp);
@@ -10150,7 +10155,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
addr = tcg_temp_new_i32();
tcg_gen_movi_i32(addr, val);
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(addr);
store_reg(s, rd, tmp);
break;
@@ -10353,28 +10358,28 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
switch (op) {
case 0: /* str */
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
break;
case 1: /* strh */
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
break;
case 2: /* strb */
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
break;
case 3: /* ldrsb */
- gen_aa32_ld8s(tmp, addr, IS_USER(s));
+ gen_aa32_ld8s(tmp, addr, MEM_INDEX(s));
break;
case 4: /* ldr */
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
break;
case 5: /* ldrh */
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
break;
case 6: /* ldrb */
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
break;
case 7: /* ldrsh */
- gen_aa32_ld16s(tmp, addr, IS_USER(s));
+ gen_aa32_ld16s(tmp, addr, MEM_INDEX(s));
break;
}
if (op >= 3) { /* load */
@@ -10396,12 +10401,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@@ -10418,12 +10423,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld8u(tmp, addr, IS_USER(s));
+ gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st8(tmp, addr, IS_USER(s));
+ gen_aa32_st8(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@@ -10440,12 +10445,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld16u(tmp, addr, IS_USER(s));
+ gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st16(tmp, addr, IS_USER(s));
+ gen_aa32_st16(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@@ -10461,12 +10466,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@@ -10534,12 +10539,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* pop */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
store_reg(s, i, tmp);
} else {
/* push */
tmp = load_reg(s, i);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
/* advance to the next address. */
@@ -10551,13 +10556,13 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* pop pc */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
/* don't set the pc until the rest of the instruction
has completed */
} else {
/* push lr */
tmp = load_reg(s, 14);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
tcg_gen_addi_i32(addr, addr, 4);
@@ -10686,7 +10691,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(tmp, addr, IS_USER(s));
+ gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
if (i == rn) {
loaded_var = tmp;
} else {
@@ -10695,7 +10700,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
} else {
/* store */
tmp = load_reg(s, i);
- gen_aa32_st32(tmp, addr, IS_USER(s));
+ gen_aa32_st32(tmp, addr, MEM_INDEX(s));
tcg_temp_free_i32(tmp);
}
/* advance to the next address */
@@ -10813,6 +10818,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
#if !defined(CONFIG_USER_ONLY)
dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
dc->ns = ARM_TBFLAG_NS(tb->flags);
+ dc->mem_idx = (IS_USER(dc) ? MMU_USER_BIT : 0) |
+ (IS_NS(dc) ? 0 : MMU_SECURE_BIT);
#endif
dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags);
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 5732738..eeb77fb 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -20,6 +20,7 @@ typedef struct DisasContext {
#if !defined(CONFIG_USER_ONLY)
int user;
int ns;
+ int mem_idx;
#endif
bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
bool vfp_enabled; /* FP enabled via FPSCR.EN */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (12 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64 Fabian Aggeler
@ 2014-05-13 16:15 ` Fabian Aggeler
2014-05-14 16:42 ` Greg Bellows
` (2 more replies)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 15/23] target-arm: Restrict EL3 to Aarch32 state Fabian Aggeler
` (9 subsequent siblings)
23 siblings, 3 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
Banked CP registers can be defined with a A32_BANKED_REG macro which defines
a non-secure instance of the register followed by an adjacent secure instance.
Using a union makes the code backwards-compatible since the non-secure
instance can normally be accessed by its existing name.
When translating a banked CP register access instruction in monitor mode,
the SCR.NS bit determines which instance is going to be accessed.
If EL3 is operating in Aarch64 state coprocessor registers are not
banked anymore but in some cases have its own _EL3 instance.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
target-arm/helper.c | 64 ++++++++++++++++++++++++--
target-arm/translate.c | 19 +++++---
3 files changed, 184 insertions(+), 20 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a970d55..9e325ac 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -80,6 +80,16 @@
#define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
#endif
+/* Define a banked coprocessor register state field. Use %name as the
+ * register field name for the secure instance. The non-secure instance
+ * has a "_nonsecure" suffix.
+ */
+#define A32_BANKED_REG(type, name) \
+ union { \
+ type name; \
+ type name##_banked[2]; \
+ }
+
/* Meanings of the ARMCPU object's two inbound GPIO lines */
#define ARM_CPU_IRQ 0
#define ARM_CPU_FIQ 1
@@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
int dstreg, int operand);
+
struct arm_boot_info;
#define NB_MMU_MODES 5
@@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
return arm_feature(env, ARM_FEATURE_AARCH64);
}
+/* When EL3 is operating in Aarch32 state, the NS-bit determines
+ * whether the secure instance of a cp-register should be used. */
+#define USE_SECURE_REG(env) ( \
+ arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
+ !arm_el_is_aa64(env, 3) && \
+ !((env)->cp15.c1_scr & 1/*NS*/))
+
+#define NONSECURE_BANK 0
+#define SECURE_BANK 1
+
+#define A32_BANKED_REG_GET(env, regname) \
+ ((USE_SECURE_REG(env)) ? \
+ (env)->cp15.regname##_banked[SECURE_BANK] : \
+ (env)->cp15.regname)
+
+#define A32_MAPPED_EL3_REG_GET(env, regname) \
+ (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (USE_SECURE_REG(env))) ? \
+ (env)->cp15.regname##_el3 : \
+ (env)->cp15.regname##_el1)
+
+#define A32_BANKED_REG_SET(env, regname, val) \
+ do { \
+ if (USE_SECURE_REG(env)) { \
+ (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
+ } else { \
+ (env)->cp15.regname = (val); \
+ } \
+ } while (0)
+
+#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
+ do { \
+ if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (USE_SECURE_REG(env))) { \
+ (env)->cp15.regname##_el3 = (val); \
+ } else { \
+ (env)->cp15.regname##_el1 = (val); \
+ } \
+ } while (0)
+
+
+#define A32_BANKED_CURRENT_REG_GET(env, regname) \
+ ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
+ (env)->cp15.regname##_banked[SECURE_BANK] : \
+ (env)->cp15.regname)
+
+#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
+ (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
+ (env)->cp15.regname##_el3 : \
+ (env)->cp15.regname##_el1)
+
+#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
+ do { \
+ if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
+ (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
+ } else { \
+ (env)->cp15.regname = (val); \
+ } \
+ } while (0)
+
+#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
+ do { \
+ if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
+ (env)->cp15.regname##_el3 = (val); \
+ } else { \
+ (env)->cp15.regname##_el1 = (val); \
+ } \
+ } while (0)
+
+
void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
/* Interface between CPU and Interrupt controller. */
@@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
* Crn, Crm, opc1, opc2 fields
* 32 or 64 bit register (ie is it accessed via MRC/MCR
* or via MRRC/MCRR?)
+ * nonsecure/secure bank (Aarch32 only)
* We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
* (In this case crn and opc2 should be zero.)
* For AArch64, there is no 32/64 bit size distinction;
@@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
#define CP_REG_AA64_SHIFT 28
#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
-#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
- (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
- ((crm) << 7) | ((opc1) << 3) | (opc2))
+/* To enable banking of coprocessor registers depending on ns-bit we
+ * add a bit to distinguish between secure and non-secure cpregs in the
+ * hashtable.
+ */
+#define CP_REG_NS_SHIFT 27
+#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
+
+#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
+ (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
+ ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
(CP_REG_AA64_MASK | \
@@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
* IO indicates that this register does I/O and therefore its accesses
* need to be surrounded by gen_io_start()/gen_io_end(). In particular,
* registers which implement clocks or timers require this.
+ * In an implementation with Security Extensions supporting Aarch32 cp regs can
+ * be banked or common. If a register is common it references the same variable
+ * from both worlds (non-secure and secure). For cp regs which neither set
+ * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
+ * will be inserted twice into the hashtable. If a register has
+ * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
+ * different offset respectively. This way Aarch32 registers which can be
+ * mapped to Aarch64 PL3 registers can be inserted individually.
*/
#define ARM_CP_SPECIAL 1
#define ARM_CP_CONST 2
@@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
#define ARM_CP_OVERRIDE 16
#define ARM_CP_NO_MIGRATE 32
#define ARM_CP_IO 64
-#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
-#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
-#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
-#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
-#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
+#define ARM_CP_SECURE (1 << 7)
+#define ARM_CP_NONSECURE (1 << 8)
+#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
+#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
+#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
+#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
+#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
+#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
/* Used only as a terminator for ARMCPRegInfo lists */
#define ARM_CP_SENTINEL 0xffff
/* Mask of only the flag bits in a type field */
-#define ARM_CP_FLAG_MASK 0x7f
+#define ARM_CP_FLAG_MASK 0x3ff
/* Valid values for ARMCPRegInfo state field, indicating which of
* the AArch32 and AArch64 execution states this register is visible in.
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9326ef8..98c3dc9 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
void *opaque, int state,
- int crm, int opc1, int opc2)
+ int crm, int opc1, int opc2, int nsbit)
{
/* Private utility function for define_one_arm_cp_reg_with_opaque():
* add a single reginfo struct to the hash table.
@@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
}
#endif
}
+
+ if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
+ if (r2->fieldoffset) {
+ /* We simplify register definitions by providing a type
+ * ARM_CP_BANKED, for which the fieldoffset of the secure instance
+ * will be increased to point at the second entry of the array.
+ *
+ * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
+ * wide the banked register is because some registers are 64bit
+ * wide but the register is not defined as 64bit because it is
+ * mapped to the lower 32 bit.
+ * Therefore two separate types for 64bit banked registers and
+ * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
+ */
+ r2->fieldoffset +=
+ ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
+ sizeof(uint64_t) : sizeof(uint32_t);
+ }
+ }
+ /* For A32 we want to be able to know whether the secure or non-secure
+ * instance wants to be accessed. A64 does not know this banking scheme
+ * anymore, but it might use the same readfn/writefn as A32 which might
+ * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
+ * Reset the type according to ns-bit passed as argument.
+ */
+ r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
+ r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
+
if (state == ARM_CP_STATE_AA64) {
/* To allow abbreviation of ARMCPRegInfo
* definitions, we treat cp == 0 as equivalent to
@@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
*key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
r2->opc0, opc1, opc2);
} else {
- *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
+ *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
}
if (opaque) {
r2->opaque = opaque;
@@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
oldreg = g_hash_table_lookup(cpu->cp_regs, key);
if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
fprintf(stderr, "Register redefined: cp=%d %d bit "
- "crn=%d crm=%d opc1=%d opc2=%d, "
+ "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
"was %s, now %s\n", r2->cp, 32 + 32 * is64,
r2->crn, r2->crm, r2->opc1, r2->opc2,
+ (r2->type & ARM_CP_NONSECURE),
oldreg->name, r2->name);
g_assert_not_reached();
}
@@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
continue;
}
- add_cpreg_to_hashtable(cpu, r, opaque, state,
- crm, opc1, opc2);
+
+ if (state == ARM_CP_STATE_AA32) {
+ if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
+ (r->type & ARM_CP_BANKED) == 0) {
+ /* Under Aarch32 CP registers can be common
+ * (same for secure and non-secure world) or banked.
+ * Register definitions with neither secure nor
+ * non-secure type set (common) or with both bits
+ * set (banked) will be inserted twice into the
+ * hashtable.
+ */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 0);
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 1);
+ } else {
+ /* Only one of both bank types were specified */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2,
+ (r->type & ARM_CP_NONSECURE) ? 1 : 0);
+ }
+ } else {
+ /* Aarch64 registers get mapped to non-secure instance
+ * of Aarch32 */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 1);
+ }
}
}
}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index bbd4c77..3a429ac 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
{
- int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
+ int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
const ARMCPRegInfo *ri;
cpnum = (insn >> 8) & 0xf;
@@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
isread = (insn >> 20) & 1;
rt = (insn >> 12) & 0xf;
+ /* Monitor mode is always treated as secure but cp register reads/writes
+ * can access secure and non-secure instances using SCR.NS bit*/
+ ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
ri = get_arm_cp_reginfo(s->cp_regs,
- ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
+ ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
if (ri) {
/* Check access permissions */
if (!cp_access_ok(s->current_pl, ri, isread)) {
@@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
*/
if (is64) {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
- "64 bit system register cp:%d opc1: %d crm:%d\n",
- isread ? "read" : "write", cpnum, opc1, crm);
+ "64 bit system register cp:%d opc1: %d crm:%d "
+ "(%s)\n",
+ isread ? "read" : "write", cpnum, opc1, crm,
+ ns ? "non-secure" : "secure");
} else {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
- "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
- isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
+ "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
+ "(%s)\n",
+ isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
+ ns ? "non-secure" : "secure");
}
return 1;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 15/23] target-arm: Restrict EL3 to Aarch32 state
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (13 preceding siblings ...)
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR Fabian Aggeler
` (8 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Fabian Aggeler, peter.maydell
This behaviour can be changed after all needed Aarch64 (_EL3)
registers are implemented and respected at locations where
behaviour is different when EL3 is in Aarch64 state.
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 9e325ac..a4bb6bd 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -671,11 +671,15 @@ static inline bool arm_is_secure(CPUARMState *env)
/* Return true if the specified exception level is running in AArch64 state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{
- /* We don't currently support EL2 or EL3, and this isn't valid for EL0
+ /* We don't currently support EL2, and this isn't valid for EL0
* (if we're in EL0, is_a64() is what you want, and if we're not in EL0
* then the state of EL0 isn't well defined.)
*/
- assert(el == 1);
+ assert(el == 1 || el == 3);
+ /* EL3 can only run in Aarch32 at the moment */
+ if (el == 3) {
+ return false;
+ }
/* AArch64-capable CPUs always run with EL1 in AArch64 mode. This
* is a QEMU-imposed simplification which we may wish to change later.
* If we in future support EL2 and/or EL3, then the state of lower
@@ -755,7 +759,6 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
} \
} while (0)
-
void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
/* Interface between CPU and Interrupt controller. */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (14 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 15/23] target-arm: Restrict EL3 to Aarch32 state Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-22 7:33 ` Edgar E. Iglesias
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible Fabian Aggeler
` (7 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Fabian Aggeler, peter.maydell
Add SCTLR_EL3 and introduce new function to access correct
instance of SCTLR in different modes/worlds.
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
hw/arm/pxa2xx.c | 2 +-
target-arm/cpu-qom.h | 1 +
target-arm/cpu.c | 4 +--
target-arm/cpu.h | 14 ++++++++++-
target-arm/helper.c | 67 ++++++++++++++++++++++++++++++++++++++------------
target-arm/op_helper.c | 2 +-
6 files changed, 69 insertions(+), 21 deletions(-)
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index e0cd847..8b69e72 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -274,7 +274,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
case 3:
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
- s->cpu->env.cp15.c1_sys = 0;
+ s->cpu->env.cp15.c1_sys_el1 = 0;
s->cpu->env.cp15.c1_coproc = 0;
s->cpu->env.cp15.ttbr0_el1 = 0;
s->cpu->env.cp15.c3 = 0;
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index edc7f26..38cbd43 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -119,6 +119,7 @@ typedef struct ARMCPU {
uint32_t mvfr2;
uint32_t ctr;
uint32_t reset_sctlr;
+ uint32_t reset_sctlr_el3;
uint32_t id_pfr0;
uint32_t id_pfr1;
uint32_t id_dfr0;
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index b0d4a9b..bdbdbb1 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -100,7 +100,7 @@ static void arm_cpu_reset(CPUState *s)
#if defined(CONFIG_USER_ONLY)
env->pstate = PSTATE_MODE_EL0t;
/* Userspace expects access to CTL_EL0 and the cache ops */
- env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
+ env->cp15.c1_sys_el1 |= SCTLR_UCT | SCTLR_UCI;
/* and to the FP/Neon instructions */
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
#else
@@ -146,7 +146,7 @@ static void arm_cpu_reset(CPUState *s)
}
}
- if (env->cp15.c1_sys & SCTLR_V) {
+ if (arm_current_sctlr(env) & SCTLR_V) {
env->regs[15] = 0xFFFF0000;
}
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a4bb6bd..780c1f5 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -180,7 +180,8 @@ typedef struct CPUARMState {
struct {
uint32_t c0_cpuid;
uint64_t c0_cssel; /* Cache size selection. */
- uint64_t c1_sys; /* System control register. */
+ uint64_t c1_sys_el1; /* System control register (EL1). */
+ uint64_t c1_sys_el3; /* System control register (EL3). */
uint64_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
@@ -971,6 +972,17 @@ static inline int arm_current_pl(CPUARMState *env)
return 1;
}
+static inline uint64_t arm_current_sctlr(CPUARMState *env)
+{
+ if (is_a64(env) && arm_current_pl(env) == 3) {
+ /* EL3 has its own SCTLR */
+ return env->cp15.c1_sys_el3;
+ } else {
+ /* Only A32 with NS-bit clear accesses secure instance of SCTLR */
+ return A32_MAPPED_EL3_REG_GET(env, c1_sys);
+ }
+}
+
typedef struct ARMCPRegInfo ARMCPRegInfo;
typedef enum CPAccessResult {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 98c3dc9..ac8b15a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1767,7 +1767,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
- if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
+ if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
return CP_ACCESS_TRAP;
}
return CP_ACCESS_OK;
@@ -1785,7 +1785,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
* SCTLR_EL1.UCI is set.
*/
- if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
+ if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCI)) {
return CP_ACCESS_TRAP;
}
return CP_ACCESS_OK;
@@ -1823,7 +1823,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
/* We don't implement EL2, so the only control on DC ZVA is the
* bit in the SCTLR which can prohibit access for EL0.
*/
- if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
+ if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_DZE)) {
return CP_ACCESS_TRAP;
}
return CP_ACCESS_OK;
@@ -2146,7 +2146,7 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
* but the AArch32 CTR has its own reginfo struct)
*/
- if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
+ if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCT)) {
return CP_ACCESS_TRAP;
}
return CP_ACCESS_OK;
@@ -2573,10 +2573,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
/* Generic registers whose values depend on the implementation */
{
- ARMCPRegInfo sctlr = {
- .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys),
+ ARMCPRegInfo sctlr_el1 = {
+ .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
+ .type = ARM_CP_NONSECURE, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0,
+ .opc2 = 0, .access = PL1_RW,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el1),
.writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
.raw_writefn = raw_write,
};
@@ -2585,9 +2586,43 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* arch/arm/mach-pxa/sleep.S expects two instructions following
* an MMU enable to execute from cache. Imitate this behaviour.
*/
- sctlr.type |= ARM_CP_SUPPRESS_TB_END;
+ sctlr_el1.type |= ARM_CP_SUPPRESS_TB_END;
}
- define_one_arm_cp_reg(cpu, &sctlr);
+ define_one_arm_cp_reg(cpu, &sctlr_el1);
+
+ ARMCPRegInfo sctlr_el1_s = {
+ .name = "SCTLR_EL1(S)", .type = ARM_CP_SECURE,
+ .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
+ .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
+ .raw_writefn = raw_write,
+ };
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ /* Normally we would always end the TB on an SCTLR write, but Linux
+ * arch/arm/mach-pxa/sleep.S expects two instructions following
+ * an MMU enable to execute from cache. Imitate this behaviour.
+ */
+ sctlr_el1_s.type |= ARM_CP_SUPPRESS_TB_END;
+ }
+ define_one_arm_cp_reg(cpu, &sctlr_el1_s);
+
+ ARMCPRegInfo sctlr_el3 = {
+ .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
+ .access = PL3_RW, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
+ .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr_el3,
+ .raw_writefn = raw_write,
+ };
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ /* Normally we would always end the TB on an SCTLR write, but Linux
+ * arch/arm/mach-pxa/sleep.S expects two instructions following
+ * an MMU enable to execute from cache. Imitate this behaviour.
+ */
+ sctlr_el3.type |= ARM_CP_SUPPRESS_TB_END;
+ }
+ define_one_arm_cp_reg(cpu, &sctlr_el3);
}
}
@@ -3475,7 +3510,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
return; /* Never happens. Keep compiler happy. */
}
/* High vectors. */
- if (env->cp15.c1_sys & SCTLR_V) {
+ if (arm_current_sctlr(env) & SCTLR_V) {
/* when enabled, base address cannot be remapped. */
addr += 0xffff0000;
} else {
@@ -3498,7 +3533,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
/* this is a lie, as the was no c1_sys on V4T/V5, but who cares
* and we should just guard the thumb mode on V4 */
if (arm_feature(env, ARM_FEATURE_V4T)) {
- env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0;
+ env->thumb = (arm_current_sctlr(env) & SCTLR_TE) != 0;
}
env->regs[14] = env->regs[15] + offset;
env->regs[15] = addr;
@@ -3529,7 +3564,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
}
if (access_type == 1)
return 0;
- switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) {
+ switch (arm_current_sctlr(env) & (SCTLR_S | SCTLR_R)) {
case SCTLR_S:
return is_user ? 0 : PAGE_READ;
case SCTLR_R:
@@ -3763,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
goto do_fault;
/* The simplified model uses AP[0] as an access control bit. */
- if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) {
+ if ((arm_current_sctlr(env) & SCTLR_AFE) && (ap & 1) == 0) {
/* Access flag fault. */
code = (code == 15) ? 6 : 3;
goto do_fault;
@@ -4099,7 +4134,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
if (address < 0x02000000)
address += env->cp15.c13_fcse;
- if ((env->cp15.c1_sys & SCTLR_M) == 0) {
+ if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
/* MMU/MPU disabled. */
*phys_ptr = address;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -4112,7 +4147,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
} else if (extended_addresses_enabled(env)) {
return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
prot, page_size);
- } else if (env->cp15.c1_sys & SCTLR_XP) {
+ } else if (arm_current_sctlr(env) & SCTLR_XP) {
return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
prot, page_size);
} else {
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index fb90676..3eacea8 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -365,7 +365,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
* Note that SPSel is never OK from EL0; we rely on handle_msr_i()
* to catch that case at translate time.
*/
- if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
+ if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
raise_exception(env, EXCP_UDEF);
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (15 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-14 17:32 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers Fabian Aggeler
` (6 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Fabian Aggeler, peter.maydell
This way less case distinctions are necessary for different modes/worlds
as the reginfos already point at the correct offset.
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/helper.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index ac8b15a..757e07b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -319,7 +319,7 @@ static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
- env->cp15.c3 = value;
+ raw_write(env, ri, value);
tlb_flush(CPU(cpu), 1); /* Flush TLB as domain not tracked in TLB */
}
@@ -327,12 +327,12 @@ static void fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
- if (env->cp15.c13_fcse != value) {
+ if (raw_read(env, ri) != value) {
/* Unlike real hardware the qemu TLB uses virtual addresses,
* not modified virtual addresses, so this causes a TLB flush.
*/
tlb_flush(CPU(cpu), 1);
- env->cp15.c13_fcse = value;
+ raw_write(env, ri, value);
}
}
@@ -341,7 +341,7 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
ARMCPU *cpu = arm_env_get_cpu(env);
- if (env->cp15.contextidr_el1 != value && !arm_feature(env, ARM_FEATURE_MPU)
+ if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_MPU)
&& !extended_addresses_enabled(env)) {
/* For VMSA (when not using the LPAE long descriptor page table
* format) this register includes the ASID, so do a TLB flush.
@@ -349,7 +349,7 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
*/
tlb_flush(CPU(cpu), 1);
}
- env->cp15.contextidr_el1 = value;
+ raw_write(env, ri, value);
}
static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -680,7 +680,7 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
* contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
* requires the bottom five bits to be RAZ/WI because they're UNK/SBZP.)
*/
- env->cp15.c12_vbar = value & ~0x1FULL;
+ raw_write(env, ri, value & ~0x1Ful);
}
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -692,7 +692,7 @@ static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- env->cp15.c0_cssel = value & 0xf;
+ raw_write(env, ri, value & 0xf);
}
static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -1212,11 +1212,11 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
if (arm_feature(env, ARM_FEATURE_LPAE)) {
- env->cp15.par_el1 = value;
+ raw_write(env, ri, value);
} else if (arm_feature(env, ARM_FEATURE_V7)) {
- env->cp15.par_el1 = value & 0xfffff6ff;
+ raw_write(env, ri, value & 0xfffff6ff);
} else {
- env->cp15.par_el1 = value & 0xfffff1ff;
+ raw_write(env, ri, value & 0xfffff1ff);
}
}
@@ -1424,7 +1424,7 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
* for long-descriptor tables the TTBCR fields are used differently
* and the c2_mask and c2_base_mask values are meaningless.
*/
- env->cp15.c2_control = value;
+ raw_write(env, ri, value);
env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift);
env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift);
}
@@ -1457,7 +1457,7 @@ static void vmsa_tcr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */
tlb_flush(CPU(cpu), 1);
- env->cp15.c2_control = value;
+ raw_write(env, ri, value);
}
static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -2111,7 +2111,7 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
| SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
}
- env->cp15.c1_sys = value;
+ raw_write(env, ri, value);
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu), 1);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (16 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-14 19:47 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers Fabian Aggeler
` (5 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
Use new macro A32_BANKED_REG() for registers which are banked in Aarch32
and not mapped an EL3 register in Aarch64.
Using raw_write and raw_read in .readfn/.writefn to be able to use the
same .readfn/writefn for secure and non-secure instance without case
distinction.
Whenever accessing banked registers using A32_BANKED_REG_GET macro or
A32_MAPPED_EL3_REG_GET for registers which we map to EL3 registers.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
linux-user/main.c | 2 +-
target-arm/cpu.h | 32 ++++++----
target-arm/helper-a64.c | 3 +-
target-arm/helper.c | 155 ++++++++++++++++++++++++++++++++++--------------
4 files changed, 132 insertions(+), 60 deletions(-)
diff --git a/linux-user/main.c b/linux-user/main.c
index c38fecf..809d731 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -566,7 +566,7 @@ do_kernel_trap(CPUARMState *env)
end_exclusive();
break;
case 0xffff0fe0: /* __kernel_get_tls */
- env->regs[0] = env->cp15.tpidrro_el0;
+ env->regs[0] = A32_BANKED_CURRENT_REG_GET(env, tpidrro_el0);
break;
case 0xffff0f60: /* __kernel_cmpxchg64 */
arm_kernel_cmpxchg64_helper(env);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 780c1f5..c20c44a 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -179,7 +179,8 @@ typedef struct CPUARMState {
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
- uint64_t c0_cssel; /* Cache size selection. */
+ A32_BANKED_REG(uint64_t, c0_cssel); /* Cache size selection
+ (banked in Aarch32). */
uint64_t c1_sys_el1; /* System control register (EL1). */
uint64_t c1_sys_el3; /* System control register (EL3). */
uint64_t c1_coproc; /* Coprocessor access register. */
@@ -187,22 +188,28 @@ typedef struct CPUARMState {
uint32_t c1_scr; /* secure config register. */
uint32_t c1_sder; /* Secure debug enable register. */
uint32_t c1_nsacr; /* Non-secure access control register. */
- uint64_t ttbr0_el1; /* MMU translation table base 0. */
- uint64_t ttbr1_el1; /* MMU translation table base 1. */
- uint64_t c2_control; /* MMU translation table base control. */
+ uint64_t ttbr0_el1;/* MMU translation table base 0. */
+ uint64_t ttbr0_el3;
+ uint64_t ttbr1_el1;/* MMU translation table base 1. */
+ uint64_t ttbr1_el3;
+ A32_BANKED_REG(uint64_t, c2_control);/* MMU translation table base
+ control. (banked in Aarch32) */
uint32_t c2_mask; /* MMU translation table base selection mask. */
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
uint32_t c2_data; /* MPU data cachable bits. */
uint32_t c2_insn; /* MPU instruction cachable bits. */
- uint32_t c3; /* MMU domain access control register
+ A32_BANKED_REG(uint32_t, c3); /* MMU domain access control register
MPU write buffer control. */
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
- uint32_t ifsr_el2; /* Fault status registers. */
+ A32_BANKED_REG(uint32_t, ifsr_el2); /* Fault status registers. */
uint64_t esr_el1;
+ uint64_t esr_el3;
uint32_t c6_region[8]; /* MPU base/size registers. */
uint64_t far_el1; /* Fault address registers. */
+ uint64_t far_el3;
uint64_t par_el1; /* Translation result. */
+ uint64_t par_el3;
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
uint32_t c9_pmcr; /* performance monitor control register */
@@ -212,12 +219,13 @@ typedef struct CPUARMState {
uint32_t c9_pmuserenr; /* perf monitor user enable */
uint32_t c9_pminten; /* perf monitor interrupt enables */
uint64_t mair_el1;
- uint64_t c12_vbar; /* vector base address register */
- uint32_t c13_fcse; /* FCSE PID. */
- uint64_t contextidr_el1; /* Context ID. */
- uint64_t tpidr_el0; /* User RW Thread register. */
- uint64_t tpidrro_el0; /* User RO Thread register. */
- uint64_t tpidr_el1; /* Privileged Thread register. */
+ uint64_t c12_vbar_el1; /* vector base address register */
+ uint64_t c12_vbar_el3; /* vector base address register */
+ A32_BANKED_REG(uint32_t, c13_fcse); /* FCSE PID. */
+ A32_BANKED_REG(uint64_t, contextidr_el1); /* Context ID. */
+ A32_BANKED_REG(uint64_t, tpidr_el0); /* User RW Thread register. */
+ A32_BANKED_REG(uint64_t, tpidrro_el0); /* User RO Thread register. */
+ A32_BANKED_REG(uint64_t, tpidr_el1); /* Privileged Thread register. */
uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */
ARMGenericTimer c14_timer[NUM_GTIMERS];
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index bf921cc..765ddf5 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -443,7 +443,8 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
- target_ulong addr = env->cp15.c12_vbar;
+ target_ulong addr = (arm_current_pl(env) == 3) ?
+ env->cp15.c12_vbar_el3 : env->cp15.c12_vbar_el1;
int i;
if (arm_current_pl(env) == 0) {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 757e07b..c76a86b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -397,10 +397,11 @@ static const ARMCPRegInfo cp_reginfo[] = {
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse),
- .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, },
+ .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write,
+ .type = ARM_CP_BANKED },
{ .name = "CONTEXTIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1,
- .access = PL1_RW,
+ .access = PL1_RW, .type = ARM_CP_BANKED_64BIT,
.fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1),
.resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, },
REGINFO_SENTINEL
@@ -413,7 +414,8 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = {
/* MMU Domain access control / MPU write buffer control */
{ .name = "DACR", .cp = 15,
.crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3),
+ .access = PL1_RW, .type = ARM_CP_BANKED,
+ .fieldoffset = offsetof(CPUARMState, cp15.c3),
.resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, },
/* ??? This covers not just the impdef TLB lockdown registers but also
* some v7VMSA registers relating to TEX remap, so it is overly broad.
@@ -519,9 +521,13 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
{ .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
.access = PL0_W, .type = ARM_CP_NOP },
{ .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
- .access = PL1_RW,
+ .access = PL1_RW, .type = ARM_CP_NONSECURE,
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
.resetvalue = 0, },
+ { .name = "IFAR(S)", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .access = PL3_RW, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el3),
+ .resetvalue = 0, },
/* Watchpoint Fault Address Register : should actually only be present
* for 1136, 1176, 11MPCore.
*/
@@ -686,7 +692,7 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = arm_env_get_cpu(env);
- return cpu->ccsidr[env->cp15.c0_cssel];
+ return cpu->ccsidr[A32_BANKED_REG_GET(env, c0_cssel)];
}
static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -786,15 +792,25 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
.resetvalue = 0, .writefn = pmintenclr_write, },
- { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
+ { .name = "VBAR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .writefn = vbar_write,
- .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
+ .access = PL1_RW, .writefn = vbar_write, .type = ARM_CP_NONSECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el1),
+ .resetvalue = 0 },
+ { .name = "VBAR_EL1(S)",
+ .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .writefn = vbar_write, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el3),
+ .resetvalue = 0 },
+ { .name = "VBAR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 4, .opc2 = 5,
+ .access = PL3_RW, .writefn = vbar_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el3),
.resetvalue = 0 },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
- { .name = "CSSELR", .state = ARM_CP_STATE_BOTH,
+ { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .type = ARM_CP_BANKED_64BIT,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel),
.writefn = csselr_write, .resetvalue = 0 },
@@ -871,7 +887,7 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
.access = PL0_RW,
.fieldoffset = offsetof(CPUARMState, cp15.tpidr_el0), .resetvalue = 0 },
{ .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2,
- .access = PL0_RW,
+ .access = PL0_RW, .type = ARM_CP_BANKED_64BIT,
.fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0),
.resetfn = arm_cp_reset_ignore },
{ .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64,
@@ -879,12 +895,12 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
.access = PL0_R|PL1_W,
.fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el0), .resetvalue = 0 },
{ .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3,
- .access = PL0_R|PL1_W,
+ .access = PL0_R|PL1_W, .type = ARM_CP_BANKED_64BIT,
.fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0),
.resetfn = arm_cp_reset_ignore },
{ .name = "TPIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0,
- .access = PL1_RW,
+ .access = PL1_RW, .type = ARM_CP_BANKED_64BIT,
.fieldoffset = offsetof(CPUARMState, cp15.tpidr_el1), .resetvalue = 0 },
REGINFO_SENTINEL
};
@@ -1263,7 +1279,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
* fault.
*/
}
- env->cp15.par_el1 = par64;
+ A32_MAPPED_EL3_REG_SET(env, par, par64);
} else {
/* ret is a DFSR/IFSR value for the short descriptor
* translation table format (with WnR always clear).
@@ -1273,14 +1289,15 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
/* We do not set any attribute bits in the PAR */
if (page_size == (1 << 24)
&& arm_feature(env, ARM_FEATURE_V7)) {
- env->cp15.par_el1 = (phys_addr & 0xff000000) | 1 << 1;
+ A32_MAPPED_EL3_REG_SET(env, par,
+ (phys_addr & 0xff000000) | 1 << 1);
} else {
- env->cp15.par_el1 = phys_addr & 0xfffff000;
+ A32_MAPPED_EL3_REG_SET(env, par, phys_addr & 0xfffff000);
}
} else {
- env->cp15.par_el1 = ((ret & (1 << 10)) >> 5) |
+ A32_MAPPED_EL3_REG_SET(env, par, ((ret & (1 << 10)) >> 5) |
((ret & (1 << 12)) >> 6) |
- ((ret & 0xf) << 1) | 1;
+ ((ret & 0xf) << 1) | 1);
}
}
}
@@ -1288,9 +1305,13 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
static const ARMCPRegInfo vapa_cp_reginfo[] = {
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .resetvalue = 0,
+ .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_NONSECURE,
.fieldoffset = offsetoflow32(CPUARMState, cp15.par_el1),
.writefn = par_write },
+ { .name = "PAR(S)", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .resetvalue = 0, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.par_el3),
+ .writefn = par_write },
#ifndef CONFIG_USER_ONLY
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
.access = PL1_W, .accessfn = ats_access,
@@ -1476,23 +1497,39 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static const ARMCPRegInfo vmsa_cp_reginfo[] = {
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
+ .access = PL1_RW, .type = ARM_CP_NO_MIGRATE | ARM_CP_NONSECURE,
.fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
.resetfn = arm_cp_reset_ignore, },
+ { .name = "DFSR(S)", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .type = ARM_CP_SECURE, .resetvalue = 0,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el3) },
{ .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
- .access = PL1_RW,
+ .access = PL1_RW, .type = ARM_CP_BANKED,
.fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, },
{ .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
+ { .name = "ESR_EL3", .state = ARM_CP_STATE_AA64, .crn = 5, .crm = 2,
+ .opc0 = 3, .opc1 = 6, .opc2 = 0, .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.esr_el3) },
{ .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
+ .access = PL1_RW, .type = ARM_CP_NONSECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
+ .writefn = vmsa_ttbr_write, .resetvalue = 0 },
+ { .name = "TTBR0(S)", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3),
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
{ .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
+ .access = PL1_RW, .type = ARM_CP_NONSECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
+ .writefn = vmsa_ttbr_write, .resetvalue = 0 },
+ { .name = "TTBR1(S)", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3),
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
{ .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
@@ -1500,14 +1537,18 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
.fieldoffset = offsetof(CPUARMState, cp15.c2_control) },
{ .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
- .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
- .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
+ .access = PL1_RW, .type = ARM_CP_NO_MIGRATE | ARM_CP_BANKED_64BIT,
+ .writefn = vmsa_ttbcr_write, .resetfn = arm_cp_reset_ignore,
+ .raw_writefn = vmsa_ttbcr_raw_write,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
/* 64-bit FAR; this entry also gives us the AArch32 DFAR */
- { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
+ { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH, .type = ARM_CP_NONSECURE,
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
.resetvalue = 0, },
+ { .name = "DFAR(S)", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .type = ARM_CP_SECURE, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.far_el3)},
REGINFO_SENTINEL
};
@@ -1545,9 +1586,15 @@ static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
static const ARMCPRegInfo omap_cp_reginfo[] = {
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
- .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
+ .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW,
+ .type = ARM_CP_OVERRIDE | ARM_CP_NONSECURE,
.fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
.resetvalue = 0, },
+ { .name = "DFSR(S)", .cp = 15, .crn = 5, .crm = CP_ANY,
+ .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL3_RW,
+ .type = ARM_CP_OVERRIDE | ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el3),
+ .resetvalue = 0, },
{ .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
@@ -1730,7 +1777,13 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
{ .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
- .access = PL1_RW, .type = ARM_CP_64BIT,
+ .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NONSECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 },
+ { .name = "PAR(S)", .cp = 15, .crm = 7, .opc1 = 0,
+ .access = PL3_RW, .type = ARM_CP_64BIT | ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.par_el3), .resetvalue = 0 },
+ { .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .crn = 7, .crm = 4, .opc2 = 0, .access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 },
{ .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
@@ -2131,6 +2184,10 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
.resetvalue = 0, },
+ { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
+ .resetvalue = 0 },
{ .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
.access = PL3_RW, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
@@ -3469,22 +3526,25 @@ void arm_cpu_do_interrupt(CPUState *cs)
env->exception.fsr = 2;
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
- env->cp15.ifsr_el2 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
- env->exception.vaddress);
+ A32_BANKED_CURRENT_REG_SET(env, ifsr_el2, env->exception.fsr);
+ A32_MAPPED_EL3_CURRENT_REG_SET(env, far,
+ deposit64(A32_MAPPED_EL3_CURRENT_REG_GET(env, far), 32, 32,
+ env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
- env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
+ A32_BANKED_CURRENT_REG_GET(env, ifsr_el2),
+ (uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x0c;
mask = CPSR_A | CPSR_I;
offset = 4;
break;
case EXCP_DATA_ABORT:
- env->cp15.esr_el1 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
- env->exception.vaddress);
+ A32_MAPPED_EL3_CURRENT_REG_SET(env, esr, env->exception.fsr);
+ A32_MAPPED_EL3_CURRENT_REG_SET(env, far,
+ deposit64(A32_MAPPED_EL3_CURRENT_REG_GET(env, far), 0, 32,
+ env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
- (uint32_t)env->cp15.esr_el1,
+ (uint32_t)A32_MAPPED_EL3_CURRENT_REG_GET(env, esr),
(uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x10;
@@ -3521,7 +3581,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
* and is never in monitor mode this feature is always active.
* Note: only bits 31:5 are valid.
*/
- addr += env->cp15.c12_vbar;
+ addr += A32_MAPPED_EL3_CURRENT_REG_GET(env, c12_vbar);
}
switch_mode (env, new_mode);
env->spsr = cpsr_read(env);
@@ -3601,9 +3661,10 @@ static uint32_t get_level1_table_address(CPUARMState *env, uint32_t address)
uint32_t table;
if (address & env->cp15.c2_mask)
- table = env->cp15.ttbr1_el1 & 0xffffc000;
+ table = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr1) & 0xffffc000;
else
- table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask;
+ table =
+ A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr0) & env->cp15.c2_base_mask;
table |= (address >> 18) & 0x3ffc;
return table;
@@ -3737,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
/* Page or Section. */
domain = (desc >> 5) & 0x0f;
}
- domain_prot = (env->cp15.c3 >> (domain * 2)) & 3;
+ domain_prot = (A32_BANKED_CURRENT_REG_GET(env, c3) >> (domain * 2)) & 3;
if (domain_prot == 0 || domain_prot == 2) {
if (type != 1) {
code = 9; /* Section domain fault. */
@@ -3863,12 +3924,14 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
* This is a Non-secure PL0/1 stage 1 translation, so controlled by
* TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32:
*/
- uint32_t t0sz = extract32(env->cp15.c2_control, 0, 6);
+ uint32_t t0sz = extract32(
+ A32_BANKED_CURRENT_REG_GET(env, c2_control), 0, 6);
if (arm_el_is_aa64(env, 1)) {
t0sz = MIN(t0sz, 39);
t0sz = MAX(t0sz, 16);
}
- uint32_t t1sz = extract32(env->cp15.c2_control, 16, 6);
+ uint32_t t1sz = extract32(
+ A32_BANKED_CURRENT_REG_GET(env, c2_control), 16, 6);
if (arm_el_is_aa64(env, 1)) {
t1sz = MIN(t1sz, 39);
t1sz = MAX(t1sz, 16);
@@ -3899,8 +3962,8 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
* we will always flush the TLB any time the ASID is changed).
*/
if (ttbr_select == 0) {
- ttbr = env->cp15.ttbr0_el1;
- epd = extract32(env->cp15.c2_control, 7, 1);
+ ttbr = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr0);
+ epd = extract32(A32_BANKED_CURRENT_REG_GET(env, c2_control), 7, 1);
tsz = t0sz;
tg = extract32(env->cp15.c2_control, 14, 2);
@@ -3911,8 +3974,8 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
granule_sz = 11;
}
} else {
- ttbr = env->cp15.ttbr1_el1;
- epd = extract32(env->cp15.c2_control, 23, 1);
+ ttbr = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr1);
+ epd = extract32(A32_BANKED_CURRENT_REG_GET(env, c2_control), 23, 1);
tsz = t1sz;
tg = extract32(env->cp15.c2_control, 30, 2);
@@ -4132,7 +4195,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
{
/* Fast Context Switch Extension. */
if (address < 0x02000000)
- address += env->cp15.c13_fcse;
+ address += A32_BANKED_CURRENT_REG_GET(env, c13_fcse);
if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
/* MMU/MPU disabled. */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (17 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-14 21:20 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 20/23] target-arm: add MVBAR support Fabian Aggeler
` (4 subsequent siblings)
23 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
Some of SCTRL bits are common for secure and non-secure state.
Translation table base masks are updated on NS-bit switch as
well as on TTBCR writes.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 10 ++++++++++
target-arm/helper.c | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c20c44a..7893004 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -425,6 +425,14 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
#define SCTLR_AFE (1U << 29)
#define SCTLR_TE (1U << 30)
+/* Bitmask for banked bits (Security Extensions) */
+#define SCTLR_BANKED (SCTLR_TE | SCTLR_AFE | SCTLR_TRE | SCTLR_EE | \
+ SCTLR_VE | SCTLR_HA | SCTLR_UWXN | SCTLR_WXN | SCTLR_V | \
+ SCTLR_I | SCTLR_Z | SCTLR_SW | SCTLR_CP15BEN | SCTLR_C | \
+ SCTLR_A | SCTLR_M)
+/* Treat bits that are not explicitly banked as common */
+#define SCTLR_COMMON (~SCTLR_BANKED)
+
#define CPSR_M (0x1fU)
#define CPSR_T (1U << 5)
#define CPSR_F (1U << 6)
@@ -662,6 +670,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
return (env->features & (1ULL << feature)) != 0;
}
+#define SCR_NS (1U << 0)
+
/* Return true if the processor is in secure state */
static inline bool arm_is_secure(CPUARMState *env)
{
diff --git a/target-arm/helper.c b/target-arm/helper.c
index c76a86b..618fd31 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2165,12 +2165,49 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
raw_write(env, ri, value);
+
+ if (!arm_el_is_aa64(env, 3)) {
+ /* Aarch32 has some bits that are common to secure (mapped to
+ * SCTLR_EL3) and non-secure instances of the SCTLR. */
+
+ env->cp15.c1_sys_el1 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ env->cp15.c1_sys_el3 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ }
+
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu), 1);
}
#ifndef CONFIG_USER_ONLY
+static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
+{
+ if (!arm_el_is_aa64(env, 3) &&
+ (value & SCR_NS) != (env->cp15.c1_scr & SCR_NS)) {
+ /* If EL3 is using Aarch32 switching NS-bit may make the CPU use a
+ * different instance (secure or non-secure) when accessing CP
+ * registers.
+ * Common bits of otherwise banked registers need to by synchronized
+ * at this point.
+ */
+ env->cp15.c1_sys_el1 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ env->cp15.c1_sys_el3 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ }
+
+ env->cp15.c1_scr = value;
+
+ /* After possible switch, calculate c2_mask and c2_base_mask again for the
+ * instance which is now active (secure or non-secure).
+ */
+ int maskshift = extract32(A32_BANKED_REG_GET(env, c2_control), 0, 3);
+ env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift);
+ env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift);
+
+}
static void nsacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
@@ -2183,7 +2220,7 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
#ifndef CONFIG_USER_ONLY
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
+ .resetvalue = 0, .writefn = scr_write },
{ .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 20/23] target-arm: add MVBAR support
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (18 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 21/23] target-arm: implement SMC instruction Fabian Aggeler
` (3 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
Use MVBAR register as exception vector base address for
exceptions taken to CPU monitor mode.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 12 +++++++-----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 7893004..9b6f8bd 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -226,6 +226,7 @@ typedef struct CPUARMState {
A32_BANKED_REG(uint64_t, tpidr_el0); /* User RW Thread register. */
A32_BANKED_REG(uint64_t, tpidrro_el0); /* User RO Thread register. */
A32_BANKED_REG(uint64_t, tpidr_el1); /* Privileged Thread register. */
+ uint64_t c12_mvbar; /* (monitor) vector base address register */
uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */
ARMGenericTimer c14_timer[NUM_GTIMERS];
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 618fd31..808b822 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2225,6 +2225,9 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
.opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
.resetvalue = 0 },
+ { .name = "MVBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_mvbar) },
{ .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
.access = PL3_RW, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
@@ -3606,16 +3609,15 @@ void arm_cpu_do_interrupt(CPUState *cs)
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
return; /* Never happens. Keep compiler happy. */
}
- /* High vectors. */
- if (arm_current_sctlr(env) & SCTLR_V) {
+ if (new_mode == ARM_CPU_MODE_MON) {
+ addr += env->cp15.c12_mvbar;
+ } else if (arm_current_sctlr(env) & SCTLR_V) { /* High vectors. */
/* when enabled, base address cannot be remapped. */
addr += 0xffff0000;
} else {
/* ARM v7 architectures provide a vector base address register to remap
* the interrupt vector table.
- * This register is only followed in non-monitor mode, and has a secure
- * and un-secure copy. Since the cpu is always in a un-secure operation
- * and is never in monitor mode this feature is always active.
+ * This register is only followed in non-monitor mode, and is banked.
* Note: only bits 31:5 are valid.
*/
addr += A32_MAPPED_EL3_CURRENT_REG_GET(env, c12_vbar);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 21/23] target-arm: implement SMC instruction
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (19 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 20/23] target-arm: add MVBAR support Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 22/23] target-arm: implement IRQ/FIQ routing to Monitor mode Fabian Aggeler
` (2 subsequent siblings)
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
From: Sergey Fedorov <s.fedorov@samsung.com>
SMC instruction is implemented similar to SVC instruction. When
executing SMC instruction from monitor CPU mode SCR.NS bit is reset.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 11 +++++++++++
target-arm/translate.c | 38 ++++++++++++++++++++++++++++----------
target-arm/translate.h | 2 ++
4 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 9b6f8bd..f6261c2 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -51,6 +51,7 @@
#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */
#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */
#define EXCP_STREX 10
+#define EXCP_SMC 11 /* secure monitor call */
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 808b822..deff3de 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3605,6 +3605,12 @@ void arm_cpu_do_interrupt(CPUState *cs)
mask = CPSR_A | CPSR_I | CPSR_F;
offset = 4;
break;
+ case EXCP_SMC:
+ new_mode = ARM_CPU_MODE_MON;
+ addr = 0x08;
+ mask = CPSR_A | CPSR_I | CPSR_F;
+ offset = 0;
+ break;
default:
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
return; /* Never happens. Keep compiler happy. */
@@ -3622,6 +3628,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
*/
addr += A32_MAPPED_EL3_CURRENT_REG_GET(env, c12_vbar);
}
+
+ if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) {
+ env->cp15.c1_scr &= ~1 /* NS */;
+ }
+
switch_mode (env, new_mode);
env->spsr = cpsr_read(env);
/* Clear IT bits. */
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 3a429ac..e7a6cfa 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7767,15 +7767,23 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
case 7:
{
int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
- /* SMC instruction (op1 == 3)
- and undefined instructions (op1 == 0 || op1 == 2)
- will trap */
- if (op1 != 1) {
+ if (op1 == 1) {
+ /* bkpt */
+ ARCH(5);
+ gen_exception_insn(s, 4, EXCP_BKPT,
+ syn_aa32_bkpt(imm16, false));
+ } else if (op1 == 3) {
+ /* smi/smc */
+ if (!arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) ||
+ IS_USER(s)) {
+ goto illegal_op;
+ }
+ gen_set_pc_im(s, s->pc);
+ s->is_jmp = DISAS_SMC;
+ break;
+ } else {
goto illegal_op;
}
- /* bkpt */
- ARCH(5);
- gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));
break;
}
case 0x8: /* signed multiply */
@@ -9597,9 +9605,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
if (insn & (1 << 26)) {
/* Secure monitor call (v6Z) */
- qemu_log_mask(LOG_UNIMP,
- "arm: unimplemented secure monitor call\n");
- goto illegal_op; /* not implemented. */
+ if (!arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) ||
+ IS_USER(s)) {
+ goto illegal_op;
+ }
+ gen_set_pc_im(s, s->pc);
+ s->is_jmp = DISAS_SMC;
} else {
op = (insn >> 20) & 7;
switch (op) {
@@ -10998,6 +11009,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI) {
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
+ } else if (dc->is_jmp == DISAS_SMC) {
+ gen_exception(EXCP_SMC, syn_uncategorized());
} else {
gen_exception_internal(EXCP_DEBUG);
}
@@ -11010,6 +11023,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
+ } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
+ gen_exception(EXCP_SMC, syn_uncategorized());
} else {
/* FIXME: Single stepping a WFI insn will not halt
the CPU. */
@@ -11047,6 +11062,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
case DISAS_SWI:
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
break;
+ case DISAS_SMC:
+ gen_exception(EXCP_SMC, syn_uncategorized());
+ break;
}
if (dc->condjmp) {
gen_set_label(dc->condlabel);
diff --git a/target-arm/translate.h b/target-arm/translate.h
index eeb77fb..bd9a416 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -67,6 +67,8 @@ static inline int arm_dc_feature(DisasContext *dc, int feature)
#define DISAS_EXC 6
/* WFE */
#define DISAS_WFE 7
+/* Secure Monitor Call (SMC) */
+#define DISAS_SMC 8
#ifdef TARGET_AARCH64
void a64_translate_init(void);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 22/23] target-arm: implement IRQ/FIQ routing to Monitor mode
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (20 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 21/23] target-arm: implement SMC instruction Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 23/23] target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI Fabian Aggeler
2014-05-15 18:57 ` [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Sergey Fedorov
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, Fabian Aggeler, peter.maydell
SCR.{IRQ/FIQ} bits allows to route IRQ/FIQ exceptions to monitor CPU
mode. When taking IRQ exception to monitor mode FIQ exception is
additionally masked.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 2 ++
target-arm/helper.c | 9 +++++++++
2 files changed, 11 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f6261c2..212cb64 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -673,6 +673,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
}
#define SCR_NS (1U << 0)
+#define SCR_IRQ (1U << 1)
+#define SCR_FIQ (1U << 2)
/* Return true if the processor is in secure state */
static inline bool arm_is_secure(CPUARMState *env)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index deff3de..a5ba480 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3597,12 +3597,21 @@ void arm_cpu_do_interrupt(CPUState *cs)
/* Disable IRQ and imprecise data aborts. */
mask = CPSR_A | CPSR_I;
offset = 4;
+ if (env->cp15.c1_scr & SCR_IRQ) {
+ /* IRQ routed to monitor mode */
+ new_mode = ARM_CPU_MODE_MON;
+ mask |= CPSR_F;
+ }
break;
case EXCP_FIQ:
new_mode = ARM_CPU_MODE_FIQ;
addr = 0x1c;
/* Disable FIQ, IRQ and imprecise data aborts. */
mask = CPSR_A | CPSR_I | CPSR_F;
+ if (env->cp15.c1_scr & SCR_FIQ) {
+ /* FIQ routed to monitor mode */
+ new_mode = ARM_CPU_MODE_MON;
+ }
offset = 4;
break;
case EXCP_SMC:
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* [Qemu-devel] [PATCH v2 23/23] target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (21 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 22/23] target-arm: implement IRQ/FIQ routing to Monitor mode Fabian Aggeler
@ 2014-05-13 16:16 ` Fabian Aggeler
2014-05-15 18:57 ` [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Sergey Fedorov
23 siblings, 0 replies; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-13 16:16 UTC (permalink / raw)
To: qemu-devel; +Cc: edgar.iglesias, Fabian Aggeler, peter.maydell
bits when modifying CPSR.
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
---
target-arm/cpu.h | 2 ++
target-arm/helper.c | 41 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 212cb64..5de0c77 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -675,6 +675,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
#define SCR_NS (1U << 0)
#define SCR_IRQ (1U << 1)
#define SCR_FIQ (1U << 2)
+#define SCR_FW (1U << 4)
+#define SCR_AW (1U << 5)
/* Return true if the processor is in secure state */
static inline bool arm_is_secure(CPUARMState *env)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index a5ba480..7151325 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3169,9 +3169,6 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
env->GE = (val >> 16) & 0xf;
}
- env->daif &= ~(CPSR_AIF & mask);
- env->daif |= val & CPSR_AIF & mask;
-
if ((env->uncached_cpsr ^ val) & mask & CPSR_M) {
if (bad_mode_switch(env, val & CPSR_M)) {
/* Attempt to switch to an invalid mode: this is UNPREDICTABLE.
@@ -3183,6 +3180,44 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
switch_mode(env, val & CPSR_M);
}
}
+
+ /* In an implementation that does not include Virtualization Extensions
+ * the SCR.FW and SCR.AW bit control whether non-secure software is allowed
+ * to change the CPSR_F and CPSR_A bits respectively.
+ */
+ if ((mask & CPSR_A)
+ && (val & CPSR_A) != (env->uncached_cpsr & CPSR_A)
+ && arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)
+ && !(env->cp15.c1_scr & SCR_AW) && !arm_is_secure(env)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to switch CPSR_A "
+ "flag from non-secure world with SCR.AW bit set\n");
+ mask &= ~CPSR_A;
+ }
+
+ if ((mask & CPSR_F)) {
+
+ /* Check whether non-maskable FIQ (NMFI) support is enabled.
+ * If this bit is set software is not allowed to mask FIQs,
+ * but is allowed to set CPSR_F to 0.
+ */
+ if ((arm_current_sctlr(env) & SCTLR_NMFI) && (val & CPSR_F)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to enable CPSR_F "
+ "flag (non-maskable FIQ [NMFI] support enabled)\n");
+ mask &= ~CPSR_F;
+ }
+
+ if ((val & CPSR_F) != (env->uncached_cpsr & CPSR_F)
+ && arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)
+ && !(env->cp15.c1_scr & SCR_FW) && !arm_is_secure(env)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to switch CPSR_F "
+ "flag from non-secure world with SCR.FW bit set\n");
+ mask &= ~CPSR_F;
+ }
+ }
+
+ env->daif &= ~(CPSR_AIF & mask);
+ env->daif |= val & CPSR_AIF & mask;
+
mask &= ~CACHED_CPSR_BITS;
env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR Fabian Aggeler
@ 2014-05-14 5:43 ` Sergey Fedorov
2014-05-21 16:12 ` Peter Maydell
0 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-14 5:43 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel
Cc: edgar.iglesias, Sergey Fedorov, Svetlana Fedoseeva, peter.maydell
On 13.05.2014 20:15, Fabian Aggeler wrote:
> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>
> Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 9c3269f..2b57ad9 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2083,6 +2083,11 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
>
> + if (arm_feature(env, ARM_FEATURE_V7)) {
> + value |= SCTLR_XP | SCTLR_U | SCTLR_nTWE | SCTLR_nTWI | SCTLR_L
> + | SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
Actually, some of these bits are RAO/WI since v6. Also, there are some
RAZ/WI bits varying over architecture variants. There is some overview
at ARM ARM v7-AP section L.7.4. Maybe it is worth to fix more precisely
over supported architecture variants? By the way, this patch could be
separated from security extensions support patch set.
Thanks,
Sergey.
> + }
> +
> env->cp15.c1_sys = value;
> /* ??? Lots of these bits are not implemented. */
> /* This may enable/disable the MMU, so do a TLB flush. */
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function Fabian Aggeler
@ 2014-05-14 5:53 ` Sergey Fedorov
2014-05-14 14:42 ` Greg Bellows
0 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-14 5:53 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
On 13.05.2014 20:15, Fabian Aggeler wrote:
> arm_is_secure() function allows to determine CPU security state
> if the CPU implements Security Extensions.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/cpu.h | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index a56d3d6..6ea0432 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -640,6 +640,21 @@ static inline int arm_feature(CPUARMState *env, int feature)
> return (env->features & (1ULL << feature)) != 0;
> }
>
> +/* Return true if the processor is in secure state */
> +static inline bool arm_is_secure(CPUARMState *env)
> +{
> +#if !defined(CONFIG_USER_ONLY)
> + if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
I think feature test can be safely avoided here. Without this feature
that should be no way to switch to monitor mode and to access SCR register.
> + return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
> + !(env->cp15.c1_scr & 1);
> + } else {
> + return false;
> + }
> +#else
> + return false;
That is a good question how to treat user emulation: secure or
non-secure. Perhaps assuming user emulation in secure state may simplify
code in the following patches.
> +#endif
> +}
> +
> /* Return true if the specified exception level is running in AArch64 state. */
> static inline bool arm_el_is_aa64(CPUARMState *env, int el)
> {
Thanks,
Sergey.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic Fabian Aggeler
@ 2014-05-14 6:06 ` Sergey Fedorov
2014-05-14 18:39 ` Fedorov Sergey
2014-05-14 13:09 ` Peter Crosthwaite
1 sibling, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-14 6:06 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
On 13.05.2014 20:15, Fabian Aggeler wrote:
> From: Sergey Fedorov <s.fedorov@samsung.com>
>
> CPACR register allows to control access rights to coprocessor 0-13
> interfaces. Bits corresponding to unimplemented coprocessors should be
> RAZ/WI. QEMU implements only VFP coprocessor on ARMv6+ targets. So only
> cp10 & cp11 bits are writable.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 6 ++++++
> target-arm/translate.c | 26 +++++++++++++++++++++++---
> 2 files changed, 29 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index cf1f88c..4e82259 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -477,6 +477,12 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
> static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> uint64_t value)
> {
> + uint32_t mask = 0;
> +
> + if (arm_feature(env, ARM_FEATURE_VFP)) {
> + mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
> + }
> + value &= mask;
> if (env->cp15.c1_coproc != value) {
> env->cp15.c1_coproc = value;
> /* ??? Is this safe when called from within a TB? */
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 87d0918..c815fb3 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6866,9 +6866,29 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> const ARMCPRegInfo *ri;
>
> cpnum = (insn >> 8) & 0xf;
> - if (arm_feature(env, ARM_FEATURE_XSCALE)
> - && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
> - return 1;
> + if (cpnum < 14) {
> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> + if (~env->cp15.c15_cpar & (1 << cpnum)) {
> + return 1;
> + }
> + } else {
> + /* Bits [20:21] of CPACR control access to cp10
> + * Bits [23:22] of CPACR control access to cp11 */
> + switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
> + case 0: /* access denied */
> + return 1;
> + case 1: /* privileged mode access only */
> + if (IS_USER(s)) {
> + return 1;
> + }
> + break;
> + case 2: /* reserved */
> + return 1;
> + case 3: /* privileged and user mode access */
> + break;
> + }
> + }
> + }
>
> /* First check for coprocessor space used for actual instructions */
> switch (cpnum) {
Please, look at disas_vfp_insn() and disas_neon_*_insn() functions.
Looks like them should be updated. In that case do not forget to adjust
arm_cpu_reset() so user emulation would be able to execute VFP/NEON
instructions.
Thanks,
Sergey.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64 Fabian Aggeler
@ 2014-05-14 6:15 ` Sergey Fedorov
0 siblings, 0 replies; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-14 6:15 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
On 13.05.2014 20:15, Fabian Aggeler wrote:
> This patch is based on ideas found in a patch at
> git://github.com/jowinter/qemu-trustzone.git
> a9ad01767c4b25e14700b5682a412f4fd8146ee8 by
> Johannes Winter <johannes.winter@iaik.tugraz.at>.
>
> Each world (secure and non-secure) has its own MMU state. Providing
> a separate TLB for each state prevents flushing it on each transition
> from secure to non-secure world and vice versa.
>
> For EL3 in Aarch64 state another MMU state is introduced since
> EL3 will be able to configure its own translation regime.
>
> Do not use IS_USER() macro anymore as MMU index in translation
> code. Use new MEM_INDEX() and MEM_INDEX_USER() macros instead.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/cpu.h | 42 +++++++-
> target-arm/helper.c | 2 +-
> target-arm/translate-a64.c | 9 +-
> target-arm/translate.c | 247 +++++++++++++++++++++++----------------------
> target-arm/translate.h | 1 +
> 5 files changed, 176 insertions(+), 125 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 76c9e90..a970d55 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -91,7 +91,7 @@ typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
>
> struct arm_boot_info;
>
> -#define NB_MMU_MODES 2
> +#define NB_MMU_MODES 5
>
> /* We currently assume float and double are IEEE single and double
> precision respectively.
> @@ -1104,10 +1104,43 @@ static inline CPUARMState *cpu_init(const char *cpu_model)
> /* MMU modes definitions */
> #define MMU_MODE0_SUFFIX _kernel
> #define MMU_MODE1_SUFFIX _user
> -#define MMU_USER_IDX 1
> +#define MMU_MODE2_SUFFIX _secure_kernel
> +#define MMU_MODE3_SUFFIX _secure_user
> +#define MMU_MODE4_SUFFIX _el3
> +#define MMU_USER_BIT 1
> +#define MMU_SECURE_BIT (1 << 1)
> +#define MMU_EL3_BIT (1 << 2)
> +#define MMU_KERN_IDX (0)
> +#define MMU_USER_IDX (MMU_USER_BIT)
> +#define MMU_SECURE_KERN_IDX (MMU_SECURE_BIT | MMU_KERN_IDX)
> +#define MMU_SECURE_USER_IDX (MMU_SECURE_BIT | MMU_USER_IDX)
> static inline int cpu_mmu_index (CPUARMState *env)
> {
> - return arm_current_pl(env) ? 0 : 1;
> + int mmu_index = 0;
> + int current_pl;
> + /* Security Extensions introduce two separate virtual MMUs for each CPU,
> + * one each for secure and non-secure world. If EL3 is in Aarch64 state it
> + * gets its own MMU which it can configure through the SCTLR_EL3 register.*/
> +
> + current_pl = arm_current_pl(env);
> + if (current_pl == 3 && arm_el_is_aa64(env, 3)) {
> + /* Bit 3: 1 for EL3 in Aarch64 state */
> + return 1 << 3;
> + } else {
> + /* Bit 0: 0 for PL1/2/3, 1 for PL0
> + * Bit 1: 0 for non-secure, 1 for secure
> + */
> + if (arm_is_secure(env)) {
> + mmu_index |= MMU_SECURE_BIT;
> + }
> +
> + if (current_pl == 0) {
> + mmu_index |= MMU_USER_BIT;
> + }
> +
> + return mmu_index;
> + }
> +
> }
>
> #include "exec/cpu-all.h"
> @@ -1182,6 +1215,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
> if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
> *flags |= ARM_TBFLAG_AA64_FPEN_MASK;
> }
> + if (!arm_is_secure(env)) {
> + *flags |= ARM_TBFLAG_NS_MASK;
> + }
> } else {
> int privmode;
> *pc = env->regs[15];
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 00dc4af..9326ef8 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -4079,7 +4079,7 @@ int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
> uint32_t syn;
> bool same_el = (arm_current_pl(env) != 0);
>
> - is_user = mmu_idx == MMU_USER_IDX;
> + is_user = mmu_idx & MMU_USER_BIT;
> ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,
> &page_size);
> if (ret == 0) {
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index b62db4d..1b4c932 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -167,7 +167,13 @@ static int get_mem_index(DisasContext *s)
> #ifdef CONFIG_USER_ONLY
> return 1;
> #else
> - return s->user;
> + /* EL3 in Aarch64 state has its own MMU */
> + if (s->current_pl == 3) {
> + return MMU_EL3_BIT;
> + } else {
> + return (s->user ? MMU_USER_BIT : 0) |
> + (s->ns ? 0 : MMU_SECURE_BIT);
> + }
> #endif
> }
>
> @@ -10661,6 +10667,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
> dc->condexec_cond = 0;
> #if !defined(CONFIG_USER_ONLY)
> dc->user = (ARM_TBFLAG_AA64_EL(tb->flags) == 0);
> + dc->ns = ARM_TBFLAG_NS(tb->flags);
This hank is better to be placed into the patch 9.
> #endif
> dc->cpacr_fpen = ARM_TBFLAG_AA64_FPEN(tb->flags);
> dc->vec_len = 0;
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 4ebd9f7..bbd4c77 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -54,9 +54,13 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
> #if defined(CONFIG_USER_ONLY)
> #define IS_USER(s) 1
> #define IS_NS(s) 1
> +#define MEM_INDEX(s) MMU_USER_IDX
> +#define MEM_INDEX_USER(S) MMU_USER_IDX
> #else
> #define IS_USER(s) (s->user)
> #define IS_NS(s) (s->ns)
> +#define MEM_INDEX(s) (s->mem_idx)
> +#define MEM_INDEX_USER(S) (MEM_INDEX(s) | MMU_USER_BIT)
> #endif
>
> TCGv_ptr cpu_env;
> @@ -1167,18 +1171,18 @@ VFP_GEN_FIX(ulto, )
> static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
> {
> if (dp) {
> - gen_aa32_ld64(cpu_F0d, addr, IS_USER(s));
> + gen_aa32_ld64(cpu_F0d, addr, MEM_INDEX(s));
> } else {
> - gen_aa32_ld32u(cpu_F0s, addr, IS_USER(s));
> + gen_aa32_ld32u(cpu_F0s, addr, MEM_INDEX(s));
> }
> }
>
> static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
> {
> if (dp) {
> - gen_aa32_st64(cpu_F0d, addr, IS_USER(s));
> + gen_aa32_st64(cpu_F0d, addr, MEM_INDEX(s));
> } else {
> - gen_aa32_st32(cpu_F0s, addr, IS_USER(s));
> + gen_aa32_st32(cpu_F0s, addr, MEM_INDEX(s));
> }
> }
>
> @@ -1516,24 +1520,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
> if (insn & ARM_CP_RW_BIT) {
> if ((insn >> 28) == 0xf) { /* WLDRW wCx */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> iwmmxt_store_creg(wrd, tmp);
> } else {
> i = 1;
> if (insn & (1 << 8)) {
> if (insn & (1 << 22)) { /* WLDRD */
> - gen_aa32_ld64(cpu_M0, addr, IS_USER(s));
> + gen_aa32_ld64(cpu_M0, addr, MEM_INDEX(s));
> i = 0;
> } else { /* WLDRW wRd */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> }
> } else {
> tmp = tcg_temp_new_i32();
> if (insn & (1 << 22)) { /* WLDRH */
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> } else { /* WLDRB */
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> }
> }
> if (i) {
> @@ -1545,24 +1549,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
> } else {
> if ((insn >> 28) == 0xf) { /* WSTRW wCx */
> tmp = iwmmxt_load_creg(wrd);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> } else {
> gen_op_iwmmxt_movq_M0_wRn(wrd);
> tmp = tcg_temp_new_i32();
> if (insn & (1 << 8)) {
> if (insn & (1 << 22)) { /* WSTRD */
> - gen_aa32_st64(cpu_M0, addr, IS_USER(s));
> + gen_aa32_st64(cpu_M0, addr, MEM_INDEX(s));
> } else { /* WSTRW wRd */
> tcg_gen_trunc_i64_i32(tmp, cpu_M0);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> }
> } else {
> if (insn & (1 << 22)) { /* WSTRH */
> tcg_gen_trunc_i64_i32(tmp, cpu_M0);
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> } else { /* WSTRB */
> tcg_gen_trunc_i64_i32(tmp, cpu_M0);
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> }
> }
> }
> @@ -2627,15 +2631,15 @@ static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
> TCGv_i32 tmp = tcg_temp_new_i32();
> switch (size) {
> case 0:
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> gen_neon_dup_u8(tmp, 0);
> break;
> case 1:
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> gen_neon_dup_low16(tmp);
> break;
> case 2:
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> default: /* Avoid compiler warnings. */
> abort();
> @@ -4306,11 +4310,11 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> if (size == 3) {
> tmp64 = tcg_temp_new_i64();
> if (load) {
> - gen_aa32_ld64(tmp64, addr, IS_USER(s));
> + gen_aa32_ld64(tmp64, addr, MEM_INDEX(s));
> neon_store_reg64(tmp64, rd);
> } else {
> neon_load_reg64(tmp64, rd);
> - gen_aa32_st64(tmp64, addr, IS_USER(s));
> + gen_aa32_st64(tmp64, addr, MEM_INDEX(s));
> }
> tcg_temp_free_i64(tmp64);
> tcg_gen_addi_i32(addr, addr, stride);
> @@ -4319,21 +4323,21 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> if (size == 2) {
> if (load) {
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> neon_store_reg(rd, pass, tmp);
> } else {
> tmp = neon_load_reg(rd, pass);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_gen_addi_i32(addr, addr, stride);
> } else if (size == 1) {
> if (load) {
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> tcg_gen_addi_i32(addr, addr, stride);
> tmp2 = tcg_temp_new_i32();
> - gen_aa32_ld16u(tmp2, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp2, addr, MEM_INDEX(s));
> tcg_gen_addi_i32(addr, addr, stride);
> tcg_gen_shli_i32(tmp2, tmp2, 16);
> tcg_gen_or_i32(tmp, tmp, tmp2);
> @@ -4343,10 +4347,10 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> tmp = neon_load_reg(rd, pass);
> tmp2 = tcg_temp_new_i32();
> tcg_gen_shri_i32(tmp2, tmp, 16);
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> tcg_gen_addi_i32(addr, addr, stride);
> - gen_aa32_st16(tmp2, addr, IS_USER(s));
> + gen_aa32_st16(tmp2, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp2);
> tcg_gen_addi_i32(addr, addr, stride);
> }
> @@ -4355,7 +4359,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> TCGV_UNUSED_I32(tmp2);
> for (n = 0; n < 4; n++) {
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> tcg_gen_addi_i32(addr, addr, stride);
> if (n == 0) {
> tmp2 = tmp;
> @@ -4375,7 +4379,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> } else {
> tcg_gen_shri_i32(tmp, tmp2, n * 8);
> }
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> tcg_gen_addi_i32(addr, addr, stride);
> }
> @@ -4499,13 +4503,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> tmp = tcg_temp_new_i32();
> switch (size) {
> case 0:
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 1:
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> default: /* Avoid compiler warnings. */
> abort();
> @@ -4523,13 +4527,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> tcg_gen_shri_i32(tmp, tmp, shift);
> switch (size) {
> case 0:
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> break;
> case 1:
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> break;
> }
> tcg_temp_free_i32(tmp);
> @@ -7202,14 +7206,14 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
>
> switch (size) {
> case 0:
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 1:
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> case 3:
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -7220,7 +7224,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
> TCGv_i32 tmp3 = tcg_temp_new_i32();
>
> tcg_gen_addi_i32(tmp2, addr, 4);
> - gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
> + gen_aa32_ld32u(tmp3, tmp2, MEM_INDEX(s));
> tcg_temp_free_i32(tmp2);
> tcg_gen_concat_i32_i64(cpu_exclusive_val, tmp, tmp3);
> store_reg(s, rt2, tmp3);
> @@ -7271,14 +7275,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> tmp = tcg_temp_new_i32();
> switch (size) {
> case 0:
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 1:
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> case 3:
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -7289,7 +7293,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> TCGv_i32 tmp2 = tcg_temp_new_i32();
> TCGv_i32 tmp3 = tcg_temp_new_i32();
> tcg_gen_addi_i32(tmp2, addr, 4);
> - gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
> + gen_aa32_ld32u(tmp3, tmp2, MEM_INDEX(s));
> tcg_temp_free_i32(tmp2);
> tcg_gen_concat_i32_i64(val64, tmp, tmp3);
> tcg_temp_free_i32(tmp3);
> @@ -7304,14 +7308,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> tmp = load_reg(s, rt);
> switch (size) {
> case 0:
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> break;
> case 1:
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> case 3:
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -7320,7 +7324,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> if (size == 3) {
> tcg_gen_addi_i32(addr, addr, 4);
> tmp = load_reg(s, rt2);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_gen_movi_i32(cpu_R[rd], 0);
> @@ -7367,11 +7371,11 @@ static void gen_srs(DisasContext *s,
> }
> tcg_gen_addi_i32(addr, addr, offset);
> tmp = load_reg(s, 14);
> - gen_aa32_st32(tmp, addr, 0);
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> tmp = load_cpu_field(spsr);
> tcg_gen_addi_i32(addr, addr, 4);
> - gen_aa32_st32(tmp, addr, 0);
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> if (writeback) {
> switch (amode) {
> @@ -7524,10 +7528,10 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> tcg_gen_addi_i32(addr, addr, offset);
> /* Load PC into tmp and CPSR into tmp2. */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, 0);
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> tcg_gen_addi_i32(addr, addr, 4);
> tmp2 = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp2, addr, 0);
> + gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
> if (insn & (1 << 21)) {
> /* Base writeback. */
> switch (i) {
> @@ -8116,13 +8120,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> tmp = tcg_temp_new_i32();
> switch (op1) {
> case 0: /* lda */
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> case 2: /* ldab */
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 3: /* ldah */
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -8133,13 +8137,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> tmp = load_reg(s, rm);
> switch (op1) {
> case 0: /* stl */
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> break;
> case 2: /* stlb */
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> break;
> case 3: /* stlh */
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -8194,11 +8198,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> tmp = load_reg(s, rm);
> tmp2 = tcg_temp_new_i32();
> if (insn & (1 << 22)) {
> - gen_aa32_ld8u(tmp2, addr, IS_USER(s));
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp2, addr, MEM_INDEX(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> } else {
> - gen_aa32_ld32u(tmp2, addr, IS_USER(s));
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> }
> tcg_temp_free_i32(tmp);
> tcg_temp_free_i32(addr);
> @@ -8220,14 +8224,14 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> tmp = tcg_temp_new_i32();
> switch(sh) {
> case 1:
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 2:
> - gen_aa32_ld8s(tmp, addr, IS_USER(s));
> + gen_aa32_ld8s(tmp, addr, MEM_INDEX(s));
> break;
> default:
> case 3:
> - gen_aa32_ld16s(tmp, addr, IS_USER(s));
> + gen_aa32_ld16s(tmp, addr, MEM_INDEX(s));
> break;
> }
> load = 1;
> @@ -8237,21 +8241,21 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> if (sh & 1) {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> tcg_gen_addi_i32(addr, addr, 4);
> tmp = load_reg(s, rd + 1);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> load = 0;
> } else {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> tcg_gen_addi_i32(addr, addr, 4);
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> rd++;
> load = 1;
> }
> @@ -8259,7 +8263,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> } else {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> load = 0;
> }
> @@ -8597,7 +8601,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> rn = (insn >> 16) & 0xf;
> rd = (insn >> 12) & 0xf;
> tmp2 = load_reg(s, rn);
> - i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
> + i = (insn & 0x01200000) == 0x00200000 ?
> + MEM_INDEX_USER(s) : MEM_INDEX(s);
> if (insn & (1 << 24))
> gen_add_data_offset(s, insn, tmp2);
> if (insn & (1 << 20)) {
> @@ -8681,7 +8686,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> if (insn & (1 << 20)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> if (user) {
> tmp2 = tcg_const_i32(i);
> gen_helper_set_user_reg(cpu_env, tmp2, tmp);
> @@ -8708,7 +8713,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
> } else {
> tmp = load_reg(s, i);
> }
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> j++;
> @@ -8974,20 +8979,20 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> if (insn & (1 << 20)) {
> /* ldrd */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rs, tmp);
> tcg_gen_addi_i32(addr, addr, 4);
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> } else {
> /* strd */
> tmp = load_reg(s, rs);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> tcg_gen_addi_i32(addr, addr, 4);
> tmp = load_reg(s, rd);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> if (insn & (1 << 21)) {
> @@ -9025,11 +9030,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tcg_gen_add_i32(addr, addr, tmp);
> tcg_temp_free_i32(tmp);
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> } else { /* tbb */
> tcg_temp_free_i32(tmp);
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> }
> tcg_temp_free_i32(addr);
> tcg_gen_shli_i32(tmp, tmp, 1);
> @@ -9066,13 +9071,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tmp = tcg_temp_new_i32();
> switch (op) {
> case 0: /* ldab */
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 1: /* ldah */
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 2: /* lda */
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -9082,13 +9087,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tmp = load_reg(s, rs);
> switch (op) {
> case 0: /* stlb */
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> break;
> case 1: /* stlh */
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> break;
> case 2: /* stl */
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> break;
> default:
> abort();
> @@ -9116,10 +9121,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tcg_gen_addi_i32(addr, addr, -8);
> /* Load PC into tmp and CPSR into tmp2. */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, 0);
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> tcg_gen_addi_i32(addr, addr, 4);
> tmp2 = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp2, addr, 0);
> + gen_aa32_ld32u(tmp2, addr, MEM_INDEX(s));
> if (insn & (1 << 21)) {
> /* Base writeback. */
> if (insn & (1 << 24)) {
> @@ -9158,7 +9163,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> if (insn & (1 << 20)) {
> /* Load. */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> if (i == 15) {
> gen_bx(s, tmp);
> } else if (i == rn) {
> @@ -9170,7 +9175,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> } else {
> /* Store. */
> tmp = load_reg(s, i);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_gen_addi_i32(addr, addr, 4);
> @@ -9870,7 +9875,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> {
> int postinc = 0;
> int writeback = 0;
> - int user;
> + int mem_idx;
> if ((insn & 0x01100000) == 0x01000000) {
> if (disas_neon_ls_insn(env, s, insn))
> goto illegal_op;
> @@ -9914,7 +9919,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> return 1;
> }
> }
> - user = IS_USER(s);
> + mem_idx = MEM_INDEX(s);
> if (rn == 15) {
> addr = tcg_temp_new_i32();
> /* PC relative. */
> @@ -9951,7 +9956,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> break;
> case 0xe: /* User privilege. */
> tcg_gen_addi_i32(addr, addr, imm);
> - user = 1;
> + mem_idx = MEM_INDEX_USER(s);
> break;
> case 0x9: /* Post-decrement. */
> imm = -imm;
> @@ -9978,19 +9983,19 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tmp = tcg_temp_new_i32();
> switch (op) {
> case 0:
> - gen_aa32_ld8u(tmp, addr, user);
> + gen_aa32_ld8u(tmp, addr, mem_idx);
> break;
> case 4:
> - gen_aa32_ld8s(tmp, addr, user);
> + gen_aa32_ld8s(tmp, addr, mem_idx);
> break;
> case 1:
> - gen_aa32_ld16u(tmp, addr, user);
> + gen_aa32_ld16u(tmp, addr, mem_idx);
> break;
> case 5:
> - gen_aa32_ld16s(tmp, addr, user);
> + gen_aa32_ld16s(tmp, addr, mem_idx);
> break;
> case 2:
> - gen_aa32_ld32u(tmp, addr, user);
> + gen_aa32_ld32u(tmp, addr, mem_idx);
> break;
> default:
> tcg_temp_free_i32(tmp);
> @@ -10007,13 +10012,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tmp = load_reg(s, rs);
> switch (op) {
> case 0:
> - gen_aa32_st8(tmp, addr, user);
> + gen_aa32_st8(tmp, addr, mem_idx);
> break;
> case 1:
> - gen_aa32_st16(tmp, addr, user);
> + gen_aa32_st16(tmp, addr, mem_idx);
> break;
> case 2:
> - gen_aa32_st32(tmp, addr, user);
> + gen_aa32_st32(tmp, addr, mem_idx);
> break;
> default:
> tcg_temp_free_i32(tmp);
> @@ -10150,7 +10155,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> addr = tcg_temp_new_i32();
> tcg_gen_movi_i32(addr, val);
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(addr);
> store_reg(s, rd, tmp);
> break;
> @@ -10353,28 +10358,28 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>
> switch (op) {
> case 0: /* str */
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> break;
> case 1: /* strh */
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> break;
> case 2: /* strb */
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> break;
> case 3: /* ldrsb */
> - gen_aa32_ld8s(tmp, addr, IS_USER(s));
> + gen_aa32_ld8s(tmp, addr, MEM_INDEX(s));
> break;
> case 4: /* ldr */
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> break;
> case 5: /* ldrh */
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> break;
> case 6: /* ldrb */
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> break;
> case 7: /* ldrsh */
> - gen_aa32_ld16s(tmp, addr, IS_USER(s));
> + gen_aa32_ld16s(tmp, addr, MEM_INDEX(s));
> break;
> }
> if (op >= 3) { /* load */
> @@ -10396,12 +10401,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> } else {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_temp_free_i32(addr);
> @@ -10418,12 +10423,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld8u(tmp, addr, IS_USER(s));
> + gen_aa32_ld8u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> } else {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st8(tmp, addr, IS_USER(s));
> + gen_aa32_st8(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_temp_free_i32(addr);
> @@ -10440,12 +10445,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld16u(tmp, addr, IS_USER(s));
> + gen_aa32_ld16u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> } else {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st16(tmp, addr, IS_USER(s));
> + gen_aa32_st16(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_temp_free_i32(addr);
> @@ -10461,12 +10466,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, rd, tmp);
> } else {
> /* store */
> tmp = load_reg(s, rd);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_temp_free_i32(addr);
> @@ -10534,12 +10539,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* pop */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> store_reg(s, i, tmp);
> } else {
> /* push */
> tmp = load_reg(s, i);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> /* advance to the next address. */
> @@ -10551,13 +10556,13 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* pop pc */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> /* don't set the pc until the rest of the instruction
> has completed */
> } else {
> /* push lr */
> tmp = load_reg(s, 14);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> tcg_gen_addi_i32(addr, addr, 4);
> @@ -10686,7 +10691,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> if (insn & (1 << 11)) {
> /* load */
> tmp = tcg_temp_new_i32();
> - gen_aa32_ld32u(tmp, addr, IS_USER(s));
> + gen_aa32_ld32u(tmp, addr, MEM_INDEX(s));
> if (i == rn) {
> loaded_var = tmp;
> } else {
> @@ -10695,7 +10700,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
> } else {
> /* store */
> tmp = load_reg(s, i);
> - gen_aa32_st32(tmp, addr, IS_USER(s));
> + gen_aa32_st32(tmp, addr, MEM_INDEX(s));
> tcg_temp_free_i32(tmp);
> }
> /* advance to the next address */
> @@ -10813,6 +10818,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
> #if !defined(CONFIG_USER_ONLY)
> dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
> dc->ns = ARM_TBFLAG_NS(tb->flags);
> + dc->mem_idx = (IS_USER(dc) ? MMU_USER_BIT : 0) |
> + (IS_NS(dc) ? 0 : MMU_SECURE_BIT);
> #endif
> dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags);
> dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
> diff --git a/target-arm/translate.h b/target-arm/translate.h
> index 5732738..eeb77fb 100644
> --- a/target-arm/translate.h
> +++ b/target-arm/translate.h
> @@ -20,6 +20,7 @@ typedef struct DisasContext {
> #if !defined(CONFIG_USER_ONLY)
> int user;
> int ns;
> + int mem_idx;
> #endif
> bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
> bool vfp_enabled; /* FP enabled via FPSCR.EN */
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic Fabian Aggeler
2014-05-14 6:06 ` Sergey Fedorov
@ 2014-05-14 13:09 ` Peter Crosthwaite
1 sibling, 0 replies; 75+ messages in thread
From: Peter Crosthwaite @ 2014-05-14 13:09 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov,
qemu-devel@nongnu.org Developers, Peter Maydell
On Tue, May 13, 2014 at 4:15 PM, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> From: Sergey Fedorov <s.fedorov@samsung.com>
>
> CPACR register allows to control access rights to coprocessor 0-13
> interfaces. Bits corresponding to unimplemented coprocessors should be
> RAZ/WI. QEMU implements only VFP coprocessor on ARMv6+ targets. So only
> cp10 & cp11 bits are writable.
>
Is this patch sec-ext specific? It looks to have no deps on EL3/MON so
is it candidate for more immediate merge?
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 6 ++++++
> target-arm/translate.c | 26 +++++++++++++++++++++++---
> 2 files changed, 29 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index cf1f88c..4e82259 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -477,6 +477,12 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
> static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> uint64_t value)
> {
> + uint32_t mask = 0;
> +
> + if (arm_feature(env, ARM_FEATURE_VFP)) {
> + mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
> + }
> + value &= mask;
> if (env->cp15.c1_coproc != value) {
> env->cp15.c1_coproc = value;
> /* ??? Is this safe when called from within a TB? */
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 87d0918..c815fb3 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6866,9 +6866,29 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> const ARMCPRegInfo *ri;
>
> cpnum = (insn >> 8) & 0xf;
> - if (arm_feature(env, ARM_FEATURE_XSCALE)
> - && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
> - return 1;
> + if (cpnum < 14) {
> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> + if (~env->cp15.c15_cpar & (1 << cpnum)) {
> + return 1;
> + }
> + } else {
> + /* Bits [20:21] of CPACR control access to cp10
> + * Bits [23:22] of CPACR control access to cp11 */
Newline before */
> + switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
> + case 0: /* access denied */
> + return 1;
> + case 1: /* privileged mode access only */
> + if (IS_USER(s)) {
> + return 1;
> + }
> + break;
> + case 2: /* reserved */
> + return 1;
This looks like a guest error and probably should get a
qemu_log(LOG_GUEST_ERROR,
Regards,
Peter
> + case 3: /* privileged and user mode access */
> + break;
> + }
> + }
> + }
>
> /* First check for coprocessor space used for actual instructions */
> switch (cpnum) {
> --
> 1.8.3.2
>
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list Fabian Aggeler
@ 2014-05-14 14:19 ` Greg Bellows
2014-05-15 9:28 ` Aggeler Fabian
2014-05-21 14:57 ` Peter Maydell
1 sibling, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 14:19 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
[-- Attachment #1: Type: text/plain, Size: 2525 bytes --]
On 13 May 2014 11:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> From: Sergey Fedorov <s.fedorov@samsung.com>
>
> Define a new ARM CP register info list for the Security Extension feature.
> Register that list only for ARM cores with Security Extension support.
> Moving SCR into Security Extension register group.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 3be917c..7898f40 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -768,9 +768,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
> .access = PL1_RW, .writefn = vbar_write,
> .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
> .resetvalue = 0 },
> - { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> - .resetvalue = 0, },
> { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
> .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
> @@ -2087,6 +2084,15 @@ static void sctlr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> tlb_flush(CPU(cpu), 1);
> }
>
> +static const ARMCPRegInfo tz_cp_reginfo[] = {
>
Sticking with the feature name switch from TRUSTZONE to SECURITY, for
consistency we should call this security_cp_reginfo.
> +#ifndef CONFIG_USER_ONLY
> + { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> + .resetvalue = 0, },
> +#endif
> + REGINFO_SENTINEL
> +};
> +
> static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo
> *ri)
> {
> /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
> @@ -2364,6 +2370,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> if (arm_feature(env, ARM_FEATURE_LPAE)) {
> define_arm_cp_regs(cpu, lpae_cp_reginfo);
> }
> + if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
> + define_arm_cp_regs(cpu, tz_cp_reginfo);
> + }
> /* Slightly awkwardly, the OMAP and StrongARM cores need all of
> * cp15 crn=0 to be writes-ignored, whereas for other cores they
> should
> * be read-only (ie write causes UNDEF exception).
> --
> 1.8.3.2
>
>
>
[-- Attachment #2: Type: text/html, Size: 3636 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 5:53 ` Sergey Fedorov
@ 2014-05-14 14:42 ` Greg Bellows
2014-05-14 18:35 ` Fedorov Sergey
0 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 14:42 UTC (permalink / raw)
To: Sergey Fedorov
Cc: Peter Maydell, Fabian Aggeler, Sergey Fedorov, QEMU Developers,
Edgar E. Iglesias
[-- Attachment #1: Type: text/plain, Size: 1928 bytes --]
On 14 May 2014 00:53, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> On 13.05.2014 20:15, Fabian Aggeler wrote:
> > arm_is_secure() function allows to determine CPU security state
> > if the CPU implements Security Extensions.
> >
> > Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> > Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> > ---
> > target-arm/cpu.h | 15 +++++++++++++++
> > 1 file changed, 15 insertions(+)
> >
> > diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> > index a56d3d6..6ea0432 100644
> > --- a/target-arm/cpu.h
> > +++ b/target-arm/cpu.h
> > @@ -640,6 +640,21 @@ static inline int arm_feature(CPUARMState *env, int
> feature)
> > return (env->features & (1ULL << feature)) != 0;
> > }
> >
> > +/* Return true if the processor is in secure state */
> > +static inline bool arm_is_secure(CPUARMState *env)
> > +{
> > +#if !defined(CONFIG_USER_ONLY)
> > + if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
>
> I think feature test can be safely avoided here. Without this feature
> that should be no way to switch to monitor mode and to access SCR register.
>
I agree with the feature check here. For correctness, we should only be
examining c1_scr if the security extension is enabled. This is consistent
with only registering the SCR register if the feature is enabled.
> > + return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
> > + !(env->cp15.c1_scr & 1);
> > + } else {
> > + return false;
> > + }
> > +#else
> > + return false;
>
> That is a good question how to treat user emulation: secure or
> non-secure. Perhaps assuming user emulation in secure state may simplify
> code in the following patches.
> > +#endif
> > +}
> > +
> > /* Return true if the specified exception level is running in AArch64
> state. */
> > static inline bool arm_el_is_aa64(CPUARMState *env, int el)
> > {
>
> Thanks,
> Sergey.
>
>
[-- Attachment #2: Type: text/html, Size: 2961 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
@ 2014-05-14 16:42 ` Greg Bellows
2014-05-15 9:02 ` Aggeler Fabian
2014-05-15 18:42 ` Sergey Fedorov
2014-05-22 7:41 ` Edgar E. Iglesias
2 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 16:42 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
[-- Attachment #1: Type: text/plain, Size: 17441 bytes --]
On 13 May 2014 11:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> Banked CP registers can be defined with a A32_BANKED_REG macro which
> defines
> a non-secure instance of the register followed by an adjacent secure
> instance.
> Using a union makes the code backwards-compatible since the non-secure
> instance can normally be accessed by its existing name.
>
This comment indicates that the 0th entry or the default name is the
non-secure bank, which differs from the code below.
>
> When translating a banked CP register access instruction in monitor mode,
> the SCR.NS bit determines which instance is going to be accessed.
>
> If EL3 is operating in Aarch64 state coprocessor registers are not
> banked anymore but in some cases have its own _EL3 instance.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/cpu.h | 121
> +++++++++++++++++++++++++++++++++++++++++++++----
> target-arm/helper.c | 64 ++++++++++++++++++++++++--
> target-arm/translate.c | 19 +++++---
> 3 files changed, 184 insertions(+), 20 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index a970d55..9e325ac 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -80,6 +80,16 @@
> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
> #endif
>
> +/* Define a banked coprocessor register state field. Use %name as the
> + * register field name for the secure instance. The non-secure instance
> + * has a "_nonsecure" suffix.
>
Where is the "_nonsecure" suffix?
The above comment appears to be incorrect as the code assumes that the 0th
entry as the non-secure bank.
+ */
> +#define A32_BANKED_REG(type, name) \
> + union { \
> + type name; \
> + type name##_banked[2]; \
> + }
> +
/* Meanings of the ARMCPU object's two inbound GPIO lines */
> #define ARM_CPU_IRQ 0
> #define ARM_CPU_FIQ 1
> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
> int dstreg, int operand);
>
> +
> struct arm_boot_info;
>
> #define NB_MMU_MODES 5
> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env,
> int el)
> return arm_feature(env, ARM_FEATURE_AARCH64);
> }
>
> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
> + * whether the secure instance of a cp-register should be used. */
> +#define USE_SECURE_REG(env) ( \
> + arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)
> && \
> + !arm_el_is_aa64(env, 3) && \
> + !((env)->cp15.c1_scr & 1/*NS*/))
> +
> +#define NONSECURE_BANK 0
> +#define SECURE_BANK 1
+
> +#define A32_BANKED_REG_GET(env, regname) \
> + ((USE_SECURE_REG(env)) ? \
> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> + (env)->cp15.regname)
> +
> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (USE_SECURE_REG(env))) ? \
> + (env)->cp15.regname##_el3 : \
> + (env)->cp15.regname##_el1)
> +
> +#define A32_BANKED_REG_SET(env, regname, val) \
> + do { \
> + if (USE_SECURE_REG(env)) { \
> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> + } else { \
> + (env)->cp15.regname = (val); \
> + } \
> + } while (0)
> +
> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
> + do { \
> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (USE_SECURE_REG(env))) { \
> + (env)->cp15.regname##_el3 = (val); \
> + } else { \
> + (env)->cp15.regname##_el1 = (val); \
> + } \
> + } while (0)
> +
> +
> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> + (env)->cp15.regname)
> +
> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
> + (env)->cp15.regname##_el3 : \
> + (env)->cp15.regname##_el1)
> +
> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
> + do { \
> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> + } else { \
> + (env)->cp15.regname = (val); \
> + } \
> + } while (0)
> +
> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
> + do { \
> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
> + (env)->cp15.regname##_el3 = (val); \
> + } else { \
> + (env)->cp15.regname##_el1 = (val); \
> + } \
> + } while (0)
> +
> +
> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>
> /* Interface between CPU and Interrupt controller. */
> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
> * Crn, Crm, opc1, opc2 fields
> * 32 or 64 bit register (ie is it accessed via MRC/MCR
> * or via MRRC/MCRR?)
> + * nonsecure/secure bank (Aarch32 only)
> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
> * (In this case crn and opc2 should be zero.)
> * For AArch64, there is no 32/64 bit size distinction;
> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
> #define CP_REG_AA64_SHIFT 28
> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>
> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
> - ((crm) << 7) | ((opc1) << 3) | (opc2))
> +/* To enable banking of coprocessor registers depending on ns-bit we
> + * add a bit to distinguish between secure and non-secure cpregs in the
> + * hashtable.
> + */
> +#define CP_REG_NS_SHIFT 27
> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
> +
> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>
> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
> (CP_REG_AA64_MASK | \
> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t
> cpregid)
> * IO indicates that this register does I/O and therefore its accesses
> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
> * registers which implement clocks or timers require this.
> + * In an implementation with Security Extensions supporting Aarch32 cp
> regs can
> + * be banked or common. If a register is common it references the same
> variable
> + * from both worlds (non-secure and secure). For cp regs which neither set
> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and
> it
> + * will be inserted twice into the hashtable. If a register has
> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but
> with
> + * different offset respectively. This way Aarch32 registers which can be
> + * mapped to Aarch64 PL3 registers can be inserted individually.
> */
> #define ARM_CP_SPECIAL 1
> #define ARM_CP_CONST 2
> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t
> cpregid)
> #define ARM_CP_OVERRIDE 16
> #define ARM_CP_NO_MIGRATE 32
> #define ARM_CP_IO 64
> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
> +#define ARM_CP_SECURE (1 << 7)
> +#define ARM_CP_NONSECURE (1 << 8)
> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
> /* Used only as a terminator for ARMCPRegInfo lists */
> #define ARM_CP_SENTINEL 0xffff
> /* Mask of only the flag bits in a type field */
> -#define ARM_CP_FLAG_MASK 0x7f
> +#define ARM_CP_FLAG_MASK 0x3ff
>
> /* Valid values for ARMCPRegInfo state field, indicating which of
> * the AArch32 and AArch64 execution states this register is visible in.
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 9326ef8..98c3dc9 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList
> *arch_query_cpu_definitions(Error **errp)
>
> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> void *opaque, int state,
> - int crm, int opc1, int opc2)
> + int crm, int opc1, int opc2, int nsbit)
> {
> /* Private utility function for define_one_arm_cp_reg_with_opaque():
> * add a single reginfo struct to the hash table.
> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu,
> const ARMCPRegInfo *r,
> }
> #endif
> }
> +
> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
+ if (r2->fieldoffset) {
> + /* We simplify register definitions by providing a type
> + * ARM_CP_BANKED, for which the fieldoffset of the secure
> instance
> + * will be increased to point at the second entry of the
> array.
> + *
> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to know
> how
> + * wide the banked register is because some registers are
> 64bit
> + * wide but the register is not defined as 64bit because it is
> + * mapped to the lower 32 bit.
> + * Therefore two separate types for 64bit banked registers and
> + * 32bit registers are used
> (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
> + */
> + r2->fieldoffset +=
> + ((r->type & ARM_CP_BANKED_64BIT) ==
> ARM_CP_BANKED_64BIT) ?
> + sizeof(uint64_t) : sizeof(uint32_t);
>
Do we want the register info descriptors of banked registers to point to
the same storage if the security extension is not enabled?
> + }
> + }
> + /* For A32 we want to be able to know whether the secure or non-secure
> + * instance wants to be accessed. A64 does not know this banking
> scheme
> + * anymore, but it might use the same readfn/writefn as A32 which
> might
> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
> + * Reset the type according to ns-bit passed as argument.
> + */
> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
> +
> if (state == ARM_CP_STATE_AA64) {
> /* To allow abbreviation of ARMCPRegInfo
> * definitions, we treat cp == 0 as equivalent to
> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu,
> const ARMCPRegInfo *r,
> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> r2->opc0, opc1, opc2);
> } else {
> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2,
> nsbit);
> }
> if (opaque) {
> r2->opaque = opaque;
> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu,
> const ARMCPRegInfo *r,
> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
> fprintf(stderr, "Register redefined: cp=%d %d bit "
> - "crn=%d crm=%d opc1=%d opc2=%d, "
> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
> r2->crn, r2->crm, r2->opc1, r2->opc2,
> + (r2->type & ARM_CP_NONSECURE),
> oldreg->name, r2->name);
> g_assert_not_reached();
> }
> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
> if (r->state != state && r->state !=
> ARM_CP_STATE_BOTH) {
> continue;
> }
> - add_cpreg_to_hashtable(cpu, r, opaque, state,
> - crm, opc1, opc2);
> +
> + if (state == ARM_CP_STATE_AA32) {
> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
> + (r->type & ARM_CP_BANKED) == 0) {
> + /* Under Aarch32 CP registers can be common
> + * (same for secure and non-secure world) or
> banked.
> + * Register definitions with neither secure
> nor
> + * non-secure type set (common) or with both
> bits
> + * set (banked) will be inserted twice into
> the
> + * hashtable.
> + */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 0);
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 1);
> + } else {
> + /* Only one of both bank types were specified
> */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2,
> + (r->type & ARM_CP_NONSECURE) ? 1 : 0);
> + }
> + } else {
> + /* Aarch64 registers get mapped to non-secure
> instance
> + * of Aarch32 */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 1);
+ }
> }
> }
> }
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index bbd4c77..3a429ac 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env,
> DisasContext *s, uint32_t ins
>
> static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t
> insn)
> {
> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
> const ARMCPRegInfo *ri;
>
> cpnum = (insn >> 8) & 0xf;
> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env,
> DisasContext *s, uint32_t insn)
> isread = (insn >> 20) & 1;
> rt = (insn >> 12) & 0xf;
>
> + /* Monitor mode is always treated as secure but cp register
> reads/writes
> + * can access secure and non-secure instances using SCR.NS bit*/
> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
>
While monitor mode is always considered secure, which system register
accessed is still based on the NS bit, so unless I am missing something,
shouldn't the ns setting be purely based on USE_SECURE_REG?
Also, doesn't IS_NS() simply indicate the the TB was generated for secure
state and not necessarily monitor mode? Plus, shouldn't this code still be
allowed to access the non-secure bank?
> ri = get_arm_cp_reginfo(s->cp_regs,
> - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1,
> opc2));
> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
> if (ri) {
> /* Check access permissions */
> if (!cp_access_ok(s->current_pl, ri, isread)) {
> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env,
> DisasContext *s, uint32_t insn)
> */
> if (is64) {
> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> - "64 bit system register cp:%d opc1: %d crm:%d\n",
> - isread ? "read" : "write", cpnum, opc1, crm);
> + "64 bit system register cp:%d opc1: %d crm:%d "
> + "(%s)\n",
> + isread ? "read" : "write", cpnum, opc1, crm,
> + ns ? "non-secure" : "secure");
> } else {
> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> - "system register cp:%d opc1:%d crn:%d crm:%d
> opc2:%d\n",
> - isread ? "read" : "write", cpnum, opc1, crn, crm,
> opc2);
> + "system register cp:%d opc1:%d crn:%d crm:%d
> opc2:%d "
> + "(%s)\n",
> + isread ? "read" : "write", cpnum, opc1, crn, crm,
> opc2,
> + ns ? "non-secure" : "secure");
> }
>
> return 1;
> --
> 1.8.3.2
>
>
>
[-- Attachment #2: Type: text/html, Size: 22709 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible Fabian Aggeler
@ 2014-05-14 17:32 ` Greg Bellows
0 siblings, 0 replies; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 17:32 UTC (permalink / raw)
To: Fabian Aggeler; +Cc: Edgar E. Iglesias, QEMU Developers, Peter Maydell
[-- Attachment #1: Type: text/plain, Size: 4874 bytes --]
On 13 May 2014 11:16, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> This way less case distinctions are necessary for different modes/worlds
> as the reginfos already point at the correct offset.
>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 26 +++++++++++++-------------
> 1 file changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index ac8b15a..757e07b 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -319,7 +319,7 @@ static void dacr_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
>
> - env->cp15.c3 = value;
> + raw_write(env, ri, value);
> tlb_flush(CPU(cpu), 1); /* Flush TLB as domain not tracked in TLB */
> }
>
> @@ -327,12 +327,12 @@ static void fcse_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
>
> - if (env->cp15.c13_fcse != value) {
> + if (raw_read(env, ri) != value) {
> /* Unlike real hardware the qemu TLB uses virtual addresses,
> * not modified virtual addresses, so this causes a TLB flush.
> */
> tlb_flush(CPU(cpu), 1);
> - env->cp15.c13_fcse = value;
> + raw_write(env, ri, value);
> }
> }
>
> @@ -341,7 +341,7 @@ static void contextidr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
>
> - if (env->cp15.contextidr_el1 != value && !arm_feature(env,
> ARM_FEATURE_MPU)
> + if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_MPU)
> && !extended_addresses_enabled(env)) {
> /* For VMSA (when not using the LPAE long descriptor page table
> * format) this register includes the ASID, so do a TLB flush.
> @@ -349,7 +349,7 @@ static void contextidr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> */
> tlb_flush(CPU(cpu), 1);
> }
> - env->cp15.contextidr_el1 = value;
> + raw_write(env, ri, value);
> }
>
> static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
> @@ -680,7 +680,7 @@ static void vbar_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> * contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
> * requires the bottom five bits to be RAZ/WI because they're
> UNK/SBZP.)
> */
> - env->cp15.c12_vbar = value & ~0x1FULL;
> + raw_write(env, ri, value & ~0x1Ful);
> }
>
> static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> @@ -692,7 +692,7 @@ static uint64_t ccsidr_read(CPUARMState *env, const
> ARMCPRegInfo *ri)
> static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> uint64_t value)
> {
> - env->cp15.c0_cssel = value & 0xf;
> + raw_write(env, ri, value & 0xf);
> }
>
> static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> @@ -1212,11 +1212,11 @@ static const ARMCPRegInfo
> generic_timer_cp_reginfo[] = {
> static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t
> value)
> {
> if (arm_feature(env, ARM_FEATURE_LPAE)) {
> - env->cp15.par_el1 = value;
> + raw_write(env, ri, value);
> } else if (arm_feature(env, ARM_FEATURE_V7)) {
> - env->cp15.par_el1 = value & 0xfffff6ff;
> + raw_write(env, ri, value & 0xfffff6ff);
> } else {
> - env->cp15.par_el1 = value & 0xfffff1ff;
> + raw_write(env, ri, value & 0xfffff1ff);
> }
> }
>
> @@ -1424,7 +1424,7 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env,
> const ARMCPRegInfo *ri,
> * for long-descriptor tables the TTBCR fields are used differently
> * and the c2_mask and c2_base_mask values are meaningless.
> */
> - env->cp15.c2_control = value;
> + raw_write(env, ri, value);
> env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift);
> env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift);
> }
> @@ -1457,7 +1457,7 @@ static void vmsa_tcr_el1_write(CPUARMState *env,
> const ARMCPRegInfo *ri,
>
> /* For AArch64 the A1 bit could result in a change of ASID, so TLB
> flush. */
> tlb_flush(CPU(cpu), 1);
> - env->cp15.c2_control = value;
> + raw_write(env, ri, value);
> }
>
> static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> @@ -2111,7 +2111,7 @@ static void sctlr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> | SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
> }
>
> - env->cp15.c1_sys = value;
> + raw_write(env, ri, value);
> /* ??? Lots of these bits are not implemented. */
> /* This may enable/disable the MMU, so do a TLB flush. */
> tlb_flush(CPU(cpu), 1);
> --
> 1.8.3.2
>
>
>
These changes may be better off submitted separate from the trustzone
updates.
[-- Attachment #2: Type: text/html, Size: 5971 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 14:42 ` Greg Bellows
@ 2014-05-14 18:35 ` Fedorov Sergey
2014-05-14 20:22 ` Greg Bellows
0 siblings, 1 reply; 75+ messages in thread
From: Fedorov Sergey @ 2014-05-14 18:35 UTC (permalink / raw)
To: Greg Bellows
Cc: Peter Maydell, Fabian Aggeler, Sergey Fedorov, QEMU Developers,
Edgar E. Iglesias
14.05.2014 18:42, Greg Bellows пишет:
> On 14 May 2014 00:53, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>
>> On 13.05.2014 20:15, Fabian Aggeler wrote:
>>> arm_is_secure() function allows to determine CPU security state
>>> if the CPU implements Security Extensions.
>>>
>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>>> ---
>>> target-arm/cpu.h | 15 +++++++++++++++
>>> 1 file changed, 15 insertions(+)
>>>
>>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>>> index a56d3d6..6ea0432 100644
>>> --- a/target-arm/cpu.h
>>> +++ b/target-arm/cpu.h
>>> @@ -640,6 +640,21 @@ static inline int arm_feature(CPUARMState *env, int
>> feature)
>>> return (env->features & (1ULL << feature)) != 0;
>>> }
>>>
>>> +/* Return true if the processor is in secure state */
>>> +static inline bool arm_is_secure(CPUARMState *env)
>>> +{
>>> +#if !defined(CONFIG_USER_ONLY)
>>> + if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
>> I think feature test can be safely avoided here. Without this feature
>> that should be no way to switch to monitor mode and to access SCR register.
>>
> I agree with the feature check here. For correctness, we should only be
> examining c1_scr if the security extension is enabled. This is consistent
> with only registering the SCR register if the feature is enabled.
So this check will be done every time arm_is_secure() is called, e.g. on
each MMU table walk.
Moreover I've noticed that this function deviates from ARM ARM v7-AR
description in section B1.5.1 which states: "The IsSecure() function
returns TRUE if the processor is in Secure state, or if the
implementation does not include
the Security Extensions, and FALSE otherwise." Then there is a pseudo
code for that function.
>
>>> + return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
>>> + !(env->cp15.c1_scr & 1);
>>> + } else {
>>> + return false;
>>> + }
>>> +#else
>>> + return false;
>> That is a good question how to treat user emulation: secure or
>> non-secure. Perhaps assuming user emulation in secure state may simplify
>> code in the following patches.
>
>>> +#endif
>>> +}
>>> +
>>> /* Return true if the specified exception level is running in AArch64
>> state. */
>>> static inline bool arm_el_is_aa64(CPUARMState *env, int el)
>>> {
>> Thanks,
>> Sergey.
>>
>>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-14 6:06 ` Sergey Fedorov
@ 2014-05-14 18:39 ` Fedorov Sergey
2014-05-15 14:44 ` Fabian Aggeler
0 siblings, 1 reply; 75+ messages in thread
From: Fedorov Sergey @ 2014-05-14 18:39 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
14.05.2014 10:06, Sergey Fedorov пишет:
> On 13.05.2014 20:15, Fabian Aggeler wrote:
>> From: Sergey Fedorov <s.fedorov@samsung.com>
>>
>> CPACR register allows to control access rights to coprocessor 0-13
>> interfaces. Bits corresponding to unimplemented coprocessors should be
>> RAZ/WI. QEMU implements only VFP coprocessor on ARMv6+ targets. So only
>> cp10 & cp11 bits are writable.
>>
>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>> ---
>> target-arm/helper.c | 6 ++++++
>> target-arm/translate.c | 26 +++++++++++++++++++++++---
>> 2 files changed, 29 insertions(+), 3 deletions(-)
>>
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index cf1f88c..4e82259 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -477,6 +477,12 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
>> static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>> uint64_t value)
>> {
>> + uint32_t mask = 0;
>> +
>> + if (arm_feature(env, ARM_FEATURE_VFP)) {
>> + mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
>> + }
>> + value &= mask;
>> if (env->cp15.c1_coproc != value) {
>> env->cp15.c1_coproc = value;
>> /* ??? Is this safe when called from within a TB? */
>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>> index 87d0918..c815fb3 100644
>> --- a/target-arm/translate.c
>> +++ b/target-arm/translate.c
>> @@ -6866,9 +6866,29 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>> const ARMCPRegInfo *ri;
>>
>> cpnum = (insn >> 8) & 0xf;
>> - if (arm_feature(env, ARM_FEATURE_XSCALE)
>> - && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
>> - return 1;
>> + if (cpnum < 14) {
>> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
>> + if (~env->cp15.c15_cpar & (1 << cpnum)) {
>> + return 1;
>> + }
>> + } else {
>> + /* Bits [20:21] of CPACR control access to cp10
>> + * Bits [23:22] of CPACR control access to cp11 */
>> + switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
>> + case 0: /* access denied */
>> + return 1;
>> + case 1: /* privileged mode access only */
>> + if (IS_USER(s)) {
>> + return 1;
>> + }
>> + break;
>> + case 2: /* reserved */
>> + return 1;
>> + case 3: /* privileged and user mode access */
>> + break;
>> + }
>> + }
>> + }
>>
>> /* First check for coprocessor space used for actual instructions */
>> switch (cpnum) {
> Please, look at disas_vfp_insn() and disas_neon_*_insn() functions.
> Looks like them should be updated. In that case do not forget to adjust
> arm_cpu_reset() so user emulation would be able to execute VFP/NEON
> instructions.
See ARM ARM v7-AR B1.11.1
>
> Thanks,
> Sergey.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers Fabian Aggeler
@ 2014-05-14 19:47 ` Greg Bellows
0 siblings, 0 replies; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 19:47 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
[-- Attachment #1: Type: text/plain, Size: 26405 bytes --]
On 13 May 2014 11:16, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> Use new macro A32_BANKED_REG() for registers which are banked in Aarch32
> and not mapped an EL3 register in Aarch64.
>
> Using raw_write and raw_read in .readfn/.writefn to be able to use the
> same .readfn/writefn for secure and non-secure instance without case
> distinction.
>
> Whenever accessing banked registers using A32_BANKED_REG_GET macro or
> A32_MAPPED_EL3_REG_GET for registers which we map to EL3 registers.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> linux-user/main.c | 2 +-
> target-arm/cpu.h | 32 ++++++----
> target-arm/helper-a64.c | 3 +-
> target-arm/helper.c | 155
> ++++++++++++++++++++++++++++++++++--------------
> 4 files changed, 132 insertions(+), 60 deletions(-)
>
> diff --git a/linux-user/main.c b/linux-user/main.c
> index c38fecf..809d731 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -566,7 +566,7 @@ do_kernel_trap(CPUARMState *env)
> end_exclusive();
> break;
> case 0xffff0fe0: /* __kernel_get_tls */
> - env->regs[0] = env->cp15.tpidrro_el0;
> + env->regs[0] = A32_BANKED_CURRENT_REG_GET(env, tpidrro_el0);
> break;
> case 0xffff0f60: /* __kernel_cmpxchg64 */
> arm_kernel_cmpxchg64_helper(env);
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 780c1f5..c20c44a 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -179,7 +179,8 @@ typedef struct CPUARMState {
> /* System control coprocessor (cp15) */
> struct {
> uint32_t c0_cpuid;
> - uint64_t c0_cssel; /* Cache size selection. */
> + A32_BANKED_REG(uint64_t, c0_cssel); /* Cache size selection
> + (banked in Aarch32). */
> uint64_t c1_sys_el1; /* System control register (EL1). */
> uint64_t c1_sys_el3; /* System control register (EL3). */
> uint64_t c1_coproc; /* Coprocessor access register. */
> @@ -187,22 +188,28 @@ typedef struct CPUARMState {
> uint32_t c1_scr; /* secure config register. */
> uint32_t c1_sder; /* Secure debug enable register. */
> uint32_t c1_nsacr; /* Non-secure access control register. */
> - uint64_t ttbr0_el1; /* MMU translation table base 0. */
> - uint64_t ttbr1_el1; /* MMU translation table base 1. */
> - uint64_t c2_control; /* MMU translation table base control. */
> + uint64_t ttbr0_el1;/* MMU translation table base 0. */
> + uint64_t ttbr0_el3;
> + uint64_t ttbr1_el1;/* MMU translation table base 1. */
> + uint64_t ttbr1_el3;
> + A32_BANKED_REG(uint64_t, c2_control);/* MMU translation table base
> + control. (banked in
> Aarch32) */
> uint32_t c2_mask; /* MMU translation table base selection mask.
> */
> uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
>
Should either c2_mask and/or c2_base_mask be "banked" given that the
correspond to the value set in c2_control which is banked?
> uint32_t c2_data; /* MPU data cachable bits. */
> uint32_t c2_insn; /* MPU instruction cachable bits. */
> - uint32_t c3; /* MMU domain access control register
> + A32_BANKED_REG(uint32_t, c3); /* MMU domain access control
> register
> MPU write buffer control. */
> uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
> uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
> - uint32_t ifsr_el2; /* Fault status registers. */
> + A32_BANKED_REG(uint32_t, ifsr_el2); /* Fault status registers. */
> uint64_t esr_el1;
> + uint64_t esr_el3;
> uint32_t c6_region[8]; /* MPU base/size registers. */
> uint64_t far_el1; /* Fault address registers. */
> + uint64_t far_el3;
> uint64_t par_el1; /* Translation result. */
> + uint64_t par_el3;
> uint32_t c9_insn; /* Cache lockdown registers. */
> uint32_t c9_data;
> uint32_t c9_pmcr; /* performance monitor control register */
> @@ -212,12 +219,13 @@ typedef struct CPUARMState {
> uint32_t c9_pmuserenr; /* perf monitor user enable */
> uint32_t c9_pminten; /* perf monitor interrupt enables */
> uint64_t mair_el1;
> - uint64_t c12_vbar; /* vector base address register */
> - uint32_t c13_fcse; /* FCSE PID. */
> - uint64_t contextidr_el1; /* Context ID. */
> - uint64_t tpidr_el0; /* User RW Thread register. */
> - uint64_t tpidrro_el0; /* User RO Thread register. */
> - uint64_t tpidr_el1; /* Privileged Thread register. */
> + uint64_t c12_vbar_el1; /* vector base address register */
> + uint64_t c12_vbar_el3; /* vector base address register */
> + A32_BANKED_REG(uint32_t, c13_fcse); /* FCSE PID. */
> + A32_BANKED_REG(uint64_t, contextidr_el1); /* Context ID. */
> + A32_BANKED_REG(uint64_t, tpidr_el0); /* User RW Thread register.
> */
> + A32_BANKED_REG(uint64_t, tpidrro_el0); /* User RO Thread
> register. */
> + A32_BANKED_REG(uint64_t, tpidr_el1); /* Privileged Thread
> register. */
> uint64_t c14_cntfrq; /* Counter Frequency register */
> uint64_t c14_cntkctl; /* Timer Control register */
> ARMGenericTimer c14_timer[NUM_GTIMERS];
> diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
> index bf921cc..765ddf5 100644
> --- a/target-arm/helper-a64.c
> +++ b/target-arm/helper-a64.c
> @@ -443,7 +443,8 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
> {
> ARMCPU *cpu = ARM_CPU(cs);
> CPUARMState *env = &cpu->env;
> - target_ulong addr = env->cp15.c12_vbar;
> + target_ulong addr = (arm_current_pl(env) == 3) ?
> + env->cp15.c12_vbar_el3 : env->cp15.c12_vbar_el1;
> int i;
>
> if (arm_current_pl(env) == 0) {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 757e07b..c76a86b 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -397,10 +397,11 @@ static const ARMCPRegInfo cp_reginfo[] = {
> .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
> { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
> = 0,
> .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.c13_fcse),
> - .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, },
> + .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write,
> + .type = ARM_CP_BANKED },
> { .name = "CONTEXTIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1,
> - .access = PL1_RW,
> + .access = PL1_RW, .type = ARM_CP_BANKED_64BIT,
> .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1),
> .resetvalue = 0, .writefn = contextidr_write, .raw_writefn =
> raw_write, },
> REGINFO_SENTINEL
> @@ -413,7 +414,8 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = {
> /* MMU Domain access control / MPU write buffer control */
> { .name = "DACR", .cp = 15,
> .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3),
> + .access = PL1_RW, .type = ARM_CP_BANKED,
> + .fieldoffset = offsetof(CPUARMState, cp15.c3),
> .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, },
> /* ??? This covers not just the impdef TLB lockdown registers but also
> * some v7VMSA registers relating to TEX remap, so it is overly broad.
> @@ -519,9 +521,13 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
> { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
> .access = PL0_W, .type = ARM_CP_NOP },
> { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
> - .access = PL1_RW,
> + .access = PL1_RW, .type = ARM_CP_NONSECURE,
> .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
> .resetvalue = 0, },
> + { .name = "IFAR(S)", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 =
> 2,
> + .access = PL3_RW, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el3),
> + .resetvalue = 0, },
> /* Watchpoint Fault Address Register : should actually only be present
> * for 1136, 1176, 11MPCore.
> */
> @@ -686,7 +692,7 @@ static void vbar_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> {
> ARMCPU *cpu = arm_env_get_cpu(env);
> - return cpu->ccsidr[env->cp15.c0_cssel];
> + return cpu->ccsidr[A32_BANKED_REG_GET(env, c0_cssel)];
> }
>
> static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> @@ -786,15 +792,25 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
> .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
> .resetvalue = 0, .writefn = pmintenclr_write, },
> - { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
> + { .name = "VBAR_EL1", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .writefn = vbar_write,
> - .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
> + .access = PL1_RW, .writefn = vbar_write, .type = ARM_CP_NONSECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el1),
> + .resetvalue = 0 },
> + { .name = "VBAR_EL1(S)",
> + .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW, .writefn = vbar_write, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el3),
> + .resetvalue = 0 },
> + { .name = "VBAR_EL3", .state = ARM_CP_STATE_AA64,
> + .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 4, .opc2 = 5,
> + .access = PL3_RW, .writefn = vbar_write,
> + .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar_el3),
> .resetvalue = 0 },
> { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
> .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
> - { .name = "CSSELR", .state = ARM_CP_STATE_BOTH,
> + { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .type =
> ARM_CP_BANKED_64BIT,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0,
> .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.c0_cssel),
> .writefn = csselr_write, .resetvalue = 0 },
> @@ -871,7 +887,7 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
> .access = PL0_RW,
> .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el0), .resetvalue =
> 0 },
> { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
> = 2,
> - .access = PL0_RW,
> + .access = PL0_RW, .type = ARM_CP_BANKED_64BIT,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0),
> .resetfn = arm_cp_reset_ignore },
> { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64,
> @@ -879,12 +895,12 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
> .access = PL0_R|PL1_W,
> .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el0), .resetvalue
> = 0 },
> { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
> = 3,
> - .access = PL0_R|PL1_W,
> + .access = PL0_R|PL1_W, .type = ARM_CP_BANKED_64BIT,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0),
> .resetfn = arm_cp_reset_ignore },
> { .name = "TPIDR_EL1", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0,
> - .access = PL1_RW,
> + .access = PL1_RW, .type = ARM_CP_BANKED_64BIT,
> .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el1), .resetvalue =
> 0 },
> REGINFO_SENTINEL
> };
> @@ -1263,7 +1279,7 @@ static void ats_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
> * fault.
> */
> }
> - env->cp15.par_el1 = par64;
> + A32_MAPPED_EL3_REG_SET(env, par, par64);
> } else {
> /* ret is a DFSR/IFSR value for the short descriptor
> * translation table format (with WnR always clear).
> @@ -1273,14 +1289,15 @@ static void ats_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
> /* We do not set any attribute bits in the PAR */
> if (page_size == (1 << 24)
> && arm_feature(env, ARM_FEATURE_V7)) {
> - env->cp15.par_el1 = (phys_addr & 0xff000000) | 1 << 1;
> + A32_MAPPED_EL3_REG_SET(env, par,
> + (phys_addr & 0xff000000) | 1 << 1);
> } else {
> - env->cp15.par_el1 = phys_addr & 0xfffff000;
> + A32_MAPPED_EL3_REG_SET(env, par, phys_addr & 0xfffff000);
> }
> } else {
> - env->cp15.par_el1 = ((ret & (1 << 10)) >> 5) |
> + A32_MAPPED_EL3_REG_SET(env, par, ((ret & (1 << 10)) >> 5) |
> ((ret & (1 << 12)) >> 6) |
> - ((ret & 0xf) << 1) | 1;
> + ((ret & 0xf) << 1) | 1);
> }
> }
> }
> @@ -1288,9 +1305,13 @@ static void ats_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
>
> static const ARMCPRegInfo vapa_cp_reginfo[] = {
> { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .resetvalue = 0,
> + .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_NONSECURE,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.par_el1),
> .writefn = par_write },
> + { .name = "PAR(S)", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 =
> 0,
+ .access = PL3_RW, .resetvalue = 0, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.par_el3),
> + .writefn = par_write },
> #ifndef CONFIG_USER_ONLY
> { .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 =
> CP_ANY,
> .access = PL1_W, .accessfn = ats_access,
> @@ -1476,23 +1497,39 @@ static void vmsa_ttbr_write(CPUARMState *env,
> const ARMCPRegInfo *ri,
>
> static const ARMCPRegInfo vmsa_cp_reginfo[] = {
> { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> + .access = PL1_RW, .type = ARM_CP_NO_MIGRATE | ARM_CP_NONSECURE,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> .resetfn = arm_cp_reset_ignore, },
> + { .name = "DFSR(S)", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 =
> 0,
> + .access = PL3_RW, .type = ARM_CP_SECURE, .resetvalue = 0,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el3) },
> { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
> - .access = PL1_RW,
> + .access = PL1_RW, .type = ARM_CP_BANKED,
> .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue =
> 0, },
> { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
> .access = PL1_RW,
> .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue =
> 0, },
> + { .name = "ESR_EL3", .state = ARM_CP_STATE_AA64, .crn = 5, .crm = 2,
> + .opc0 = 3, .opc1 = 6, .opc2 = 0, .access = PL3_RW, .resetvalue = 0,
> + .fieldoffset = offsetof(CPUARMState, cp15.esr_el3) },
> { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.ttbr0_el1),
> + .access = PL1_RW, .type = ARM_CP_NONSECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
> + .writefn = vmsa_ttbr_write, .resetvalue = 0 },
> + { .name = "TTBR0(S)", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2
> = 0,
> + .access = PL3_RW, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3),
> .writefn = vmsa_ttbr_write, .resetvalue = 0 },
> { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.ttbr1_el1),
> + .access = PL1_RW, .type = ARM_CP_NONSECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
> + .writefn = vmsa_ttbr_write, .resetvalue = 0 },
> + { .name = "TTBR1(S)", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2
> = 1,
> + .access = PL3_RW, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3),
> .writefn = vmsa_ttbr_write, .resetvalue = 0 },
> { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
> @@ -1500,14 +1537,18 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
> .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
> .fieldoffset = offsetof(CPUARMState, cp15.c2_control) },
> { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
> - .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn =
> vmsa_ttbcr_write,
> - .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
> + .access = PL1_RW, .type = ARM_CP_NO_MIGRATE | ARM_CP_BANKED_64BIT,
> + .writefn = vmsa_ttbcr_write, .resetfn = arm_cp_reset_ignore,
> + .raw_writefn = vmsa_ttbcr_raw_write,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
> /* 64-bit FAR; this entry also gives us the AArch32 DFAR */
> - { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
> + { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH, .type =
> ARM_CP_NONSECURE,
> .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.far_el1),
> .resetvalue = 0, },
> + { .name = "DFAR(S)", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 =
> 0,
> + .access = PL3_RW, .type = ARM_CP_SECURE, .resetvalue = 0,
> + .fieldoffset = offsetof(CPUARMState, cp15.far_el3)},
> REGINFO_SENTINEL
> };
>
> @@ -1545,9 +1586,15 @@ static void omap_cachemaint_write(CPUARMState *env,
> const ARMCPRegInfo *ri,
>
> static const ARMCPRegInfo omap_cp_reginfo[] = {
> { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
> - .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type =
> ARM_CP_OVERRIDE,
> + .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW,
> + .type = ARM_CP_OVERRIDE | ARM_CP_NONSECURE,
> .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> .resetvalue = 0, },
> + { .name = "DFSR(S)", .cp = 15, .crn = 5, .crm = CP_ANY,
> + .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL3_RW,
> + .type = ARM_CP_OVERRIDE | ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el3),
> + .resetvalue = 0, },
> { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
> .access = PL1_RW, .type = ARM_CP_NOP },
> { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2
> = 0,
> @@ -1730,7 +1777,13 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
> { .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
> .access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0
> },
> { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
> - .access = PL1_RW, .type = ARM_CP_64BIT,
> + .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NONSECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0
> },
> + { .name = "PAR(S)", .cp = 15, .crm = 7, .opc1 = 0,
> + .access = PL3_RW, .type = ARM_CP_64BIT | ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.par_el3), .resetvalue = 0
> },
> + { .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
> + .opc0 = 3, .crn = 7, .crm = 4, .opc2 = 0, .access = PL1_RW,
> .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0
> },
> { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
> .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
> @@ -2131,6 +2184,10 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
> { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> .resetvalue = 0, },
> + { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
> + .opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> + .resetvalue = 0 },
> { .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
> .access = PL3_RW, .resetvalue = 0,
> .fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
> @@ -3469,22 +3526,25 @@ void arm_cpu_do_interrupt(CPUState *cs)
> env->exception.fsr = 2;
> /* Fall through to prefetch abort. */
> case EXCP_PREFETCH_ABORT:
> - env->cp15.ifsr_el2 = env->exception.fsr;
> - env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
> - env->exception.vaddress);
> + A32_BANKED_CURRENT_REG_SET(env, ifsr_el2, env->exception.fsr);
> + A32_MAPPED_EL3_CURRENT_REG_SET(env, far,
> + deposit64(A32_MAPPED_EL3_CURRENT_REG_GET(env, far), 32,
> 32,
> + env->exception.vaddress));
> qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
> - env->cp15.ifsr_el2,
> (uint32_t)env->exception.vaddress);
> + A32_BANKED_CURRENT_REG_GET(env, ifsr_el2),
> + (uint32_t)env->exception.vaddress);
> new_mode = ARM_CPU_MODE_ABT;
> addr = 0x0c;
> mask = CPSR_A | CPSR_I;
> offset = 4;
> break;
> case EXCP_DATA_ABORT:
> - env->cp15.esr_el1 = env->exception.fsr;
> - env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
> - env->exception.vaddress);
> + A32_MAPPED_EL3_CURRENT_REG_SET(env, esr, env->exception.fsr);
> + A32_MAPPED_EL3_CURRENT_REG_SET(env, far,
> + deposit64(A32_MAPPED_EL3_CURRENT_REG_GET(env, far), 0, 32,
> + env->exception.vaddress));
> qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
> - (uint32_t)env->cp15.esr_el1,
> + (uint32_t)A32_MAPPED_EL3_CURRENT_REG_GET(env, esr),
> (uint32_t)env->exception.vaddress);
> new_mode = ARM_CPU_MODE_ABT;
> addr = 0x10;
> @@ -3521,7 +3581,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> * and is never in monitor mode this feature is always active.
> * Note: only bits 31:5 are valid.
> */
> - addr += env->cp15.c12_vbar;
> + addr += A32_MAPPED_EL3_CURRENT_REG_GET(env, c12_vbar);
> }
> switch_mode (env, new_mode);
> env->spsr = cpsr_read(env);
> @@ -3601,9 +3661,10 @@ static uint32_t
> get_level1_table_address(CPUARMState *env, uint32_t address)
> uint32_t table;
>
> if (address & env->cp15.c2_mask)
> - table = env->cp15.ttbr1_el1 & 0xffffc000;
> + table = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr1) & 0xffffc000;
> else
> - table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask;
> + table =
> + A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr0) &
> env->cp15.c2_base_mask;
>
> table |= (address >> 18) & 0x3ffc;
> return table;
> @@ -3737,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env,
> uint32_t address, int access_type,
> /* Page or Section. */
> domain = (desc >> 5) & 0x0f;
> }
> - domain_prot = (env->cp15.c3 >> (domain * 2)) & 3;
> + domain_prot = (A32_BANKED_CURRENT_REG_GET(env, c3) >> (domain * 2)) &
> 3;
> if (domain_prot == 0 || domain_prot == 2) {
> if (type != 1) {
> code = 9; /* Section domain fault. */
> @@ -3863,12 +3924,14 @@ static int get_phys_addr_lpae(CPUARMState *env,
> target_ulong address,
> * This is a Non-secure PL0/1 stage 1 translation, so controlled by
> * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32:
> */
> - uint32_t t0sz = extract32(env->cp15.c2_control, 0, 6);
> + uint32_t t0sz = extract32(
> + A32_BANKED_CURRENT_REG_GET(env, c2_control), 0, 6);
> if (arm_el_is_aa64(env, 1)) {
> t0sz = MIN(t0sz, 39);
> t0sz = MAX(t0sz, 16);
> }
> - uint32_t t1sz = extract32(env->cp15.c2_control, 16, 6);
> + uint32_t t1sz = extract32(
> + A32_BANKED_CURRENT_REG_GET(env, c2_control), 16, 6);
> if (arm_el_is_aa64(env, 1)) {
> t1sz = MIN(t1sz, 39);
> t1sz = MAX(t1sz, 16);
> @@ -3899,8 +3962,8 @@ static int get_phys_addr_lpae(CPUARMState *env,
> target_ulong address,
> * we will always flush the TLB any time the ASID is changed).
> */
> if (ttbr_select == 0) {
> - ttbr = env->cp15.ttbr0_el1;
> - epd = extract32(env->cp15.c2_control, 7, 1);
> + ttbr = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr0);
> + epd = extract32(A32_BANKED_CURRENT_REG_GET(env, c2_control), 7,
> 1);
> tsz = t0sz;
>
> tg = extract32(env->cp15.c2_control, 14, 2);
> @@ -3911,8 +3974,8 @@ static int get_phys_addr_lpae(CPUARMState *env,
> target_ulong address,
> granule_sz = 11;
> }
> } else {
> - ttbr = env->cp15.ttbr1_el1;
> - epd = extract32(env->cp15.c2_control, 23, 1);
> + ttbr = A32_MAPPED_EL3_CURRENT_REG_GET(env, ttbr1);
> + epd = extract32(A32_BANKED_CURRENT_REG_GET(env, c2_control), 23,
> 1);
> tsz = t1sz;
>
> tg = extract32(env->cp15.c2_control, 30, 2);
> @@ -4132,7 +4195,7 @@ static inline int get_phys_addr(CPUARMState *env,
> target_ulong address,
> {
> /* Fast Context Switch Extension. */
> if (address < 0x02000000)
> - address += env->cp15.c13_fcse;
> + address += A32_BANKED_CURRENT_REG_GET(env, c13_fcse);
>
> if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
> /* MMU/MPU disabled. */
> --
> 1.8.3.2
>
>
>
[-- Attachment #2: Type: text/html, Size: 31178 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 18:35 ` Fedorov Sergey
@ 2014-05-14 20:22 ` Greg Bellows
2014-05-14 21:29 ` Peter Maydell
0 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 20:22 UTC (permalink / raw)
To: Fedorov Sergey
Cc: Peter Maydell, Fabian Aggeler, Sergey Fedorov, QEMU Developers,
Edgar E. Iglesias
[-- Attachment #1: Type: text/plain, Size: 3029 bytes --]
I suppose it depends on how true we want to be to the specification and
whether our default is NS=0 or NS=1 when the security extension is present
or not. The code currently assumes non-secure as the default state.
Is there a convention in qemu? How closely do we attempt to stay to the
pseudo code provided in the spec?
On 14 May 2014 13:35, Fedorov Sergey <serge.fdrv@gmail.com> wrote:
>
> 14.05.2014 18:42, Greg Bellows пишет:
> > On 14 May 2014 00:53, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> >
> >> On 13.05.2014 20:15, Fabian Aggeler wrote:
> >>> arm_is_secure() function allows to determine CPU security state
> >>> if the CPU implements Security Extensions.
> >>>
> >>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> >>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> >>> ---
> >>> target-arm/cpu.h | 15 +++++++++++++++
> >>> 1 file changed, 15 insertions(+)
> >>>
> >>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> >>> index a56d3d6..6ea0432 100644
> >>> --- a/target-arm/cpu.h
> >>> +++ b/target-arm/cpu.h
> >>> @@ -640,6 +640,21 @@ static inline int arm_feature(CPUARMState *env,
> int
> >> feature)
> >>> return (env->features & (1ULL << feature)) != 0;
> >>> }
> >>>
> >>> +/* Return true if the processor is in secure state */
> >>> +static inline bool arm_is_secure(CPUARMState *env)
> >>> +{
> >>> +#if !defined(CONFIG_USER_ONLY)
> >>> + if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
> >> I think feature test can be safely avoided here. Without this feature
> >> that should be no way to switch to monitor mode and to access SCR
> register.
> >>
> > I agree with the feature check here. For correctness, we should only be
> > examining c1_scr if the security extension is enabled. This is
> consistent
> > with only registering the SCR register if the feature is enabled.
>
> So this check will be done every time arm_is_secure() is called, e.g. on
> each MMU table walk.
>
> Moreover I've noticed that this function deviates from ARM ARM v7-AR
> description in section B1.5.1 which states: "The IsSecure() function
> returns TRUE if the processor is in Secure state, or if the
> implementation does not include
> the Security Extensions, and FALSE otherwise." Then there is a pseudo
> code for that function.
>
> >
> >>> + return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
> >>> + !(env->cp15.c1_scr & 1);
> >>> + } else {
> >>> + return false;
> >>> + }
> >>> +#else
> >>> + return false;
> >> That is a good question how to treat user emulation: secure or
> >> non-secure. Perhaps assuming user emulation in secure state may simplify
> >> code in the following patches.
> >
> >>> +#endif
> >>> +}
> >>> +
> >>> /* Return true if the specified exception level is running in AArch64
> >> state. */
> >>> static inline bool arm_el_is_aa64(CPUARMState *env, int el)
> >>> {
> >> Thanks,
> >> Sergey.
> >>
> >>
>
>
[-- Attachment #2: Type: text/html, Size: 4227 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers Fabian Aggeler
@ 2014-05-14 21:20 ` Greg Bellows
2014-05-15 13:10 ` Aggeler Fabian
0 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 21:20 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
[-- Attachment #1: Type: text/plain, Size: 4583 bytes --]
On 13 May 2014 11:16, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> Some of SCTRL bits are common for secure and non-secure state.
> Translation table base masks are updated on NS-bit switch as
> well as on TTBCR writes.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/cpu.h | 10 ++++++++++
> target-arm/helper.c | 39 ++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index c20c44a..7893004 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -425,6 +425,14 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr
> address, int rw,
> #define SCTLR_AFE (1U << 29)
> #define SCTLR_TE (1U << 30)
>
> +/* Bitmask for banked bits (Security Extensions) */
> +#define SCTLR_BANKED (SCTLR_TE | SCTLR_AFE | SCTLR_TRE | SCTLR_EE | \
> + SCTLR_VE | SCTLR_HA | SCTLR_UWXN | SCTLR_WXN | SCTLR_V | \
> + SCTLR_I | SCTLR_Z | SCTLR_SW | SCTLR_CP15BEN | SCTLR_C | \
> + SCTLR_A | SCTLR_M)
> +/* Treat bits that are not explicitly banked as common */
> +#define SCTLR_COMMON (~SCTLR_BANKED)
> +
> #define CPSR_M (0x1fU)
> #define CPSR_T (1U << 5)
> #define CPSR_F (1U << 6)
> @@ -662,6 +670,8 @@ static inline int arm_feature(CPUARMState *env, int
> feature)
> return (env->features & (1ULL << feature)) != 0;
> }
>
> +#define SCR_NS (1U << 0)
> +
> /* Return true if the processor is in secure state */
> static inline bool arm_is_secure(CPUARMState *env)
> {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index c76a86b..618fd31 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2165,12 +2165,49 @@ static void sctlr_write(CPUARMState *env, const
> ARMCPRegInfo *ri,
> }
>
> raw_write(env, ri, value);
> +
> + if (!arm_el_is_aa64(env, 3)) {
> + /* Aarch32 has some bits that are common to secure (mapped to
> + * SCTLR_EL3) and non-secure instances of the SCTLR. */
> +
> + env->cp15.c1_sys_el1 &= SCTLR_BANKED |
> + (arm_current_sctlr(env) & SCTLR_COMMON);
> + env->cp15.c1_sys_el3 &= SCTLR_BANKED |
> + (arm_current_sctlr(env) & SCTLR_COMMON);
> + }
> +
> /* ??? Lots of these bits are not implemented. */
> /* This may enable/disable the MMU, so do a TLB flush. */
> tlb_flush(CPU(cpu), 1);
> }
>
> #ifndef CONFIG_USER_ONLY
> +static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t
> value)
> +{
> + if (!arm_el_is_aa64(env, 3) &&
> + (value & SCR_NS) != (env->cp15.c1_scr & SCR_NS)) {
> + /* If EL3 is using Aarch32 switching NS-bit may make the CPU use a
> + * different instance (secure or non-secure) when accessing CP
> + * registers.
> + * Common bits of otherwise banked registers need to by
> synchronized
> + * at this point.
> + */
> + env->cp15.c1_sys_el1 &= SCTLR_BANKED |
> + (arm_current_sctlr(env) & SCTLR_COMMON);
> + env->cp15.c1_sys_el3 &= SCTLR_BANKED |
> + (arm_current_sctlr(env) & SCTLR_COMMON);
>
I must be missing something, if the common bits are sync'd across the banks
in sctlr_write(), why do we need to do it here?
> + }
> +
> + env->cp15.c1_scr = value;
> +
> + /* After possible switch, calculate c2_mask and c2_base_mask again
> for the
> + * instance which is now active (secure or non-secure).
> + */
> + int maskshift = extract32(A32_BANKED_REG_GET(env, c2_control), 0, 3);
> + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift);
> + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift);
>
As mentioned elsewhere, does it make sense to bank the c2_mask fields so
they stay in sync with c2_control? Presumably we would not need to do
these updates in this case.
> +
> +}
>
> static void nsacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> uint64_t value)
> @@ -2183,7 +2220,7 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
> #ifndef CONFIG_USER_ONLY
> { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> - .resetvalue = 0, },
> + .resetvalue = 0, .writefn = scr_write },
> { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
> .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> --
> 1.8.3.2
>
>
>
[-- Attachment #2: Type: text/html, Size: 6005 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 20:22 ` Greg Bellows
@ 2014-05-14 21:29 ` Peter Maydell
2014-05-14 22:22 ` Greg Bellows
0 siblings, 1 reply; 75+ messages in thread
From: Peter Maydell @ 2014-05-14 21:29 UTC (permalink / raw)
To: Greg Bellows
Cc: Fedorov Sergey, Sergey Fedorov, Edgar E. Iglesias,
QEMU Developers, Fabian Aggeler
On 14 May 2014 21:22, Greg Bellows <greg.bellows@linaro.org> wrote:
> I suppose it depends on how true we want to be to the specification and
> whether our default is NS=0 or NS=1 when the security extension is present
> or not. The code currently assumes non-secure as the default state.
The v8 ARM ARM at least allows the CPU to behave as if only
NS was present if there is no implementation of the Security
extensions. I haven't checked the v7 wording.
(In general I think QEMU's implementation of this should follow
the v8 ARM ARM and treat v7 CPUs as a sort of special degenerate
case.)
> Is there a convention in qemu? How closely do we attempt to stay to the
> pseudo code provided in the spec?
The pseudocode in the ARM ARM is part of the spec. We should
strive to follow the spec. This doesn't necessarily mean matching
pseudocode functions exactly -- the requirement is to be
behaviourally the same, and sometimes the pseudocode is
written to be clear rather than efficient or to deal with situations
we don't necessarily care about.
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 21:29 ` Peter Maydell
@ 2014-05-14 22:22 ` Greg Bellows
2014-05-15 13:00 ` Aggeler Fabian
0 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-14 22:22 UTC (permalink / raw)
To: Peter Maydell
Cc: Fedorov Sergey, Sergey Fedorov, Edgar E. Iglesias,
QEMU Developers, Fabian Aggeler
[-- Attachment #1: Type: text/plain, Size: 1620 bytes --]
Thanks for the input Peter.
>From briefly looking, it actually looks like the ARMv7 spec more strictly
states that the default is secure. ARMv8 on the other hand appears to
leave it open as implementation defined,
Based on out past discussions, I assumed non-secure as the default and that
appears to be the direction of Fabian's code as well. Clearly if we want
to follow the spec, we'd both need to change this default.
Greg
On 14 May 2014 16:29, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 14 May 2014 21:22, Greg Bellows <greg.bellows@linaro.org> wrote:
> > I suppose it depends on how true we want to be to the specification and
> > whether our default is NS=0 or NS=1 when the security extension is
> present
> > or not. The code currently assumes non-secure as the default state.
>
> The v8 ARM ARM at least allows the CPU to behave as if only
> NS was present if there is no implementation of the Security
> extensions. I haven't checked the v7 wording.
>
> (In general I think QEMU's implementation of this should follow
> the v8 ARM ARM and treat v7 CPUs as a sort of special degenerate
> case.)
>
> > Is there a convention in qemu? How closely do we attempt to stay to the
> > pseudo code provided in the spec?
>
> The pseudocode in the ARM ARM is part of the spec. We should
> strive to follow the spec. This doesn't necessarily mean matching
> pseudocode functions exactly -- the requirement is to be
> behaviourally the same, and sometimes the pseudocode is
> written to be clear rather than efficient or to deal with situations
> we don't necessarily care about.
>
> thanks
> -- PMM
>
[-- Attachment #2: Type: text/html, Size: 2225 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-14 16:42 ` Greg Bellows
@ 2014-05-15 9:02 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-15 9:02 UTC (permalink / raw)
To: Greg Bellows
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
On 14 May 2014, at 18:42, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
On 13 May 2014 11:15, Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>> wrote:
Banked CP registers can be defined with a A32_BANKED_REG macro which defines
a non-secure instance of the register followed by an adjacent secure instance.
Using a union makes the code backwards-compatible since the non-secure
instance can normally be accessed by its existing name.
This comment indicates that the 0th entry or the default name is the non-secure bank, which differs from the code below.
The code does indeed use the 0th entry as non-secure and 1st entry as secure. Using the union the default name points to the
0th entry. Am I missing something here?
When translating a banked CP register access instruction in monitor mode,
the SCR.NS bit determines which instance is going to be accessed.
If EL3 is operating in Aarch64 state coprocessor registers are not
banked anymore but in some cases have its own _EL3 instance.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com<mailto:s.fedorov@samsung.com>>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>>
---
target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
target-arm/helper.c | 64 ++++++++++++++++++++++++--
target-arm/translate.c | 19 +++++---
3 files changed, 184 insertions(+), 20 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a970d55..9e325ac 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -80,6 +80,16 @@
#define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
#endif
+/* Define a banked coprocessor register state field. Use %name as the
+ * register field name for the secure instance. The non-secure instance
+ * has a "_nonsecure" suffix.
Where is the "_nonsecure" suffix?
The above comment appears to be incorrect as the code assumes that the 0th entry as the non-secure bank.
That comment is wrong and still reflects an earlier implementation where I didn’t yet use a union to be able to retain
the existing name. I will adjust it. Thanks for catching this.
+ */
+#define A32_BANKED_REG(type, name) \
+ union { \
+ type name; \
+ type name##_banked[2]; \
+ }
+
/* Meanings of the ARMCPU object's two inbound GPIO lines */
#define ARM_CPU_IRQ 0
#define ARM_CPU_FIQ 1
@@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
int dstreg, int operand);
+
struct arm_boot_info;
#define NB_MMU_MODES 5
@@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
return arm_feature(env, ARM_FEATURE_AARCH64);
}
+/* When EL3 is operating in Aarch32 state, the NS-bit determines
+ * whether the secure instance of a cp-register should be used. */
+#define USE_SECURE_REG(env) ( \
+ arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
+ !arm_el_is_aa64(env, 3) && \
+ !((env)->cp15.c1_scr & 1/*NS*/))
+
+#define NONSECURE_BANK 0
+#define SECURE_BANK 1
+
+#define A32_BANKED_REG_GET(env, regname) \
+ ((USE_SECURE_REG(env)) ? \
+ (env)->cp15.regname##_banked[SECURE_BANK] : \
+ (env)->cp15.regname)
+
+#define A32_MAPPED_EL3_REG_GET(env, regname) \
+ (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (USE_SECURE_REG(env))) ? \
+ (env)->cp15.regname##_el3 : \
+ (env)->cp15.regname##_el1)
+
+#define A32_BANKED_REG_SET(env, regname, val) \
+ do { \
+ if (USE_SECURE_REG(env)) { \
+ (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
+ } else { \
+ (env)->cp15.regname = (val); \
+ } \
+ } while (0)
+
+#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
+ do { \
+ if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (USE_SECURE_REG(env))) { \
+ (env)->cp15.regname##_el3 = (val); \
+ } else { \
+ (env)->cp15.regname##_el1 = (val); \
+ } \
+ } while (0)
+
+
+#define A32_BANKED_CURRENT_REG_GET(env, regname) \
+ ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
+ (env)->cp15.regname##_banked[SECURE_BANK] : \
+ (env)->cp15.regname)
+
+#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
+ (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
+ (env)->cp15.regname##_el3 : \
+ (env)->cp15.regname##_el1)
+
+#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
+ do { \
+ if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
+ (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
+ } else { \
+ (env)->cp15.regname = (val); \
+ } \
+ } while (0)
+
+#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
+ do { \
+ if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
+ (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
+ (env)->cp15.regname##_el3 = (val); \
+ } else { \
+ (env)->cp15.regname##_el1 = (val); \
+ } \
+ } while (0)
+
+
void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
/* Interface between CPU and Interrupt controller. */
@@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
* Crn, Crm, opc1, opc2 fields
* 32 or 64 bit register (ie is it accessed via MRC/MCR
* or via MRRC/MCRR?)
+ * nonsecure/secure bank (Aarch32 only)
* We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
* (In this case crn and opc2 should be zero.)
* For AArch64, there is no 32/64 bit size distinction;
@@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
#define CP_REG_AA64_SHIFT 28
#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
-#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
- (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
- ((crm) << 7) | ((opc1) << 3) | (opc2))
+/* To enable banking of coprocessor registers depending on ns-bit we
+ * add a bit to distinguish between secure and non-secure cpregs in the
+ * hashtable.
+ */
+#define CP_REG_NS_SHIFT 27
+#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
+
+#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
+ (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
+ ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
(CP_REG_AA64_MASK | \
@@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
* IO indicates that this register does I/O and therefore its accesses
* need to be surrounded by gen_io_start()/gen_io_end(). In particular,
* registers which implement clocks or timers require this.
+ * In an implementation with Security Extensions supporting Aarch32 cp regs can
+ * be banked or common. If a register is common it references the same variable
+ * from both worlds (non-secure and secure). For cp regs which neither set
+ * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
+ * will be inserted twice into the hashtable. If a register has
+ * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
+ * different offset respectively. This way Aarch32 registers which can be
+ * mapped to Aarch64 PL3 registers can be inserted individually.
*/
#define ARM_CP_SPECIAL 1
#define ARM_CP_CONST 2
@@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
#define ARM_CP_OVERRIDE 16
#define ARM_CP_NO_MIGRATE 32
#define ARM_CP_IO 64
-#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
-#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
-#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
-#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
-#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
+#define ARM_CP_SECURE (1 << 7)
+#define ARM_CP_NONSECURE (1 << 8)
+#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
+#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
+#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
+#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
+#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
+#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
/* Used only as a terminator for ARMCPRegInfo lists */
#define ARM_CP_SENTINEL 0xffff
/* Mask of only the flag bits in a type field */
-#define ARM_CP_FLAG_MASK 0x7f
+#define ARM_CP_FLAG_MASK 0x3ff
/* Valid values for ARMCPRegInfo state field, indicating which of
* the AArch32 and AArch64 execution states this register is visible in.
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9326ef8..98c3dc9 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
void *opaque, int state,
- int crm, int opc1, int opc2)
+ int crm, int opc1, int opc2, int nsbit)
{
/* Private utility function for define_one_arm_cp_reg_with_opaque():
* add a single reginfo struct to the hash table.
@@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
}
#endif
}
+
+ if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
+ if (r2->fieldoffset) {
+ /* We simplify register definitions by providing a type
+ * ARM_CP_BANKED, for which the fieldoffset of the secure instance
+ * will be increased to point at the second entry of the array.
+ *
+ * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
+ * wide the banked register is because some registers are 64bit
+ * wide but the register is not defined as 64bit because it is
+ * mapped to the lower 32 bit.
+ * Therefore two separate types for 64bit banked registers and
+ * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
+ */
+ r2->fieldoffset +=
+ ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
+ sizeof(uint64_t) : sizeof(uint32_t);
Do we want the register info descriptors of banked registers to point to the same storage if the security extension is not enabled?
Good point. We could only point the registers which are of type ARM_CP_BANKED to their non-secure instance though (by not adding
the additional offset here), as most of the secure cpregs point to the _EL3 variable.
+ }
+ }
+ /* For A32 we want to be able to know whether the secure or non-secure
+ * instance wants to be accessed. A64 does not know this banking scheme
+ * anymore, but it might use the same readfn/writefn as A32 which might
+ * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
+ * Reset the type according to ns-bit passed as argument.
+ */
+ r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
+ r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
+
if (state == ARM_CP_STATE_AA64) {
/* To allow abbreviation of ARMCPRegInfo
* definitions, we treat cp == 0 as equivalent to
@@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
*key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
r2->opc0, opc1, opc2);
} else {
- *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
+ *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
}
if (opaque) {
r2->opaque = opaque;
@@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
oldreg = g_hash_table_lookup(cpu->cp_regs, key);
if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
fprintf(stderr, "Register redefined: cp=%d %d bit "
- "crn=%d crm=%d opc1=%d opc2=%d, "
+ "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
"was %s, now %s\n", r2->cp, 32 + 32 * is64,
r2->crn, r2->crm, r2->opc1, r2->opc2,
+ (r2->type & ARM_CP_NONSECURE),
oldreg->name, r2->name);
g_assert_not_reached();
}
@@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
continue;
}
- add_cpreg_to_hashtable(cpu, r, opaque, state,
- crm, opc1, opc2);
+
+ if (state == ARM_CP_STATE_AA32) {
+ if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
+ (r->type & ARM_CP_BANKED) == 0) {
+ /* Under Aarch32 CP registers can be common
+ * (same for secure and non-secure world) or banked.
+ * Register definitions with neither secure nor
+ * non-secure type set (common) or with both bits
+ * set (banked) will be inserted twice into the
+ * hashtable.
+ */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 0);
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 1);
+ } else {
+ /* Only one of both bank types were specified */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2,
+ (r->type & ARM_CP_NONSECURE) ? 1 : 0);
+ }
+ } else {
+ /* Aarch64 registers get mapped to non-secure instance
+ * of Aarch32 */
+ add_cpreg_to_hashtable(cpu, r, opaque, state,
+ crm, opc1, opc2, 1);
+ }
}
}
}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index bbd4c77..3a429ac 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
{
- int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
+ int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
const ARMCPRegInfo *ri;
cpnum = (insn >> 8) & 0xf;
@@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
isread = (insn >> 20) & 1;
rt = (insn >> 12) & 0xf;
+ /* Monitor mode is always treated as secure but cp register reads/writes
+ * can access secure and non-secure instances using SCR.NS bit*/
+ ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
While monitor mode is always considered secure, which system register accessed is still based on the NS bit, so unless I am missing something, shouldn't the ns setting be purely based on USE_SECURE_REG?
Also, doesn't IS_NS() simply indicate the the TB was generated for secure state and not necessarily monitor mode? Plus, shouldn't this code still be allowed to access the non-secure bank?
My thinking was: ns = 1 gets the non-secure instance from the hashtable while ns = 0 gets the secure instance.
IS_NS(s) is true if the CPU does not implement Security Extensions or if the TB was generated for non-secure state and false otherwise.
In case it is false, we are in secure state and therefore have to use USE_SECURE_REG to determine whether the code wants to access
the secure or non-secure instance since monitor mode should be able to access both.
ri = get_arm_cp_reginfo(s->cp_regs,
- ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
+ ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
if (ri) {
/* Check access permissions */
if (!cp_access_ok(s->current_pl, ri, isread)) {
@@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
*/
if (is64) {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
- "64 bit system register cp:%d opc1: %d crm:%d\n",
- isread ? "read" : "write", cpnum, opc1, crm);
+ "64 bit system register cp:%d opc1: %d crm:%d "
+ "(%s)\n",
+ isread ? "read" : "write", cpnum, opc1, crm,
+ ns ? "non-secure" : "secure");
} else {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
- "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
- isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
+ "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
+ "(%s)\n",
+ isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
+ ns ? "non-secure" : "secure");
}
return 1;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list
2014-05-14 14:19 ` Greg Bellows
@ 2014-05-15 9:28 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-15 9:28 UTC (permalink / raw)
To: Greg Bellows
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
On 14 May 2014, at 16:19, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
On 13 May 2014 11:15, Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>> wrote:
From: Sergey Fedorov <s.fedorov@samsung.com<mailto:s.fedorov@samsung.com>>
Define a new ARM CP register info list for the Security Extension feature.
Register that list only for ARM cores with Security Extension support.
Moving SCR into Security Extension register group.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com<mailto:s.fedorov@samsung.com>>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>>
---
target-arm/helper.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3be917c..7898f40 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -768,9 +768,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.access = PL1_RW, .writefn = vbar_write,
.fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
.resetvalue = 0 },
- { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
@@ -2087,6 +2084,15 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush(CPU(cpu), 1);
}
+static const ARMCPRegInfo tz_cp_reginfo[] = {
Sticking with the feature name switch from TRUSTZONE to SECURITY, for consistency we should call this security_cp_reginfo.
Makes sense. I will change it.
+#ifndef CONFIG_USER_ONLY
+ { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
+ .resetvalue = 0, },
+#endif
+ REGINFO_SENTINEL
+};
+
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
@@ -2364,6 +2370,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_LPAE)) {
define_arm_cp_regs(cpu, lpae_cp_reginfo);
}
+ if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
+ define_arm_cp_regs(cpu, tz_cp_reginfo);
+ }
/* Slightly awkwardly, the OMAP and StrongARM cores need all of
* cp15 crn=0 to be writes-ignored, whereas for other cores they should
* be read-only (ie write causes UNDEF exception).
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function
2014-05-14 22:22 ` Greg Bellows
@ 2014-05-15 13:00 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-15 13:00 UTC (permalink / raw)
To: Greg Bellows
Cc: Peter Maydell, Sergey Fedorov, Edgar E. Iglesias, QEMU Developers,
Fedorov Sergey
The v8 ARM ARM only leaves it as implementation defined when EL2 is not implemented,
otherwise is has only a non-secure state as Peter said. Another reason why I chose to make
the default non-secure is the suggested mapping of non-secure Aarch32 registers to EL1 and
secure Aarch32 registers to EL3 (D1.20.1).
To me it seems that it depends whether we want to follow the ARM ARM v7 or v8. Based on Peter’s
comment I’d go for the NS-only approach.
Fabian
On 15 May 2014, at 00:22, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
Thanks for the input Peter.
>From briefly looking, it actually looks like the ARMv7 spec more strictly states that the default is secure. ARMv8 on the other hand appears to leave it open as implementation defined,
Based on out past discussions, I assumed non-secure as the default and that appears to be the direction of Fabian's code as well. Clearly if we want to follow the spec, we'd both need to change this default.
Greg
On 14 May 2014 16:29, Peter Maydell <peter.maydell@linaro.org<mailto:peter.maydell@linaro.org>> wrote:
On 14 May 2014 21:22, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
> I suppose it depends on how true we want to be to the specification and
> whether our default is NS=0 or NS=1 when the security extension is present
> or not. The code currently assumes non-secure as the default state.
The v8 ARM ARM at least allows the CPU to behave as if only
NS was present if there is no implementation of the Security
extensions. I haven't checked the v7 wording.
(In general I think QEMU's implementation of this should follow
the v8 ARM ARM and treat v7 CPUs as a sort of special degenerate
case.)
> Is there a convention in qemu? How closely do we attempt to stay to the
> pseudo code provided in the spec?
The pseudocode in the ARM ARM is part of the spec. We should
strive to follow the spec. This doesn't necessarily mean matching
pseudocode functions exactly -- the requirement is to be
behaviourally the same, and sometimes the pseudocode is
written to be clear rather than efficient or to deal with situations
we don't necessarily care about.
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers
2014-05-14 21:20 ` Greg Bellows
@ 2014-05-15 13:10 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-15 13:10 UTC (permalink / raw)
To: Greg Bellows
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers, Peter Maydell
On 14 May 2014, at 23:20, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
On 13 May 2014 11:16, Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>> wrote:
Some of SCTRL bits are common for secure and non-secure state.
Translation table base masks are updated on NS-bit switch as
well as on TTBCR writes.
Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com<mailto:s.fedorov@samsung.com>>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch<mailto:aggelerf@ethz.ch>>
---
target-arm/cpu.h | 10 ++++++++++
target-arm/helper.c | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c20c44a..7893004 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -425,6 +425,14 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
#define SCTLR_AFE (1U << 29)
#define SCTLR_TE (1U << 30)
+/* Bitmask for banked bits (Security Extensions) */
+#define SCTLR_BANKED (SCTLR_TE | SCTLR_AFE | SCTLR_TRE | SCTLR_EE | \
+ SCTLR_VE | SCTLR_HA | SCTLR_UWXN | SCTLR_WXN | SCTLR_V | \
+ SCTLR_I | SCTLR_Z | SCTLR_SW | SCTLR_CP15BEN | SCTLR_C | \
+ SCTLR_A | SCTLR_M)
+/* Treat bits that are not explicitly banked as common */
+#define SCTLR_COMMON (~SCTLR_BANKED)
+
#define CPSR_M (0x1fU)
#define CPSR_T (1U << 5)
#define CPSR_F (1U << 6)
@@ -662,6 +670,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
return (env->features & (1ULL << feature)) != 0;
}
+#define SCR_NS (1U << 0)
+
/* Return true if the processor is in secure state */
static inline bool arm_is_secure(CPUARMState *env)
{
diff --git a/target-arm/helper.c b/target-arm/helper.c
index c76a86b..618fd31 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2165,12 +2165,49 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
raw_write(env, ri, value);
+
+ if (!arm_el_is_aa64(env, 3)) {
+ /* Aarch32 has some bits that are common to secure (mapped to
+ * SCTLR_EL3) and non-secure instances of the SCTLR. */
+
+ env->cp15.c1_sys_el1 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ env->cp15.c1_sys_el3 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ }
+
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu), 1);
}
#ifndef CONFIG_USER_ONLY
+static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
+{
+ if (!arm_el_is_aa64(env, 3) &&
+ (value & SCR_NS) != (env->cp15.c1_scr & SCR_NS)) {
+ /* If EL3 is using Aarch32 switching NS-bit may make the CPU use a
+ * different instance (secure or non-secure) when accessing CP
+ * registers.
+ * Common bits of otherwise banked registers need to by synchronized
+ * at this point.
+ */
+ env->cp15.c1_sys_el1 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
+ env->cp15.c1_sys_el3 &= SCTLR_BANKED |
+ (arm_current_sctlr(env) & SCTLR_COMMON);
I must be missing something, if the common bits are sync'd across the banks in sctlr_write(), why do we need to do it here?
Right, should not be needed. I’ll remove it.
+ }
+
+ env->cp15.c1_scr = value;
+
+ /* After possible switch, calculate c2_mask and c2_base_mask again for the
+ * instance which is now active (secure or non-secure).
+ */
+ int maskshift = extract32(A32_BANKED_REG_GET(env, c2_control), 0, 3);
+ env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift);
+ env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift);
As mentioned elsewhere, does it make sense to bank the c2_mask fields so they stay in sync with c2_control? Presumably we would not need to do these updates in this case.
Good idea, I will bank them and remove this bit.
+
+}
static void nsacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
@@ -2183,7 +2220,7 @@ static const ARMCPRegInfo tz_cp_reginfo[] = {
#ifndef CONFIG_USER_ONLY
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
+ .resetvalue = 0, .writefn = scr_write },
{ .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 6, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
--
1.8.3.2
^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-14 18:39 ` Fedorov Sergey
@ 2014-05-15 14:44 ` Fabian Aggeler
2014-05-15 15:06 ` Sergey Fedorov
0 siblings, 1 reply; 75+ messages in thread
From: Fabian Aggeler @ 2014-05-15 14:44 UTC (permalink / raw)
To: Fedorov Sergey, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
On 14/05/14 20:39, Fedorov Sergey wrote:
>
> 14.05.2014 10:06, Sergey Fedorov пишет:
>> On 13.05.2014 20:15, Fabian Aggeler wrote:
>>> From: Sergey Fedorov <s.fedorov@samsung.com>
>>>
>>> CPACR register allows to control access rights to coprocessor 0-13
>>> interfaces. Bits corresponding to unimplemented coprocessors should be
>>> RAZ/WI. QEMU implements only VFP coprocessor on ARMv6+ targets. So only
>>> cp10 & cp11 bits are writable.
>>>
>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>>> ---
>>> target-arm/helper.c | 6 ++++++
>>> target-arm/translate.c | 26 +++++++++++++++++++++++---
>>> 2 files changed, 29 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>>> index cf1f88c..4e82259 100644
>>> --- a/target-arm/helper.c
>>> +++ b/target-arm/helper.c
>>> @@ -477,6 +477,12 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
>>> static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>>> uint64_t value)
>>> {
>>> + uint32_t mask = 0;
>>> +
>>> + if (arm_feature(env, ARM_FEATURE_VFP)) {
>>> + mask |= 0x00f00000; /* VFP coprocessor: cp10 & cp11 */
>>> + }
>>> + value &= mask;
>>> if (env->cp15.c1_coproc != value) {
>>> env->cp15.c1_coproc = value;
>>> /* ??? Is this safe when called from within a TB? */
>>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>>> index 87d0918..c815fb3 100644
>>> --- a/target-arm/translate.c
>>> +++ b/target-arm/translate.c
>>> @@ -6866,9 +6866,29 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>> const ARMCPRegInfo *ri;
>>>
>>> cpnum = (insn >> 8) & 0xf;
>>> - if (arm_feature(env, ARM_FEATURE_XSCALE)
>>> - && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
>>> - return 1;
>>> + if (cpnum < 14) {
>>> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
>>> + if (~env->cp15.c15_cpar & (1 << cpnum)) {
>>> + return 1;
>>> + }
>>> + } else {
>>> + /* Bits [20:21] of CPACR control access to cp10
>>> + * Bits [23:22] of CPACR control access to cp11 */
>>> + switch ((env->cp15.c1_coproc >> (cpnum * 2)) & 3) {
>>> + case 0: /* access denied */
>>> + return 1;
>>> + case 1: /* privileged mode access only */
>>> + if (IS_USER(s)) {
>>> + return 1;
>>> + }
>>> + break;
>>> + case 2: /* reserved */
>>> + return 1;
>>> + case 3: /* privileged and user mode access */
>>> + break;
>>> + }
>>> + }
>>> + }
>>>
>>> /* First check for coprocessor space used for actual instructions */
>>> switch (cpnum) {
>> Please, look at disas_vfp_insn() and disas_neon_*_insn() functions.
>> Looks like them should be updated. In that case do not forget to adjust
>> arm_cpu_reset() so user emulation would be able to execute VFP/NEON
>> instructions.
>
> See ARM ARM v7-AR B1.11.1
>
I don't quite get what you mean. Bits 20-24 of c1_coproc already get set
to 1 for user emulation in arm_cpu_reset(). And disas_cfp_insn and
disas_neon_*_insn() all check s->cpacr_fpen in the beginning (which gets
set in cpu_get_tb_cpu_state() if bits 20-22 of c1_coproc are set to 3 or
(1 && cpu is in user mode)).
So I guess we should add some checks for NSACR, to only set that flag if
the corresponding NSACR bit is set.
>>
>> Thanks,
>> Sergey.
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic
2014-05-15 14:44 ` Fabian Aggeler
@ 2014-05-15 15:06 ` Sergey Fedorov
0 siblings, 0 replies; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-15 15:06 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
On 15.05.2014 18:44, Fabian Aggeler wrote:
>>> Please, look at disas_vfp_insn() and disas_neon_*_insn() functions.
>>> Looks like them should be updated. In that case do not forget to adjust
>>> arm_cpu_reset() so user emulation would be able to execute VFP/NEON
>>> instructions.
>>
>> See ARM ARM v7-AR B1.11.1
>>
>
> I don't quite get what you mean. Bits 20-24 of c1_coproc already get
> set to 1 for user emulation in arm_cpu_reset(). And disas_cfp_insn and
> disas_neon_*_insn() all check s->cpacr_fpen in the beginning (which
> gets set in cpu_get_tb_cpu_state() if bits 20-22 of c1_coproc are set
> to 3 or (1 && cpu is in user mode)).
>
> So I guess we should add some checks for NSACR, to only set that flag
> if the corresponding NSACR bit is set.
Sorry, you are right.
Regards,
Sergey.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
2014-05-14 16:42 ` Greg Bellows
@ 2014-05-15 18:42 ` Sergey Fedorov
2014-05-15 19:10 ` Aggeler Fabian
2014-05-22 7:41 ` Edgar E. Iglesias
2 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-15 18:42 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, Sergey Fedorov, peter.maydell
13.05.2014 20:15, Fabian Aggeler wrote:
> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
> * IO indicates that this register does I/O and therefore its accesses
> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
> * registers which implement clocks or timers require this.
> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
> + * be banked or common. If a register is common it references the same variable
> + * from both worlds (non-secure and secure). For cp regs which neither set
> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
> + * will be inserted twice into the hashtable. If a register has
> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
> + * different offset respectively. This way Aarch32 registers which can be
> + * mapped to Aarch64 PL3 registers can be inserted individually.
> */
I think it could be done with just adding a single flag indicating that
NS tag of reginfo should be considered, otherwise insert reginfo into
the hashtable twice.
In order to distinguish 64 bit register, there is already ARM_CP_64BIT
macro defined.
Regards,
Sergey
> #define ARM_CP_SPECIAL 1
> #define ARM_CP_CONST 2
> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
> #define ARM_CP_OVERRIDE 16
> #define ARM_CP_NO_MIGRATE 32
> #define ARM_CP_IO 64
> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
> +#define ARM_CP_SECURE (1 << 7)
> +#define ARM_CP_NONSECURE (1 << 8)
> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
> /* Used only as a terminator for ARMCPRegInfo lists */
> #define ARM_CP_SENTINEL 0xffff
> /* Mask of only the flag bits in a type field */
> -#define ARM_CP_FLAG_MASK 0x7f
> +#define ARM_CP_FLAG_MASK 0x3ff
>
> /* Valid values for ARMCPRegInfo state field, indicating which of
> * the AArch32 and AArch64 execution states this register is visible in.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
` (22 preceding siblings ...)
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 23/23] target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI Fabian Aggeler
@ 2014-05-15 18:57 ` Sergey Fedorov
2014-05-16 6:00 ` Aggeler Fabian
23 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-15 18:57 UTC (permalink / raw)
To: Fabian Aggeler, qemu-devel; +Cc: edgar.iglesias, peter.maydell
Can s.fedorov@samsung.com be removed from CC list since this mailbox has
been deleted? That was my address when I worked for Samsung. Now sending
to this address results with annoying delivery failure notification.
Thanks,
Sergey.
13.05.2014 20:15, Fabian Aggeler wrote:
> Hi,
>
> This is a rework of the Samsung patches sent last year to add Security
> Extensions. The patches have been changed based on the discussion on
> the mailing list. Other changes became necessary because of Aarch64
> support which got added in the meantime. This patchset makes it possible
> to run a kernel in the secure world and then switch to non-secure
> on CPUs that implement Security Extensions. It works for EL3 in Aarch32
> state, but may add _EL3 registers where necessary to reflect the mapping
> of secure instances of cp registers to _EL3 registers.
>
> Banking of cp registers has been changed from active mass-swapping to
> the mechanism discussed on the mailing list, where every Aarch32 cp
> register goes into the hashtable twice. A ns-bit is added to the key
> of the register which is used when accessing a cp register to get the
> correct instance.
>
> Magic numbers have been changed to bitshifted constants or macros to make
> the code easier to read.
>
> The whole patchset now uses the term Security Extensions instead of
> TrustZone as this is the term which is used in the ARM ARM.
>
> I am happy for any feedback, especially for the banking of course. It should
> not be too hard to combine these changes with the recent effort towards EL3
> in A64.
>
> Thanks,
> Fabian
>
> Fabian Aggeler (12):
> target-arm: add arm_is_secure() function
> target-arm: add NSACR support
> target-arm: Split TLB for secure state and EL3 in Aarch64
> target-arm: add banked coprocessor register type and macros
> target-arm: Restrict EL3 to Aarch32 state
> target-arm: Use arm_current_sctlr to access SCTLR
> target-arm: Use raw_write/raw_read whenever possible
> target-arm: Convert banked coprocessor registers
> target-arm: maintain common bits of banked CP registers
> target-arm: add MVBAR support
> target-arm: implement IRQ/FIQ routing to Monitor mode
> target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI
>
> Sergey Fedorov (8):
> target-arm: move SCR into Security Extensions register list
> target-arm: adjust TTBCR for Security Extension feature
> target-arm: reject switching to monitor mode from non-secure state
> target-arm: adjust arm_current_pl() for Security Extensions
> target-arm: add non-secure Translation Block flag
> target-arm: implement CPACR register logic
> target-arm: add SDER definition
> target-arm: implement SMC instruction
>
> Svetlana Fedoseeva (3):
> target-arm: add new CPU feature for Security Extensions
> target-arm: preserve RAO/WI bits of ARMv7 SCTLR
> target-arm: add CPU Monitor mode
>
> hw/arm/pxa2xx.c | 2 +-
> linux-user/main.c | 2 +-
> target-arm/cpu-qom.h | 1 +
> target-arm/cpu.c | 8 +-
> target-arm/cpu.h | 271 ++++++++++++++++++++++---
> target-arm/helper-a64.c | 3 +-
> target-arm/helper.c | 489 ++++++++++++++++++++++++++++++++++++---------
> target-arm/machine.c | 6 +-
> target-arm/op_helper.c | 2 +-
> target-arm/translate-a64.c | 9 +-
> target-arm/translate.c | 342 ++++++++++++++++++-------------
> target-arm/translate.h | 4 +
> 12 files changed, 866 insertions(+), 273 deletions(-)
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-15 18:42 ` Sergey Fedorov
@ 2014-05-15 19:10 ` Aggeler Fabian
2014-05-16 7:06 ` Sergey Fedorov
0 siblings, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-15 19:10 UTC (permalink / raw)
To: Sergey Fedorov; +Cc: Edgar E. Iglesias, QEMU Developers, Peter Maydell
On 15 May 2014, at 20:42, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> 13.05.2014 20:15, Fabian Aggeler wrote:
>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>> * IO indicates that this register does I/O and therefore its accesses
>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
>> * registers which implement clocks or timers require this.
>> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
>> + * be banked or common. If a register is common it references the same variable
>> + * from both worlds (non-secure and secure). For cp regs which neither set
>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
>> + * will be inserted twice into the hashtable. If a register has
>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
>> + * different offset respectively. This way Aarch32 registers which can be
>> + * mapped to Aarch64 PL3 registers can be inserted individually.
>> */
>
> I think it could be done with just adding a single flag indicating that
> NS tag of reginfo should be considered, otherwise insert reginfo into
> the hashtable twice.
> In order to distinguish 64 bit register, there is already ARM_CP_64BIT
> macro defined.
The distinction whether the underlying field is 64bit or 32bit was necessary
because some cp regs are not of type ARM_CP_64BIT but get mapped
to (the lower or upper 32 bits of) a 64bit field. So to be able to add the correct offset
in the case of a banked register I came up with these two types.
Since there are only a few registers left which don’t get mapped to EL3 registers
we could define them explicitly and therefore get rid of ARM_CP_BANKED and
ARM_CP_BANKED_64BIT as well as increasing the offset before adding them to
the hashtable.
But like this we would still need 2 bits, one to specify whether it is ns or not, and
one whether it is common or banked. Or am I missing something here?
>
> Regards,
> Sergey
>
>> #define ARM_CP_SPECIAL 1
>> #define ARM_CP_CONST 2
>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>> #define ARM_CP_OVERRIDE 16
>> #define ARM_CP_NO_MIGRATE 32
>> #define ARM_CP_IO 64
>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
>> +#define ARM_CP_SECURE (1 << 7)
>> +#define ARM_CP_NONSECURE (1 << 8)
>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
>> /* Used only as a terminator for ARMCPRegInfo lists */
>> #define ARM_CP_SENTINEL 0xffff
>> /* Mask of only the flag bits in a type field */
>> -#define ARM_CP_FLAG_MASK 0x7f
>> +#define ARM_CP_FLAG_MASK 0x3ff
>>
>> /* Valid values for ARMCPRegInfo state field, indicating which of
>> * the AArch32 and AArch64 execution states this register is visible in.
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-15 18:57 ` [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Sergey Fedorov
@ 2014-05-16 6:00 ` Aggeler Fabian
2014-05-16 20:56 ` Greg Bellows
0 siblings, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-16 6:00 UTC (permalink / raw)
To: Sergey Fedorov
Cc: edgar.iglesias@gmail.com, qemu-devel@nongnu.org, Aggeler Fabian,
peter.maydell@linaro.org
Yes, sorry about that.
Best,
Fabian
> On 15.05.2014, at 20:58, "Sergey Fedorov" <serge.fdrv@gmail.com> wrote:
>
> Can s.fedorov@samsung.com be removed from CC list since this mailbox has
> been deleted? That was my address when I worked for Samsung. Now sending
> to this address results with annoying delivery failure notification.
>
> Thanks,
> Sergey.
>
> 13.05.2014 20:15, Fabian Aggeler wrote:
>> Hi,
>>
>> This is a rework of the Samsung patches sent last year to add Security
>> Extensions. The patches have been changed based on the discussion on
>> the mailing list. Other changes became necessary because of Aarch64
>> support which got added in the meantime. This patchset makes it possible
>> to run a kernel in the secure world and then switch to non-secure
>> on CPUs that implement Security Extensions. It works for EL3 in Aarch32
>> state, but may add _EL3 registers where necessary to reflect the mapping
>> of secure instances of cp registers to _EL3 registers.
>>
>> Banking of cp registers has been changed from active mass-swapping to
>> the mechanism discussed on the mailing list, where every Aarch32 cp
>> register goes into the hashtable twice. A ns-bit is added to the key
>> of the register which is used when accessing a cp register to get the
>> correct instance.
>>
>> Magic numbers have been changed to bitshifted constants or macros to make
>> the code easier to read.
>>
>> The whole patchset now uses the term Security Extensions instead of
>> TrustZone as this is the term which is used in the ARM ARM.
>>
>> I am happy for any feedback, especially for the banking of course. It should
>> not be too hard to combine these changes with the recent effort towards EL3
>> in A64.
>>
>> Thanks,
>> Fabian
>>
>> Fabian Aggeler (12):
>> target-arm: add arm_is_secure() function
>> target-arm: add NSACR support
>> target-arm: Split TLB for secure state and EL3 in Aarch64
>> target-arm: add banked coprocessor register type and macros
>> target-arm: Restrict EL3 to Aarch32 state
>> target-arm: Use arm_current_sctlr to access SCTLR
>> target-arm: Use raw_write/raw_read whenever possible
>> target-arm: Convert banked coprocessor registers
>> target-arm: maintain common bits of banked CP registers
>> target-arm: add MVBAR support
>> target-arm: implement IRQ/FIQ routing to Monitor mode
>> target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI
>>
>> Sergey Fedorov (8):
>> target-arm: move SCR into Security Extensions register list
>> target-arm: adjust TTBCR for Security Extension feature
>> target-arm: reject switching to monitor mode from non-secure state
>> target-arm: adjust arm_current_pl() for Security Extensions
>> target-arm: add non-secure Translation Block flag
>> target-arm: implement CPACR register logic
>> target-arm: add SDER definition
>> target-arm: implement SMC instruction
>>
>> Svetlana Fedoseeva (3):
>> target-arm: add new CPU feature for Security Extensions
>> target-arm: preserve RAO/WI bits of ARMv7 SCTLR
>> target-arm: add CPU Monitor mode
>>
>> hw/arm/pxa2xx.c | 2 +-
>> linux-user/main.c | 2 +-
>> target-arm/cpu-qom.h | 1 +
>> target-arm/cpu.c | 8 +-
>> target-arm/cpu.h | 271 ++++++++++++++++++++++---
>> target-arm/helper-a64.c | 3 +-
>> target-arm/helper.c | 489 ++++++++++++++++++++++++++++++++++++---------
>> target-arm/machine.c | 6 +-
>> target-arm/op_helper.c | 2 +-
>> target-arm/translate-a64.c | 9 +-
>> target-arm/translate.c | 342 ++++++++++++++++++-------------
>> target-arm/translate.h | 4 +
>> 12 files changed, 866 insertions(+), 273 deletions(-)
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-15 19:10 ` Aggeler Fabian
@ 2014-05-16 7:06 ` Sergey Fedorov
0 siblings, 0 replies; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-16 7:06 UTC (permalink / raw)
To: Aggeler Fabian; +Cc: Edgar E. Iglesias, QEMU Developers, Peter Maydell
On 15.05.2014 23:10, Aggeler Fabian wrote:
> On 15 May 2014, at 20:42, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>
>> 13.05.2014 20:15, Fabian Aggeler wrote:
>>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>> * IO indicates that this register does I/O and therefore its accesses
>>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
>>> * registers which implement clocks or timers require this.
>>> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
>>> + * be banked or common. If a register is common it references the same variable
>>> + * from both worlds (non-secure and secure). For cp regs which neither set
>>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
>>> + * will be inserted twice into the hashtable. If a register has
>>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
>>> + * different offset respectively. This way Aarch32 registers which can be
>>> + * mapped to Aarch64 PL3 registers can be inserted individually.
>>> */
>> I think it could be done with just adding a single flag indicating that
>> NS tag of reginfo should be considered, otherwise insert reginfo into
>> the hashtable twice.
>> In order to distinguish 64 bit register, there is already ARM_CP_64BIT
>> macro defined.
> The distinction whether the underlying field is 64bit or 32bit was necessary
> because some cp regs are not of type ARM_CP_64BIT but get mapped
> to (the lower or upper 32 bits of) a 64bit field. So to be able to add the correct offset
> in the case of a banked register I came up with these two types.
>
> Since there are only a few registers left which don’t get mapped to EL3 registers
> we could define them explicitly and therefore get rid of ARM_CP_BANKED and
> ARM_CP_BANKED_64BIT as well as increasing the offset before adding them to
> the hashtable.
>
> But like this we would still need 2 bits, one to specify whether it is ns or not, and
> one whether it is common or banked. Or am I missing something here?
NS tag can be added into ARMCPRegInfo structure, just like that was with
AArch64 (ARMCPRegInfo::state).
Regards,
Sergey.
>
>> Regards,
>> Sergey
>>
>>> #define ARM_CP_SPECIAL 1
>>> #define ARM_CP_CONST 2
>>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>> #define ARM_CP_OVERRIDE 16
>>> #define ARM_CP_NO_MIGRATE 32
>>> #define ARM_CP_IO 64
>>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
>>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
>>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
>>> +#define ARM_CP_SECURE (1 << 7)
>>> +#define ARM_CP_NONSECURE (1 << 8)
>>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
>>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
>>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
>>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
>>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
>>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
>>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
>>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
>>> /* Used only as a terminator for ARMCPRegInfo lists */
>>> #define ARM_CP_SENTINEL 0xffff
>>> /* Mask of only the flag bits in a type field */
>>> -#define ARM_CP_FLAG_MASK 0x7f
>>> +#define ARM_CP_FLAG_MASK 0x3ff
>>>
>>> /* Valid values for ARMCPRegInfo state field, indicating which of
>>> * the AArch32 and AArch64 execution states this register is visible in.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-16 6:00 ` Aggeler Fabian
@ 2014-05-16 20:56 ` Greg Bellows
2014-05-20 10:00 ` Aggeler Fabian
2014-05-21 13:55 ` Peter Maydell
0 siblings, 2 replies; 75+ messages in thread
From: Greg Bellows @ 2014-05-16 20:56 UTC (permalink / raw)
To: Aggeler Fabian
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org,
edgar.iglesias@gmail.com
[-- Attachment #1: Type: text/plain, Size: 24872 bytes --]
As mentioned in an earlier thread, I too have been building on Sergey's
trustzone changes. I wanted to share a subset of my changes related to
banked register support as an alternative.
*Overview*:
The approach delicately hashes all the SP registers just as Fabian's
approach does. The primary difference is that all the existing
ARMCPRegInfo entries are left as-is and are blindly registered for both
NS-bit settings (encoded in the hash key). Once all of the existing
registers have been added to the hash, the set of security specific
registers are hashed. Hashing of these registers involves a single new
type to indicate that the ARMCPRegInfo is a security update of an existing
register. On receipt of this type, a hash lookup is performed on the
register and it is updated for the security specifics. This primarily
involves updating the fieldoffset to point at the secure bank.
There are benefits to both approaches. In the above approach it avoids to
mark all register declarations as secure or banked and isolates the
security registers to their own mechanism. This can also be considered a
detriment as the existing registers are not explicitly marked.
*Update:*
Since the coding of the approach and reviewing of Fabian's changes, I have
discovered that further optimizations may be possible over the diffs
provided below.
- The registration of the security registers do not need to go through
add_cpreg_to_hash_table but rather have a simpler routine that takes the
ARMCPRegInfo group and walks through updating each register.
- The CP register duplication can be isolated to the routine used to
update the security registers. This cuts down on the entries in the hash
when the security extension is not present.
*Diffs:*
Below are a subset of the differences required for the aforementioned
approach. The diffs are built on top of Sergey's original patches and
against a recent baselevel. I have omitted code unnecessary for
demonstrating the approach. Also, my implementation is intended for ARMv7
only.
*diff --combined target-arm/cpu.h*
index 467eaa5,c83f249..0000000
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@@ -90,41 -89,9 +90,41 @@@ typedef void ARMWriteCPFunc(void *opaqu
typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
int dstreg, int operand);
+#define CP15_DEFAULT_BANK 1
+
+/* Define a banked coprocessor register state field. Use %name as the
active
+ * register state field name. The banked register state array field name
has
+ * "banked_" prefix. The banked register state array indexes corresponds
to
+ * SCR.NS bit value.
+ */
+#define BANKED_CP_REG(type, name) \
+ union { \
+ struct { \
+ type name##_sec; \
+ type name; \
+ }; \
+ type banked_##name[2]; \
+ }
+
+/* Secure bank selector macro
+ * Determines whether a co-processor access instruction should use a
banked
+ * Non-secure copy of a register instead of active one.
+ */
+#define CP_REG_BANK(env) \
+ (arm_feature((env), ARM_FEATURE_SECURITY) ? \
+ ((env)->cp15.c1_scr & 1) : CP15_DEFAULT_BANK)
+
+/* Get a banked CP15 register in co-processor access instruction handler
*/
+#define BANKED_CP15_REG_GET(env, regname) \
+ (env)->cp15.banked_##regname[CP_REG_BANK(env)]
+
+/* Set a banked CP15 register in co-processor access instruction handler
*/
+#define BANKED_CP15_REG_SET(env, regname, val) \
+ (env)->cp15.banked_##regname[CP_REG_BANK(env)] = (val)
+
struct arm_boot_info;
-#define NB_MMU_MODES 2
+#define NB_MMU_MODES 4
/* We currently assume float and double are IEEE single and double
precision respectively.
@@@ -201,29 -168,27 +201,29 @@@
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
- uint64_t c0_cssel; /* Cache size selection. */
- uint64_t c1_sys; /* System control register. */
+ BANKED_CP_REG(uint64_t, c0_cssel); /* Cache size selection. */
+ BANKED_CP_REG(uint64_t, c1_sys); /* System control register. */
uint64_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
- uint64_t ttbr0_el1; /* MMU translation table base 0. */
- uint64_t ttbr1_el1; /* MMU translation table base 1. */
- uint64_t c2_control; /* MMU translation table base control. */
+ uint32_t c1_sder; /* Secure debug enable register. */
+ uint32_t c1_nsacr; /* Non-secure access control register. */
+ BANKED_CP_REG(uint64_t, ttbr0_el1); /* MMU translation table base
0. */
+ BANKED_CP_REG(uint64_t, ttbr1_el1); /* MMU translation table base
1. */
+ BANKED_CP_REG(uint64_t, c2_control); /* MMU x-lation tbl base
cntrl.*/
uint32_t c2_mask; /* MMU translation table base selection mask.
*/
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
uint32_t c2_data; /* MPU data cachable bits. */
uint32_t c2_insn; /* MPU instruction cachable bits. */
- uint32_t c3; /* MMU domain access control register
- MPU write buffer control. */
+ BANKED_CP_REG(uint32_t, c3); /* MMU domain access control register
+ MPU write buffer control. */
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
- uint32_t ifsr_el2; /* Fault status registers. */
- uint64_t esr_el1;
+ BANKED_CP_REG(uint32_t, ifsr_el2); /* Fault status registers. */
+ BANKED_CP_REG(uint64_t, esr_el1);
uint32_t c6_region[8]; /* MPU base/size registers. */
- uint64_t far_el1; /* Fault address registers. */
- uint64_t par_el1; /* Translation result. */
+ BANKED_CP_REG(uint64_t, far_el1); /* Fault address registers. */
+ BANKED_CP_REG(uint64_t, par_el1); /* Translation result. */
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
uint32_t c9_pmcr; /* performance monitor control register */
@@@ -232,13 -197,12 +232,13 @@@
uint32_t c9_pmxevtyper; /* perf monitor event type */
uint32_t c9_pmuserenr; /* perf monitor user enable */
uint32_t c9_pminten; /* perf monitor interrupt enables */
- uint64_t mair_el1;
- uint64_t c12_vbar; /* vector base address register */
- uint32_t c13_fcse; /* FCSE PID. */
- uint64_t contextidr_el1; /* Context ID. */
- uint64_t tpidr_el0; /* User RW Thread register. */
- uint64_t tpidrro_el0; /* User RO Thread register. */
+ BANKED_CP_REG(uint64_t, mair_el1);
+ BANKED_CP_REG(uint64_t, c12_vbar); /* vector base address
register */
+ uint32_t c12_mvbar; /* monitor vector base address register */
+ BANKED_CP_REG(uint32_t, c13_fcse); /* FCSE PID. */
+ BANKED_CP_REG(uint64_t, contextidr_el1); /* Context ID. */
+ BANKED_CP_REG(uint64_t, tpidr_el0); /* User RW Thread register.
*/
+ BANKED_CP_REG(uint64_t ,tpidrro_el0); /* User RO Thread register.
*/
uint64_t tpidr_el1; /* Privileged Thread register. */
uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */
@@@ -676,17 -638,6 +676,17 @@@
return (env->features & (1ULL << feature)) != 0;
}
+/* Return true if the processor is in Secure state */
+static inline bool arm_is_secure(CPUARMState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
+ !(env->cp15.c1_scr & 1);
+#else
+ return false;
+#endif
+}
+
/* Return true if the specified exception level is running in AArch64
state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{
@@@ -738,8 -689,8 +738,8 @@@ void armv7m_nvic_complete_irq(void *opa
#define CP_REG_AA64_SHIFT 28
#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
-#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
- (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
+#define ENCODE_CP_REG(ns, cp, is64, crn, crm, opc1, opc2) \
+ (((ns) << 31) | ((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
((crm) << 7) | ((opc1) << 3) | (opc2))
#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
@@@ -809,12 -760,6 +809,12 @@@ static inline uint64_t cpreg_to_kvm_id(
#define ARM_CP_OVERRIDE 16
#define ARM_CP_NO_MIGRATE 32
#define ARM_CP_IO 64
+/* Secure CP register type.
+ * This flag indicates that the ARMCPRegInfo is a secure register entry.
+ * This flag includes override as the registration may override the
+ * previously registered attributes.
+ */
+#define ARM_CP_SECURE (ARM_CP_OVERRIDE | 128)
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
*diff --combined target-arm/helper.c*
index 70f34c0,3be917c..0000000
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@@ -768,6 -763,14 +768,6 @@@ static const ARMCPRegInfo v7_cp_reginfo
.access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
.resetvalue = 0, .writefn = pmintenclr_write, },
- { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .writefn = vbar_write,
- .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
- .resetvalue = 0 },
- { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
+static const ARMCPRegInfo security_cp_reginfo[] = {
+#ifndef CONFIG_USER_ONLY
+ /*
+ * Restricted access registers
+ * These registers are restricted to secure state access only. Just
like
+ * the non-secure registers, both ns-bit settings are registered.
These
+ * registers are not marked secure as they are not banked.
+ */
+ { .name = "VBAR", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .writefn = vbar_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
+ .resetvalue = 0 },
+ { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
+ .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
+ .writefn = scr_write, .resetvalue = 0 },
+ { .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
+ { .name = "MVBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 =
1,
+ .access = PL3_RW, .resetvalue = 0,
+ .writefn = vbar_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_mvbar) },
+ { .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 2,
+ .access = PL3_RW | PL1_R | PL2_R, .resetvalue = 0, .writefn =
nsacr_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_nsacr) },
+
+ /*
+ * Banked registers
+ * These registers are banked so we need to reregister the secure bank
+ * to use a new register location. It is expected that the register
was
+ * previously registered, in which case we will preserve the previous
+ * settings besides the fieldoffset and type.
+ */
+ { .name = "CSSELR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 =
0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel_sec) },
+ { .name = "SCTLR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_sec),
+ .writefn = sctlr_write, .raw_writefn = raw_write},
+ /* TODO: ADD ACTLR */
+ { .name = "TTBR0_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2
= 0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1_sec) },
+ { .name = "TTBR1_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2
= 1,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1_sec) },
+ /* TODO: ADD in TTBR0/1 for LPAE */
+ { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .type =
ARM_CP_SECURE,
+ .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .fieldoffset = offsetof(CPUARMState, cp15.c2_control_sec) },
+ { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control_sec) },
+ { .name = "DACR",
+ .cp = 15, .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c3_sec) },
+ { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1_sec) },
+ { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2_sec) },
+ { .name = "FAR_EL1", .state = ARM_CP_STATE_AA32, .type =
ARM_CP_SECURE,
+ .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.far_el1_sec) },
+ { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1_sec) },
+ { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.par_el1_sec) },
+ { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1_sec) },
+ { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1_sec) },
+ { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
= 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse_sec) },
+ { .name = "CONTEXTIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0,
.opc2 = 1,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1_sec) },
+ { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
= 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0_sec) },
+ { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
= 3,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0_sec) },
+#endif
+ REGINFO_SENTINEL
+};
+
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@@@ -2665,13 -2532,6 +2665,13 @@@
}
define_one_arm_cp_reg(cpu, &sctlr);
}
+ /*
+ * Register the security extension registers last as they may
override the
+ * bank of previsously registered registers.
+ */
+ if (arm_feature(env, ARM_FEATURE_SECURITY)) {
+ define_arm_cp_regs(cpu, security_cp_reginfo);
+ }
}
ARMCPU *cpu_arm_init(const char *cpu_model)
@@@ -2785,7 -2645,7 +2785,7 @@@ CpuDefinitionInfoList *arch_query_cpu_d
}
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
- void *opaque, int state,
+ void *opaque, int state, int ns,
int crm, int opc1, int opc2)
{
/* Private utility function for define_one_arm_cp_reg_with_opaque():
@@@ -2810,11 -2670,6 +2810,11 @@@
#endif
}
if (state == ARM_CP_STATE_AA64) {
+ if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
+ g_free(key);
+ g_free(r2);
+ return;
+ }
/* To allow abbreviation of ARMCPRegInfo
* definitions, we treat cp == 0 as equivalent to
* the value for "standard guest-visible sysreg".
@@@ -2825,7 -2680,7 +2825,7 @@@
*key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
r2->opc0, opc1, opc2);
} else {
- *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
+ *key = ENCODE_CP_REG(ns, r2->cp, is64, r2->crn, crm, opc1, opc2);
}
if (opaque) {
r2->opaque = opaque;
@@@ -2868,30 -2723,6 +2868,30 @@@
g_assert_not_reached();
}
}
+
+ if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
+ if (ns == 1) {
+ /* SECURE registers only apply to the ns = 0, so skip the ns
= 1,
+ * version, but first free the allocated hash data..
+ */
+ g_free(key);
+ g_free(r2);
+ return;
+ }
+
+ ARMCPRegInfo *oldreg = g_hash_table_lookup(cpu->cp_regs, key);
+ /* If we find a match for the key then we can leave it in the
hash and
+ * simply update the necessary fields. Once updated we can
release the
+ * allocated hash data and return.
+ */
+ if (oldreg) {
+ oldreg->type |= ARM_CP_SECURE;
+ oldreg->fieldoffset = r->fieldoffset;
+ g_free(key);
+ g_free(r2);
+ return;
+ }
+ }
g_hash_table_insert(cpu->cp_regs, key, r2);
}
@@@ -2999,16 -2829,8 +2999,16 @@@
if (r->state != state && r->state !=
ARM_CP_STATE_BOTH) {
continue;
}
- add_cpreg_to_hashtable(cpu, r, opaque, state,
- crm, opc1, opc2);
+ for (ns = 0; ns < 2; ns++) {
+ /* We are not encoding 64-bit CP registers with
the
+ * secure bit so skip the non-secure bit instance.
+ */
+ if (state == ARM_CP_STATE_AA64 && ns == 1) {
+ continue;
+ }
+ add_cpreg_to_hashtable(cpu, r, opaque, state, ns,
+ crm, opc1, opc2);
+ }
}
}
}
@@@ -3501,25 -3319,22 +3501,25 @@@ void arm_cpu_do_interrupt(CPUState *cs
env->exception.fsr = 2;
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
- env->cp15.ifsr_el2 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
- env->exception.vaddress);
+ BANKED_CP15_REG_SET(env, ifsr_el2, env->exception.fsr);
+ BANKED_CP15_REG_SET(env, far_el1,
+ deposit64(BANKED_CP15_REG_GET(env, far_el1),
+ 32, 32, env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
- env->cp15.ifsr_el2,
(uint32_t)env->exception.vaddress);
+ BANKED_CP15_REG_GET(env, ifsr_el2),
+ (uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x0c;
mask = CPSR_A | CPSR_I;
offset = 4;
break;
case EXCP_DATA_ABORT:
- env->cp15.esr_el1 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
- env->exception.vaddress);
+ BANKED_CP15_REG_SET(env, esr_el1, env->exception.fsr);
+ BANKED_CP15_REG_SET(env, far_el1,
+ deposit64(BANKED_CP15_REG_GET(env, far_el1),
+ 0, 32, env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
- (uint32_t)env->cp15.esr_el1,
+ (uint32_t)BANKED_CP15_REG_GET(env, esr_el1),
(uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x10;
On 16 May 2014 01:00, Aggeler Fabian <aggelerf@student.ethz.ch> wrote:
> Yes, sorry about that.
>
> Best,
> Fabian
>
> > On 15.05.2014, at 20:58, "Sergey Fedorov" <serge.fdrv@gmail.com> wrote:
> >
> > Can s.fedorov@samsung.com be removed from CC list since this mailbox has
> > been deleted? That was my address when I worked for Samsung. Now sending
> > to this address results with annoying delivery failure notification.
> >
> > Thanks,
> > Sergey.
> >
> > 13.05.2014 20:15, Fabian Aggeler wrote:
> >> Hi,
> >>
> >> This is a rework of the Samsung patches sent last year to add Security
> >> Extensions. The patches have been changed based on the discussion on
> >> the mailing list. Other changes became necessary because of Aarch64
> >> support which got added in the meantime. This patchset makes it possible
> >> to run a kernel in the secure world and then switch to non-secure
> >> on CPUs that implement Security Extensions. It works for EL3 in Aarch32
> >> state, but may add _EL3 registers where necessary to reflect the mapping
> >> of secure instances of cp registers to _EL3 registers.
> >>
> >> Banking of cp registers has been changed from active mass-swapping to
> >> the mechanism discussed on the mailing list, where every Aarch32 cp
> >> register goes into the hashtable twice. A ns-bit is added to the key
> >> of the register which is used when accessing a cp register to get the
> >> correct instance.
> >>
> >> Magic numbers have been changed to bitshifted constants or macros to
> make
> >> the code easier to read.
> >>
> >> The whole patchset now uses the term Security Extensions instead of
> >> TrustZone as this is the term which is used in the ARM ARM.
> >>
> >> I am happy for any feedback, especially for the banking of course. It
> should
> >> not be too hard to combine these changes with the recent effort towards
> EL3
> >> in A64.
> >>
> >> Thanks,
> >> Fabian
> >>
> >> Fabian Aggeler (12):
> >> target-arm: add arm_is_secure() function
> >> target-arm: add NSACR support
> >> target-arm: Split TLB for secure state and EL3 in Aarch64
> >> target-arm: add banked coprocessor register type and macros
> >> target-arm: Restrict EL3 to Aarch32 state
> >> target-arm: Use arm_current_sctlr to access SCTLR
> >> target-arm: Use raw_write/raw_read whenever possible
> >> target-arm: Convert banked coprocessor registers
> >> target-arm: maintain common bits of banked CP registers
> >> target-arm: add MVBAR support
> >> target-arm: implement IRQ/FIQ routing to Monitor mode
> >> target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI
> >>
> >> Sergey Fedorov (8):
> >> target-arm: move SCR into Security Extensions register list
> >> target-arm: adjust TTBCR for Security Extension feature
> >> target-arm: reject switching to monitor mode from non-secure state
> >> target-arm: adjust arm_current_pl() for Security Extensions
> >> target-arm: add non-secure Translation Block flag
> >> target-arm: implement CPACR register logic
> >> target-arm: add SDER definition
> >> target-arm: implement SMC instruction
> >>
> >> Svetlana Fedoseeva (3):
> >> target-arm: add new CPU feature for Security Extensions
> >> target-arm: preserve RAO/WI bits of ARMv7 SCTLR
> >> target-arm: add CPU Monitor mode
> >>
> >> hw/arm/pxa2xx.c | 2 +-
> >> linux-user/main.c | 2 +-
> >> target-arm/cpu-qom.h | 1 +
> >> target-arm/cpu.c | 8 +-
> >> target-arm/cpu.h | 271 ++++++++++++++++++++++---
> >> target-arm/helper-a64.c | 3 +-
> >> target-arm/helper.c | 489
> ++++++++++++++++++++++++++++++++++++---------
> >> target-arm/machine.c | 6 +-
> >> target-arm/op_helper.c | 2 +-
> >> target-arm/translate-a64.c | 9 +-
> >> target-arm/translate.c | 342 ++++++++++++++++++-------------
> >> target-arm/translate.h | 4 +
> >> 12 files changed, 866 insertions(+), 273 deletions(-)
> >
>
>
[-- Attachment #2: Type: text/html, Size: 53895 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-16 20:56 ` Greg Bellows
@ 2014-05-20 10:00 ` Aggeler Fabian
2014-05-20 15:43 ` Greg Bellows
2014-05-21 13:55 ` Peter Maydell
1 sibling, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-20 10:00 UTC (permalink / raw)
To: Greg Bellows
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org,
edgar.iglesias@gmail.com
Hi Greg
Thanks for sharing your approach. I like your idea of keeping the hashtable small when Security Extensions are not present as well as isolating Sec-Ext specific registers in their own group. How do you want to proceed in this matter? Are you going to continue working on the banking and Sec-Ext patchset in general? Just so I know what I should focus on.
Best,
Fabian
On 16 May 2014, at 22:56, Greg Bellows <greg.bellows@linaro.org<mailto:greg.bellows@linaro.org>> wrote:
As mentioned in an earlier thread, I too have been building on Sergey's trustzone changes. I wanted to share a subset of my changes related to banked register support as an alternative.
Overview:
The approach delicately hashes all the SP registers just as Fabian's approach does. The primary difference is that all the existing ARMCPRegInfo entries are left as-is and are blindly registered for both NS-bit settings (encoded in the hash key). Once all of the existing registers have been added to the hash, the set of security specific registers are hashed. Hashing of these registers involves a single new type to indicate that the ARMCPRegInfo is a security update of an existing register. On receipt of this type, a hash lookup is performed on the register and it is updated for the security specifics. This primarily involves updating the fieldoffset to point at the secure bank.
There are benefits to both approaches. In the above approach it avoids to mark all register declarations as secure or banked and isolates the security registers to their own mechanism. This can also be considered a detriment as the existing registers are not explicitly marked.
Update:
Since the coding of the approach and reviewing of Fabian's changes, I have discovered that further optimizations may be possible over the diffs provided below.
* The registration of the security registers do not need to go through add_cpreg_to_hash_table but rather have a simpler routine that takes the ARMCPRegInfo group and walks through updating each register.
* The CP register duplication can be isolated to the routine used to update the security registers. This cuts down on the entries in the hash when the security extension is not present.
Diffs:
Below are a subset of the differences required for the aforementioned approach. The diffs are built on top of Sergey's original patches and against a recent baselevel. I have omitted code unnecessary for demonstrating the approach. Also, my implementation is intended for ARMv7 only.
diff --combined target-arm/cpu.h
index 467eaa5,c83f249..0000000
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@@ -90,41 -89,9 +90,41 @@@ typedef void ARMWriteCPFunc(void *opaqu
typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
int dstreg, int operand);
+#define CP15_DEFAULT_BANK 1
+
+/* Define a banked coprocessor register state field. Use %name as the active
+ * register state field name. The banked register state array field name has
+ * "banked_" prefix. The banked register state array indexes corresponds to
+ * SCR.NS bit value.
+ */
+#define BANKED_CP_REG(type, name) \
+ union { \
+ struct { \
+ type name##_sec; \
+ type name; \
+ }; \
+ type banked_##name[2]; \
+ }
+
+/* Secure bank selector macro
+ * Determines whether a co-processor access instruction should use a banked
+ * Non-secure copy of a register instead of active one.
+ */
+#define CP_REG_BANK(env) \
+ (arm_feature((env), ARM_FEATURE_SECURITY) ? \
+ ((env)->cp15.c1_scr & 1) : CP15_DEFAULT_BANK)
+
+/* Get a banked CP15 register in co-processor access instruction handler */
+#define BANKED_CP15_REG_GET(env, regname) \
+ (env)->cp15.banked_##regname[CP_REG_BANK(env)]
+
+/* Set a banked CP15 register in co-processor access instruction handler */
+#define BANKED_CP15_REG_SET(env, regname, val) \
+ (env)->cp15.banked_##regname[CP_REG_BANK(env)] = (val)
+
struct arm_boot_info;
-#define NB_MMU_MODES 2
+#define NB_MMU_MODES 4
/* We currently assume float and double are IEEE single and double
precision respectively.
@@@ -201,29 -168,27 +201,29 @@@
/* System control coprocessor (cp15) */
struct {
uint32_t c0_cpuid;
- uint64_t c0_cssel; /* Cache size selection. */
- uint64_t c1_sys; /* System control register. */
+ BANKED_CP_REG(uint64_t, c0_cssel); /* Cache size selection. */
+ BANKED_CP_REG(uint64_t, c1_sys); /* System control register. */
uint64_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
uint32_t c1_scr; /* secure config register. */
- uint64_t ttbr0_el1; /* MMU translation table base 0. */
- uint64_t ttbr1_el1; /* MMU translation table base 1. */
- uint64_t c2_control; /* MMU translation table base control. */
+ uint32_t c1_sder; /* Secure debug enable register. */
+ uint32_t c1_nsacr; /* Non-secure access control register. */
+ BANKED_CP_REG(uint64_t, ttbr0_el1); /* MMU translation table base 0. */
+ BANKED_CP_REG(uint64_t, ttbr1_el1); /* MMU translation table base 1. */
+ BANKED_CP_REG(uint64_t, c2_control); /* MMU x-lation tbl base cntrl.*/
uint32_t c2_mask; /* MMU translation table base selection mask. */
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
uint32_t c2_data; /* MPU data cachable bits. */
uint32_t c2_insn; /* MPU instruction cachable bits. */
- uint32_t c3; /* MMU domain access control register
- MPU write buffer control. */
+ BANKED_CP_REG(uint32_t, c3); /* MMU domain access control register
+ MPU write buffer control. */
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
- uint32_t ifsr_el2; /* Fault status registers. */
- uint64_t esr_el1;
+ BANKED_CP_REG(uint32_t, ifsr_el2); /* Fault status registers. */
+ BANKED_CP_REG(uint64_t, esr_el1);
uint32_t c6_region[8]; /* MPU base/size registers. */
- uint64_t far_el1; /* Fault address registers. */
- uint64_t par_el1; /* Translation result. */
+ BANKED_CP_REG(uint64_t, far_el1); /* Fault address registers. */
+ BANKED_CP_REG(uint64_t, par_el1); /* Translation result. */
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
uint32_t c9_pmcr; /* performance monitor control register */
@@@ -232,13 -197,12 +232,13 @@@
uint32_t c9_pmxevtyper; /* perf monitor event type */
uint32_t c9_pmuserenr; /* perf monitor user enable */
uint32_t c9_pminten; /* perf monitor interrupt enables */
- uint64_t mair_el1;
- uint64_t c12_vbar; /* vector base address register */
- uint32_t c13_fcse; /* FCSE PID. */
- uint64_t contextidr_el1; /* Context ID. */
- uint64_t tpidr_el0; /* User RW Thread register. */
- uint64_t tpidrro_el0; /* User RO Thread register. */
+ BANKED_CP_REG(uint64_t, mair_el1);
+ BANKED_CP_REG(uint64_t, c12_vbar); /* vector base address register */
+ uint32_t c12_mvbar; /* monitor vector base address register */
+ BANKED_CP_REG(uint32_t, c13_fcse); /* FCSE PID. */
+ BANKED_CP_REG(uint64_t, contextidr_el1); /* Context ID. */
+ BANKED_CP_REG(uint64_t, tpidr_el0); /* User RW Thread register. */
+ BANKED_CP_REG(uint64_t ,tpidrro_el0); /* User RO Thread register. */
uint64_t tpidr_el1; /* Privileged Thread register. */
uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */
@@@ -676,17 -638,6 +676,17 @@@
return (env->features & (1ULL << feature)) != 0;
}
+/* Return true if the processor is in Secure state */
+static inline bool arm_is_secure(CPUARMState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
+ !(env->cp15.c1_scr & 1);
+#else
+ return false;
+#endif
+}
+
/* Return true if the specified exception level is running in AArch64 state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{
@@@ -738,8 -689,8 +738,8 @@@ void armv7m_nvic_complete_irq(void *opa
#define CP_REG_AA64_SHIFT 28
#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
-#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
- (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
+#define ENCODE_CP_REG(ns, cp, is64, crn, crm, opc1, opc2) \
+ (((ns) << 31) | ((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
((crm) << 7) | ((opc1) << 3) | (opc2))
#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
@@@ -809,12 -760,6 +809,12 @@@ static inline uint64_t cpreg_to_kvm_id(
#define ARM_CP_OVERRIDE 16
#define ARM_CP_NO_MIGRATE 32
#define ARM_CP_IO 64
+/* Secure CP register type.
+ * This flag indicates that the ARMCPRegInfo is a secure register entry.
+ * This flag includes override as the registration may override the
+ * previously registered attributes.
+ */
+#define ARM_CP_SECURE (ARM_CP_OVERRIDE | 128)
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
diff --combined target-arm/helper.c
index 70f34c0,3be917c..0000000
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@@ -768,6 -763,14 +768,6 @@@ static const ARMCPRegInfo v7_cp_reginfo
.access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
.resetvalue = 0, .writefn = pmintenclr_write, },
- { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .writefn = vbar_write,
- .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
- .resetvalue = 0 },
- { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
- .resetvalue = 0, },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
+static const ARMCPRegInfo security_cp_reginfo[] = {
+#ifndef CONFIG_USER_ONLY
+ /*
+ * Restricted access registers
+ * These registers are restricted to secure state access only. Just like
+ * the non-secure registers, both ns-bit settings are registered. These
+ * registers are not marked secure as they are not banked.
+ */
+ { .name = "VBAR", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .access = PL3_RW, .writefn = vbar_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
+ .resetvalue = 0 },
+ { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
+ .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
+ .writefn = scr_write, .resetvalue = 0 },
+ { .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
+ { .name = "MVBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .writefn = vbar_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c12_mvbar) },
+ { .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 2,
+ .access = PL3_RW | PL1_R | PL2_R, .resetvalue = 0, .writefn = nsacr_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_nsacr) },
+
+ /*
+ * Banked registers
+ * These registers are banked so we need to reregister the secure bank
+ * to use a new register location. It is expected that the register was
+ * previously registered, in which case we will preserve the previous
+ * settings besides the fieldoffset and type.
+ */
+ { .name = "CSSELR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel_sec) },
+ { .name = "SCTLR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_sec),
+ .writefn = sctlr_write, .raw_writefn = raw_write},
+ /* TODO: ADD ACTLR */
+ { .name = "TTBR0_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1_sec) },
+ { .name = "TTBR1_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1_sec) },
+ /* TODO: ADD in TTBR0/1 for LPAE */
+ { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_SECURE,
+ .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .fieldoffset = offsetof(CPUARMState, cp15.c2_control_sec) },
+ { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control_sec) },
+ { .name = "DACR",
+ .cp = 15, .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c3_sec) },
+ { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1_sec) },
+ { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2_sec) },
+ { .name = "FAR_EL1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.far_el1_sec) },
+ { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1_sec) },
+ { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.par_el1_sec) },
+ { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1_sec) },
+ { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
+ .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1_sec) },
+ { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 0,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse_sec) },
+ { .name = "CONTEXTIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 1,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1_sec) },
+ { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0_sec) },
+ { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3,
+ .type = ARM_CP_SECURE,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0_sec) },
+#endif
+ REGINFO_SENTINEL
+};
+
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@@@ -2665,13 -2532,6 +2665,13 @@@
}
define_one_arm_cp_reg(cpu, &sctlr);
}
+ /*
+ * Register the security extension registers last as they may override the
+ * bank of previsously registered registers.
+ */
+ if (arm_feature(env, ARM_FEATURE_SECURITY)) {
+ define_arm_cp_regs(cpu, security_cp_reginfo);
+ }
}
ARMCPU *cpu_arm_init(const char *cpu_model)
@@@ -2785,7 -2645,7 +2785,7 @@@ CpuDefinitionInfoList *arch_query_cpu_d
}
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
- void *opaque, int state,
+ void *opaque, int state, int ns,
int crm, int opc1, int opc2)
{
/* Private utility function for define_one_arm_cp_reg_with_opaque():
@@@ -2810,11 -2670,6 +2810,11 @@@
#endif
}
if (state == ARM_CP_STATE_AA64) {
+ if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
+ g_free(key);
+ g_free(r2);
+ return;
+ }
/* To allow abbreviation of ARMCPRegInfo
* definitions, we treat cp == 0 as equivalent to
* the value for "standard guest-visible sysreg".
@@@ -2825,7 -2680,7 +2825,7 @@@
*key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
r2->opc0, opc1, opc2);
} else {
- *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
+ *key = ENCODE_CP_REG(ns, r2->cp, is64, r2->crn, crm, opc1, opc2);
}
if (opaque) {
r2->opaque = opaque;
@@@ -2868,30 -2723,6 +2868,30 @@@
g_assert_not_reached();
}
}
+
+ if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
+ if (ns == 1) {
+ /* SECURE registers only apply to the ns = 0, so skip the ns = 1,
+ * version, but first free the allocated hash data..
+ */
+ g_free(key);
+ g_free(r2);
+ return;
+ }
+
+ ARMCPRegInfo *oldreg = g_hash_table_lookup(cpu->cp_regs, key);
+ /* If we find a match for the key then we can leave it in the hash and
+ * simply update the necessary fields. Once updated we can release the
+ * allocated hash data and return.
+ */
+ if (oldreg) {
+ oldreg->type |= ARM_CP_SECURE;
+ oldreg->fieldoffset = r->fieldoffset;
+ g_free(key);
+ g_free(r2);
+ return;
+ }
+ }
g_hash_table_insert(cpu->cp_regs, key, r2);
}
@@@ -2999,16 -2829,8 +2999,16 @@@
if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
continue;
}
- add_cpreg_to_hashtable(cpu, r, opaque, state,
- crm, opc1, opc2);
+ for (ns = 0; ns < 2; ns++) {
+ /* We are not encoding 64-bit CP registers with the
+ * secure bit so skip the non-secure bit instance.
+ */
+ if (state == ARM_CP_STATE_AA64 && ns == 1) {
+ continue;
+ }
+ add_cpreg_to_hashtable(cpu, r, opaque, state, ns,
+ crm, opc1, opc2);
+ }
}
}
}
@@@ -3501,25 -3319,22 +3501,25 @@@ void arm_cpu_do_interrupt(CPUState *cs
env->exception.fsr = 2;
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
- env->cp15.ifsr_el2 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
- env->exception.vaddress);
+ BANKED_CP15_REG_SET(env, ifsr_el2, env->exception.fsr);
+ BANKED_CP15_REG_SET(env, far_el1,
+ deposit64(BANKED_CP15_REG_GET(env, far_el1),
+ 32, 32, env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
- env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
+ BANKED_CP15_REG_GET(env, ifsr_el2),
+ (uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x0c;
mask = CPSR_A | CPSR_I;
offset = 4;
break;
case EXCP_DATA_ABORT:
- env->cp15.esr_el1 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
- env->exception.vaddress);
+ BANKED_CP15_REG_SET(env, esr_el1, env->exception.fsr);
+ BANKED_CP15_REG_SET(env, far_el1,
+ deposit64(BANKED_CP15_REG_GET(env, far_el1),
+ 0, 32, env->exception.vaddress));
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
- (uint32_t)env->cp15.esr_el1,
+ (uint32_t)BANKED_CP15_REG_GET(env, esr_el1),
(uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
addr = 0x10;
On 16 May 2014 01:00, Aggeler Fabian <aggelerf@student.ethz.ch<mailto:aggelerf@student.ethz.ch>> wrote:
Yes, sorry about that.
Best,
Fabian
> On 15.05.2014, at 20:58, "Sergey Fedorov" <serge.fdrv@gmail.com<mailto:serge.fdrv@gmail.com>> wrote:
>
> Can s.fedorov@samsung.com<mailto:s.fedorov@samsung.com> be removed from CC list since this mailbox has
> been deleted? That was my address when I worked for Samsung. Now sending
> to this address results with annoying delivery failure notification.
>
> Thanks,
> Sergey.
>
> 13.05.2014 20:15, Fabian Aggeler wrote:
>> Hi,
>>
>> This is a rework of the Samsung patches sent last year to add Security
>> Extensions. The patches have been changed based on the discussion on
>> the mailing list. Other changes became necessary because of Aarch64
>> support which got added in the meantime. This patchset makes it possible
>> to run a kernel in the secure world and then switch to non-secure
>> on CPUs that implement Security Extensions. It works for EL3 in Aarch32
>> state, but may add _EL3 registers where necessary to reflect the mapping
>> of secure instances of cp registers to _EL3 registers.
>>
>> Banking of cp registers has been changed from active mass-swapping to
>> the mechanism discussed on the mailing list, where every Aarch32 cp
>> register goes into the hashtable twice. A ns-bit is added to the key
>> of the register which is used when accessing a cp register to get the
>> correct instance.
>>
>> Magic numbers have been changed to bitshifted constants or macros to make
>> the code easier to read.
>>
>> The whole patchset now uses the term Security Extensions instead of
>> TrustZone as this is the term which is used in the ARM ARM.
>>
>> I am happy for any feedback, especially for the banking of course. It should
>> not be too hard to combine these changes with the recent effort towards EL3
>> in A64.
>>
>> Thanks,
>> Fabian
>>
>> Fabian Aggeler (12):
>> target-arm: add arm_is_secure() function
>> target-arm: add NSACR support
>> target-arm: Split TLB for secure state and EL3 in Aarch64
>> target-arm: add banked coprocessor register type and macros
>> target-arm: Restrict EL3 to Aarch32 state
>> target-arm: Use arm_current_sctlr to access SCTLR
>> target-arm: Use raw_write/raw_read whenever possible
>> target-arm: Convert banked coprocessor registers
>> target-arm: maintain common bits of banked CP registers
>> target-arm: add MVBAR support
>> target-arm: implement IRQ/FIQ routing to Monitor mode
>> target-arm: Respect SCR.FW, SCR.AW<http://scr.aw/> and SCTLR.NMFI
>>
>> Sergey Fedorov (8):
>> target-arm: move SCR into Security Extensions register list
>> target-arm: adjust TTBCR for Security Extension feature
>> target-arm: reject switching to monitor mode from non-secure state
>> target-arm: adjust arm_current_pl() for Security Extensions
>> target-arm: add non-secure Translation Block flag
>> target-arm: implement CPACR register logic
>> target-arm: add SDER definition
>> target-arm: implement SMC instruction
>>
>> Svetlana Fedoseeva (3):
>> target-arm: add new CPU feature for Security Extensions
>> target-arm: preserve RAO/WI bits of ARMv7 SCTLR
>> target-arm: add CPU Monitor mode
>>
>> hw/arm/pxa2xx.c | 2 +-
>> linux-user/main.c | 2 +-
>> target-arm/cpu-qom.h | 1 +
>> target-arm/cpu.c | 8 +-
>> target-arm/cpu.h | 271 ++++++++++++++++++++++---
>> target-arm/helper-a64.c | 3 +-
>> target-arm/helper.c | 489 ++++++++++++++++++++++++++++++++++++---------
>> target-arm/machine.c | 6 +-
>> target-arm/op_helper.c | 2 +-
>> target-arm/translate-a64.c | 9 +-
>> target-arm/translate.c | 342 ++++++++++++++++++-------------
>> target-arm/translate.h | 4 +
>> 12 files changed, 866 insertions(+), 273 deletions(-)
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-20 10:00 ` Aggeler Fabian
@ 2014-05-20 15:43 ` Greg Bellows
2014-05-21 14:04 ` Peter Maydell
0 siblings, 1 reply; 75+ messages in thread
From: Greg Bellows @ 2014-05-20 15:43 UTC (permalink / raw)
To: Aggeler Fabian
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org,
edgar.iglesias@gmail.com
[-- Attachment #1: Type: text/plain, Size: 27534 bytes --]
Hi Fabian,
My focus within Linaro is to add support for the security extension to qemu
for ARMv7. Given that we both started from Samsung's original patches our
code is fairly similar. However, it appears that your changes have also
incorporated some ARMv8 64-bit changes, which at this point is out of my
scope.
I think we should wait for Peter to chime in on the approach as he had
expressed interest in the more explicit registration approach that you have
presented. I threw my approach out there simply for consideration as I
thought it addressed his goal for maintaining ARMv7 features as the
"side-cases".
Depending on what Peter and the qemu community believes is best, it sounds
like we have two possible outcomes.
1. Go entirely with your changes as they are similar to mine plus some
additional changes for 64-bit.
2. Go with my changes as a base incorporating some of your additions.
In the meantime, I am begin cleaning up some of my changes and I will pull
in your changes where possible.
Greg
On 20 May 2014 05:00, Aggeler Fabian <aggelerf@student.ethz.ch> wrote:
> Hi Greg
>
> Thanks for sharing your approach. I like your idea of keeping the
> hashtable small when Security Extensions are not present as well as
> isolating Sec-Ext specific registers in their own group. How do you want to
> proceed in this matter? Are you going to continue working on the banking
> and Sec-Ext patchset in general? Just so I know what I should focus on.
>
> Best,
> Fabian
>
> On 16 May 2014, at 22:56, Greg Bellows <greg.bellows@linaro.org<mailto:
> greg.bellows@linaro.org>> wrote:
>
> As mentioned in an earlier thread, I too have been building on Sergey's
> trustzone changes. I wanted to share a subset of my changes related to
> banked register support as an alternative.
>
> Overview:
> The approach delicately hashes all the SP registers just as Fabian's
> approach does. The primary difference is that all the existing
> ARMCPRegInfo entries are left as-is and are blindly registered for both
> NS-bit settings (encoded in the hash key). Once all of the existing
> registers have been added to the hash, the set of security specific
> registers are hashed. Hashing of these registers involves a single new
> type to indicate that the ARMCPRegInfo is a security update of an existing
> register. On receipt of this type, a hash lookup is performed on the
> register and it is updated for the security specifics. This primarily
> involves updating the fieldoffset to point at the secure bank.
>
> There are benefits to both approaches. In the above approach it avoids to
> mark all register declarations as secure or banked and isolates the
> security registers to their own mechanism. This can also be considered a
> detriment as the existing registers are not explicitly marked.
>
> Update:
> Since the coding of the approach and reviewing of Fabian's changes, I have
> discovered that further optimizations may be possible over the diffs
> provided below.
>
> * The registration of the security registers do not need to go through
> add_cpreg_to_hash_table but rather have a simpler routine that takes the
> ARMCPRegInfo group and walks through updating each register.
> * The CP register duplication can be isolated to the routine used to
> update the security registers. This cuts down on the entries in the hash
> when the security extension is not present.
>
> Diffs:
> Below are a subset of the differences required for the aforementioned
> approach. The diffs are built on top of Sergey's original patches and
> against a recent baselevel. I have omitted code unnecessary for
> demonstrating the approach. Also, my implementation is intended for ARMv7
> only.
>
> diff --combined target-arm/cpu.h
> index 467eaa5,c83f249..0000000
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@@ -90,41 -89,9 +90,41 @@@ typedef void ARMWriteCPFunc(void *opaqu
> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
> int dstreg, int operand);
>
> +#define CP15_DEFAULT_BANK 1
> +
> +/* Define a banked coprocessor register state field. Use %name as the
> active
> + * register state field name. The banked register state array field name
> has
> + * "banked_" prefix. The banked register state array indexes corresponds
> to
> + * SCR.NS bit value.
> + */
> +#define BANKED_CP_REG(type, name) \
> + union { \
> + struct { \
> + type name##_sec; \
> + type name; \
> + }; \
> + type banked_##name[2]; \
> + }
> +
> +/* Secure bank selector macro
> + * Determines whether a co-processor access instruction should use a
> banked
> + * Non-secure copy of a register instead of active one.
> + */
> +#define CP_REG_BANK(env) \
> + (arm_feature((env), ARM_FEATURE_SECURITY) ? \
> + ((env)->cp15.c1_scr & 1) : CP15_DEFAULT_BANK)
> +
> +/* Get a banked CP15 register in co-processor access instruction handler
> */
> +#define BANKED_CP15_REG_GET(env, regname) \
> + (env)->cp15.banked_##regname[CP_REG_BANK(env)]
> +
> +/* Set a banked CP15 register in co-processor access instruction handler
> */
> +#define BANKED_CP15_REG_SET(env, regname, val) \
> + (env)->cp15.banked_##regname[CP_REG_BANK(env)] = (val)
> +
> struct arm_boot_info;
>
> -#define NB_MMU_MODES 2
> +#define NB_MMU_MODES 4
>
> /* We currently assume float and double are IEEE single and double
> precision respectively.
> @@@ -201,29 -168,27 +201,29 @@@
> /* System control coprocessor (cp15) */
> struct {
> uint32_t c0_cpuid;
> - uint64_t c0_cssel; /* Cache size selection. */
> - uint64_t c1_sys; /* System control register. */
> + BANKED_CP_REG(uint64_t, c0_cssel); /* Cache size selection. */
> + BANKED_CP_REG(uint64_t, c1_sys); /* System control register. */
> uint64_t c1_coproc; /* Coprocessor access register. */
> uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.
> */
> uint32_t c1_scr; /* secure config register. */
> - uint64_t ttbr0_el1; /* MMU translation table base 0. */
> - uint64_t ttbr1_el1; /* MMU translation table base 1. */
> - uint64_t c2_control; /* MMU translation table base control. */
> + uint32_t c1_sder; /* Secure debug enable register. */
> + uint32_t c1_nsacr; /* Non-secure access control register. */
> + BANKED_CP_REG(uint64_t, ttbr0_el1); /* MMU translation table
> base 0. */
> + BANKED_CP_REG(uint64_t, ttbr1_el1); /* MMU translation table
> base 1. */
> + BANKED_CP_REG(uint64_t, c2_control); /* MMU x-lation tbl base
> cntrl.*/
> uint32_t c2_mask; /* MMU translation table base selection mask.
> */
> uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
> uint32_t c2_data; /* MPU data cachable bits. */
> uint32_t c2_insn; /* MPU instruction cachable bits. */
> - uint32_t c3; /* MMU domain access control register
> - MPU write buffer control. */
> + BANKED_CP_REG(uint32_t, c3); /* MMU domain access control
> register
> + MPU write buffer control. */
> uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
> uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
> - uint32_t ifsr_el2; /* Fault status registers. */
> - uint64_t esr_el1;
> + BANKED_CP_REG(uint32_t, ifsr_el2); /* Fault status registers. */
> + BANKED_CP_REG(uint64_t, esr_el1);
> uint32_t c6_region[8]; /* MPU base/size registers. */
> - uint64_t far_el1; /* Fault address registers. */
> - uint64_t par_el1; /* Translation result. */
> + BANKED_CP_REG(uint64_t, far_el1); /* Fault address registers. */
> + BANKED_CP_REG(uint64_t, par_el1); /* Translation result. */
> uint32_t c9_insn; /* Cache lockdown registers. */
> uint32_t c9_data;
> uint32_t c9_pmcr; /* performance monitor control register */
> @@@ -232,13 -197,12 +232,13 @@@
> uint32_t c9_pmxevtyper; /* perf monitor event type */
> uint32_t c9_pmuserenr; /* perf monitor user enable */
> uint32_t c9_pminten; /* perf monitor interrupt enables */
> - uint64_t mair_el1;
> - uint64_t c12_vbar; /* vector base address register */
> - uint32_t c13_fcse; /* FCSE PID. */
> - uint64_t contextidr_el1; /* Context ID. */
> - uint64_t tpidr_el0; /* User RW Thread register. */
> - uint64_t tpidrro_el0; /* User RO Thread register. */
> + BANKED_CP_REG(uint64_t, mair_el1);
> + BANKED_CP_REG(uint64_t, c12_vbar); /* vector base address
> register */
> + uint32_t c12_mvbar; /* monitor vector base address register */
> + BANKED_CP_REG(uint32_t, c13_fcse); /* FCSE PID. */
> + BANKED_CP_REG(uint64_t, contextidr_el1); /* Context ID. */
> + BANKED_CP_REG(uint64_t, tpidr_el0); /* User RW Thread register.
> */
> + BANKED_CP_REG(uint64_t ,tpidrro_el0); /* User RO Thread
> register. */
> uint64_t tpidr_el1; /* Privileged Thread register. */
> uint64_t c14_cntfrq; /* Counter Frequency register */
> uint64_t c14_cntkctl; /* Timer Control register */
> @@@ -676,17 -638,6 +676,17 @@@
> return (env->features & (1ULL << feature)) != 0;
> }
>
> +/* Return true if the processor is in Secure state */
> +static inline bool arm_is_secure(CPUARMState *env)
> +{
> +#if !defined(CONFIG_USER_ONLY)
> + return ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) ||
> + !(env->cp15.c1_scr & 1);
> +#else
> + return false;
> +#endif
> +}
> +
> /* Return true if the specified exception level is running in AArch64
> state. */
> static inline bool arm_el_is_aa64(CPUARMState *env, int el)
> {
> @@@ -738,8 -689,8 +738,8 @@@ void armv7m_nvic_complete_irq(void *opa
> #define CP_REG_AA64_SHIFT 28
> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>
> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
> +#define ENCODE_CP_REG(ns, cp, is64, crn, crm, opc1, opc2) \
> + (((ns) << 31) | ((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
> ((crm) << 7) | ((opc1) << 3) | (opc2))
>
> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
> @@@ -809,12 -760,6 +809,12 @@@ static inline uint64_t cpreg_to_kvm_id(
> #define ARM_CP_OVERRIDE 16
> #define ARM_CP_NO_MIGRATE 32
> #define ARM_CP_IO 64
> +/* Secure CP register type.
> + * This flag indicates that the ARMCPRegInfo is a secure register entry.
> + * This flag includes override as the registration may override the
> + * previously registered attributes.
> + */
> +#define ARM_CP_SECURE (ARM_CP_OVERRIDE | 128)
> #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
> #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> #define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>
> diff --combined target-arm/helper.c
> index 70f34c0,3be917c..0000000
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@@ -768,6 -763,14 +768,6 @@@ static const ARMCPRegInfo v7_cp_reginfo
> .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
> .resetvalue = 0, .writefn = pmintenclr_write, },
> - { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
> - .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .writefn = vbar_write,
> - .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
> - .resetvalue = 0 },
> - { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.c1_scr),
> - .resetvalue = 0, },
> { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
> .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE
> },
>
> +static const ARMCPRegInfo security_cp_reginfo[] = {
> +#ifndef CONFIG_USER_ONLY
> + /*
> + * Restricted access registers
> + * These registers are restricted to secure state access only. Just
> like
> + * the non-secure registers, both ns-bit settings are registered.
> These
> + * registers are not marked secure as they are not banked.
> + */
> + { .name = "VBAR", .state = ARM_CP_STATE_AA32,
> + .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW, .writefn = vbar_write,
> + .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
> + .resetvalue = 0 },
> + { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState,
> cp15.c1_scr),
> + .writefn = scr_write, .resetvalue = 0 },
> + { .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
> + .access = PL3_RW, .resetvalue = 0,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sder) },
> + { .name = "MVBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 =
> 1,
> + .access = PL3_RW, .resetvalue = 0,
> + .writefn = vbar_write,
> + .fieldoffset = offsetof(CPUARMState, cp15.c12_mvbar) },
> + { .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 =
> 2,
> + .access = PL3_RW | PL1_R | PL2_R, .resetvalue = 0, .writefn =
> nsacr_write,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_nsacr) },
> +
> + /*
> + * Banked registers
> + * These registers are banked so we need to reregister the secure
> bank
> + * to use a new register location. It is expected that the register
> was
> + * previously registered, in which case we will preserve the previous
> + * settings besides the fieldoffset and type.
> + */
> + { .name = "CSSELR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 2, .opc2 =
> 0,
> + .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel_sec) },
> + { .name = "SCTLR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 =
> 0,
> + .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_sec),
> + .writefn = sctlr_write, .raw_writefn = raw_write},
> + /* TODO: ADD ACTLR */
> + { .name = "TTBR0_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0,
> .opc2 = 0,
> + .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1_sec) },
> + { .name = "TTBR1_EL1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0,
> .opc2 = 1,
> + .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1_sec) },
> + /* TODO: ADD in TTBR0/1 for LPAE */
> + { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .type =
> ARM_CP_SECURE,
> + .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
> + .fieldoffset = offsetof(CPUARMState, cp15.c2_control_sec) },
> + { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 =
> 2,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control_sec) },
> + { .name = "DACR",
> + .cp = 15, .crn = 3, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c3_sec) },
> + { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1_sec) },
> + { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2_sec) },
> + { .name = "FAR_EL1", .state = ARM_CP_STATE_AA32, .type =
> ARM_CP_SECURE,
> + .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> + .fieldoffset = offsetof(CPUARMState, cp15.far_el1_sec) },
> + { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1_sec) },
> + { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.par_el1_sec) },
> + { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1_sec) },
> + { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_SECURE,
> + .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1,
> + .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1_sec) },
> + { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2
> = 0,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse_sec) },
> + { .name = "CONTEXTIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0,
> .opc2 = 1,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1_sec) },
> + { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0,
> .opc2 = 2,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0_sec) },
> + { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0,
> .opc2 = 3,
> + .type = ARM_CP_SECURE,
> + .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0_sec) },
> +#endif
> + REGINFO_SENTINEL
> +};
> +
> void register_cp_regs_for_features(ARMCPU *cpu)
> {
> /* Register all the coprocessor registers based on feature bits */
> @@@ -2665,13 -2532,6 +2665,13 @@@
> }
> define_one_arm_cp_reg(cpu, &sctlr);
> }
> + /*
> + * Register the security extension registers last as they may
> override the
> + * bank of previsously registered registers.
> + */
> + if (arm_feature(env, ARM_FEATURE_SECURITY)) {
> + define_arm_cp_regs(cpu, security_cp_reginfo);
> + }
> }
>
> ARMCPU *cpu_arm_init(const char *cpu_model)
> @@@ -2785,7 -2645,7 +2785,7 @@@ CpuDefinitionInfoList *arch_query_cpu_d
> }
>
> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> - void *opaque, int state,
> + void *opaque, int state, int ns,
> int crm, int opc1, int opc2)
> {
> /* Private utility function for define_one_arm_cp_reg_with_opaque():
> @@@ -2810,11 -2670,6 +2810,11 @@@
> #endif
> }
> if (state == ARM_CP_STATE_AA64) {
> + if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
> + g_free(key);
> + g_free(r2);
> + return;
> + }
> /* To allow abbreviation of ARMCPRegInfo
> * definitions, we treat cp == 0 as equivalent to
> * the value for "standard guest-visible sysreg".
> @@@ -2825,7 -2680,7 +2825,7 @@@
> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> r2->opc0, opc1, opc2);
> } else {
> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
> + *key = ENCODE_CP_REG(ns, r2->cp, is64, r2->crn, crm, opc1, opc2);
> }
> if (opaque) {
> r2->opaque = opaque;
> @@@ -2868,30 -2723,6 +2868,30 @@@
> g_assert_not_reached();
> }
> }
> +
> + if ((r->type & ARM_CP_SECURE) == ARM_CP_SECURE) {
> + if (ns == 1) {
> + /* SECURE registers only apply to the ns = 0, so skip the ns
> = 1,
> + * version, but first free the allocated hash data..
> + */
> + g_free(key);
> + g_free(r2);
> + return;
> + }
> +
> + ARMCPRegInfo *oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> + /* If we find a match for the key then we can leave it in the
> hash and
> + * simply update the necessary fields. Once updated we can
> release the
> + * allocated hash data and return.
> + */
> + if (oldreg) {
> + oldreg->type |= ARM_CP_SECURE;
> + oldreg->fieldoffset = r->fieldoffset;
> + g_free(key);
> + g_free(r2);
> + return;
> + }
> + }
> g_hash_table_insert(cpu->cp_regs, key, r2);
> }
> @@@ -2999,16 -2829,8 +2999,16 @@@
> if (r->state != state && r->state !=
> ARM_CP_STATE_BOTH) {
> continue;
> }
> - add_cpreg_to_hashtable(cpu, r, opaque, state,
> - crm, opc1, opc2);
> + for (ns = 0; ns < 2; ns++) {
> + /* We are not encoding 64-bit CP registers with
> the
> + * secure bit so skip the non-secure bit
> instance.
> + */
> + if (state == ARM_CP_STATE_AA64 && ns == 1) {
> + continue;
> + }
> + add_cpreg_to_hashtable(cpu, r, opaque, state, ns,
> + crm, opc1, opc2);
> + }
> }
> }
> }
>
> @@@ -3501,25 -3319,22 +3501,25 @@@ void arm_cpu_do_interrupt(CPUState *cs
> env->exception.fsr = 2;
> /* Fall through to prefetch abort. */
> case EXCP_PREFETCH_ABORT:
> - env->cp15.ifsr_el2 = env->exception.fsr;
> - env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
> - env->exception.vaddress);
> + BANKED_CP15_REG_SET(env, ifsr_el2, env->exception.fsr);
> + BANKED_CP15_REG_SET(env, far_el1,
> + deposit64(BANKED_CP15_REG_GET(env, far_el1),
> + 32, 32, env->exception.vaddress));
> qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
> - env->cp15.ifsr_el2,
> (uint32_t)env->exception.vaddress);
> + BANKED_CP15_REG_GET(env, ifsr_el2),
> + (uint32_t)env->exception.vaddress);
> new_mode = ARM_CPU_MODE_ABT;
> addr = 0x0c;
> mask = CPSR_A | CPSR_I;
> offset = 4;
> break;
> case EXCP_DATA_ABORT:
> - env->cp15.esr_el1 = env->exception.fsr;
> - env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
> - env->exception.vaddress);
> + BANKED_CP15_REG_SET(env, esr_el1, env->exception.fsr);
> + BANKED_CP15_REG_SET(env, far_el1,
> + deposit64(BANKED_CP15_REG_GET(env, far_el1),
> + 0, 32, env->exception.vaddress));
> qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
> - (uint32_t)env->cp15.esr_el1,
> + (uint32_t)BANKED_CP15_REG_GET(env, esr_el1),
> (uint32_t)env->exception.vaddress);
> new_mode = ARM_CPU_MODE_ABT;
> addr = 0x10;
>
>
> On 16 May 2014 01:00, Aggeler Fabian <aggelerf@student.ethz.ch<mailto:
> aggelerf@student.ethz.ch>> wrote:
> Yes, sorry about that.
>
> Best,
> Fabian
>
> > On 15.05.2014, at 20:58, "Sergey Fedorov" <serge.fdrv@gmail.com<mailto:
> serge.fdrv@gmail.com>> wrote:
> >
> > Can s.fedorov@samsung.com<mailto:s.fedorov@samsung.com> be removed from
> CC list since this mailbox has
> > been deleted? That was my address when I worked for Samsung. Now sending
> > to this address results with annoying delivery failure notification.
> >
> > Thanks,
> > Sergey.
> >
> > 13.05.2014 20:15, Fabian Aggeler wrote:
> >> Hi,
> >>
> >> This is a rework of the Samsung patches sent last year to add Security
> >> Extensions. The patches have been changed based on the discussion on
> >> the mailing list. Other changes became necessary because of Aarch64
> >> support which got added in the meantime. This patchset makes it possible
> >> to run a kernel in the secure world and then switch to non-secure
> >> on CPUs that implement Security Extensions. It works for EL3 in Aarch32
> >> state, but may add _EL3 registers where necessary to reflect the mapping
> >> of secure instances of cp registers to _EL3 registers.
> >>
> >> Banking of cp registers has been changed from active mass-swapping to
> >> the mechanism discussed on the mailing list, where every Aarch32 cp
> >> register goes into the hashtable twice. A ns-bit is added to the key
> >> of the register which is used when accessing a cp register to get the
> >> correct instance.
> >>
> >> Magic numbers have been changed to bitshifted constants or macros to
> make
> >> the code easier to read.
> >>
> >> The whole patchset now uses the term Security Extensions instead of
> >> TrustZone as this is the term which is used in the ARM ARM.
> >>
> >> I am happy for any feedback, especially for the banking of course. It
> should
> >> not be too hard to combine these changes with the recent effort towards
> EL3
> >> in A64.
> >>
> >> Thanks,
> >> Fabian
> >>
> >> Fabian Aggeler (12):
> >> target-arm: add arm_is_secure() function
> >> target-arm: add NSACR support
> >> target-arm: Split TLB for secure state and EL3 in Aarch64
> >> target-arm: add banked coprocessor register type and macros
> >> target-arm: Restrict EL3 to Aarch32 state
> >> target-arm: Use arm_current_sctlr to access SCTLR
> >> target-arm: Use raw_write/raw_read whenever possible
> >> target-arm: Convert banked coprocessor registers
> >> target-arm: maintain common bits of banked CP registers
> >> target-arm: add MVBAR support
> >> target-arm: implement IRQ/FIQ routing to Monitor mode
> >> target-arm: Respect SCR.FW, SCR.AW<http://scr.aw/> and SCTLR.NMFI
> >>
> >> Sergey Fedorov (8):
> >> target-arm: move SCR into Security Extensions register list
> >> target-arm: adjust TTBCR for Security Extension feature
> >> target-arm: reject switching to monitor mode from non-secure state
> >> target-arm: adjust arm_current_pl() for Security Extensions
> >> target-arm: add non-secure Translation Block flag
> >> target-arm: implement CPACR register logic
> >> target-arm: add SDER definition
> >> target-arm: implement SMC instruction
> >>
> >> Svetlana Fedoseeva (3):
> >> target-arm: add new CPU feature for Security Extensions
> >> target-arm: preserve RAO/WI bits of ARMv7 SCTLR
> >> target-arm: add CPU Monitor mode
> >>
> >> hw/arm/pxa2xx.c | 2 +-
> >> linux-user/main.c | 2 +-
> >> target-arm/cpu-qom.h | 1 +
> >> target-arm/cpu.c | 8 +-
> >> target-arm/cpu.h | 271 ++++++++++++++++++++++---
> >> target-arm/helper-a64.c | 3 +-
> >> target-arm/helper.c | 489
> ++++++++++++++++++++++++++++++++++++---------
> >> target-arm/machine.c | 6 +-
> >> target-arm/op_helper.c | 2 +-
> >> target-arm/translate-a64.c | 9 +-
> >> target-arm/translate.c | 342 ++++++++++++++++++-------------
> >> target-arm/translate.h | 4 +
> >> 12 files changed, 866 insertions(+), 273 deletions(-)
> >
>
>
>
>
[-- Attachment #2: Type: text/html, Size: 32961 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-16 20:56 ` Greg Bellows
2014-05-20 10:00 ` Aggeler Fabian
@ 2014-05-21 13:55 ` Peter Maydell
1 sibling, 0 replies; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 13:55 UTC (permalink / raw)
To: Greg Bellows
Cc: Sergey Fedorov, qemu-devel@nongnu.org, Aggeler Fabian,
edgar.iglesias@gmail.com
On 16 May 2014 21:56, Greg Bellows <greg.bellows@linaro.org> wrote:
> Overview:
> The approach delicately hashes all the SP registers just as Fabian's
> approach does. The primary difference is that all the existing ARMCPRegInfo
> entries are left as-is and are blindly registered for both NS-bit settings
> (encoded in the hash key). Once all of the existing registers have been
> added to the hash, the set of security specific registers are hashed.
> Hashing of these registers involves a single new type to indicate that the
> ARMCPRegInfo is a security update of an existing register. On receipt of
> this type, a hash lookup is performed on the register and it is updated for
> the security specifics. This primarily involves updating the fieldoffset to
> point at the secure bank.
>
> There are benefits to both approaches. In the above approach it avoids to
> mark all register declarations as secure or banked and isolates the security
> registers to their own mechanism. This can also be considered a detriment
> as the existing registers are not explicitly marked.
I definitely prefer the approach where we have all the information
about a particular register (including secure/nonsecure/AArch64/AArch32
variants) in a single place.
> @@@ -809,12 -760,6 +809,12 @@@ static inline uint64_t cpreg_to_kvm_id(
> #define ARM_CP_OVERRIDE 16
> #define ARM_CP_NO_MIGRATE 32
> #define ARM_CP_IO 64
> +/* Secure CP register type.
> + * This flag indicates that the ARMCPRegInfo is a secure register entry.
> + * This flag includes override as the registration may override the
> + * previously registered attributes.
> + */
> +#define ARM_CP_SECURE (ARM_CP_OVERRIDE | 128)
This is definitely a bad idea -- we should be trying to reduce the
use of the OVERRIDE flag, because it pretty much always indicates
that something's wrong (mostly we use it to work around overly
wildcarded entries that we still have for legacy reasons).
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs
2014-05-20 15:43 ` Greg Bellows
@ 2014-05-21 14:04 ` Peter Maydell
0 siblings, 0 replies; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 14:04 UTC (permalink / raw)
To: Greg Bellows
Cc: Sergey Fedorov, qemu-devel@nongnu.org, Aggeler Fabian,
edgar.iglesias@gmail.com
On 20 May 2014 16:43, Greg Bellows <greg.bellows@linaro.org> wrote:
> My focus within Linaro is to add support for the security extension to qemu
> for ARMv7. Given that we both started from Samsung's original patches our
> code is fairly similar. However, it appears that your changes have also
> incorporated some ARMv8 64-bit changes, which at this point is out of my
> scope.
It shouldn't be out of scope in a general sense -- any design for
supporting the security extensions must at least consider how the
AArch64 security extensions would be supported, even if it does
not actually implement all the detail.
> I think we should wait for Peter to chime in on the approach as he had
> expressed interest in the more explicit registration approach that you have
> presented. I threw my approach out there simply for consideration as I
> thought it addressed his goal for maintaining ARMv7 features as the
> "side-cases".
To clarify, what I meant by that is that I'd in general prefer to see
a design which implements AArch64 security as its primary thing
with the v7 security extension support as the "this is what differs"
part. (This is just a "seems like the obvious way to approach the
problem" guideline rather than a "must be this way" rule, though; I
haven't yet thought about the problem in sufficient depth.)
> Depending on what Peter and the qemu community believes is best, it sounds
> like we have two possible outcomes.
>
> Go entirely with your changes as they are similar to mine plus some
> additional changes for 64-bit.
> Go with my changes as a base incorporating some of your additions.
If we want to take the "put all the reginfo for a register in one place"
approach it sounds like it might be best to start with Fabian's patches
and incorporate specific fixes/improvements from your tree into
those as appropriate.
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
@ 2014-05-21 14:46 ` Peter Maydell
2014-05-21 16:14 ` Christopher Covington
2014-05-21 14:51 ` Peter Maydell
1 sibling, 1 reply; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 14:46 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers,
Svetlana Fedoseeva
On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>
> Define Security Extensions CPU feature. Set that feature for relevant CPUs.
This is potentially tricky because it means that CPUs which we were
previously implementing without TZ now boot up with TZ and in
Secure mode; I think this is probably the right thing but we'll need
to check that we don't break guests which were really expecting
to run in NS.
(Also I'm not sure what the semantics of -kernel should be for
TZ-supporting CPUs -- boot the kernel in S or NS ?)
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
2014-05-21 14:46 ` Peter Maydell
@ 2014-05-21 14:51 ` Peter Maydell
2014-05-22 9:09 ` Aggeler Fabian
1 sibling, 1 reply; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 14:51 UTC (permalink / raw)
To: Fabian Aggeler
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers,
Svetlana Fedoseeva
On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -631,6 +631,7 @@ enum arm_features {
> ARM_FEATURE_CBAR, /* has cp15 CBAR */
> ARM_FEATURE_CRC, /* ARMv8 CRC instructions */
> ARM_FEATURE_CBAR_RO, /* has cp15 CBAR and it is read-only */
> + ARM_FEATURE_SECURITY_EXTENSIONS, /* has Security Extensions */
> };
Also this feature name is pretty long and unwieldy; something
shorter would be nice. I think we should probably go with
ARM_FEATURE_EL2/ARM_FEATURE_EL3 as per Edgar's
patchset.
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list Fabian Aggeler
2014-05-14 14:19 ` Greg Bellows
@ 2014-05-21 14:57 ` Peter Maydell
1 sibling, 0 replies; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 14:57 UTC (permalink / raw)
To: Fabian Aggeler; +Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers
On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> From: Sergey Fedorov <s.fedorov@samsung.com>
>
> Define a new ARM CP register info list for the Security Extension feature.
> Register that list only for ARM cores with Security Extension support.
> Moving SCR into Security Extension register group.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 15 ++++++++++++---
> 1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 3be917c..7898f40 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -768,9 +768,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
> .access = PL1_RW, .writefn = vbar_write,
> .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
> .resetvalue = 0 },
> - { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> - .resetvalue = 0, },
> { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
> .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE },
> @@ -2087,6 +2084,15 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> tlb_flush(CPU(cpu), 1);
> }
>
> +static const ARMCPRegInfo tz_cp_reginfo[] = {
> +#ifndef CONFIG_USER_ONLY
> + { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
> + .resetvalue = 0, },
> +#endif
Why has this acquired CONFIG_USER_ONLY guards? It doesn't
seem to need them...
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature Fabian Aggeler
@ 2014-05-21 16:06 ` Peter Maydell
0 siblings, 0 replies; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 16:06 UTC (permalink / raw)
To: Fabian Aggeler; +Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers
On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
> From: Sergey Fedorov <s.fedorov@samsung.com>
>
> TTBCR has additional fields PD0 and PD1 when using Short-descriptor
> translation table format on a CPU with Security Extension support.
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/helper.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 7898f40..9c3269f 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1388,6 +1388,11 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
>
> if (arm_feature(env, ARM_FEATURE_LPAE) && (value & (1 << 31))) {
> value &= ~((7 << 19) | (3 << 14) | (0xf << 3));
> + } else if (arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS)) {
> + /* In an implementation that includes the Security Extensions
> + * TTBCR has additional fields PD0 [4] and PD1 [5].
> + */
For v8 the PD0/PD1 fields exist even without the security extensions.
> + value &= (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
This is probably better written
value &= (3 << 4) | 7;
> } else {
> value &= 7;
> }
> --
> 1.8.3.2
We should probably actually implement the behaviour PD0/PD1
mandate, incidentally -- this shouldn't be hard. I might send a patch
out later...
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR
2014-05-14 5:43 ` Sergey Fedorov
@ 2014-05-21 16:12 ` Peter Maydell
2014-05-22 8:58 ` Aggeler Fabian
0 siblings, 1 reply; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 16:12 UTC (permalink / raw)
To: Sergey Fedorov
Cc: Fabian Aggeler, Svetlana Fedoseeva, QEMU Developers,
Edgar E. Iglesias
On 14 May 2014 06:43, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>
> On 13.05.2014 20:15, Fabian Aggeler wrote:
>> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>>
>> Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>> ---
>> target-arm/helper.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index 9c3269f..2b57ad9 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -2083,6 +2083,11 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>> {
>> ARMCPU *cpu = arm_env_get_cpu(env);
>>
>> + if (arm_feature(env, ARM_FEATURE_V7)) {
>> + value |= SCTLR_XP | SCTLR_U | SCTLR_nTWE | SCTLR_nTWI | SCTLR_L
>> + | SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
>
> Actually, some of these bits are RAO/WI since v6. Also, there are some
> RAZ/WI bits varying over architecture variants. There is some overview
> at ARM ARM v7-AP section L.7.4. Maybe it is worth to fix more precisely
> over supported architecture variants? By the way, this patch could be
> separated from security extensions support patch set.
Agreed. Our compliance for bits that should-be-0/1 is not great,
but if we don't actually need to do those fixes for TZ support
then they're probably better separated out (ie drop them from
this patchset for the moment and submit them separately or
later...)
Also for v8 many of these RAZ/RAO bits become RES0/RES1 and
the rules are different...
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-21 14:46 ` Peter Maydell
@ 2014-05-21 16:14 ` Christopher Covington
2014-05-21 16:33 ` Sergey Fedorov
0 siblings, 1 reply; 75+ messages in thread
From: Christopher Covington @ 2014-05-21 16:14 UTC (permalink / raw)
To: Peter Maydell
Cc: Fabian Aggeler, Svetlana Fedoseeva, Sergey Fedorov,
QEMU Developers, Edgar E. Iglesias
Hi Peter,
On 05/21/2014 10:46 AM, Peter Maydell wrote:
> On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
>> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>>
>> Define Security Extensions CPU feature. Set that feature for relevant CPUs.
>
> This is potentially tricky because it means that CPUs which we were
> previously implementing without TZ now boot up with TZ and in
> Secure mode; I think this is probably the right thing but we'll need
> to check that we don't break guests which were really expecting
> to run in NS.
>
> (Also I'm not sure what the semantics of -kernel should be for
> TZ-supporting CPUs -- boot the kernel in S or NS ?)
While Linux works in secure mode, non-secure hypervisor mode is required for
KVM to work in the guest.
"[Entry] in HYP mode ... is the recommended boot method ...."
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm/Booting#n183
Christopher
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by the Linux Foundation.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-21 16:14 ` Christopher Covington
@ 2014-05-21 16:33 ` Sergey Fedorov
2014-05-21 16:41 ` Peter Maydell
0 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-21 16:33 UTC (permalink / raw)
To: Christopher Covington, Peter Maydell
Cc: Edgar E. Iglesias, Fabian Aggeler, Sergey Fedorov,
Svetlana Fedoseeva, QEMU Developers
On 21.05.2014 20:14, Christopher Covington wrote:
> Hi Peter,
>
> On 05/21/2014 10:46 AM, Peter Maydell wrote:
>> On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
>>> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>>>
>>> Define Security Extensions CPU feature. Set that feature for relevant CPUs.
>> This is potentially tricky because it means that CPUs which we were
>> previously implementing without TZ now boot up with TZ and in
>> Secure mode; I think this is probably the right thing but we'll need
>> to check that we don't break guests which were really expecting
>> to run in NS.
>>
>> (Also I'm not sure what the semantics of -kernel should be for
>> TZ-supporting CPUs -- boot the kernel in S or NS ?)
> While Linux works in secure mode, non-secure hypervisor mode is required for
> KVM to work in the guest.
>
> "[Entry] in HYP mode ... is the recommended boot method ...."
>
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm/Booting#n183
>
> Christopher
>
AFAIK, in real hardware this switch to non-secure state is actually done
by bootloader. Why don't implement this in Qemu bootloader stub so far?
Regards,
Sergey Fedorov.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-21 16:33 ` Sergey Fedorov
@ 2014-05-21 16:41 ` Peter Maydell
2014-05-21 16:47 ` Sergey Fedorov
0 siblings, 1 reply; 75+ messages in thread
From: Peter Maydell @ 2014-05-21 16:41 UTC (permalink / raw)
To: Sergey Fedorov
Cc: QEMU Developers, Fabian Aggeler, Edgar E. Iglesias,
Christopher Covington, Svetlana Fedoseeva
On 21 May 2014 17:33, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> On 21.05.2014 20:14, Christopher Covington wrote:
>> On 05/21/2014 10:46 AM, Peter Maydell wrote:
>>> (Also I'm not sure what the semantics of -kernel should be for
>>> TZ-supporting CPUs -- boot the kernel in S or NS ?)
>> While Linux works in secure mode, non-secure hypervisor mode is required for
>> KVM to work in the guest.
>>
>> "[Entry] in HYP mode ... is the recommended boot method ...."
>>
>> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm/Booting#n183
Sure, but we don't implement HYP yet :-)
> AFAIK, in real hardware this switch to non-secure state is actually done
> by bootloader. Why don't implement this in Qemu bootloader stub so far?
If we want to have -kernel boot in NS then yes, the bootloader
stub is the place that code should go.
The difficulty with -kernel being NS is that some guest kernels
for some boards may be assuming that they will run in secure state
and can directly access h/w or registers which aren't accessible
from NS. I guess we need to implement it and then see if any of our
guest images stop working...
thanks
-- PMM
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-21 16:41 ` Peter Maydell
@ 2014-05-21 16:47 ` Sergey Fedorov
0 siblings, 0 replies; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-21 16:47 UTC (permalink / raw)
To: Peter Maydell
Cc: QEMU Developers, Fabian Aggeler, Edgar E. Iglesias,
Christopher Covington, Svetlana Fedoseeva
On 21.05.2014 20:41, Peter Maydell wrote:
> If we want to have -kernel boot in NS then yes, the bootloader
> stub is the place that code should go.
>
> The difficulty with -kernel being NS is that some guest kernels
> for some boards may be assuming that they will run in secure state
> and can directly access h/w or registers which aren't accessible
> from NS. I guess we need to implement it and then see if any of our
> guest images stop working...
Then maybe we can extend arm_boot_info structure to deal with this.
Regards,
Sergey Fedorov.
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR Fabian Aggeler
@ 2014-05-22 7:33 ` Edgar E. Iglesias
2014-05-22 14:56 ` Aggeler Fabian
0 siblings, 1 reply; 75+ messages in thread
From: Edgar E. Iglesias @ 2014-05-22 7:33 UTC (permalink / raw)
To: Fabian Aggeler; +Cc: peter.maydell, qemu-devel
On Tue, May 13, 2014 at 06:16:01PM +0200, Fabian Aggeler wrote:
> Add SCTLR_EL3 and introduce new function to access correct
> instance of SCTLR in different modes/worlds.
Hi,
AArch64 has a couple of insn/regs that do address translation
as seen by other ELs. E.g, from EL3 you can perform address
translation as seen by EL0. See for example ATS12E0R.
AArch32 has similar features, it can also lower S to NS when in S mode.
With regards to arm_current_sctlr() and the use in get_phys_addr, I
don't think it is enough here.
I was planning to post was patches that add new args to get_phys_addr()
with the translation-EL and flags to control if stage-2 translation
should be done or not. That way ats_write() can keep reusing
get_phys_addr(). We would need to pass the security state as an argument
aswell to handle AArch32. Does that make sense?
Cheers,
Edgar
>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> hw/arm/pxa2xx.c | 2 +-
> target-arm/cpu-qom.h | 1 +
> target-arm/cpu.c | 4 +--
> target-arm/cpu.h | 14 ++++++++++-
> target-arm/helper.c | 67 ++++++++++++++++++++++++++++++++++++++------------
> target-arm/op_helper.c | 2 +-
> 6 files changed, 69 insertions(+), 21 deletions(-)
>
> diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
> index e0cd847..8b69e72 100644
> --- a/hw/arm/pxa2xx.c
> +++ b/hw/arm/pxa2xx.c
> @@ -274,7 +274,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
> case 3:
> s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
> s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
> - s->cpu->env.cp15.c1_sys = 0;
> + s->cpu->env.cp15.c1_sys_el1 = 0;
> s->cpu->env.cp15.c1_coproc = 0;
> s->cpu->env.cp15.ttbr0_el1 = 0;
> s->cpu->env.cp15.c3 = 0;
> diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
> index edc7f26..38cbd43 100644
> --- a/target-arm/cpu-qom.h
> +++ b/target-arm/cpu-qom.h
> @@ -119,6 +119,7 @@ typedef struct ARMCPU {
> uint32_t mvfr2;
> uint32_t ctr;
> uint32_t reset_sctlr;
> + uint32_t reset_sctlr_el3;
> uint32_t id_pfr0;
> uint32_t id_pfr1;
> uint32_t id_dfr0;
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index b0d4a9b..bdbdbb1 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -100,7 +100,7 @@ static void arm_cpu_reset(CPUState *s)
> #if defined(CONFIG_USER_ONLY)
> env->pstate = PSTATE_MODE_EL0t;
> /* Userspace expects access to CTL_EL0 and the cache ops */
> - env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
> + env->cp15.c1_sys_el1 |= SCTLR_UCT | SCTLR_UCI;
> /* and to the FP/Neon instructions */
> env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
> #else
> @@ -146,7 +146,7 @@ static void arm_cpu_reset(CPUState *s)
> }
> }
>
> - if (env->cp15.c1_sys & SCTLR_V) {
> + if (arm_current_sctlr(env) & SCTLR_V) {
> env->regs[15] = 0xFFFF0000;
> }
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index a4bb6bd..780c1f5 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -180,7 +180,8 @@ typedef struct CPUARMState {
> struct {
> uint32_t c0_cpuid;
> uint64_t c0_cssel; /* Cache size selection. */
> - uint64_t c1_sys; /* System control register. */
> + uint64_t c1_sys_el1; /* System control register (EL1). */
> + uint64_t c1_sys_el3; /* System control register (EL3). */
> uint64_t c1_coproc; /* Coprocessor access register. */
> uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
> uint32_t c1_scr; /* secure config register. */
> @@ -971,6 +972,17 @@ static inline int arm_current_pl(CPUARMState *env)
> return 1;
> }
>
> +static inline uint64_t arm_current_sctlr(CPUARMState *env)
> +{
> + if (is_a64(env) && arm_current_pl(env) == 3) {
> + /* EL3 has its own SCTLR */
> + return env->cp15.c1_sys_el3;
> + } else {
> + /* Only A32 with NS-bit clear accesses secure instance of SCTLR */
> + return A32_MAPPED_EL3_REG_GET(env, c1_sys);
> + }
> +}
> +
> typedef struct ARMCPRegInfo ARMCPRegInfo;
>
> typedef enum CPAccessResult {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 98c3dc9..ac8b15a 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1767,7 +1767,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>
> static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
> {
> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
> return CP_ACCESS_TRAP;
> }
> return CP_ACCESS_OK;
> @@ -1785,7 +1785,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
> /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
> * SCTLR_EL1.UCI is set.
> */
> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCI)) {
> return CP_ACCESS_TRAP;
> }
> return CP_ACCESS_OK;
> @@ -1823,7 +1823,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
> /* We don't implement EL2, so the only control on DC ZVA is the
> * bit in the SCTLR which can prohibit access for EL0.
> */
> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_DZE)) {
> return CP_ACCESS_TRAP;
> }
> return CP_ACCESS_OK;
> @@ -2146,7 +2146,7 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
> /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
> * but the AArch32 CTR has its own reginfo struct)
> */
> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCT)) {
> return CP_ACCESS_TRAP;
> }
> return CP_ACCESS_OK;
> @@ -2573,10 +2573,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>
> /* Generic registers whose values depend on the implementation */
> {
> - ARMCPRegInfo sctlr = {
> - .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
> - .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys),
> + ARMCPRegInfo sctlr_el1 = {
> + .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
> + .type = ARM_CP_NONSECURE, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0,
> + .opc2 = 0, .access = PL1_RW,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el1),
> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> .raw_writefn = raw_write,
> };
> @@ -2585,9 +2586,43 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> * arch/arm/mach-pxa/sleep.S expects two instructions following
> * an MMU enable to execute from cache. Imitate this behaviour.
> */
> - sctlr.type |= ARM_CP_SUPPRESS_TB_END;
> + sctlr_el1.type |= ARM_CP_SUPPRESS_TB_END;
> }
> - define_one_arm_cp_reg(cpu, &sctlr);
> + define_one_arm_cp_reg(cpu, &sctlr_el1);
> +
> + ARMCPRegInfo sctlr_el1_s = {
> + .name = "SCTLR_EL1(S)", .type = ARM_CP_SECURE,
> + .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> + .access = PL3_RW,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> + .raw_writefn = raw_write,
> + };
> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> + /* Normally we would always end the TB on an SCTLR write, but Linux
> + * arch/arm/mach-pxa/sleep.S expects two instructions following
> + * an MMU enable to execute from cache. Imitate this behaviour.
> + */
> + sctlr_el1_s.type |= ARM_CP_SUPPRESS_TB_END;
> + }
> + define_one_arm_cp_reg(cpu, &sctlr_el1_s);
> +
> + ARMCPRegInfo sctlr_el3 = {
> + .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
> + .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
> + .access = PL3_RW, .type = ARM_CP_SECURE,
> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr_el3,
> + .raw_writefn = raw_write,
> + };
> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> + /* Normally we would always end the TB on an SCTLR write, but Linux
> + * arch/arm/mach-pxa/sleep.S expects two instructions following
> + * an MMU enable to execute from cache. Imitate this behaviour.
> + */
> + sctlr_el3.type |= ARM_CP_SUPPRESS_TB_END;
> + }
> + define_one_arm_cp_reg(cpu, &sctlr_el3);
> }
> }
>
> @@ -3475,7 +3510,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> return; /* Never happens. Keep compiler happy. */
> }
> /* High vectors. */
> - if (env->cp15.c1_sys & SCTLR_V) {
> + if (arm_current_sctlr(env) & SCTLR_V) {
> /* when enabled, base address cannot be remapped. */
> addr += 0xffff0000;
> } else {
> @@ -3498,7 +3533,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
> * and we should just guard the thumb mode on V4 */
> if (arm_feature(env, ARM_FEATURE_V4T)) {
> - env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0;
> + env->thumb = (arm_current_sctlr(env) & SCTLR_TE) != 0;
> }
> env->regs[14] = env->regs[15] + offset;
> env->regs[15] = addr;
> @@ -3529,7 +3564,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
> }
> if (access_type == 1)
> return 0;
> - switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) {
> + switch (arm_current_sctlr(env) & (SCTLR_S | SCTLR_R)) {
> case SCTLR_S:
> return is_user ? 0 : PAGE_READ;
> case SCTLR_R:
> @@ -3763,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
> goto do_fault;
>
> /* The simplified model uses AP[0] as an access control bit. */
> - if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) {
> + if ((arm_current_sctlr(env) & SCTLR_AFE) && (ap & 1) == 0) {
> /* Access flag fault. */
> code = (code == 15) ? 6 : 3;
> goto do_fault;
> @@ -4099,7 +4134,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
> if (address < 0x02000000)
> address += env->cp15.c13_fcse;
>
> - if ((env->cp15.c1_sys & SCTLR_M) == 0) {
> + if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
> /* MMU/MPU disabled. */
> *phys_ptr = address;
> *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> @@ -4112,7 +4147,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
> } else if (extended_addresses_enabled(env)) {
> return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
> prot, page_size);
> - } else if (env->cp15.c1_sys & SCTLR_XP) {
> + } else if (arm_current_sctlr(env) & SCTLR_XP) {
> return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
> prot, page_size);
> } else {
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index fb90676..3eacea8 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -365,7 +365,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
> * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
> * to catch that case at translate time.
> */
> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
> raise_exception(env, EXCP_UDEF);
> }
>
> --
> 1.8.3.2
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
2014-05-14 16:42 ` Greg Bellows
2014-05-15 18:42 ` Sergey Fedorov
@ 2014-05-22 7:41 ` Edgar E. Iglesias
2014-05-22 11:49 ` Aggeler Fabian
2 siblings, 1 reply; 75+ messages in thread
From: Edgar E. Iglesias @ 2014-05-22 7:41 UTC (permalink / raw)
To: Fabian Aggeler; +Cc: peter.maydell, Sergey Fedorov, qemu-devel
On Tue, May 13, 2014 at 06:15:59PM +0200, Fabian Aggeler wrote:
> Banked CP registers can be defined with a A32_BANKED_REG macro which defines
> a non-secure instance of the register followed by an adjacent secure instance.
> Using a union makes the code backwards-compatible since the non-secure
> instance can normally be accessed by its existing name.
>
> When translating a banked CP register access instruction in monitor mode,
> the SCR.NS bit determines which instance is going to be accessed.
>
> If EL3 is operating in Aarch64 state coprocessor registers are not
> banked anymore but in some cases have its own _EL3 instance.
Hi
Regarding the sctlr regs and the banking of S/NS regs in general, I
think the general pattern should be to arrayify the regs that need
to be indexed by EL.
This is an example of a structure (indexed by EL) with the aarch32
struct beeing here to help clarify.
union {
struct {
uint64_t pad;
uint64_t sctlr_ns;
uint64_t hsctlr;
uint64_t sctlr_s;
} aarch32;
uint64_t sctlr_el[4];
}
I think we would naturally want to register this for AArch32 as banked
with NS=sctlr_el[1] and S=sctlr_el[3].
Another register example is FAR. For FAR, things look like this
(when EL2 is available and ignoring DFAR for clarity):
union {
struct {
uint64_t pad;
uint64_t ifar_ns;
uint64_t ifar_s;
} aarch32;
uint64_t far_el[4];
}
Preferably we need something that can handle both cases.
An option could be to arrayify the .fieldoffset in reginfos?
If we don't want hardcoded TZ knowledge in the generic cpreg accessors,
maybe there could be a generic function that returns the .fieldoffset
index based on CPUState (e.g NS=0, S=1 etc). Or maybe specialized
read/write fns would be enough.
Just an idea to get the discussion going.
struct ARMCPRegInfo {
....
union {
ptrdiff_t fieldoffset;
ptrdiff_t fieldoffsets[2];
};
};
unsigned int arm_cpreg_tzbank_idx(CPUARMState *env)
{
return is_a64(env) ? 0 : arm_is_secure(env);
}
Example:
{ .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.fieldindex_fn = arm_cpreg_tzbank_idx,
.fieldoffsets[] = { offsetof(CPUARMState, cp15.far_el[1]),
offsetof(CPUARMState, cp15.far_el[2])},
.resetvalue = 0, },
ARMCPRegInfo sctlr = {
.name = "SCTLR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.fieldindex_fn = arm_cpreg_tzbank_idx,
.fieldoffsets[] = { offsetof(CPUARMState, cp15.sctlr_el[1]),
offsetof(CPUARMState, cp15.sctlr_el[3]),
},
/* Assuming raw_write and raw_read respect the indexing. */
.writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
.raw_writefn = raw_write,
};
Best regards,
Edgar
>
> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> ---
> target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
> target-arm/helper.c | 64 ++++++++++++++++++++++++--
> target-arm/translate.c | 19 +++++---
> 3 files changed, 184 insertions(+), 20 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index a970d55..9e325ac 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -80,6 +80,16 @@
> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
> #endif
>
> +/* Define a banked coprocessor register state field. Use %name as the
> + * register field name for the secure instance. The non-secure instance
> + * has a "_nonsecure" suffix.
> + */
> +#define A32_BANKED_REG(type, name) \
> + union { \
> + type name; \
> + type name##_banked[2]; \
> + }
> +
> /* Meanings of the ARMCPU object's two inbound GPIO lines */
> #define ARM_CPU_IRQ 0
> #define ARM_CPU_FIQ 1
> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
> int dstreg, int operand);
>
> +
> struct arm_boot_info;
>
> #define NB_MMU_MODES 5
> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
> return arm_feature(env, ARM_FEATURE_AARCH64);
> }
>
> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
> + * whether the secure instance of a cp-register should be used. */
> +#define USE_SECURE_REG(env) ( \
> + arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
> + !arm_el_is_aa64(env, 3) && \
> + !((env)->cp15.c1_scr & 1/*NS*/))
> +
> +#define NONSECURE_BANK 0
> +#define SECURE_BANK 1
> +
> +#define A32_BANKED_REG_GET(env, regname) \
> + ((USE_SECURE_REG(env)) ? \
> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> + (env)->cp15.regname)
> +
> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (USE_SECURE_REG(env))) ? \
> + (env)->cp15.regname##_el3 : \
> + (env)->cp15.regname##_el1)
> +
> +#define A32_BANKED_REG_SET(env, regname, val) \
> + do { \
> + if (USE_SECURE_REG(env)) { \
> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> + } else { \
> + (env)->cp15.regname = (val); \
> + } \
> + } while (0)
> +
> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
> + do { \
> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (USE_SECURE_REG(env))) { \
> + (env)->cp15.regname##_el3 = (val); \
> + } else { \
> + (env)->cp15.regname##_el1 = (val); \
> + } \
> + } while (0)
> +
> +
> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> + (env)->cp15.regname)
> +
> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
> + (env)->cp15.regname##_el3 : \
> + (env)->cp15.regname##_el1)
> +
> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
> + do { \
> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> + } else { \
> + (env)->cp15.regname = (val); \
> + } \
> + } while (0)
> +
> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
> + do { \
> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
> + (env)->cp15.regname##_el3 = (val); \
> + } else { \
> + (env)->cp15.regname##_el1 = (val); \
> + } \
> + } while (0)
> +
> +
> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>
> /* Interface between CPU and Interrupt controller. */
> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
> * Crn, Crm, opc1, opc2 fields
> * 32 or 64 bit register (ie is it accessed via MRC/MCR
> * or via MRRC/MCRR?)
> + * nonsecure/secure bank (Aarch32 only)
> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
> * (In this case crn and opc2 should be zero.)
> * For AArch64, there is no 32/64 bit size distinction;
> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
> #define CP_REG_AA64_SHIFT 28
> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>
> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
> - ((crm) << 7) | ((opc1) << 3) | (opc2))
> +/* To enable banking of coprocessor registers depending on ns-bit we
> + * add a bit to distinguish between secure and non-secure cpregs in the
> + * hashtable.
> + */
> +#define CP_REG_NS_SHIFT 27
> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
> +
> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>
> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
> (CP_REG_AA64_MASK | \
> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
> * IO indicates that this register does I/O and therefore its accesses
> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
> * registers which implement clocks or timers require this.
> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
> + * be banked or common. If a register is common it references the same variable
> + * from both worlds (non-secure and secure). For cp regs which neither set
> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
> + * will be inserted twice into the hashtable. If a register has
> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
> + * different offset respectively. This way Aarch32 registers which can be
> + * mapped to Aarch64 PL3 registers can be inserted individually.
> */
> #define ARM_CP_SPECIAL 1
> #define ARM_CP_CONST 2
> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
> #define ARM_CP_OVERRIDE 16
> #define ARM_CP_NO_MIGRATE 32
> #define ARM_CP_IO 64
> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
> +#define ARM_CP_SECURE (1 << 7)
> +#define ARM_CP_NONSECURE (1 << 8)
> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
> /* Used only as a terminator for ARMCPRegInfo lists */
> #define ARM_CP_SENTINEL 0xffff
> /* Mask of only the flag bits in a type field */
> -#define ARM_CP_FLAG_MASK 0x7f
> +#define ARM_CP_FLAG_MASK 0x3ff
>
> /* Valid values for ARMCPRegInfo state field, indicating which of
> * the AArch32 and AArch64 execution states this register is visible in.
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 9326ef8..98c3dc9 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>
> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> void *opaque, int state,
> - int crm, int opc1, int opc2)
> + int crm, int opc1, int opc2, int nsbit)
> {
> /* Private utility function for define_one_arm_cp_reg_with_opaque():
> * add a single reginfo struct to the hash table.
> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> }
> #endif
> }
> +
> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
> + if (r2->fieldoffset) {
> + /* We simplify register definitions by providing a type
> + * ARM_CP_BANKED, for which the fieldoffset of the secure instance
> + * will be increased to point at the second entry of the array.
> + *
> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
> + * wide the banked register is because some registers are 64bit
> + * wide but the register is not defined as 64bit because it is
> + * mapped to the lower 32 bit.
> + * Therefore two separate types for 64bit banked registers and
> + * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
> + */
> + r2->fieldoffset +=
> + ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
> + sizeof(uint64_t) : sizeof(uint32_t);
> + }
> + }
> + /* For A32 we want to be able to know whether the secure or non-secure
> + * instance wants to be accessed. A64 does not know this banking scheme
> + * anymore, but it might use the same readfn/writefn as A32 which might
> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
> + * Reset the type according to ns-bit passed as argument.
> + */
> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
> +
> if (state == ARM_CP_STATE_AA64) {
> /* To allow abbreviation of ARMCPRegInfo
> * definitions, we treat cp == 0 as equivalent to
> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> r2->opc0, opc1, opc2);
> } else {
> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
> }
> if (opaque) {
> r2->opaque = opaque;
> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
> fprintf(stderr, "Register redefined: cp=%d %d bit "
> - "crn=%d crm=%d opc1=%d opc2=%d, "
> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
> r2->crn, r2->crm, r2->opc1, r2->opc2,
> + (r2->type & ARM_CP_NONSECURE),
> oldreg->name, r2->name);
> g_assert_not_reached();
> }
> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
> if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
> continue;
> }
> - add_cpreg_to_hashtable(cpu, r, opaque, state,
> - crm, opc1, opc2);
> +
> + if (state == ARM_CP_STATE_AA32) {
> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
> + (r->type & ARM_CP_BANKED) == 0) {
> + /* Under Aarch32 CP registers can be common
> + * (same for secure and non-secure world) or banked.
> + * Register definitions with neither secure nor
> + * non-secure type set (common) or with both bits
> + * set (banked) will be inserted twice into the
> + * hashtable.
> + */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 0);
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 1);
> + } else {
> + /* Only one of both bank types were specified */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2,
> + (r->type & ARM_CP_NONSECURE) ? 1 : 0);
> + }
> + } else {
> + /* Aarch64 registers get mapped to non-secure instance
> + * of Aarch32 */
> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> + crm, opc1, opc2, 1);
> + }
> }
> }
> }
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index bbd4c77..3a429ac 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
>
> static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> {
> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
> const ARMCPRegInfo *ri;
>
> cpnum = (insn >> 8) & 0xf;
> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> isread = (insn >> 20) & 1;
> rt = (insn >> 12) & 0xf;
>
> + /* Monitor mode is always treated as secure but cp register reads/writes
> + * can access secure and non-secure instances using SCR.NS bit*/
> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
> ri = get_arm_cp_reginfo(s->cp_regs,
> - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
> if (ri) {
> /* Check access permissions */
> if (!cp_access_ok(s->current_pl, ri, isread)) {
> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
> */
> if (is64) {
> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> - "64 bit system register cp:%d opc1: %d crm:%d\n",
> - isread ? "read" : "write", cpnum, opc1, crm);
> + "64 bit system register cp:%d opc1: %d crm:%d "
> + "(%s)\n",
> + isread ? "read" : "write", cpnum, opc1, crm,
> + ns ? "non-secure" : "secure");
> } else {
> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
> - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
> + "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
> + "(%s)\n",
> + isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
> + ns ? "non-secure" : "secure");
> }
>
> return 1;
> --
> 1.8.3.2
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR
2014-05-21 16:12 ` Peter Maydell
@ 2014-05-22 8:58 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-22 8:58 UTC (permalink / raw)
To: Peter Maydell
Cc: Sergey Fedorov, Svetlana Fedoseeva, QEMU Developers,
Edgar E. Iglesias
On 21 May 2014, at 18:12, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 14 May 2014 06:43, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>>
>> On 13.05.2014 20:15, Fabian Aggeler wrote:
>>> From: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>>>
>>> Signed-off-by: Svetlana Fedoseeva <s.fedoseeva@samsung.com>
>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>>> ---
>>> target-arm/helper.c | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>>> index 9c3269f..2b57ad9 100644
>>> --- a/target-arm/helper.c
>>> +++ b/target-arm/helper.c
>>> @@ -2083,6 +2083,11 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>>> {
>>> ARMCPU *cpu = arm_env_get_cpu(env);
>>>
>>> + if (arm_feature(env, ARM_FEATURE_V7)) {
>>> + value |= SCTLR_XP | SCTLR_U | SCTLR_nTWE | SCTLR_nTWI | SCTLR_L
>>> + | SCTLR_CP15BEN | SCTLR_P; /* These bits are RAO/WI */
>>
>> Actually, some of these bits are RAO/WI since v6. Also, there are some
>> RAZ/WI bits varying over architecture variants. There is some overview
>> at ARM ARM v7-AP section L.7.4. Maybe it is worth to fix more precisely
>> over supported architecture variants? By the way, this patch could be
>> separated from security extensions support patch set.
>
> Agreed. Our compliance for bits that should-be-0/1 is not great,
> but if we don't actually need to do those fixes for TZ support
> then they're probably better separated out (ie drop them from
> this patchset for the moment and submit them separately or
> later...)
>
> Also for v8 many of these RAZ/RAO bits become RES0/RES1 and
> the rules are different...
>
> thanks
> — PMM
Okay, I will separate them and submit them separately.
Thanks,
Fabian
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions
2014-05-21 14:51 ` Peter Maydell
@ 2014-05-22 9:09 ` Aggeler Fabian
0 siblings, 0 replies; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-22 9:09 UTC (permalink / raw)
To: Peter Maydell
Cc: Edgar E. Iglesias, Sergey Fedorov, QEMU Developers,
Svetlana Fedoseeva
On 21 May 2014, at 16:51, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 13 May 2014 17:15, Fabian Aggeler <aggelerf@ethz.ch> wrote:
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -631,6 +631,7 @@ enum arm_features {
>> ARM_FEATURE_CBAR, /* has cp15 CBAR */
>> ARM_FEATURE_CRC, /* ARMv8 CRC instructions */
>> ARM_FEATURE_CBAR_RO, /* has cp15 CBAR and it is read-only */
>> + ARM_FEATURE_SECURITY_EXTENSIONS, /* has Security Extensions */
>> };
>
> Also this feature name is pretty long and unwieldy; something
> shorter would be nice. I think we should probably go with
> ARM_FEATURE_EL2/ARM_FEATURE_EL3 as per Edgar's
> patchset.
>
> thanks
> -- PMM
Makes sense, I will use Edgar’s ARM_FEATURE_EL3 in the next version.
Fabian
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-22 7:41 ` Edgar E. Iglesias
@ 2014-05-22 11:49 ` Aggeler Fabian
2014-05-22 12:18 ` Sergey Fedorov
0 siblings, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-22 11:49 UTC (permalink / raw)
To: Edgar E. Iglesias
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org
On 22 May 2014, at 09:41, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote:
> On Tue, May 13, 2014 at 06:15:59PM +0200, Fabian Aggeler wrote:
>> Banked CP registers can be defined with a A32_BANKED_REG macro which defines
>> a non-secure instance of the register followed by an adjacent secure instance.
>> Using a union makes the code backwards-compatible since the non-secure
>> instance can normally be accessed by its existing name.
>>
>> When translating a banked CP register access instruction in monitor mode,
>> the SCR.NS bit determines which instance is going to be accessed.
>>
>> If EL3 is operating in Aarch64 state coprocessor registers are not
>> banked anymore but in some cases have its own _EL3 instance.
>
> Hi
>
> Regarding the sctlr regs and the banking of S/NS regs in general, I
> think the general pattern should be to arrayify the regs that need
> to be indexed by EL.
>
> This is an example of a structure (indexed by EL) with the aarch32
> struct beeing here to help clarify.
> union {
> struct {
> uint64_t pad;
> uint64_t sctlr_ns;
> uint64_t hsctlr;
> uint64_t sctlr_s;
> } aarch32;
> uint64_t sctlr_el[4];
> }
>
> I think we would naturally want to register this for AArch32 as banked
> with NS=sctlr_el[1] and S=sctlr_el[3].
>
> Another register example is FAR. For FAR, things look like this
> (when EL2 is available and ignoring DFAR for clarity):
> union {
> struct {
> uint64_t pad;
> uint64_t ifar_ns;
> uint64_t ifar_s;
> } aarch32;
> uint64_t far_el[4];
> }
>
> Preferably we need something that can handle both cases.
> An option could be to arrayify the .fieldoffset in reginfos?
> If we don't want hardcoded TZ knowledge in the generic cpreg accessors,
> maybe there could be a generic function that returns the .fieldoffset
> index based on CPUState (e.g NS=0, S=1 etc). Or maybe specialized
> read/write fns would be enough.
>
> Just an idea to get the discussion going.
>
> struct ARMCPRegInfo {
> ....
> union {
> ptrdiff_t fieldoffset;
> ptrdiff_t fieldoffsets[2];
> };
> };
>
> unsigned int arm_cpreg_tzbank_idx(CPUARMState *env)
> {
> return is_a64(env) ? 0 : arm_is_secure(env);
> }
>
> Example:
> { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> .access = PL1_RW,
> .fieldindex_fn = arm_cpreg_tzbank_idx,
> .fieldoffsets[] = { offsetof(CPUARMState, cp15.far_el[1]),
> offsetof(CPUARMState, cp15.far_el[2])},
> .resetvalue = 0, },
>
> ARMCPRegInfo sctlr = {
> .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
> .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> .access = PL1_RW,
> .fieldindex_fn = arm_cpreg_tzbank_idx,
> .fieldoffsets[] = { offsetof(CPUARMState, cp15.sctlr_el[1]),
> offsetof(CPUARMState, cp15.sctlr_el[3]),
> },
> /* Assuming raw_write and raw_read respect the indexing. */
> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> .raw_writefn = raw_write,
> };
>
> Best regards,
> Edgar
>
Hi Edgar
Thanks for joining the discussion. I like the idea of arrayifying the cp regs, also for banking.
Since your patches are doing this anyways for EL registers I wanted to change the registers
which do not have EL3/EL2 equivalents (DACR, PAR,…) to use the same mechanism. These
registers are the third case which you haven’t mentioned in your examples above, where we only
have one reg in Aarch64 but two (s/ns) in Aarch32. So I in my eyes it didn’t make sense to make
the array bigger than needed, that’s why I went for 2 entries only. But if it allows us map it easier
or in a more consistent way I don’t see why we cannot do it.
union {
struct {
uint64_t par_ns;
uint64_t par_s;
} aarch32;
uint64_t par_el[2];
}
We should probably also get rid of the macros I used to define the banked registers, to make the code
look more uniform. Using your idea of arrayifying fieldset too, we could get rid of the additional cpreg
definitions. Do we need to specify a .fieldindex_fn for every cpreg in this case?
Isn’t it the same for all the cpregs which are banked (two fieldoffsets, the first one for non-secure and
the second entry for secure)? But then we still need to know whether this register is banked or common.
But what about accessing them not from within a cpreg read/write instruction? We will have at least 3
cases of different indexes ({ns=1, s=2}, {ns=1, s=3}, {ns=0, s=1}). Although by padding the last case
we could merge it with the first one so we only have 2 ways of accessing a banked register, which was
also the case in my patches, for which I introduced macros. Any ideas how to simplify that?
Thanks,
Fabian
>
>
>
>
>>
>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>> ---
>> target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
>> target-arm/helper.c | 64 ++++++++++++++++++++++++--
>> target-arm/translate.c | 19 +++++---
>> 3 files changed, 184 insertions(+), 20 deletions(-)
>>
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index a970d55..9e325ac 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -80,6 +80,16 @@
>> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
>> #endif
>>
>> +/* Define a banked coprocessor register state field. Use %name as the
>> + * register field name for the secure instance. The non-secure instance
>> + * has a "_nonsecure" suffix.
>> + */
>> +#define A32_BANKED_REG(type, name) \
>> + union { \
>> + type name; \
>> + type name##_banked[2]; \
>> + }
>> +
>> /* Meanings of the ARMCPU object's two inbound GPIO lines */
>> #define ARM_CPU_IRQ 0
>> #define ARM_CPU_FIQ 1
>> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
>> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
>> int dstreg, int operand);
>>
>> +
>> struct arm_boot_info;
>>
>> #define NB_MMU_MODES 5
>> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
>> return arm_feature(env, ARM_FEATURE_AARCH64);
>> }
>>
>> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
>> + * whether the secure instance of a cp-register should be used. */
>> +#define USE_SECURE_REG(env) ( \
>> + arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
>> + !arm_el_is_aa64(env, 3) && \
>> + !((env)->cp15.c1_scr & 1/*NS*/))
>> +
>> +#define NONSECURE_BANK 0
>> +#define SECURE_BANK 1
>> +
>> +#define A32_BANKED_REG_GET(env, regname) \
>> + ((USE_SECURE_REG(env)) ? \
>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>> + (env)->cp15.regname)
>> +
>> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>> + (USE_SECURE_REG(env))) ? \
>> + (env)->cp15.regname##_el3 : \
>> + (env)->cp15.regname##_el1)
>> +
>> +#define A32_BANKED_REG_SET(env, regname, val) \
>> + do { \
>> + if (USE_SECURE_REG(env)) { \
>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>> + } else { \
>> + (env)->cp15.regname = (val); \
>> + } \
>> + } while (0)
>> +
>> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
>> + do { \
>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>> + (USE_SECURE_REG(env))) { \
>> + (env)->cp15.regname##_el3 = (val); \
>> + } else { \
>> + (env)->cp15.regname##_el1 = (val); \
>> + } \
>> + } while (0)
>> +
>> +
>> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
>> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>> + (env)->cp15.regname)
>> +
>> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
>> + (env)->cp15.regname##_el3 : \
>> + (env)->cp15.regname##_el1)
>> +
>> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
>> + do { \
>> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>> + } else { \
>> + (env)->cp15.regname = (val); \
>> + } \
>> + } while (0)
>> +
>> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
>> + do { \
>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
>> + (env)->cp15.regname##_el3 = (val); \
>> + } else { \
>> + (env)->cp15.regname##_el1 = (val); \
>> + } \
>> + } while (0)
>> +
>> +
>> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>>
>> /* Interface between CPU and Interrupt controller. */
>> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>> * Crn, Crm, opc1, opc2 fields
>> * 32 or 64 bit register (ie is it accessed via MRC/MCR
>> * or via MRRC/MCRR?)
>> + * nonsecure/secure bank (Aarch32 only)
>> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
>> * (In this case crn and opc2 should be zero.)
>> * For AArch64, there is no 32/64 bit size distinction;
>> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>> #define CP_REG_AA64_SHIFT 28
>> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>>
>> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
>> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
>> - ((crm) << 7) | ((opc1) << 3) | (opc2))
>> +/* To enable banking of coprocessor registers depending on ns-bit we
>> + * add a bit to distinguish between secure and non-secure cpregs in the
>> + * hashtable.
>> + */
>> +#define CP_REG_NS_SHIFT 27
>> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
>> +
>> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
>> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
>> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>>
>> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
>> (CP_REG_AA64_MASK | \
>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>> * IO indicates that this register does I/O and therefore its accesses
>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
>> * registers which implement clocks or timers require this.
>> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
>> + * be banked or common. If a register is common it references the same variable
>> + * from both worlds (non-secure and secure). For cp regs which neither set
>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
>> + * will be inserted twice into the hashtable. If a register has
>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
>> + * different offset respectively. This way Aarch32 registers which can be
>> + * mapped to Aarch64 PL3 registers can be inserted individually.
>> */
>> #define ARM_CP_SPECIAL 1
>> #define ARM_CP_CONST 2
>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>> #define ARM_CP_OVERRIDE 16
>> #define ARM_CP_NO_MIGRATE 32
>> #define ARM_CP_IO 64
>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
>> +#define ARM_CP_SECURE (1 << 7)
>> +#define ARM_CP_NONSECURE (1 << 8)
>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
>> /* Used only as a terminator for ARMCPRegInfo lists */
>> #define ARM_CP_SENTINEL 0xffff
>> /* Mask of only the flag bits in a type field */
>> -#define ARM_CP_FLAG_MASK 0x7f
>> +#define ARM_CP_FLAG_MASK 0x3ff
>>
>> /* Valid values for ARMCPRegInfo state field, indicating which of
>> * the AArch32 and AArch64 execution states this register is visible in.
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index 9326ef8..98c3dc9 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>>
>> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>> void *opaque, int state,
>> - int crm, int opc1, int opc2)
>> + int crm, int opc1, int opc2, int nsbit)
>> {
>> /* Private utility function for define_one_arm_cp_reg_with_opaque():
>> * add a single reginfo struct to the hash table.
>> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>> }
>> #endif
>> }
>> +
>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
>> + if (r2->fieldoffset) {
>> + /* We simplify register definitions by providing a type
>> + * ARM_CP_BANKED, for which the fieldoffset of the secure instance
>> + * will be increased to point at the second entry of the array.
>> + *
>> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
>> + * wide the banked register is because some registers are 64bit
>> + * wide but the register is not defined as 64bit because it is
>> + * mapped to the lower 32 bit.
>> + * Therefore two separate types for 64bit banked registers and
>> + * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
>> + */
>> + r2->fieldoffset +=
>> + ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
>> + sizeof(uint64_t) : sizeof(uint32_t);
>> + }
>> + }
>> + /* For A32 we want to be able to know whether the secure or non-secure
>> + * instance wants to be accessed. A64 does not know this banking scheme
>> + * anymore, but it might use the same readfn/writefn as A32 which might
>> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
>> + * Reset the type according to ns-bit passed as argument.
>> + */
>> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
>> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
>> +
>> if (state == ARM_CP_STATE_AA64) {
>> /* To allow abbreviation of ARMCPRegInfo
>> * definitions, we treat cp == 0 as equivalent to
>> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
>> r2->opc0, opc1, opc2);
>> } else {
>> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
>> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
>> }
>> if (opaque) {
>> r2->opaque = opaque;
>> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
>> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
>> fprintf(stderr, "Register redefined: cp=%d %d bit "
>> - "crn=%d crm=%d opc1=%d opc2=%d, "
>> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
>> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
>> r2->crn, r2->crm, r2->opc1, r2->opc2,
>> + (r2->type & ARM_CP_NONSECURE),
>> oldreg->name, r2->name);
>> g_assert_not_reached();
>> }
>> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>> if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
>> continue;
>> }
>> - add_cpreg_to_hashtable(cpu, r, opaque, state,
>> - crm, opc1, opc2);
>> +
>> + if (state == ARM_CP_STATE_AA32) {
>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
>> + (r->type & ARM_CP_BANKED) == 0) {
>> + /* Under Aarch32 CP registers can be common
>> + * (same for secure and non-secure world) or banked.
>> + * Register definitions with neither secure nor
>> + * non-secure type set (common) or with both bits
>> + * set (banked) will be inserted twice into the
>> + * hashtable.
>> + */
>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>> + crm, opc1, opc2, 0);
>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>> + crm, opc1, opc2, 1);
>> + } else {
>> + /* Only one of both bank types were specified */
>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>> + crm, opc1, opc2,
>> + (r->type & ARM_CP_NONSECURE) ? 1 : 0);
>> + }
>> + } else {
>> + /* Aarch64 registers get mapped to non-secure instance
>> + * of Aarch32 */
>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>> + crm, opc1, opc2, 1);
>> + }
>> }
>> }
>> }
>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>> index bbd4c77..3a429ac 100644
>> --- a/target-arm/translate.c
>> +++ b/target-arm/translate.c
>> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
>>
>> static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>> {
>> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
>> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
>> const ARMCPRegInfo *ri;
>>
>> cpnum = (insn >> 8) & 0xf;
>> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>> isread = (insn >> 20) & 1;
>> rt = (insn >> 12) & 0xf;
>>
>> + /* Monitor mode is always treated as secure but cp register reads/writes
>> + * can access secure and non-secure instances using SCR.NS bit*/
>> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
>> ri = get_arm_cp_reginfo(s->cp_regs,
>> - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
>> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
>> if (ri) {
>> /* Check access permissions */
>> if (!cp_access_ok(s->current_pl, ri, isread)) {
>> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>> */
>> if (is64) {
>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>> - "64 bit system register cp:%d opc1: %d crm:%d\n",
>> - isread ? "read" : "write", cpnum, opc1, crm);
>> + "64 bit system register cp:%d opc1: %d crm:%d "
>> + "(%s)\n",
>> + isread ? "read" : "write", cpnum, opc1, crm,
>> + ns ? "non-secure" : "secure");
>> } else {
>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>> - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
>> - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
>> + "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
>> + "(%s)\n",
>> + isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
>> + ns ? "non-secure" : "secure");
>> }
>>
>> return 1;
>> --
>> 1.8.3.2
>>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-22 11:49 ` Aggeler Fabian
@ 2014-05-22 12:18 ` Sergey Fedorov
2014-05-22 12:50 ` Aggeler Fabian
0 siblings, 1 reply; 75+ messages in thread
From: Sergey Fedorov @ 2014-05-22 12:18 UTC (permalink / raw)
To: Aggeler Fabian, Edgar E. Iglesias
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org
On 22.05.2014 15:49, Aggeler Fabian wrote:
> On 22 May 2014, at 09:41, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote:
>
>> On Tue, May 13, 2014 at 06:15:59PM +0200, Fabian Aggeler wrote:
>>> Banked CP registers can be defined with a A32_BANKED_REG macro which defines
>>> a non-secure instance of the register followed by an adjacent secure instance.
>>> Using a union makes the code backwards-compatible since the non-secure
>>> instance can normally be accessed by its existing name.
>>>
>>> When translating a banked CP register access instruction in monitor mode,
>>> the SCR.NS bit determines which instance is going to be accessed.
>>>
>>> If EL3 is operating in Aarch64 state coprocessor registers are not
>>> banked anymore but in some cases have its own _EL3 instance.
>> Hi
>>
>> Regarding the sctlr regs and the banking of S/NS regs in general, I
>> think the general pattern should be to arrayify the regs that need
>> to be indexed by EL.
>>
>> This is an example of a structure (indexed by EL) with the aarch32
>> struct beeing here to help clarify.
>> union {
>> struct {
>> uint64_t pad;
>> uint64_t sctlr_ns;
>> uint64_t hsctlr;
>> uint64_t sctlr_s;
>> } aarch32;
>> uint64_t sctlr_el[4];
>> }
>>
>> I think we would naturally want to register this for AArch32 as banked
>> with NS=sctlr_el[1] and S=sctlr_el[3].
>>
>> Another register example is FAR. For FAR, things look like this
>> (when EL2 is available and ignoring DFAR for clarity):
>> union {
>> struct {
>> uint64_t pad;
>> uint64_t ifar_ns;
>> uint64_t ifar_s;
>> } aarch32;
>> uint64_t far_el[4];
>> }
>>
>> Preferably we need something that can handle both cases.
>> An option could be to arrayify the .fieldoffset in reginfos?
>> If we don't want hardcoded TZ knowledge in the generic cpreg accessors,
>> maybe there could be a generic function that returns the .fieldoffset
>> index based on CPUState (e.g NS=0, S=1 etc). Or maybe specialized
>> read/write fns would be enough.
>>
>> Just an idea to get the discussion going.
>>
>> struct ARMCPRegInfo {
>> ....
>> union {
>> ptrdiff_t fieldoffset;
>> ptrdiff_t fieldoffsets[2];
>> };
>> };
>>
>> unsigned int arm_cpreg_tzbank_idx(CPUARMState *env)
>> {
>> return is_a64(env) ? 0 : arm_is_secure(env);
>> }
>>
>> Example:
>> { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
>> .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
>> .access = PL1_RW,
>> .fieldindex_fn = arm_cpreg_tzbank_idx,
>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.far_el[1]),
>> offsetof(CPUARMState, cp15.far_el[2])},
>> .resetvalue = 0, },
>>
>> ARMCPRegInfo sctlr = {
>> .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
>> .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
>> .access = PL1_RW,
>> .fieldindex_fn = arm_cpreg_tzbank_idx,
>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.sctlr_el[1]),
>> offsetof(CPUARMState, cp15.sctlr_el[3]),
>> },
>> /* Assuming raw_write and raw_read respect the indexing. */
>> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
>> .raw_writefn = raw_write,
>> };
>>
>> Best regards,
>> Edgar
>>
> Hi Edgar
>
> Thanks for joining the discussion. I like the idea of arrayifying the cp regs, also for banking.
> Since your patches are doing this anyways for EL registers I wanted to change the registers
> which do not have EL3/EL2 equivalents (DACR, PAR,…) to use the same mechanism. These
> registers are the third case which you haven’t mentioned in your examples above, where we only
> have one reg in Aarch64 but two (s/ns) in Aarch32. So I in my eyes it didn’t make sense to make
> the array bigger than needed, that’s why I went for 2 entries only. But if it allows us map it easier
> or in a more consistent way I don’t see why we cannot do it.
>
> union {
> struct {
> uint64_t par_ns;
> uint64_t par_s;
> } aarch32;
> uint64_t par_el[2];
> }
>
> We should probably also get rid of the macros I used to define the banked registers, to make the code
> look more uniform. Using your idea of arrayifying fieldset too, we could get rid of the additional cpreg
> definitions. Do we need to specify a .fieldindex_fn for every cpreg in this case?
> Isn’t it the same for all the cpregs which are banked (two fieldoffsets, the first one for non-secure and
> the second entry for secure)? But then we still need to know whether this register is banked or common.
>
> But what about accessing them not from within a cpreg read/write instruction? We will have at least 3
> cases of different indexes ({ns=1, s=2}, {ns=1, s=3}, {ns=0, s=1}). Although by padding the last case
> we could merge it with the first one so we only have 2 ways of accessing a banked register, which was
> also the case in my patches, for which I introduced macros. Any ideas how to simplify that?
>
> Thanks,
> Fabian
Hi
Speculating on some changes to reginfo's fieldoffset, it is worth to
notice that then CPU state save/load could need to be adjusted. Keeping
separate reginfo for each banked register in the hash table would
eliminate any changes to CPU state save/load.
Regards,
Sergey
>>
>>
>>
>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>>> ---
>>> target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
>>> target-arm/helper.c | 64 ++++++++++++++++++++++++--
>>> target-arm/translate.c | 19 +++++---
>>> 3 files changed, 184 insertions(+), 20 deletions(-)
>>>
>>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>>> index a970d55..9e325ac 100644
>>> --- a/target-arm/cpu.h
>>> +++ b/target-arm/cpu.h
>>> @@ -80,6 +80,16 @@
>>> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
>>> #endif
>>>
>>> +/* Define a banked coprocessor register state field. Use %name as the
>>> + * register field name for the secure instance. The non-secure instance
>>> + * has a "_nonsecure" suffix.
>>> + */
>>> +#define A32_BANKED_REG(type, name) \
>>> + union { \
>>> + type name; \
>>> + type name##_banked[2]; \
>>> + }
>>> +
>>> /* Meanings of the ARMCPU object's two inbound GPIO lines */
>>> #define ARM_CPU_IRQ 0
>>> #define ARM_CPU_FIQ 1
>>> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
>>> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
>>> int dstreg, int operand);
>>>
>>> +
>>> struct arm_boot_info;
>>>
>>> #define NB_MMU_MODES 5
>>> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
>>> return arm_feature(env, ARM_FEATURE_AARCH64);
>>> }
>>>
>>> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
>>> + * whether the secure instance of a cp-register should be used. */
>>> +#define USE_SECURE_REG(env) ( \
>>> + arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
>>> + !arm_el_is_aa64(env, 3) && \
>>> + !((env)->cp15.c1_scr & 1/*NS*/))
>>> +
>>> +#define NONSECURE_BANK 0
>>> +#define SECURE_BANK 1
>>> +
>>> +#define A32_BANKED_REG_GET(env, regname) \
>>> + ((USE_SECURE_REG(env)) ? \
>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>>> + (env)->cp15.regname)
>>> +
>>> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>> + (USE_SECURE_REG(env))) ? \
>>> + (env)->cp15.regname##_el3 : \
>>> + (env)->cp15.regname##_el1)
>>> +
>>> +#define A32_BANKED_REG_SET(env, regname, val) \
>>> + do { \
>>> + if (USE_SECURE_REG(env)) { \
>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>>> + } else { \
>>> + (env)->cp15.regname = (val); \
>>> + } \
>>> + } while (0)
>>> +
>>> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
>>> + do { \
>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>> + (USE_SECURE_REG(env))) { \
>>> + (env)->cp15.regname##_el3 = (val); \
>>> + } else { \
>>> + (env)->cp15.regname##_el1 = (val); \
>>> + } \
>>> + } while (0)
>>> +
>>> +
>>> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
>>> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>>> + (env)->cp15.regname)
>>> +
>>> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
>>> + (env)->cp15.regname##_el3 : \
>>> + (env)->cp15.regname##_el1)
>>> +
>>> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
>>> + do { \
>>> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>>> + } else { \
>>> + (env)->cp15.regname = (val); \
>>> + } \
>>> + } while (0)
>>> +
>>> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
>>> + do { \
>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
>>> + (env)->cp15.regname##_el3 = (val); \
>>> + } else { \
>>> + (env)->cp15.regname##_el1 = (val); \
>>> + } \
>>> + } while (0)
>>> +
>>> +
>>> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>>>
>>> /* Interface between CPU and Interrupt controller. */
>>> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>>> * Crn, Crm, opc1, opc2 fields
>>> * 32 or 64 bit register (ie is it accessed via MRC/MCR
>>> * or via MRRC/MCRR?)
>>> + * nonsecure/secure bank (Aarch32 only)
>>> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
>>> * (In this case crn and opc2 should be zero.)
>>> * For AArch64, there is no 32/64 bit size distinction;
>>> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>>> #define CP_REG_AA64_SHIFT 28
>>> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>>>
>>> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
>>> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
>>> - ((crm) << 7) | ((opc1) << 3) | (opc2))
>>> +/* To enable banking of coprocessor registers depending on ns-bit we
>>> + * add a bit to distinguish between secure and non-secure cpregs in the
>>> + * hashtable.
>>> + */
>>> +#define CP_REG_NS_SHIFT 27
>>> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
>>> +
>>> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
>>> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
>>> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>>>
>>> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
>>> (CP_REG_AA64_MASK | \
>>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>> * IO indicates that this register does I/O and therefore its accesses
>>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
>>> * registers which implement clocks or timers require this.
>>> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
>>> + * be banked or common. If a register is common it references the same variable
>>> + * from both worlds (non-secure and secure). For cp regs which neither set
>>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
>>> + * will be inserted twice into the hashtable. If a register has
>>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
>>> + * different offset respectively. This way Aarch32 registers which can be
>>> + * mapped to Aarch64 PL3 registers can be inserted individually.
>>> */
>>> #define ARM_CP_SPECIAL 1
>>> #define ARM_CP_CONST 2
>>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>> #define ARM_CP_OVERRIDE 16
>>> #define ARM_CP_NO_MIGRATE 32
>>> #define ARM_CP_IO 64
>>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
>>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
>>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
>>> +#define ARM_CP_SECURE (1 << 7)
>>> +#define ARM_CP_NONSECURE (1 << 8)
>>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
>>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
>>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
>>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
>>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
>>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
>>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
>>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
>>> /* Used only as a terminator for ARMCPRegInfo lists */
>>> #define ARM_CP_SENTINEL 0xffff
>>> /* Mask of only the flag bits in a type field */
>>> -#define ARM_CP_FLAG_MASK 0x7f
>>> +#define ARM_CP_FLAG_MASK 0x3ff
>>>
>>> /* Valid values for ARMCPRegInfo state field, indicating which of
>>> * the AArch32 and AArch64 execution states this register is visible in.
>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>>> index 9326ef8..98c3dc9 100644
>>> --- a/target-arm/helper.c
>>> +++ b/target-arm/helper.c
>>> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>>>
>>> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>> void *opaque, int state,
>>> - int crm, int opc1, int opc2)
>>> + int crm, int opc1, int opc2, int nsbit)
>>> {
>>> /* Private utility function for define_one_arm_cp_reg_with_opaque():
>>> * add a single reginfo struct to the hash table.
>>> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>> }
>>> #endif
>>> }
>>> +
>>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
>>> + if (r2->fieldoffset) {
>>> + /* We simplify register definitions by providing a type
>>> + * ARM_CP_BANKED, for which the fieldoffset of the secure instance
>>> + * will be increased to point at the second entry of the array.
>>> + *
>>> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
>>> + * wide the banked register is because some registers are 64bit
>>> + * wide but the register is not defined as 64bit because it is
>>> + * mapped to the lower 32 bit.
>>> + * Therefore two separate types for 64bit banked registers and
>>> + * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
>>> + */
>>> + r2->fieldoffset +=
>>> + ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
>>> + sizeof(uint64_t) : sizeof(uint32_t);
>>> + }
>>> + }
>>> + /* For A32 we want to be able to know whether the secure or non-secure
>>> + * instance wants to be accessed. A64 does not know this banking scheme
>>> + * anymore, but it might use the same readfn/writefn as A32 which might
>>> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
>>> + * Reset the type according to ns-bit passed as argument.
>>> + */
>>> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
>>> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
>>> +
>>> if (state == ARM_CP_STATE_AA64) {
>>> /* To allow abbreviation of ARMCPRegInfo
>>> * definitions, we treat cp == 0 as equivalent to
>>> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
>>> r2->opc0, opc1, opc2);
>>> } else {
>>> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
>>> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
>>> }
>>> if (opaque) {
>>> r2->opaque = opaque;
>>> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
>>> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
>>> fprintf(stderr, "Register redefined: cp=%d %d bit "
>>> - "crn=%d crm=%d opc1=%d opc2=%d, "
>>> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
>>> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
>>> r2->crn, r2->crm, r2->opc1, r2->opc2,
>>> + (r2->type & ARM_CP_NONSECURE),
>>> oldreg->name, r2->name);
>>> g_assert_not_reached();
>>> }
>>> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>>> if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
>>> continue;
>>> }
>>> - add_cpreg_to_hashtable(cpu, r, opaque, state,
>>> - crm, opc1, opc2);
>>> +
>>> + if (state == ARM_CP_STATE_AA32) {
>>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
>>> + (r->type & ARM_CP_BANKED) == 0) {
>>> + /* Under Aarch32 CP registers can be common
>>> + * (same for secure and non-secure world) or banked.
>>> + * Register definitions with neither secure nor
>>> + * non-secure type set (common) or with both bits
>>> + * set (banked) will be inserted twice into the
>>> + * hashtable.
>>> + */
>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>> + crm, opc1, opc2, 0);
>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>> + crm, opc1, opc2, 1);
>>> + } else {
>>> + /* Only one of both bank types were specified */
>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>> + crm, opc1, opc2,
>>> + (r->type & ARM_CP_NONSECURE) ? 1 : 0);
>>> + }
>>> + } else {
>>> + /* Aarch64 registers get mapped to non-secure instance
>>> + * of Aarch32 */
>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>> + crm, opc1, opc2, 1);
>>> + }
>>> }
>>> }
>>> }
>>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>>> index bbd4c77..3a429ac 100644
>>> --- a/target-arm/translate.c
>>> +++ b/target-arm/translate.c
>>> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
>>>
>>> static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>> {
>>> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
>>> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
>>> const ARMCPRegInfo *ri;
>>>
>>> cpnum = (insn >> 8) & 0xf;
>>> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>> isread = (insn >> 20) & 1;
>>> rt = (insn >> 12) & 0xf;
>>>
>>> + /* Monitor mode is always treated as secure but cp register reads/writes
>>> + * can access secure and non-secure instances using SCR.NS bit*/
>>> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
>>> ri = get_arm_cp_reginfo(s->cp_regs,
>>> - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
>>> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
>>> if (ri) {
>>> /* Check access permissions */
>>> if (!cp_access_ok(s->current_pl, ri, isread)) {
>>> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>> */
>>> if (is64) {
>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>>> - "64 bit system register cp:%d opc1: %d crm:%d\n",
>>> - isread ? "read" : "write", cpnum, opc1, crm);
>>> + "64 bit system register cp:%d opc1: %d crm:%d "
>>> + "(%s)\n",
>>> + isread ? "read" : "write", cpnum, opc1, crm,
>>> + ns ? "non-secure" : "secure");
>>> } else {
>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>>> - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
>>> - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
>>> + "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
>>> + "(%s)\n",
>>> + isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
>>> + ns ? "non-secure" : "secure");
>>> }
>>>
>>> return 1;
>>> --
>>> 1.8.3.2
>>>
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-22 12:18 ` Sergey Fedorov
@ 2014-05-22 12:50 ` Aggeler Fabian
2014-05-22 22:21 ` Greg Bellows
0 siblings, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-22 12:50 UTC (permalink / raw)
To: Sergey Fedorov
Cc: Edgar E. Iglesias, qemu-devel@nongnu.org,
peter.maydell@linaro.org
On 22 May 2014, at 14:18, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>
> On 22.05.2014 15:49, Aggeler Fabian wrote:
>> On 22 May 2014, at 09:41, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote:
>>
>>> On Tue, May 13, 2014 at 06:15:59PM +0200, Fabian Aggeler wrote:
>>>> Banked CP registers can be defined with a A32_BANKED_REG macro which defines
>>>> a non-secure instance of the register followed by an adjacent secure instance.
>>>> Using a union makes the code backwards-compatible since the non-secure
>>>> instance can normally be accessed by its existing name.
>>>>
>>>> When translating a banked CP register access instruction in monitor mode,
>>>> the SCR.NS bit determines which instance is going to be accessed.
>>>>
>>>> If EL3 is operating in Aarch64 state coprocessor registers are not
>>>> banked anymore but in some cases have its own _EL3 instance.
>>> Hi
>>>
>>> Regarding the sctlr regs and the banking of S/NS regs in general, I
>>> think the general pattern should be to arrayify the regs that need
>>> to be indexed by EL.
>>>
>>> This is an example of a structure (indexed by EL) with the aarch32
>>> struct beeing here to help clarify.
>>> union {
>>> struct {
>>> uint64_t pad;
>>> uint64_t sctlr_ns;
>>> uint64_t hsctlr;
>>> uint64_t sctlr_s;
>>> } aarch32;
>>> uint64_t sctlr_el[4];
>>> }
>>>
>>> I think we would naturally want to register this for AArch32 as banked
>>> with NS=sctlr_el[1] and S=sctlr_el[3].
>>>
>>> Another register example is FAR. For FAR, things look like this
>>> (when EL2 is available and ignoring DFAR for clarity):
>>> union {
>>> struct {
>>> uint64_t pad;
>>> uint64_t ifar_ns;
>>> uint64_t ifar_s;
>>> } aarch32;
>>> uint64_t far_el[4];
>>> }
>>>
>>> Preferably we need something that can handle both cases.
>>> An option could be to arrayify the .fieldoffset in reginfos?
>>> If we don't want hardcoded TZ knowledge in the generic cpreg accessors,
>>> maybe there could be a generic function that returns the .fieldoffset
>>> index based on CPUState (e.g NS=0, S=1 etc). Or maybe specialized
>>> read/write fns would be enough.
>>>
>>> Just an idea to get the discussion going.
>>>
>>> struct ARMCPRegInfo {
>>> ....
>>> union {
>>> ptrdiff_t fieldoffset;
>>> ptrdiff_t fieldoffsets[2];
>>> };
>>> };
>>>
>>> unsigned int arm_cpreg_tzbank_idx(CPUARMState *env)
>>> {
>>> return is_a64(env) ? 0 : arm_is_secure(env);
>>> }
>>>
>>> Example:
>>> { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
>>> .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
>>> .access = PL1_RW,
>>> .fieldindex_fn = arm_cpreg_tzbank_idx,
>>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.far_el[1]),
>>> offsetof(CPUARMState, cp15.far_el[2])},
>>> .resetvalue = 0, },
>>>
>>> ARMCPRegInfo sctlr = {
>>> .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
>>> .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
>>> .access = PL1_RW,
>>> .fieldindex_fn = arm_cpreg_tzbank_idx,
>>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.sctlr_el[1]),
>>> offsetof(CPUARMState, cp15.sctlr_el[3]),
>>> },
>>> /* Assuming raw_write and raw_read respect the indexing. */
>>> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
>>> .raw_writefn = raw_write,
>>> };
>>>
>>> Best regards,
>>> Edgar
>>>
>> Hi Edgar
>>
>> Thanks for joining the discussion. I like the idea of arrayifying the cp regs, also for banking.
>> Since your patches are doing this anyways for EL registers I wanted to change the registers
>> which do not have EL3/EL2 equivalents (DACR, PAR,…) to use the same mechanism. These
>> registers are the third case which you haven’t mentioned in your examples above, where we only
>> have one reg in Aarch64 but two (s/ns) in Aarch32. So I in my eyes it didn’t make sense to make
>> the array bigger than needed, that’s why I went for 2 entries only. But if it allows us map it easier
>> or in a more consistent way I don’t see why we cannot do it.
>>
>> union {
>> struct {
>> uint64_t par_ns;
>> uint64_t par_s;
>> } aarch32;
>> uint64_t par_el[2];
>> }
>>
>> We should probably also get rid of the macros I used to define the banked registers, to make the code
>> look more uniform. Using your idea of arrayifying fieldset too, we could get rid of the additional cpreg
>> definitions. Do we need to specify a .fieldindex_fn for every cpreg in this case?
>> Isn’t it the same for all the cpregs which are banked (two fieldoffsets, the first one for non-secure and
>> the second entry for secure)? But then we still need to know whether this register is banked or common.
>>
>> But what about accessing them not from within a cpreg read/write instruction? We will have at least 3
>> cases of different indexes ({ns=1, s=2}, {ns=1, s=3}, {ns=0, s=1}). Although by padding the last case
>> we could merge it with the first one so we only have 2 ways of accessing a banked register, which was
>> also the case in my patches, for which I introduced macros. Any ideas how to simplify that?
>>
>> Thanks,
>> Fabian
>
> Hi
>
> Speculating on some changes to reginfo's fieldoffset, it is worth to
> notice that then CPU state save/load could need to be adjusted. Keeping
> separate reginfo for each banked register in the hash table would
> eliminate any changes to CPU state save/load.
>
> Regards,
> Sergey
Hi Sergey
We could still insert it twice into the hashtable (keep this approach) but make the cpreg definition
more compact and avoid the implicit adjusting of the offset for banked registers shortly before adding
them to the hashtable (where I had to distinguish between 32/64bit fields). By having a ns-bit in the type
(as it is now) or directly as a field in the ARMCPRegInfo struct as you suggested, we could still get the
correct offset when accessing the field (either in raw_read/raw_write or in the readfn/writefns) and therefore
we don’t need to change the CPU state save/load.
Best,
Fabian
>
>>>
>>>
>>>
>>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
>>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>>>> ---
>>>> target-arm/cpu.h | 121 +++++++++++++++++++++++++++++++++++++++++++++----
>>>> target-arm/helper.c | 64 ++++++++++++++++++++++++--
>>>> target-arm/translate.c | 19 +++++---
>>>> 3 files changed, 184 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>>>> index a970d55..9e325ac 100644
>>>> --- a/target-arm/cpu.h
>>>> +++ b/target-arm/cpu.h
>>>> @@ -80,6 +80,16 @@
>>>> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
>>>> #endif
>>>>
>>>> +/* Define a banked coprocessor register state field. Use %name as the
>>>> + * register field name for the secure instance. The non-secure instance
>>>> + * has a "_nonsecure" suffix.
>>>> + */
>>>> +#define A32_BANKED_REG(type, name) \
>>>> + union { \
>>>> + type name; \
>>>> + type name##_banked[2]; \
>>>> + }
>>>> +
>>>> /* Meanings of the ARMCPU object's two inbound GPIO lines */
>>>> #define ARM_CPU_IRQ 0
>>>> #define ARM_CPU_FIQ 1
>>>> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
>>>> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
>>>> int dstreg, int operand);
>>>>
>>>> +
>>>> struct arm_boot_info;
>>>>
>>>> #define NB_MMU_MODES 5
>>>> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
>>>> return arm_feature(env, ARM_FEATURE_AARCH64);
>>>> }
>>>>
>>>> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
>>>> + * whether the secure instance of a cp-register should be used. */
>>>> +#define USE_SECURE_REG(env) ( \
>>>> + arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) && \
>>>> + !arm_el_is_aa64(env, 3) && \
>>>> + !((env)->cp15.c1_scr & 1/*NS*/))
>>>> +
>>>> +#define NONSECURE_BANK 0
>>>> +#define SECURE_BANK 1
>>>> +
>>>> +#define A32_BANKED_REG_GET(env, regname) \
>>>> + ((USE_SECURE_REG(env)) ? \
>>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>>>> + (env)->cp15.regname)
>>>> +
>>>> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
>>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>>> + (USE_SECURE_REG(env))) ? \
>>>> + (env)->cp15.regname##_el3 : \
>>>> + (env)->cp15.regname##_el1)
>>>> +
>>>> +#define A32_BANKED_REG_SET(env, regname, val) \
>>>> + do { \
>>>> + if (USE_SECURE_REG(env)) { \
>>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>>>> + } else { \
>>>> + (env)->cp15.regname = (val); \
>>>> + } \
>>>> + } while (0)
>>>> +
>>>> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
>>>> + do { \
>>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>>> + (USE_SECURE_REG(env))) { \
>>>> + (env)->cp15.regname##_el3 = (val); \
>>>> + } else { \
>>>> + (env)->cp15.regname##_el1 = (val); \
>>>> + } \
>>>> + } while (0)
>>>> +
>>>> +
>>>> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
>>>> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
>>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
>>>> + (env)->cp15.regname)
>>>> +
>>>> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
>>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
>>>> + (env)->cp15.regname##_el3 : \
>>>> + (env)->cp15.regname##_el1)
>>>> +
>>>> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
>>>> + do { \
>>>> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
>>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
>>>> + } else { \
>>>> + (env)->cp15.regname = (val); \
>>>> + } \
>>>> + } while (0)
>>>> +
>>>> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
>>>> + do { \
>>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
>>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) { \
>>>> + (env)->cp15.regname##_el3 = (val); \
>>>> + } else { \
>>>> + (env)->cp15.regname##_el1 = (val); \
>>>> + } \
>>>> + } while (0)
>>>> +
>>>> +
>>>> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>>>>
>>>> /* Interface between CPU and Interrupt controller. */
>>>> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>>>> * Crn, Crm, opc1, opc2 fields
>>>> * 32 or 64 bit register (ie is it accessed via MRC/MCR
>>>> * or via MRRC/MCRR?)
>>>> + * nonsecure/secure bank (Aarch32 only)
>>>> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
>>>> * (In this case crn and opc2 should be zero.)
>>>> * For AArch64, there is no 32/64 bit size distinction;
>>>> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>>>> #define CP_REG_AA64_SHIFT 28
>>>> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
>>>>
>>>> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
>>>> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
>>>> - ((crm) << 7) | ((opc1) << 3) | (opc2))
>>>> +/* To enable banking of coprocessor registers depending on ns-bit we
>>>> + * add a bit to distinguish between secure and non-secure cpregs in the
>>>> + * hashtable.
>>>> + */
>>>> +#define CP_REG_NS_SHIFT 27
>>>> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
>>>> +
>>>> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
>>>> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
>>>> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>>>>
>>>> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
>>>> (CP_REG_AA64_MASK | \
>>>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>>> * IO indicates that this register does I/O and therefore its accesses
>>>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
>>>> * registers which implement clocks or timers require this.
>>>> + * In an implementation with Security Extensions supporting Aarch32 cp regs can
>>>> + * be banked or common. If a register is common it references the same variable
>>>> + * from both worlds (non-secure and secure). For cp regs which neither set
>>>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's common and it
>>>> + * will be inserted twice into the hashtable. If a register has
>>>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice but with
>>>> + * different offset respectively. This way Aarch32 registers which can be
>>>> + * mapped to Aarch64 PL3 registers can be inserted individually.
>>>> */
>>>> #define ARM_CP_SPECIAL 1
>>>> #define ARM_CP_CONST 2
>>>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>>>> #define ARM_CP_OVERRIDE 16
>>>> #define ARM_CP_NO_MIGRATE 32
>>>> #define ARM_CP_IO 64
>>>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>>>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
>>>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
>>>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
>>>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
>>>> +#define ARM_CP_SECURE (1 << 7)
>>>> +#define ARM_CP_NONSECURE (1 << 8)
>>>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
>>>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
>>>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
>>>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
>>>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
>>>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
>>>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
>>>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
>>>> /* Used only as a terminator for ARMCPRegInfo lists */
>>>> #define ARM_CP_SENTINEL 0xffff
>>>> /* Mask of only the flag bits in a type field */
>>>> -#define ARM_CP_FLAG_MASK 0x7f
>>>> +#define ARM_CP_FLAG_MASK 0x3ff
>>>>
>>>> /* Valid values for ARMCPRegInfo state field, indicating which of
>>>> * the AArch32 and AArch64 execution states this register is visible in.
>>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>>>> index 9326ef8..98c3dc9 100644
>>>> --- a/target-arm/helper.c
>>>> +++ b/target-arm/helper.c
>>>> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>>>>
>>>> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>>> void *opaque, int state,
>>>> - int crm, int opc1, int opc2)
>>>> + int crm, int opc1, int opc2, int nsbit)
>>>> {
>>>> /* Private utility function for define_one_arm_cp_reg_with_opaque():
>>>> * add a single reginfo struct to the hash table.
>>>> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>>> }
>>>> #endif
>>>> }
>>>> +
>>>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
>>>> + if (r2->fieldoffset) {
>>>> + /* We simplify register definitions by providing a type
>>>> + * ARM_CP_BANKED, for which the fieldoffset of the secure instance
>>>> + * will be increased to point at the second entry of the array.
>>>> + *
>>>> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to know how
>>>> + * wide the banked register is because some registers are 64bit
>>>> + * wide but the register is not defined as 64bit because it is
>>>> + * mapped to the lower 32 bit.
>>>> + * Therefore two separate types for 64bit banked registers and
>>>> + * 32bit registers are used (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
>>>> + */
>>>> + r2->fieldoffset +=
>>>> + ((r->type & ARM_CP_BANKED_64BIT) == ARM_CP_BANKED_64BIT) ?
>>>> + sizeof(uint64_t) : sizeof(uint32_t);
>>>> + }
>>>> + }
>>>> + /* For A32 we want to be able to know whether the secure or non-secure
>>>> + * instance wants to be accessed. A64 does not know this banking scheme
>>>> + * anymore, but it might use the same readfn/writefn as A32 which might
>>>> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
>>>> + * Reset the type according to ns-bit passed as argument.
>>>> + */
>>>> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
>>>> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
>>>> +
>>>> if (state == ARM_CP_STATE_AA64) {
>>>> /* To allow abbreviation of ARMCPRegInfo
>>>> * definitions, we treat cp == 0 as equivalent to
>>>> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>>> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
>>>> r2->opc0, opc1, opc2);
>>>> } else {
>>>> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
>>>> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2, nsbit);
>>>> }
>>>> if (opaque) {
>>>> r2->opaque = opaque;
>>>> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>>> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
>>>> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
>>>> fprintf(stderr, "Register redefined: cp=%d %d bit "
>>>> - "crn=%d crm=%d opc1=%d opc2=%d, "
>>>> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
>>>> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
>>>> r2->crn, r2->crm, r2->opc1, r2->opc2,
>>>> + (r2->type & ARM_CP_NONSECURE),
>>>> oldreg->name, r2->name);
>>>> g_assert_not_reached();
>>>> }
>>>> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>>>> if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
>>>> continue;
>>>> }
>>>> - add_cpreg_to_hashtable(cpu, r, opaque, state,
>>>> - crm, opc1, opc2);
>>>> +
>>>> + if (state == ARM_CP_STATE_AA32) {
>>>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED ||
>>>> + (r->type & ARM_CP_BANKED) == 0) {
>>>> + /* Under Aarch32 CP registers can be common
>>>> + * (same for secure and non-secure world) or banked.
>>>> + * Register definitions with neither secure nor
>>>> + * non-secure type set (common) or with both bits
>>>> + * set (banked) will be inserted twice into the
>>>> + * hashtable.
>>>> + */
>>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>>> + crm, opc1, opc2, 0);
>>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>>> + crm, opc1, opc2, 1);
>>>> + } else {
>>>> + /* Only one of both bank types were specified */
>>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>>> + crm, opc1, opc2,
>>>> + (r->type & ARM_CP_NONSECURE) ? 1 : 0);
>>>> + }
>>>> + } else {
>>>> + /* Aarch64 registers get mapped to non-secure instance
>>>> + * of Aarch32 */
>>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
>>>> + crm, opc1, opc2, 1);
>>>> + }
>>>> }
>>>> }
>>>> }
>>>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>>>> index bbd4c77..3a429ac 100644
>>>> --- a/target-arm/translate.c
>>>> +++ b/target-arm/translate.c
>>>> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
>>>>
>>>> static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>>> {
>>>> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
>>>> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
>>>> const ARMCPRegInfo *ri;
>>>>
>>>> cpnum = (insn >> 8) & 0xf;
>>>> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>>> isread = (insn >> 20) & 1;
>>>> rt = (insn >> 12) & 0xf;
>>>>
>>>> + /* Monitor mode is always treated as secure but cp register reads/writes
>>>> + * can access secure and non-secure instances using SCR.NS bit*/
>>>> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
>>>> ri = get_arm_cp_reginfo(s->cp_regs,
>>>> - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
>>>> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
>>>> if (ri) {
>>>> /* Check access permissions */
>>>> if (!cp_access_ok(s->current_pl, ri, isread)) {
>>>> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>>>> */
>>>> if (is64) {
>>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>>>> - "64 bit system register cp:%d opc1: %d crm:%d\n",
>>>> - isread ? "read" : "write", cpnum, opc1, crm);
>>>> + "64 bit system register cp:%d opc1: %d crm:%d "
>>>> + "(%s)\n",
>>>> + isread ? "read" : "write", cpnum, opc1, crm,
>>>> + ns ? "non-secure" : "secure");
>>>> } else {
>>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
>>>> - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
>>>> - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
>>>> + "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
>>>> + "(%s)\n",
>>>> + isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
>>>> + ns ? "non-secure" : "secure");
>>>> }
>>>>
>>>> return 1;
>>>> --
>>>> 1.8.3.2
>>>>
>>
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR
2014-05-22 7:33 ` Edgar E. Iglesias
@ 2014-05-22 14:56 ` Aggeler Fabian
2014-05-22 21:24 ` Edgar E. Iglesias
0 siblings, 1 reply; 75+ messages in thread
From: Aggeler Fabian @ 2014-05-22 14:56 UTC (permalink / raw)
To: Edgar E. Iglesias; +Cc: peter.maydell@linaro.org, qemu-devel@nongnu.org
On 22 May 2014, at 09:33, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote:
> On Tue, May 13, 2014 at 06:16:01PM +0200, Fabian Aggeler wrote:
>> Add SCTLR_EL3 and introduce new function to access correct
>> instance of SCTLR in different modes/worlds.
>
> Hi,
>
> AArch64 has a couple of insn/regs that do address translation
> as seen by other ELs. E.g, from EL3 you can perform address
> translation as seen by EL0. See for example ATS12E0R.
Good point, didn’t know about them.
> AArch32 has similar features, it can also lower S to NS when in S mode.
You mean other features than AT* operations? Or do you mean the possibility
to access both secure and non-secure instances from monitor mode by setting the
SCR.NS bit? This is currently handled by using the A32_MAPPED_EL3_REG_GET
which only gets the secure instance when the SCR.NS bit is clear.
>
> With regards to arm_current_sctlr() and the use in get_phys_addr, I
> don't think it is enough here.
>
> I was planning to post was patches that add new args to get_phys_addr()
> with the translation-EL and flags to control if stage-2 translation
> should be done or not. That way ats_write() can keep reusing
> get_phys_addr(). We would need to pass the security state as an argument
> aswell to handle AArch32. Does that make sense?
>From my view that makes sense.
I went through my changes again and in most of the locations where I changed
SCTLR access to use arm_current_sctlr() we should actually just access
SCTLR_EL1 (aa64_*_access() or ctr_el0_access()).
And otherwise:
- arm_cpu_do_interrupt() we still need to get distinguish between EL3 using
- Aarch32 (get secure/non-secure instance depending on arm_is_secure) or
- Aarch64 (get SCTLR_EL1).
- check_ap() is only used by get_phys_addr_v5/v6() so just return
secure / non-secure instance.
- arm_cpu_reset() in cpu.c we only need to check the SCTLR.V bit [13] for CPUs
without Aarch64, but need to use secure or non-secure instance depending on
the which world we are booting in.
If I didn’t miss or misinterpret something in this list I guess this does not really need
its own function then as we don’t have much duplication.
Best,
Fabian
>
> Cheers,
> Edgar
>
>>
>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
>> ---
>> hw/arm/pxa2xx.c | 2 +-
>> target-arm/cpu-qom.h | 1 +
>> target-arm/cpu.c | 4 +--
>> target-arm/cpu.h | 14 ++++++++++-
>> target-arm/helper.c | 67 ++++++++++++++++++++++++++++++++++++++------------
>> target-arm/op_helper.c | 2 +-
>> 6 files changed, 69 insertions(+), 21 deletions(-)
>>
>> diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
>> index e0cd847..8b69e72 100644
>> --- a/hw/arm/pxa2xx.c
>> +++ b/hw/arm/pxa2xx.c
>> @@ -274,7 +274,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
>> case 3:
>> s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
>> s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
>> - s->cpu->env.cp15.c1_sys = 0;
>> + s->cpu->env.cp15.c1_sys_el1 = 0;
>> s->cpu->env.cp15.c1_coproc = 0;
>> s->cpu->env.cp15.ttbr0_el1 = 0;
>> s->cpu->env.cp15.c3 = 0;
>> diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
>> index edc7f26..38cbd43 100644
>> --- a/target-arm/cpu-qom.h
>> +++ b/target-arm/cpu-qom.h
>> @@ -119,6 +119,7 @@ typedef struct ARMCPU {
>> uint32_t mvfr2;
>> uint32_t ctr;
>> uint32_t reset_sctlr;
>> + uint32_t reset_sctlr_el3;
>> uint32_t id_pfr0;
>> uint32_t id_pfr1;
>> uint32_t id_dfr0;
>> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
>> index b0d4a9b..bdbdbb1 100644
>> --- a/target-arm/cpu.c
>> +++ b/target-arm/cpu.c
>> @@ -100,7 +100,7 @@ static void arm_cpu_reset(CPUState *s)
>> #if defined(CONFIG_USER_ONLY)
>> env->pstate = PSTATE_MODE_EL0t;
>> /* Userspace expects access to CTL_EL0 and the cache ops */
>> - env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
>> + env->cp15.c1_sys_el1 |= SCTLR_UCT | SCTLR_UCI;
>> /* and to the FP/Neon instructions */
>> env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
>> #else
>> @@ -146,7 +146,7 @@ static void arm_cpu_reset(CPUState *s)
>> }
>> }
>>
>> - if (env->cp15.c1_sys & SCTLR_V) {
>> + if (arm_current_sctlr(env) & SCTLR_V) {
>> env->regs[15] = 0xFFFF0000;
>> }
>>
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index a4bb6bd..780c1f5 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -180,7 +180,8 @@ typedef struct CPUARMState {
>> struct {
>> uint32_t c0_cpuid;
>> uint64_t c0_cssel; /* Cache size selection. */
>> - uint64_t c1_sys; /* System control register. */
>> + uint64_t c1_sys_el1; /* System control register (EL1). */
>> + uint64_t c1_sys_el3; /* System control register (EL3). */
>> uint64_t c1_coproc; /* Coprocessor access register. */
>> uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
>> uint32_t c1_scr; /* secure config register. */
>> @@ -971,6 +972,17 @@ static inline int arm_current_pl(CPUARMState *env)
>> return 1;
>> }
>>
>> +static inline uint64_t arm_current_sctlr(CPUARMState *env)
>> +{
>> + if (is_a64(env) && arm_current_pl(env) == 3) {
>> + /* EL3 has its own SCTLR */
>> + return env->cp15.c1_sys_el3;
>> + } else {
>> + /* Only A32 with NS-bit clear accesses secure instance of SCTLR */
>> + return A32_MAPPED_EL3_REG_GET(env, c1_sys);
>> + }
>> +}
>> +
>> typedef struct ARMCPRegInfo ARMCPRegInfo;
>>
>> typedef enum CPAccessResult {
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index 98c3dc9..ac8b15a 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -1767,7 +1767,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>>
>> static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
>> {
>> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
>> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
>> return CP_ACCESS_TRAP;
>> }
>> return CP_ACCESS_OK;
>> @@ -1785,7 +1785,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
>> /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
>> * SCTLR_EL1.UCI is set.
>> */
>> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
>> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCI)) {
>> return CP_ACCESS_TRAP;
>> }
>> return CP_ACCESS_OK;
>> @@ -1823,7 +1823,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
>> /* We don't implement EL2, so the only control on DC ZVA is the
>> * bit in the SCTLR which can prohibit access for EL0.
>> */
>> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
>> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_DZE)) {
>> return CP_ACCESS_TRAP;
>> }
>> return CP_ACCESS_OK;
>> @@ -2146,7 +2146,7 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
>> /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
>> * but the AArch32 CTR has its own reginfo struct)
>> */
>> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
>> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCT)) {
>> return CP_ACCESS_TRAP;
>> }
>> return CP_ACCESS_OK;
>> @@ -2573,10 +2573,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>>
>> /* Generic registers whose values depend on the implementation */
>> {
>> - ARMCPRegInfo sctlr = {
>> - .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
>> - .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
>> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys),
>> + ARMCPRegInfo sctlr_el1 = {
>> + .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
>> + .type = ARM_CP_NONSECURE, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0,
>> + .opc2 = 0, .access = PL1_RW,
>> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el1),
>> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
>> .raw_writefn = raw_write,
>> };
>> @@ -2585,9 +2586,43 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>> * arch/arm/mach-pxa/sleep.S expects two instructions following
>> * an MMU enable to execute from cache. Imitate this behaviour.
>> */
>> - sctlr.type |= ARM_CP_SUPPRESS_TB_END;
>> + sctlr_el1.type |= ARM_CP_SUPPRESS_TB_END;
>> }
>> - define_one_arm_cp_reg(cpu, &sctlr);
>> + define_one_arm_cp_reg(cpu, &sctlr_el1);
>> +
>> + ARMCPRegInfo sctlr_el1_s = {
>> + .name = "SCTLR_EL1(S)", .type = ARM_CP_SECURE,
>> + .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
>> + .access = PL3_RW,
>> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
>> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
>> + .raw_writefn = raw_write,
>> + };
>> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
>> + /* Normally we would always end the TB on an SCTLR write, but Linux
>> + * arch/arm/mach-pxa/sleep.S expects two instructions following
>> + * an MMU enable to execute from cache. Imitate this behaviour.
>> + */
>> + sctlr_el1_s.type |= ARM_CP_SUPPRESS_TB_END;
>> + }
>> + define_one_arm_cp_reg(cpu, &sctlr_el1_s);
>> +
>> + ARMCPRegInfo sctlr_el3 = {
>> + .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
>> + .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
>> + .access = PL3_RW, .type = ARM_CP_SECURE,
>> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
>> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr_el3,
>> + .raw_writefn = raw_write,
>> + };
>> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
>> + /* Normally we would always end the TB on an SCTLR write, but Linux
>> + * arch/arm/mach-pxa/sleep.S expects two instructions following
>> + * an MMU enable to execute from cache. Imitate this behaviour.
>> + */
>> + sctlr_el3.type |= ARM_CP_SUPPRESS_TB_END;
>> + }
>> + define_one_arm_cp_reg(cpu, &sctlr_el3);
>> }
>> }
>>
>> @@ -3475,7 +3510,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
>> return; /* Never happens. Keep compiler happy. */
>> }
>> /* High vectors. */
>> - if (env->cp15.c1_sys & SCTLR_V) {
>> + if (arm_current_sctlr(env) & SCTLR_V) {
>> /* when enabled, base address cannot be remapped. */
>> addr += 0xffff0000;
>> } else {
>> @@ -3498,7 +3533,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
>> /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
>> * and we should just guard the thumb mode on V4 */
>> if (arm_feature(env, ARM_FEATURE_V4T)) {
>> - env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0;
>> + env->thumb = (arm_current_sctlr(env) & SCTLR_TE) != 0;
>> }
>> env->regs[14] = env->regs[15] + offset;
>> env->regs[15] = addr;
>> @@ -3529,7 +3564,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
>> }
>> if (access_type == 1)
>> return 0;
>> - switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) {
>> + switch (arm_current_sctlr(env) & (SCTLR_S | SCTLR_R)) {
>> case SCTLR_S:
>> return is_user ? 0 : PAGE_READ;
>> case SCTLR_R:
>> @@ -3763,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
>> goto do_fault;
>>
>> /* The simplified model uses AP[0] as an access control bit. */
>> - if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) {
>> + if ((arm_current_sctlr(env) & SCTLR_AFE) && (ap & 1) == 0) {
>> /* Access flag fault. */
>> code = (code == 15) ? 6 : 3;
>> goto do_fault;
>> @@ -4099,7 +4134,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
>> if (address < 0x02000000)
>> address += env->cp15.c13_fcse;
>>
>> - if ((env->cp15.c1_sys & SCTLR_M) == 0) {
>> + if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
>> /* MMU/MPU disabled. */
>> *phys_ptr = address;
>> *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
>> @@ -4112,7 +4147,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
>> } else if (extended_addresses_enabled(env)) {
>> return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
>> prot, page_size);
>> - } else if (env->cp15.c1_sys & SCTLR_XP) {
>> + } else if (arm_current_sctlr(env) & SCTLR_XP) {
>> return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
>> prot, page_size);
>> } else {
>> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
>> index fb90676..3eacea8 100644
>> --- a/target-arm/op_helper.c
>> +++ b/target-arm/op_helper.c
>> @@ -365,7 +365,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
>> * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
>> * to catch that case at translate time.
>> */
>> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
>> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
>> raise_exception(env, EXCP_UDEF);
>> }
>>
>> --
>> 1.8.3.2
>>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR
2014-05-22 14:56 ` Aggeler Fabian
@ 2014-05-22 21:24 ` Edgar E. Iglesias
0 siblings, 0 replies; 75+ messages in thread
From: Edgar E. Iglesias @ 2014-05-22 21:24 UTC (permalink / raw)
To: Aggeler Fabian; +Cc: peter.maydell@linaro.org, qemu-devel@nongnu.org
On Thu, May 22, 2014 at 02:56:22PM +0000, Aggeler Fabian wrote:
>
> On 22 May 2014, at 09:33, Edgar E. Iglesias <edgar.iglesias@gmail.com> wrote:
>
> > On Tue, May 13, 2014 at 06:16:01PM +0200, Fabian Aggeler wrote:
> >> Add SCTLR_EL3 and introduce new function to access correct
> >> instance of SCTLR in different modes/worlds.
> >
> > Hi,
> >
> > AArch64 has a couple of insn/regs that do address translation
> > as seen by other ELs. E.g, from EL3 you can perform address
> > translation as seen by EL0. See for example ATS12E0R.
>
> Good point, didn’t know about them.
>
> > AArch32 has similar features, it can also lower S to NS when in S mode.
>
> You mean other features than AT* operations?
Sorry, as in a similar set of AT* operations. If AArch32 is in S mode, it can
for example do address translation as seen by NS mode.
> Or do you mean the possibility
> to access both secure and non-secure instances from monitor mode by setting the
> SCR.NS bit? This is currently handled by using the A32_MAPPED_EL3_REG_GET
> which only gets the secure instance when the SCR.NS bit is clear.
Right, this should work.
Cheers,
Edgar
>
> >
> > With regards to arm_current_sctlr() and the use in get_phys_addr, I
> > don't think it is enough here.
> >
> > I was planning to post was patches that add new args to get_phys_addr()
> > with the translation-EL and flags to control if stage-2 translation
> > should be done or not. That way ats_write() can keep reusing
> > get_phys_addr(). We would need to pass the security state as an argument
> > aswell to handle AArch32. Does that make sense?
>
> From my view that makes sense.
>
> I went through my changes again and in most of the locations where I changed
> SCTLR access to use arm_current_sctlr() we should actually just access
> SCTLR_EL1 (aa64_*_access() or ctr_el0_access()).
>
> And otherwise:
>
> - arm_cpu_do_interrupt() we still need to get distinguish between EL3 using
> - Aarch32 (get secure/non-secure instance depending on arm_is_secure) or
> - Aarch64 (get SCTLR_EL1).
>
> - check_ap() is only used by get_phys_addr_v5/v6() so just return
> secure / non-secure instance.
>
> - arm_cpu_reset() in cpu.c we only need to check the SCTLR.V bit [13] for CPUs
> without Aarch64, but need to use secure or non-secure instance depending on
> the which world we are booting in.
>
> If I didn’t miss or misinterpret something in this list I guess this does not really need
> its own function then as we don’t have much duplication.
>
> Best,
> Fabian
>
>
> >
> > Cheers,
> > Edgar
> >
> >>
> >> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> >> ---
> >> hw/arm/pxa2xx.c | 2 +-
> >> target-arm/cpu-qom.h | 1 +
> >> target-arm/cpu.c | 4 +--
> >> target-arm/cpu.h | 14 ++++++++++-
> >> target-arm/helper.c | 67 ++++++++++++++++++++++++++++++++++++++------------
> >> target-arm/op_helper.c | 2 +-
> >> 6 files changed, 69 insertions(+), 21 deletions(-)
> >>
> >> diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
> >> index e0cd847..8b69e72 100644
> >> --- a/hw/arm/pxa2xx.c
> >> +++ b/hw/arm/pxa2xx.c
> >> @@ -274,7 +274,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
> >> case 3:
> >> s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
> >> s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
> >> - s->cpu->env.cp15.c1_sys = 0;
> >> + s->cpu->env.cp15.c1_sys_el1 = 0;
> >> s->cpu->env.cp15.c1_coproc = 0;
> >> s->cpu->env.cp15.ttbr0_el1 = 0;
> >> s->cpu->env.cp15.c3 = 0;
> >> diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
> >> index edc7f26..38cbd43 100644
> >> --- a/target-arm/cpu-qom.h
> >> +++ b/target-arm/cpu-qom.h
> >> @@ -119,6 +119,7 @@ typedef struct ARMCPU {
> >> uint32_t mvfr2;
> >> uint32_t ctr;
> >> uint32_t reset_sctlr;
> >> + uint32_t reset_sctlr_el3;
> >> uint32_t id_pfr0;
> >> uint32_t id_pfr1;
> >> uint32_t id_dfr0;
> >> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> >> index b0d4a9b..bdbdbb1 100644
> >> --- a/target-arm/cpu.c
> >> +++ b/target-arm/cpu.c
> >> @@ -100,7 +100,7 @@ static void arm_cpu_reset(CPUState *s)
> >> #if defined(CONFIG_USER_ONLY)
> >> env->pstate = PSTATE_MODE_EL0t;
> >> /* Userspace expects access to CTL_EL0 and the cache ops */
> >> - env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
> >> + env->cp15.c1_sys_el1 |= SCTLR_UCT | SCTLR_UCI;
> >> /* and to the FP/Neon instructions */
> >> env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
> >> #else
> >> @@ -146,7 +146,7 @@ static void arm_cpu_reset(CPUState *s)
> >> }
> >> }
> >>
> >> - if (env->cp15.c1_sys & SCTLR_V) {
> >> + if (arm_current_sctlr(env) & SCTLR_V) {
> >> env->regs[15] = 0xFFFF0000;
> >> }
> >>
> >> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> >> index a4bb6bd..780c1f5 100644
> >> --- a/target-arm/cpu.h
> >> +++ b/target-arm/cpu.h
> >> @@ -180,7 +180,8 @@ typedef struct CPUARMState {
> >> struct {
> >> uint32_t c0_cpuid;
> >> uint64_t c0_cssel; /* Cache size selection. */
> >> - uint64_t c1_sys; /* System control register. */
> >> + uint64_t c1_sys_el1; /* System control register (EL1). */
> >> + uint64_t c1_sys_el3; /* System control register (EL3). */
> >> uint64_t c1_coproc; /* Coprocessor access register. */
> >> uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
> >> uint32_t c1_scr; /* secure config register. */
> >> @@ -971,6 +972,17 @@ static inline int arm_current_pl(CPUARMState *env)
> >> return 1;
> >> }
> >>
> >> +static inline uint64_t arm_current_sctlr(CPUARMState *env)
> >> +{
> >> + if (is_a64(env) && arm_current_pl(env) == 3) {
> >> + /* EL3 has its own SCTLR */
> >> + return env->cp15.c1_sys_el3;
> >> + } else {
> >> + /* Only A32 with NS-bit clear accesses secure instance of SCTLR */
> >> + return A32_MAPPED_EL3_REG_GET(env, c1_sys);
> >> + }
> >> +}
> >> +
> >> typedef struct ARMCPRegInfo ARMCPRegInfo;
> >>
> >> typedef enum CPAccessResult {
> >> diff --git a/target-arm/helper.c b/target-arm/helper.c
> >> index 98c3dc9..ac8b15a 100644
> >> --- a/target-arm/helper.c
> >> +++ b/target-arm/helper.c
> >> @@ -1767,7 +1767,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> >>
> >> static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
> >> {
> >> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
> >> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
> >> return CP_ACCESS_TRAP;
> >> }
> >> return CP_ACCESS_OK;
> >> @@ -1785,7 +1785,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
> >> /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
> >> * SCTLR_EL1.UCI is set.
> >> */
> >> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
> >> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCI)) {
> >> return CP_ACCESS_TRAP;
> >> }
> >> return CP_ACCESS_OK;
> >> @@ -1823,7 +1823,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
> >> /* We don't implement EL2, so the only control on DC ZVA is the
> >> * bit in the SCTLR which can prohibit access for EL0.
> >> */
> >> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
> >> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_DZE)) {
> >> return CP_ACCESS_TRAP;
> >> }
> >> return CP_ACCESS_OK;
> >> @@ -2146,7 +2146,7 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
> >> /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
> >> * but the AArch32 CTR has its own reginfo struct)
> >> */
> >> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
> >> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UCT)) {
> >> return CP_ACCESS_TRAP;
> >> }
> >> return CP_ACCESS_OK;
> >> @@ -2573,10 +2573,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> >>
> >> /* Generic registers whose values depend on the implementation */
> >> {
> >> - ARMCPRegInfo sctlr = {
> >> - .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
> >> - .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> >> - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys),
> >> + ARMCPRegInfo sctlr_el1 = {
> >> + .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
> >> + .type = ARM_CP_NONSECURE, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0,
> >> + .opc2 = 0, .access = PL1_RW,
> >> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el1),
> >> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> >> .raw_writefn = raw_write,
> >> };
> >> @@ -2585,9 +2586,43 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> >> * arch/arm/mach-pxa/sleep.S expects two instructions following
> >> * an MMU enable to execute from cache. Imitate this behaviour.
> >> */
> >> - sctlr.type |= ARM_CP_SUPPRESS_TB_END;
> >> + sctlr_el1.type |= ARM_CP_SUPPRESS_TB_END;
> >> }
> >> - define_one_arm_cp_reg(cpu, &sctlr);
> >> + define_one_arm_cp_reg(cpu, &sctlr_el1);
> >> +
> >> + ARMCPRegInfo sctlr_el1_s = {
> >> + .name = "SCTLR_EL1(S)", .type = ARM_CP_SECURE,
> >> + .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> >> + .access = PL3_RW,
> >> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
> >> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> >> + .raw_writefn = raw_write,
> >> + };
> >> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> >> + /* Normally we would always end the TB on an SCTLR write, but Linux
> >> + * arch/arm/mach-pxa/sleep.S expects two instructions following
> >> + * an MMU enable to execute from cache. Imitate this behaviour.
> >> + */
> >> + sctlr_el1_s.type |= ARM_CP_SUPPRESS_TB_END;
> >> + }
> >> + define_one_arm_cp_reg(cpu, &sctlr_el1_s);
> >> +
> >> + ARMCPRegInfo sctlr_el3 = {
> >> + .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
> >> + .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
> >> + .access = PL3_RW, .type = ARM_CP_SECURE,
> >> + .fieldoffset = offsetof(CPUARMState, cp15.c1_sys_el3),
> >> + .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr_el3,
> >> + .raw_writefn = raw_write,
> >> + };
> >> + if (arm_feature(env, ARM_FEATURE_XSCALE)) {
> >> + /* Normally we would always end the TB on an SCTLR write, but Linux
> >> + * arch/arm/mach-pxa/sleep.S expects two instructions following
> >> + * an MMU enable to execute from cache. Imitate this behaviour.
> >> + */
> >> + sctlr_el3.type |= ARM_CP_SUPPRESS_TB_END;
> >> + }
> >> + define_one_arm_cp_reg(cpu, &sctlr_el3);
> >> }
> >> }
> >>
> >> @@ -3475,7 +3510,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> >> return; /* Never happens. Keep compiler happy. */
> >> }
> >> /* High vectors. */
> >> - if (env->cp15.c1_sys & SCTLR_V) {
> >> + if (arm_current_sctlr(env) & SCTLR_V) {
> >> /* when enabled, base address cannot be remapped. */
> >> addr += 0xffff0000;
> >> } else {
> >> @@ -3498,7 +3533,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> >> /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
> >> * and we should just guard the thumb mode on V4 */
> >> if (arm_feature(env, ARM_FEATURE_V4T)) {
> >> - env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0;
> >> + env->thumb = (arm_current_sctlr(env) & SCTLR_TE) != 0;
> >> }
> >> env->regs[14] = env->regs[15] + offset;
> >> env->regs[15] = addr;
> >> @@ -3529,7 +3564,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
> >> }
> >> if (access_type == 1)
> >> return 0;
> >> - switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) {
> >> + switch (arm_current_sctlr(env) & (SCTLR_S | SCTLR_R)) {
> >> case SCTLR_S:
> >> return is_user ? 0 : PAGE_READ;
> >> case SCTLR_R:
> >> @@ -3763,7 +3798,7 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
> >> goto do_fault;
> >>
> >> /* The simplified model uses AP[0] as an access control bit. */
> >> - if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) {
> >> + if ((arm_current_sctlr(env) & SCTLR_AFE) && (ap & 1) == 0) {
> >> /* Access flag fault. */
> >> code = (code == 15) ? 6 : 3;
> >> goto do_fault;
> >> @@ -4099,7 +4134,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
> >> if (address < 0x02000000)
> >> address += env->cp15.c13_fcse;
> >>
> >> - if ((env->cp15.c1_sys & SCTLR_M) == 0) {
> >> + if ((arm_current_sctlr(env) & SCTLR_M) == 0) {
> >> /* MMU/MPU disabled. */
> >> *phys_ptr = address;
> >> *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> >> @@ -4112,7 +4147,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
> >> } else if (extended_addresses_enabled(env)) {
> >> return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
> >> prot, page_size);
> >> - } else if (env->cp15.c1_sys & SCTLR_XP) {
> >> + } else if (arm_current_sctlr(env) & SCTLR_XP) {
> >> return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
> >> prot, page_size);
> >> } else {
> >> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> >> index fb90676..3eacea8 100644
> >> --- a/target-arm/op_helper.c
> >> +++ b/target-arm/op_helper.c
> >> @@ -365,7 +365,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
> >> * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
> >> * to catch that case at translate time.
> >> */
> >> - if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
> >> + if (arm_current_pl(env) == 0 && !(arm_current_sctlr(env) & SCTLR_UMA)) {
> >> raise_exception(env, EXCP_UDEF);
> >> }
> >>
> >> --
> >> 1.8.3.2
> >>
>
^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros
2014-05-22 12:50 ` Aggeler Fabian
@ 2014-05-22 22:21 ` Greg Bellows
0 siblings, 0 replies; 75+ messages in thread
From: Greg Bellows @ 2014-05-22 22:21 UTC (permalink / raw)
To: Aggeler Fabian
Cc: peter.maydell@linaro.org, Sergey Fedorov, qemu-devel@nongnu.org,
Edgar E. Iglesias
[-- Attachment #1: Type: text/plain, Size: 27339 bytes --]
Hi Fabian,
In regards to the 0/1 comments/response on your code. The issue I was
trying to express is that we seem to flip-flop between when NS is 1 or 0
(plus the stale comment did not help). Just as you mentioned in your
response to my comments, you mention that the 0th entry is non-secure and
the 1st entry is secure.. so ns=0 and s=1. Then in a later response you
suggest that ns=1 going into the hash and s=0. Not having a consistent
numbering may inadvertently cause issues in the future.
On the register structure/mapping, If we are adopting the more explicit
approach then it certainly makes sense to also explicitly assign the
fieldoffsets in the definition, this is a good idea. I am also in favor of
the more explicit mapping/unionizing of the 32 to 64 bit registers, it
certainly makes the code more readable.
One thing we need to be careful about is conflating exception levels and
secure state as they are distinct concepts. There are a number of ARMv8
registers that are EL1 but have both secure and nonsecure instances. This
case would likely diverge in the formatting/naming.
It would certainly be nice to use the array approach, but as Fabian points
out it does not present a uniform accessing method, and may complicate
mapping. It also tends to require padding in order to allow logical
accesses. Instead, perhaps it is better to just name things explicitly...
For instance, the SCTLR mapping is the same, but without the need for
padding.
union {
struct {
uint64_t sctlr_ns;
uint64_t hsctlr;
uint64_t sctlr_s;
} aarch32;
struct {
uint64_t sctlr_el1;
uint64_t sctlr_el2;
uint64_t sctlr_el3;
} aarch64; // or this can be anonymous
}
FAR is a more interesting case as DFAR/IFAR are architecturally mapped to a
single EL level register. Below is an example of what this might look
like. Clearly, endianness would need to be considered in such a union, but
is omitted for clarity.
union {
struct {
uint32_t dfar_ns
uint32_t ifar_ns;
uint32_t dfar_s;
uint32_t ifar_s;
} aarch32;
struct {
uint64_t far_el1;
uint64_t far_el2;
} aarch64; // or this can be anonymous
}
uint64_t far_el3; // Not required to be mapped to secure, so left
separate.
While we would lose the variable based indexing, accesses could still be
abstracted to allow variable based selection. Plus, this may make it
easier to follow in the code.
Regards,
Greg
On 22 May 2014 07:50, Aggeler Fabian <aggelerf@student.ethz.ch> wrote:
>
> On 22 May 2014, at 14:18, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>
> >
> > On 22.05.2014 15:49, Aggeler Fabian wrote:
> >> On 22 May 2014, at 09:41, Edgar E. Iglesias <edgar.iglesias@gmail.com>
> wrote:
> >>
> >>> On Tue, May 13, 2014 at 06:15:59PM +0200, Fabian Aggeler wrote:
> >>>> Banked CP registers can be defined with a A32_BANKED_REG macro which
> defines
> >>>> a non-secure instance of the register followed by an adjacent secure
> instance.
> >>>> Using a union makes the code backwards-compatible since the non-secure
> >>>> instance can normally be accessed by its existing name.
> >>>>
> >>>> When translating a banked CP register access instruction in monitor
> mode,
> >>>> the SCR.NS bit determines which instance is going to be accessed.
> >>>>
> >>>> If EL3 is operating in Aarch64 state coprocessor registers are not
> >>>> banked anymore but in some cases have its own _EL3 instance.
> >>> Hi
> >>>
> >>> Regarding the sctlr regs and the banking of S/NS regs in general, I
> >>> think the general pattern should be to arrayify the regs that need
> >>> to be indexed by EL.
> >>>
> >>> This is an example of a structure (indexed by EL) with the aarch32
> >>> struct beeing here to help clarify.
> >>> union {
> >>> struct {
> >>> uint64_t pad;
> >>> uint64_t sctlr_ns;
> >>> uint64_t hsctlr;
> >>> uint64_t sctlr_s;
> >>> } aarch32;
> >>> uint64_t sctlr_el[4];
> >>> }
> >>>
> >>> I think we would naturally want to register this for AArch32 as banked
> >>> with NS=sctlr_el[1] and S=sctlr_el[3].
> >>>
> >>> Another register example is FAR. For FAR, things look like this
> >>> (when EL2 is available and ignoring DFAR for clarity):
> >>> union {
> >>> struct {
> >>> uint64_t pad;
> >>> uint64_t ifar_ns;
> >>> uint64_t ifar_s;
> >>> } aarch32;
> >>> uint64_t far_el[4];
> >>> }
> >>>
> >>> Preferably we need something that can handle both cases.
> >>> An option could be to arrayify the .fieldoffset in reginfos?
> >>> If we don't want hardcoded TZ knowledge in the generic cpreg accessors,
> >>> maybe there could be a generic function that returns the .fieldoffset
> >>> index based on CPUState (e.g NS=0, S=1 etc). Or maybe specialized
> >>> read/write fns would be enough.
> >>>
> >>> Just an idea to get the discussion going.
> >>>
> >>> struct ARMCPRegInfo {
> >>> ....
> >>> union {
> >>> ptrdiff_t fieldoffset;
> >>> ptrdiff_t fieldoffsets[2];
> >>> };
> >>> };
> >>>
> >>> unsigned int arm_cpreg_tzbank_idx(CPUARMState *env)
> >>> {
> >>> return is_a64(env) ? 0 : arm_is_secure(env);
> >>> }
> >>>
> >>> Example:
> >>> { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
> >>> .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> >>> .access = PL1_RW,
> >>> .fieldindex_fn = arm_cpreg_tzbank_idx,
> >>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.far_el[1]),
> >>> offsetof(CPUARMState, cp15.far_el[2])},
> >>> .resetvalue = 0, },
> >>>
> >>> ARMCPRegInfo sctlr = {
> >>> .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
> >>> .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
> >>> .access = PL1_RW,
> >>> .fieldindex_fn = arm_cpreg_tzbank_idx,
> >>> .fieldoffsets[] = { offsetof(CPUARMState, cp15.sctlr_el[1]),
> >>> offsetof(CPUARMState, cp15.sctlr_el[3]),
> >>> },
> >>> /* Assuming raw_write and raw_read respect the indexing. */
> >>> .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
> >>> .raw_writefn = raw_write,
> >>> };
> >>>
> >>> Best regards,
> >>> Edgar
> >>>
> >> Hi Edgar
> >>
> >> Thanks for joining the discussion. I like the idea of arrayifying the
> cp regs, also for banking.
> >> Since your patches are doing this anyways for EL registers I wanted to
> change the registers
> >> which do not have EL3/EL2 equivalents (DACR, PAR,…) to use the same
> mechanism. These
> >> registers are the third case which you haven’t mentioned in your
> examples above, where we only
> >> have one reg in Aarch64 but two (s/ns) in Aarch32. So I in my eyes it
> didn’t make sense to make
> >> the array bigger than needed, that’s why I went for 2 entries only. But
> if it allows us map it easier
> >> or in a more consistent way I don’t see why we cannot do it.
> >>
> >> union {
> >> struct {
> >> uint64_t par_ns;
> >> uint64_t par_s;
> >> } aarch32;
> >> uint64_t par_el[2];
> >> }
> >>
> >> We should probably also get rid of the macros I used to define the
> banked registers, to make the code
> >> look more uniform. Using your idea of arrayifying fieldset too, we
> could get rid of the additional cpreg
> >> definitions. Do we need to specify a .fieldindex_fn for every cpreg in
> this case?
> >> Isn’t it the same for all the cpregs which are banked (two
> fieldoffsets, the first one for non-secure and
> >> the second entry for secure)? But then we still need to know whether
> this register is banked or common.
> >>
> >> But what about accessing them not from within a cpreg read/write
> instruction? We will have at least 3
> >> cases of different indexes ({ns=1, s=2}, {ns=1, s=3}, {ns=0, s=1}).
> Although by padding the last case
> >> we could merge it with the first one so we only have 2 ways of
> accessing a banked register, which was
> >> also the case in my patches, for which I introduced macros. Any ideas
> how to simplify that?
> >>
> >> Thanks,
> >> Fabian
> >
> > Hi
> >
> > Speculating on some changes to reginfo's fieldoffset, it is worth to
> > notice that then CPU state save/load could need to be adjusted. Keeping
> > separate reginfo for each banked register in the hash table would
> > eliminate any changes to CPU state save/load.
> >
> > Regards,
> > Sergey
>
> Hi Sergey
>
> We could still insert it twice into the hashtable (keep this approach) but
> make the cpreg definition
> more compact and avoid the implicit adjusting of the offset for banked
> registers shortly before adding
> them to the hashtable (where I had to distinguish between 32/64bit
> fields). By having a ns-bit in the type
> (as it is now) or directly as a field in the ARMCPRegInfo struct as you
> suggested, we could still get the
> correct offset when accessing the field (either in raw_read/raw_write or
> in the readfn/writefns) and therefore
> we don’t need to change the CPU state save/load.
>
> Best,
> Fabian
>
> >
> >>>
> >>>
> >>>
> >>>> Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
> >>>> Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
> >>>> ---
> >>>> target-arm/cpu.h | 121
> +++++++++++++++++++++++++++++++++++++++++++++----
> >>>> target-arm/helper.c | 64 ++++++++++++++++++++++++--
> >>>> target-arm/translate.c | 19 +++++---
> >>>> 3 files changed, 184 insertions(+), 20 deletions(-)
> >>>>
> >>>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> >>>> index a970d55..9e325ac 100644
> >>>> --- a/target-arm/cpu.h
> >>>> +++ b/target-arm/cpu.h
> >>>> @@ -80,6 +80,16 @@
> >>>> #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t))
> >>>> #endif
> >>>>
> >>>> +/* Define a banked coprocessor register state field. Use %name as the
> >>>> + * register field name for the secure instance. The non-secure
> instance
> >>>> + * has a "_nonsecure" suffix.
> >>>> + */
> >>>> +#define A32_BANKED_REG(type, name) \
> >>>> + union { \
> >>>> + type name; \
> >>>> + type name##_banked[2]; \
> >>>> + }
> >>>> +
> >>>> /* Meanings of the ARMCPU object's two inbound GPIO lines */
> >>>> #define ARM_CPU_IRQ 0
> >>>> #define ARM_CPU_FIQ 1
> >>>> @@ -89,6 +99,7 @@ typedef void ARMWriteCPFunc(void *opaque, int
> cp_info,
> >>>> typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
> >>>> int dstreg, int operand);
> >>>>
> >>>> +
> >>>> struct arm_boot_info;
> >>>>
> >>>> #define NB_MMU_MODES 5
> >>>> @@ -673,6 +684,78 @@ static inline bool arm_el_is_aa64(CPUARMState
> *env, int el)
> >>>> return arm_feature(env, ARM_FEATURE_AARCH64);
> >>>> }
> >>>>
> >>>> +/* When EL3 is operating in Aarch32 state, the NS-bit determines
> >>>> + * whether the secure instance of a cp-register should be used. */
> >>>> +#define USE_SECURE_REG(env) ( \
> >>>> + arm_feature(env,
> ARM_FEATURE_SECURITY_EXTENSIONS) && \
> >>>> + !arm_el_is_aa64(env, 3) && \
> >>>> + !((env)->cp15.c1_scr & 1/*NS*/))
> >>>> +
> >>>> +#define NONSECURE_BANK 0
> >>>> +#define SECURE_BANK 1
> >>>> +
> >>>> +#define A32_BANKED_REG_GET(env, regname) \
> >>>> + ((USE_SECURE_REG(env)) ? \
> >>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> >>>> + (env)->cp15.regname)
> >>>> +
> >>>> +#define A32_MAPPED_EL3_REG_GET(env, regname) \
> >>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> >>>> + (USE_SECURE_REG(env))) ? \
> >>>> + (env)->cp15.regname##_el3 : \
> >>>> + (env)->cp15.regname##_el1)
> >>>> +
> >>>> +#define A32_BANKED_REG_SET(env, regname, val) \
> >>>> + do { \
> >>>> + if (USE_SECURE_REG(env)) { \
> >>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> >>>> + } else { \
> >>>> + (env)->cp15.regname = (val); \
> >>>> + } \
> >>>> + } while (0)
> >>>> +
> >>>> +#define A32_MAPPED_EL3_REG_SET(env, regname, val) \
> >>>> + do { \
> >>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3)
> || \
> >>>> + (USE_SECURE_REG(env))) { \
> >>>> + (env)->cp15.regname##_el3 = (val); \
> >>>> + } else { \
> >>>> + (env)->cp15.regname##_el1 = (val); \
> >>>> + } \
> >>>> + } while (0)
> >>>> +
> >>>> +
> >>>> +#define A32_BANKED_CURRENT_REG_GET(env, regname) \
> >>>> + ((!arm_el_is_aa64(env, 3) && arm_is_secure(env)) ? \
> >>>> + (env)->cp15.regname##_banked[SECURE_BANK] : \
> >>>> + (env)->cp15.regname)
> >>>> +
> >>>> +#define A32_MAPPED_EL3_CURRENT_REG_GET(env, regname) \
> >>>> + (((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3) || \
> >>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env))) ? \
> >>>> + (env)->cp15.regname##_el3 : \
> >>>> + (env)->cp15.regname##_el1)
> >>>> +
> >>>> +#define A32_BANKED_CURRENT_REG_SET(env, regname, val) \
> >>>> + do { \
> >>>> + if (!arm_el_is_aa64(env, 3) && arm_is_secure(env)) { \
> >>>> + (env)->cp15.regname##_banked[SECURE_BANK] = (val); \
> >>>> + } else { \
> >>>> + (env)->cp15.regname = (val); \
> >>>> + } \
> >>>> + } while (0)
> >>>> +
> >>>> +#define A32_MAPPED_EL3_CURRENT_REG_SET(env, regname, val) \
> >>>> + do { \
> >>>> + if ((arm_el_is_aa64(env, 3) && arm_current_pl(env) == 3)
> || \
> >>>> + (!arm_el_is_aa64(env, 3) && arm_is_secure(env)))
> { \
> >>>> + (env)->cp15.regname##_el3 = (val); \
> >>>> + } else { \
> >>>> + (env)->cp15.regname##_el1 = (val); \
> >>>> + } \
> >>>> + } while (0)
> >>>> +
> >>>> +
> >>>> void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
> >>>>
> >>>> /* Interface between CPU and Interrupt controller. */
> >>>> @@ -691,6 +774,7 @@ void armv7m_nvic_complete_irq(void *opaque, int
> irq);
> >>>> * Crn, Crm, opc1, opc2 fields
> >>>> * 32 or 64 bit register (ie is it accessed via MRC/MCR
> >>>> * or via MRRC/MCRR?)
> >>>> + * nonsecure/secure bank (Aarch32 only)
> >>>> * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
> >>>> * (In this case crn and opc2 should be zero.)
> >>>> * For AArch64, there is no 32/64 bit size distinction;
> >>>> @@ -708,9 +792,16 @@ void armv7m_nvic_complete_irq(void *opaque, int
> irq);
> >>>> #define CP_REG_AA64_SHIFT 28
> >>>> #define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
> >>>>
> >>>> -#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2) \
> >>>> - (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \
> >>>> - ((crm) << 7) | ((opc1) << 3) | (opc2))
> >>>> +/* To enable banking of coprocessor registers depending on ns-bit we
> >>>> + * add a bit to distinguish between secure and non-secure cpregs in
> the
> >>>> + * hashtable.
> >>>> + */
> >>>> +#define CP_REG_NS_SHIFT 27
> >>>> +#define CP_REG_NS_MASK(nsbit) (nsbit << CP_REG_NS_SHIFT)
> >>>> +
> >>>> +#define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2, ns) \
> >>>> + (CP_REG_NS_MASK(ns) | ((cp) << 16) | ((is64) << 15) | \
> >>>> + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
> >>>>
> >>>> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
> >>>> (CP_REG_AA64_MASK | \
> >>>> @@ -771,6 +862,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t
> cpregid)
> >>>> * IO indicates that this register does I/O and therefore its accesses
> >>>> * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
> >>>> * registers which implement clocks or timers require this.
> >>>> + * In an implementation with Security Extensions supporting Aarch32
> cp regs can
> >>>> + * be banked or common. If a register is common it references the
> same variable
> >>>> + * from both worlds (non-secure and secure). For cp regs which
> neither set
> >>>> + * ARM_CP_SECURE nor ARM_CP_NONSECURE (default) we assume it's
> common and it
> >>>> + * will be inserted twice into the hashtable. If a register has
> >>>> + * ARM_CP_BANKED/ARM_CP_BANKED_64BIT set, it will be inserted twice
> but with
> >>>> + * different offset respectively. This way Aarch32 registers which
> can be
> >>>> + * mapped to Aarch64 PL3 registers can be inserted individually.
> >>>> */
> >>>> #define ARM_CP_SPECIAL 1
> >>>> #define ARM_CP_CONST 2
> >>>> @@ -779,16 +878,20 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t
> cpregid)
> >>>> #define ARM_CP_OVERRIDE 16
> >>>> #define ARM_CP_NO_MIGRATE 32
> >>>> #define ARM_CP_IO 64
> >>>> -#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
> >>>> -#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> >>>> -#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> >>>> -#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
> >>>> -#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
> >>>> +#define ARM_CP_SECURE (1 << 7)
> >>>> +#define ARM_CP_NONSECURE (1 << 8)
> >>>> +#define ARM_CP_BANKED (ARM_CP_NONSECURE | ARM_CP_SECURE)
> >>>> +#define ARM_CP_BANKED_64BIT ((1 << 9) | ARM_CP_BANKED)
> >>>> +#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 10))
> >>>> +#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 10))
> >>>> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 10))
> >>>> +#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 10))
> >>>> +#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 10))
> >>>> #define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
> >>>> /* Used only as a terminator for ARMCPRegInfo lists */
> >>>> #define ARM_CP_SENTINEL 0xffff
> >>>> /* Mask of only the flag bits in a type field */
> >>>> -#define ARM_CP_FLAG_MASK 0x7f
> >>>> +#define ARM_CP_FLAG_MASK 0x3ff
> >>>>
> >>>> /* Valid values for ARMCPRegInfo state field, indicating which of
> >>>> * the AArch32 and AArch64 execution states this register is visible
> in.
> >>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
> >>>> index 9326ef8..98c3dc9 100644
> >>>> --- a/target-arm/helper.c
> >>>> +++ b/target-arm/helper.c
> >>>> @@ -2703,7 +2703,7 @@ CpuDefinitionInfoList
> *arch_query_cpu_definitions(Error **errp)
> >>>>
> >>>> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> >>>> void *opaque, int state,
> >>>> - int crm, int opc1, int opc2)
> >>>> + int crm, int opc1, int opc2, int
> nsbit)
> >>>> {
> >>>> /* Private utility function for
> define_one_arm_cp_reg_with_opaque():
> >>>> * add a single reginfo struct to the hash table.
> >>>> @@ -2726,6 +2726,34 @@ static void add_cpreg_to_hashtable(ARMCPU
> *cpu, const ARMCPRegInfo *r,
> >>>> }
> >>>> #endif
> >>>> }
> >>>> +
> >>>> + if ((r->type & ARM_CP_BANKED) == ARM_CP_BANKED && !nsbit) {
> >>>> + if (r2->fieldoffset) {
> >>>> + /* We simplify register definitions by providing a type
> >>>> + * ARM_CP_BANKED, for which the fieldoffset of the
> secure instance
> >>>> + * will be increased to point at the second entry of the
> array.
> >>>> + *
> >>>> + * We cannot use is64 or the type ARM_CP_STATE_BOTH to
> know how
> >>>> + * wide the banked register is because some registers
> are 64bit
> >>>> + * wide but the register is not defined as 64bit because
> it is
> >>>> + * mapped to the lower 32 bit.
> >>>> + * Therefore two separate types for 64bit banked
> registers and
> >>>> + * 32bit registers are used
> (ARM_CP_BANKED/ARM_CP_BANKED_64BIT).
> >>>> + */
> >>>> + r2->fieldoffset +=
> >>>> + ((r->type & ARM_CP_BANKED_64BIT) ==
> ARM_CP_BANKED_64BIT) ?
> >>>> + sizeof(uint64_t) : sizeof(uint32_t);
> >>>> + }
> >>>> + }
> >>>> + /* For A32 we want to be able to know whether the secure or
> non-secure
> >>>> + * instance wants to be accessed. A64 does not know this banking
> scheme
> >>>> + * anymore, but it might use the same readfn/writefn as A32
> which might
> >>>> + * rely on it (e.g. in the case of ARM_CP_STATE_BOTH).
> >>>> + * Reset the type according to ns-bit passed as argument.
> >>>> + */
> >>>> + r2->type &= ~(ARM_CP_NONSECURE | ARM_CP_SECURE);
> >>>> + r2->type |= nsbit ? ARM_CP_NONSECURE : ARM_CP_SECURE;
> >>>> +
> >>>> if (state == ARM_CP_STATE_AA64) {
> >>>> /* To allow abbreviation of ARMCPRegInfo
> >>>> * definitions, we treat cp == 0 as equivalent to
> >>>> @@ -2737,7 +2765,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu,
> const ARMCPRegInfo *r,
> >>>> *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
> >>>> r2->opc0, opc1, opc2);
> >>>> } else {
> >>>> - *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2);
> >>>> + *key = ENCODE_CP_REG(r2->cp, is64, r2->crn, crm, opc1, opc2,
> nsbit);
> >>>> }
> >>>> if (opaque) {
> >>>> r2->opaque = opaque;
> >>>> @@ -2773,9 +2801,10 @@ static void add_cpreg_to_hashtable(ARMCPU
> *cpu, const ARMCPRegInfo *r,
> >>>> oldreg = g_hash_table_lookup(cpu->cp_regs, key);
> >>>> if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
> >>>> fprintf(stderr, "Register redefined: cp=%d %d bit "
> >>>> - "crn=%d crm=%d opc1=%d opc2=%d, "
> >>>> + "crn=%d crm=%d opc1=%d opc2=%d ns=%d, "
> >>>> "was %s, now %s\n", r2->cp, 32 + 32 * is64,
> >>>> r2->crn, r2->crm, r2->opc1, r2->opc2,
> >>>> + (r2->type & ARM_CP_NONSECURE),
> >>>> oldreg->name, r2->name);
> >>>> g_assert_not_reached();
> >>>> }
> >>>> @@ -2886,8 +2915,33 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU
> *cpu,
> >>>> if (r->state != state && r->state !=
> ARM_CP_STATE_BOTH) {
> >>>> continue;
> >>>> }
> >>>> - add_cpreg_to_hashtable(cpu, r, opaque, state,
> >>>> - crm, opc1, opc2);
> >>>> +
> >>>> + if (state == ARM_CP_STATE_AA32) {
> >>>> + if ((r->type & ARM_CP_BANKED) ==
> ARM_CP_BANKED ||
> >>>> + (r->type & ARM_CP_BANKED) == 0) {
> >>>> + /* Under Aarch32 CP registers can be
> common
> >>>> + * (same for secure and non-secure
> world) or banked.
> >>>> + * Register definitions with neither
> secure nor
> >>>> + * non-secure type set (common) or with
> both bits
> >>>> + * set (banked) will be inserted twice
> into the
> >>>> + * hashtable.
> >>>> + */
> >>>> + add_cpreg_to_hashtable(cpu, r, opaque,
> state,
> >>>> + crm, opc1, opc2, 0);
> >>>> + add_cpreg_to_hashtable(cpu, r, opaque,
> state,
> >>>> + crm, opc1, opc2, 1);
> >>>> + } else {
> >>>> + /* Only one of both bank types were
> specified */
> >>>> + add_cpreg_to_hashtable(cpu, r, opaque,
> state,
> >>>> + crm, opc1, opc2,
> >>>> + (r->type & ARM_CP_NONSECURE) ? 1
> : 0);
> >>>> + }
> >>>> + } else {
> >>>> + /* Aarch64 registers get mapped to
> non-secure instance
> >>>> + * of Aarch32 */
> >>>> + add_cpreg_to_hashtable(cpu, r, opaque, state,
> >>>> + crm, opc1, opc2, 1);
> >>>> + }
> >>>> }
> >>>> }
> >>>> }
> >>>> diff --git a/target-arm/translate.c b/target-arm/translate.c
> >>>> index bbd4c77..3a429ac 100644
> >>>> --- a/target-arm/translate.c
> >>>> +++ b/target-arm/translate.c
> >>>> @@ -6866,7 +6866,7 @@ static int disas_neon_data_insn(CPUARMState *
> env, DisasContext *s, uint32_t ins
> >>>>
> >>>> static int disas_coproc_insn(CPUARMState * env, DisasContext *s,
> uint32_t insn)
> >>>> {
> >>>> - int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
> >>>> + int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2, ns;
> >>>> const ARMCPRegInfo *ri;
> >>>>
> >>>> cpnum = (insn >> 8) & 0xf;
> >>>> @@ -6937,8 +6937,11 @@ static int disas_coproc_insn(CPUARMState *
> env, DisasContext *s, uint32_t insn)
> >>>> isread = (insn >> 20) & 1;
> >>>> rt = (insn >> 12) & 0xf;
> >>>>
> >>>> + /* Monitor mode is always treated as secure but cp register
> reads/writes
> >>>> + * can access secure and non-secure instances using SCR.NS bit*/
> >>>> + ns = IS_NS(s) ? 1 : !USE_SECURE_REG(env);
> >>>> ri = get_arm_cp_reginfo(s->cp_regs,
> >>>> - ENCODE_CP_REG(cpnum, is64, crn, crm,
> opc1, opc2));
> >>>> + ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2, ns));
> >>>> if (ri) {
> >>>> /* Check access permissions */
> >>>> if (!cp_access_ok(s->current_pl, ri, isread)) {
> >>>> @@ -7125,12 +7128,16 @@ static int disas_coproc_insn(CPUARMState *
> env, DisasContext *s, uint32_t insn)
> >>>> */
> >>>> if (is64) {
> >>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> >>>> - "64 bit system register cp:%d opc1: %d
> crm:%d\n",
> >>>> - isread ? "read" : "write", cpnum, opc1, crm);
> >>>> + "64 bit system register cp:%d opc1: %d crm:%d "
> >>>> + "(%s)\n",
> >>>> + isread ? "read" : "write", cpnum, opc1, crm,
> >>>> + ns ? "non-secure" : "secure");
> >>>> } else {
> >>>> qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
> >>>> - "system register cp:%d opc1:%d crn:%d crm:%d
> opc2:%d\n",
> >>>> - isread ? "read" : "write", cpnum, opc1, crn,
> crm, opc2);
> >>>> + "system register cp:%d opc1:%d crn:%d crm:%d
> opc2:%d "
> >>>> + "(%s)\n",
> >>>> + isread ? "read" : "write", cpnum, opc1, crn,
> crm, opc2,
> >>>> + ns ? "non-secure" : "secure");
> >>>> }
> >>>>
> >>>> return 1;
> >>>> --
> >>>> 1.8.3.2
> >>>>
> >>
> >
>
>
>
[-- Attachment #2: Type: text/html, Size: 38592 bytes --]
^ permalink raw reply [flat|nested] 75+ messages in thread
end of thread, other threads:[~2014-05-22 22:22 UTC | newest]
Thread overview: 75+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-13 16:15 [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 01/23] target-arm: add new CPU feature for Security Extensions Fabian Aggeler
2014-05-21 14:46 ` Peter Maydell
2014-05-21 16:14 ` Christopher Covington
2014-05-21 16:33 ` Sergey Fedorov
2014-05-21 16:41 ` Peter Maydell
2014-05-21 16:47 ` Sergey Fedorov
2014-05-21 14:51 ` Peter Maydell
2014-05-22 9:09 ` Aggeler Fabian
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 02/23] target-arm: move SCR into Security Extensions register list Fabian Aggeler
2014-05-14 14:19 ` Greg Bellows
2014-05-15 9:28 ` Aggeler Fabian
2014-05-21 14:57 ` Peter Maydell
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 03/23] target-arm: adjust TTBCR for Security Extension feature Fabian Aggeler
2014-05-21 16:06 ` Peter Maydell
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 04/23] target-arm: preserve RAO/WI bits of ARMv7 SCTLR Fabian Aggeler
2014-05-14 5:43 ` Sergey Fedorov
2014-05-21 16:12 ` Peter Maydell
2014-05-22 8:58 ` Aggeler Fabian
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 05/23] target-arm: add CPU Monitor mode Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 06/23] target-arm: add arm_is_secure() function Fabian Aggeler
2014-05-14 5:53 ` Sergey Fedorov
2014-05-14 14:42 ` Greg Bellows
2014-05-14 18:35 ` Fedorov Sergey
2014-05-14 20:22 ` Greg Bellows
2014-05-14 21:29 ` Peter Maydell
2014-05-14 22:22 ` Greg Bellows
2014-05-15 13:00 ` Aggeler Fabian
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 07/23] target-arm: reject switching to monitor mode from non-secure state Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 08/23] target-arm: adjust arm_current_pl() for Security Extensions Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 09/23] target-arm: add non-secure Translation Block flag Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 10/23] target-arm: implement CPACR register logic Fabian Aggeler
2014-05-14 6:06 ` Sergey Fedorov
2014-05-14 18:39 ` Fedorov Sergey
2014-05-15 14:44 ` Fabian Aggeler
2014-05-15 15:06 ` Sergey Fedorov
2014-05-14 13:09 ` Peter Crosthwaite
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 11/23] target-arm: add NSACR support Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 12/23] target-arm: add SDER definition Fabian Aggeler
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 13/23] target-arm: Split TLB for secure state and EL3 in Aarch64 Fabian Aggeler
2014-05-14 6:15 ` Sergey Fedorov
2014-05-13 16:15 ` [Qemu-devel] [PATCH v2 14/23] target-arm: add banked coprocessor register type and macros Fabian Aggeler
2014-05-14 16:42 ` Greg Bellows
2014-05-15 9:02 ` Aggeler Fabian
2014-05-15 18:42 ` Sergey Fedorov
2014-05-15 19:10 ` Aggeler Fabian
2014-05-16 7:06 ` Sergey Fedorov
2014-05-22 7:41 ` Edgar E. Iglesias
2014-05-22 11:49 ` Aggeler Fabian
2014-05-22 12:18 ` Sergey Fedorov
2014-05-22 12:50 ` Aggeler Fabian
2014-05-22 22:21 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 15/23] target-arm: Restrict EL3 to Aarch32 state Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 16/23] target-arm: Use arm_current_sctlr to access SCTLR Fabian Aggeler
2014-05-22 7:33 ` Edgar E. Iglesias
2014-05-22 14:56 ` Aggeler Fabian
2014-05-22 21:24 ` Edgar E. Iglesias
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 17/23] target-arm: Use raw_write/raw_read whenever possible Fabian Aggeler
2014-05-14 17:32 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 18/23] target-arm: Convert banked coprocessor registers Fabian Aggeler
2014-05-14 19:47 ` Greg Bellows
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 19/23] target-arm: maintain common bits of banked CP registers Fabian Aggeler
2014-05-14 21:20 ` Greg Bellows
2014-05-15 13:10 ` Aggeler Fabian
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 20/23] target-arm: add MVBAR support Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 21/23] target-arm: implement SMC instruction Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 22/23] target-arm: implement IRQ/FIQ routing to Monitor mode Fabian Aggeler
2014-05-13 16:16 ` [Qemu-devel] [PATCH v2 23/23] target-arm: Respect SCR.FW, SCR.AW and SCTLR.NMFI Fabian Aggeler
2014-05-15 18:57 ` [Qemu-devel] [PATCH v2 00/23] target-arm: add Security Extensions for CPUs Sergey Fedorov
2014-05-16 6:00 ` Aggeler Fabian
2014-05-16 20:56 ` Greg Bellows
2014-05-20 10:00 ` Aggeler Fabian
2014-05-20 15:43 ` Greg Bellows
2014-05-21 14:04 ` Peter Maydell
2014-05-21 13:55 ` Peter Maydell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).