From 1ecc3a2df168034b8ab33ff5ba6434ce3593dbb5 Mon Sep 17 00:00:00 2001 From: Liviu Ionescu Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: Pass semihosting exit code back to system. In order to run unit tests under semihosting, it is necessary to pass the application exit code back to the system. ARM defines only the code to be used for non-error application exit (ADP_Stopped_ApplicationExit), all other codes should return non-zero exit codes. This patch checks if the application code passed via TARGET_SYS_EXIT is ADP_Stopped_ApplicationExit, and return 0, otherwise return 1. Signed-off-by: Liviu Ionescu Signed-off-by: Peter Maydell --- target-arm/arm-semi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c index ebb5235..a8b83e6 100644 --- a/target-arm/arm-semi.c +++ b/target-arm/arm-semi.c @@ -58,6 +58,10 @@ #define TARGET_SYS_HEAPINFO 0x16 #define TARGET_SYS_EXIT 0x18 +/* ADP_Stopped_ApplicationExit is used for exit(0), + * anything else is implemented as exit(1) */ +#define ADP_Stopped_ApplicationExit (0x20026) + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -551,8 +555,11 @@ uint32_t do_arm_semihosting(CPUARMState *env) return 0; } case TARGET_SYS_EXIT: - gdb_exit(env, 0); - exit(0); + /* ARM specifies only Stopped_ApplicationExit as normal + * exit, everything else is considered an error */ + ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1; + gdb_exit(env, ret); + exit(ret); default: fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); cpu_dump_state(cs, stderr, fprintf, 0); -- cgit v1.1 From a38bb0792ca8b4082d81884a6cb25fa0d334b4a6 Mon Sep 17 00:00:00 2001 From: Liviu Ionescu Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: Add the "-semihosting-config" option. The usual semihosting behaviour is to process the system calls locally and return; unfortuantelly the initial implementation dinamically changed the target to GDB during debug sessions, which, for the usual arm-none-eabi-gdb, is not implemented. The result was that during debug sessions the semihosting calls were discarded. This patch adds a configuration variable and an option to set it on the command line: -semihosting-config [enable=on|off,]target=native|gdb|auto This option enables semihosting and defines where the semihosting calls will be addressed, to QEMU ('native') or to GDB ('gdb'). The default is auto, which means 'gdb' during debug sessions and 'native' otherwise. Signed-off-by: Liviu Ionescu Message-id: 1416341957-9796-1-git-send-email-ilg@livius.net [PMM: moved declaration and definition of semihosting_target to gdbstub.h and gdbstub.c to fix build failure on linux-user] Signed-off-by: Peter Maydell --- gdbstub.c | 15 +++++++++++++-- include/exec/gdbstub.h | 6 ++++++ qemu-options.hx | 12 +++++++++++- vl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 0faca56..e4a1a79 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -317,6 +317,8 @@ static GDBState *gdbserver_state; bool gdb_has_xml; +int semihosting_target = SEMIHOSTING_TARGET_AUTO; + #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -351,10 +353,19 @@ static enum { GDB_SYS_DISABLED, } gdb_syscall_mode; -/* If gdb is connected when the first semihosting syscall occurs then use - remote gdb syscalls. Otherwise use native file IO. */ +/* Decide if either remote gdb syscalls or native file IO should be used. */ int use_gdb_syscalls(void) { + if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) { + /* -semihosting-config target=native */ + return false; + } else if (semihosting_target == SEMIHOSTING_TARGET_GDB) { + /* -semihosting-config target=gdb */ + return true; + } + + /* -semihosting-config target=auto */ + /* On the first call check if gdb is connected and remember. */ if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED : GDB_SYS_DISABLED); diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index a608a26..c633248 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -95,4 +95,10 @@ extern bool gdb_has_xml; /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; +/* Command line option defining whether semihosting should go via gdb or not */ +extern int semihosting_target; +#define SEMIHOSTING_TARGET_AUTO 0 +#define SEMIHOSTING_TARGET_NATIVE 1 +#define SEMIHOSTING_TARGET_GDB 2 + #endif diff --git a/qemu-options.hx b/qemu-options.hx index 64af16d..afab995 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3218,7 +3218,17 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting, STEXI @item -semihosting @findex -semihosting -Semihosting mode (ARM, M68K, Xtensa only). +Enable semihosting mode (ARM, M68K, Xtensa only). +ETEXI +DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, + "-semihosting-config [enable=on|off,]target=native|gdb|auto semihosting configuration\n", +QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) +STEXI +@item -semihosting-config [enable=on|off,]target=native|gdb|auto +@findex -semihosting-config +Enable semihosting and define where the semihosting calls will be addressed, +to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means +@code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only). ETEXI DEF("old-param", 0, QEMU_OPTION_old_param, "-old-param old param mode\n", QEMU_ARCH_ARM) diff --git a/vl.c b/vl.c index eb89d62..7cdfd49 100644 --- a/vl.c +++ b/vl.c @@ -554,6 +554,22 @@ static QemuOptsList qemu_icount_opts = { }, }; +static QemuOptsList qemu_semihosting_config_opts = { + .name = "semihosting-config", + .implied_opt_name = "enable", + .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head), + .desc = { + { + .name = "enable", + .type = QEMU_OPT_BOOL, + }, { + .name = "target", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + /** * Get machine options * @@ -2811,6 +2827,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_name_opts); qemu_add_opts(&qemu_numa_opts); qemu_add_opts(&qemu_icount_opts); + qemu_add_opts(&qemu_semihosting_config_opts); runstate_init(); @@ -3618,6 +3635,37 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_semihosting: semihosting_enabled = 1; + semihosting_target = SEMIHOSTING_TARGET_AUTO; + break; + case QEMU_OPTION_semihosting_config: + semihosting_enabled = 1; + opts = qemu_opts_parse(qemu_find_opts("semihosting-config"), + optarg, 0); + if (opts != NULL) { + semihosting_enabled = qemu_opt_get_bool(opts, "enable", + true); + const char *target = qemu_opt_get(opts, "target"); + if (target != NULL) { + if (strcmp("native", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_NATIVE; + } else if (strcmp("gdb", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_GDB; + } else if (strcmp("auto", target) == 0) { + semihosting_target = SEMIHOSTING_TARGET_AUTO; + } else { + fprintf(stderr, "Unsupported semihosting-config" + " %s\n", + optarg); + exit(1); + } + } else { + semihosting_target = SEMIHOSTING_TARGET_AUTO; + } + } else { + fprintf(stderr, "Unsupported semihosting-config %s\n", + optarg); + exit(1); + } break; case QEMU_OPTION_tdf: fprintf(stderr, "Warning: user space PIT time drift fix " -- cgit v1.1 From 57e3a0c7cb0ac2f0288890482e0a463adce2080a Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: target-arm: extend async excp masking This patch extends arm_excp_unmasked() to use lookup tables for determining whether IRQ and FIQ exceptions are masked. The lookup tables are based on the ARMv8 and ARMv7 specification physical interrupt masking tables. If EL3 is using AArch64 IRQ/FIQ masking is ignored in all exception levels other than EL3 if SCR.{FIQ|IRQ} is set to 1 (routed to EL3). Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-2-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 66 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7f80090..810cc0b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1247,27 +1247,50 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx) CPUARMState *env = cs->env_ptr; unsigned int cur_el = arm_current_el(env); unsigned int target_el = arm_excp_target_el(cs, excp_idx); - /* FIXME: Use actual secure state. */ - bool secure = false; - /* If in EL1/0, Physical IRQ routing to EL2 only happens from NS state. */ - bool irq_can_hyp = !secure && cur_el < 2 && target_el == 2; - - /* Don't take exceptions if they target a lower EL. */ + bool secure = arm_is_secure(env); + uint32_t scr; + uint32_t hcr; + bool pstate_unmasked; + int8_t unmasked = 0; + + /* Don't take exceptions if they target a lower EL. + * This check should catch any exceptions that would not be taken but left + * pending. + */ if (cur_el > target_el) { return false; } switch (excp_idx) { case EXCP_FIQ: - if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_FMO)) { - return true; - } - return !(env->daif & PSTATE_F); + /* If FIQs are routed to EL3 or EL2 then there are cases where we + * override the CPSR.F in determining if the exception is masked or + * not. If neither of these are set then we fall back to the CPSR.F + * setting otherwise we further assess the state below. + */ + hcr = (env->cp15.hcr_el2 & HCR_FMO); + scr = (env->cp15.scr_el3 & SCR_FIQ); + + /* When EL3 is 32-bit, the SCR.FW bit controls whether the CPSR.F bit + * masks FIQ interrupts when taken in non-secure state. If SCR.FW is + * set then FIQs can be masked by CPSR.F when non-secure but only + * when FIQs are only routed to EL3. + */ + scr &= !((env->cp15.scr_el3 & SCR_FW) && !hcr); + pstate_unmasked = !(env->daif & PSTATE_F); + break; + case EXCP_IRQ: - if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) { - return true; - } - return !(env->daif & PSTATE_I); + /* When EL3 execution state is 32-bit, if HCR.IMO is set then we may + * override the CPSR.I masking when in non-secure state. The SCR.IRQ + * setting has already been taken into consideration when setting the + * target EL, so it does not have a further affect here. + */ + hcr = (env->cp15.hcr_el2 & HCR_IMO); + scr = false; + pstate_unmasked = !(env->daif & PSTATE_I); + break; + case EXCP_VFIQ: if (secure || !(env->cp15.hcr_el2 & HCR_FMO)) { /* VFIQs are only taken when hypervized and non-secure. */ @@ -1283,6 +1306,21 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx) default: g_assert_not_reached(); } + + /* Use the target EL, current execution state and SCR/HCR settings to + * determine whether the corresponding CPSR bit is used to mask the + * interrupt. + */ + if ((target_el > cur_el) && (target_el != 1)) { + if (arm_el_is_aa64(env, 3) || ((scr || hcr) && (!secure))) { + unmasked = 1; + } + } + + /* The PSTATE bits only mask the interrupt if we have not overriden the + * ability above. + */ + return unmasked || pstate_unmasked; } static inline CPUARMState *cpu_init(const char *cpu_model) -- cgit v1.1 From 0eeb17d618361a0f4faddc160e33598b23da6dd5 Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: target-arm: add async excp target_el function Adds a dedicated function and a lookup table for determining the target exception level of IRQ and FIQ exceptions. The lookup table is taken from the ARMv7 and ARMv8 specification exception routing tables. Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-3-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/helper.c | 116 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 19 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index b74d348..a4483d8 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3761,6 +3761,101 @@ void switch_mode(CPUARMState *env, int mode) env->spsr = env->banked_spsr[i]; } +/* Physical Interrupt Target EL Lookup Table + * + * [ From ARM ARM section G1.13.4 (Table G1-15) ] + * + * The below multi-dimensional table is used for looking up the target + * exception level given numerous condition criteria. Specifically, the + * target EL is based on SCR and HCR routing controls as well as the + * currently executing EL and secure state. + * + * Dimensions: + * target_el_table[2][2][2][2][2][4] + * | | | | | +--- Current EL + * | | | | +------ Non-secure(0)/Secure(1) + * | | | +--------- HCR mask override + * | | +------------ SCR exec state control + * | +--------------- SCR mask override + * +------------------ 32-bit(0)/64-bit(1) EL3 + * + * The table values are as such: + * 0-3 = EL0-EL3 + * -1 = Cannot occur + * + * The ARM ARM target EL table includes entries indicating that an "exception + * is not taken". The two cases where this is applicable are: + * 1) An exception is taken from EL3 but the SCR does not have the exception + * routed to EL3. + * 2) An exception is taken from EL2 but the HCR does not have the exception + * routed to EL2. + * In these two cases, the below table contain a target of EL1. This value is + * returned as it is expected that the consumer of the table data will check + * for "target EL >= current EL" to ensure the exception is not taken. + * + * SCR HCR + * 64 EA AMO From + * BIT IRQ IMO Non-secure Secure + * EL3 FIQ RW FMO EL0 EL1 EL2 EL3 EL0 EL1 EL2 EL3 + */ +const int8_t target_el_table[2][2][2][2][2][4] = { + {{{{/* 0 0 0 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 0 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 0 1 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 1 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},},}, + {{{/* 0 1 0 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 0 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 1 1 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 1 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},},},}, + {{{{/* 1 0 0 0 */{ 1, 1, 2, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 0 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},}, + {{/* 1 0 1 0 */{ 1, 1, 1, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 1 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},},}, + {{{/* 1 1 0 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 0 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},}, + {{/* 1 1 1 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 1 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},},},}, +}; + +/* + * Determine the target EL for physical exceptions + */ +static inline uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, + uint32_t cur_el, bool secure) +{ + CPUARMState *env = cs->env_ptr; + int rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); + int scr; + int hcr; + int target_el; + int is64 = arm_el_is_aa64(env, 3); + + switch (excp_idx) { + case EXCP_IRQ: + scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ); + hcr = ((env->cp15.hcr_el2 & HCR_IMO) == HCR_IMO); + break; + case EXCP_FIQ: + scr = ((env->cp15.scr_el3 & SCR_FIQ) == SCR_FIQ); + hcr = ((env->cp15.hcr_el2 & HCR_FMO) == HCR_FMO); + break; + default: + scr = ((env->cp15.scr_el3 & SCR_EA) == SCR_EA); + hcr = ((env->cp15.hcr_el2 & HCR_AMO) == HCR_AMO); + break; + }; + + /* If HCR.TGE is set then HCR is treated as being 1 */ + hcr |= ((env->cp15.hcr_el2 & HCR_TGE) == HCR_TGE); + + /* Perform a table-lookup for the target EL given the current state */ + target_el = target_el_table[is64][scr][rw][hcr][secure][cur_el]; + + assert(target_el > 0); + + return target_el; +} + /* * Determine the target EL for a given exception type. */ @@ -3770,13 +3865,7 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) CPUARMState *env = &cpu->env; unsigned int cur_el = arm_current_el(env); unsigned int target_el; - /* FIXME: Use actual secure state. */ - bool secure = false; - - if (!env->aarch64) { - /* TODO: Add EL2 and 3 exception handling for AArch32. */ - return 1; - } + bool secure = arm_is_secure(env); switch (excp_idx) { case EXCP_HVC: @@ -3788,19 +3877,8 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) break; case EXCP_FIQ: case EXCP_IRQ: - { - const uint64_t hcr_mask = excp_idx == EXCP_FIQ ? HCR_FMO : HCR_IMO; - const uint32_t scr_mask = excp_idx == EXCP_FIQ ? SCR_FIQ : SCR_IRQ; - - target_el = 1; - if (!secure && (env->cp15.hcr_el2 & hcr_mask)) { - target_el = 2; - } - if (env->cp15.scr_el3 & scr_mask) { - target_el = 3; - } + target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure); break; - } case EXCP_VIRQ: case EXCP_VFIQ: target_el = 1; -- cgit v1.1 From ea30a4b824ecc3c829b70eb9999ac5457dc5790f Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: target-arm: add banked register accessors If EL3 is in AArch32 state certain cp registers are banked (secure and non-secure instance). When reading or writing to coprocessor registers the following macros can be used. - A32_BANKED macros are used for choosing the banked register based on provided input security argument. This macro is used to choose the bank during translation of MRC/MCR instructions that are dependent on something other than the current secure state. - A32_BANKED_CURRENT macros are used for choosing the banked register based on current secure state. This is NOT to be used for choosing the bank used during translation as it breaks monitor mode. If EL3 is operating in AArch64 state coprocessor registers are not banked anymore. The macros use the non-secure instance (_ns) in this case, which is architecturally mapped to the AArch64 EL register. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-4-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 810cc0b..1ad5d38 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -817,6 +817,33 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el) return arm_feature(env, ARM_FEATURE_AARCH64); } +/* Macros for accessing a specified CP register bank */ +#define A32_BANKED_REG_GET(_env, _regname, _secure) \ + ((_secure) ? (_env)->cp15._regname##_s : (_env)->cp15._regname##_ns) + +#define A32_BANKED_REG_SET(_env, _regname, _secure, _val) \ + do { \ + if (_secure) { \ + (_env)->cp15._regname##_s = (_val); \ + } else { \ + (_env)->cp15._regname##_ns = (_val); \ + } \ + } while (0) + +/* Macros for automatically accessing a specific CP register bank depending on + * the current secure state of the system. These macros are not intended for + * supporting instruction translation reads/writes as these are dependent + * solely on the SCR.NS bit and not the mode. + */ +#define A32_BANKED_CURRENT_REG_GET(_env, _regname) \ + A32_BANKED_REG_GET((_env), _regname, \ + ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env)))) + +#define A32_BANKED_CURRENT_REG_SET(_env, _regname, _val) \ + A32_BANKED_REG_SET((_env), _regname, \ + ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env))), \ + (_val)) + void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx); -- cgit v1.1 From 3f342b9e0e64ad681cd39840bfa75ef12d2807c1 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 11 Dec 2014 12:07:48 +0000 Subject: target-arm: add non-secure Translation Block flag This patch is based on idea found in patch at git://github.com/jowinter/qemu-trustzone.git f3d955c6c0ed8c46bc0eb10b634201032a651dd2 by Johannes Winter . The TBFLAG captures the SCR NS secure state at the time when a TB is created so the correct bank is accessed on system register accesses. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-5-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 27 +++++++++++++++++++++++++++ target-arm/translate.c | 1 + target-arm/translate.h | 1 + 3 files changed, 29 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1ad5d38..6881098 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -817,6 +817,22 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el) return arm_feature(env, ARM_FEATURE_AARCH64); } +/* Function for determing whether guest cp register reads and writes should + * access the secure or non-secure bank of a cp register. When EL3 is + * operating in AArch32 state, the NS-bit determines whether the secure + * instance of a cp register should be used. When EL3 is AArch64 (or if + * it doesn't exist at all) then there is no register banking, and all + * accesses are to the non-secure version. + */ +static inline bool access_secure_reg(CPUARMState *env) +{ + bool ret = (arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3) && + !(env->cp15.scr_el3 & SCR_NS)); + + return ret; +} + /* Macros for accessing a specified CP register bank */ #define A32_BANKED_REG_GET(_env, _regname, _secure) \ ((_secure) ? (_env)->cp15._regname##_s : (_env)->cp15._regname##_ns) @@ -1467,6 +1483,12 @@ static inline bool arm_singlestep_active(CPUARMState *env) */ #define ARM_TBFLAG_XSCALE_CPAR_SHIFT 20 #define ARM_TBFLAG_XSCALE_CPAR_MASK (3 << ARM_TBFLAG_XSCALE_CPAR_SHIFT) +/* Indicates whether cp register reads and writes by guest code should access + * the secure or nonsecure bank of banked registers; note that this is not + * the same thing as the current security state of the processor! + */ +#define ARM_TBFLAG_NS_SHIFT 22 +#define ARM_TBFLAG_NS_MASK (1 << ARM_TBFLAG_NS_SHIFT) /* Bit usage when in AArch64 state */ #define ARM_TBFLAG_AA64_EL_SHIFT 0 @@ -1511,6 +1533,8 @@ static inline bool arm_singlestep_active(CPUARMState *env) (((F) & ARM_TBFLAG_AA64_SS_ACTIVE_MASK) >> ARM_TBFLAG_AA64_SS_ACTIVE_SHIFT) #define ARM_TBFLAG_AA64_PSTATE_SS(F) \ (((F) & ARM_TBFLAG_AA64_PSTATE_SS_MASK) >> ARM_TBFLAG_AA64_PSTATE_SS_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) @@ -1560,6 +1584,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, if (privmode) { *flags |= ARM_TBFLAG_PRIV_MASK; } + if (!(access_secure_reg(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 af51568..17c459a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -11031,6 +11031,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, #if !defined(CONFIG_USER_ONLY) dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0); #endif + dc->ns = ARM_TBFLAG_NS(tb->flags); dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags); dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags); dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags); diff --git a/target-arm/translate.h b/target-arm/translate.h index 41a9071..f6ee789 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; #endif + bool ns; /* Use non-secure CPREG bank on access */ bool cpacr_fpen; /* FP enabled via CPACR.FPEN */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; -- cgit v1.1 From c3e302606253a17568dc3ef30238f102468f7ee1 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: add CPREG secure state support Prepare ARMCPRegInfo to support specifying two fieldoffsets per register definition. This will allow us to keep one register definition for banked registers (different offsets for secure/ non-secure world). Also added secure state tracking field and flags. This allows for identification of the register info secure state. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-6-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 6881098..dd7d229 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -993,6 +993,21 @@ enum { ARM_CP_STATE_BOTH = 2, }; +/* ARM CP register secure state flags. These flags identify security state + * attributes for a given CP register entry. + * The existence of both or neither secure and non-secure flags indicates that + * the register has both a secure and non-secure hash entry. A single one of + * these flags causes the register to only be hashed for the specified + * security state. + * Although definitions may have any combination of the S/NS bits, each + * registered entry will only have one to identify whether the entry is secure + * or non-secure. + */ +enum { + ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */ + ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */ +}; + /* Return true if cptype is a valid type field. This is used to try to * catch errors where the sentinel has been accidentally left off the end * of a list of registers. @@ -1127,6 +1142,8 @@ struct ARMCPRegInfo { int type; /* Access rights: PL*_[RW] */ int access; + /* Security state: ARM_CP_SECSTATE_* bits/values */ + int secure; /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when * this register was defined: can be used to hand data through to the * register read/write functions, since they are passed the ARMCPRegInfo*. @@ -1136,12 +1153,27 @@ struct ARMCPRegInfo { * fieldoffset is non-zero, the reset value of the register. */ uint64_t resetvalue; - /* Offset of the field in CPUARMState for this register. This is not - * needed if either: + /* Offset of the field in CPUARMState for this register. + * + * This is not needed if either: * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs * 2. both readfn and writefn are specified */ ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */ + + /* Offsets of the secure and non-secure fields in CPUARMState for the + * register if it is banked. These fields are only used during the static + * registration of a register. During hashing the bank associated + * with a given security state is copied to fieldoffset which is used from + * there on out. + * + * It is expected that register definitions use either fieldoffset or + * bank_fieldoffsets in the definition but not both. It is also expected + * that both bank offsets are set when defining a banked register. This + * use indicates that a register is banked. + */ + ptrdiff_t bank_fieldoffsets[2]; + /* Function for making any access checks for this register in addition to * those specified by the 'access' permissions bits. If NULL, no extra * checks required. The access check is performed at runtime, not at -- cgit v1.1 From 51a79b039728277e35fd19f7a7b4bc6cb323697f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: add secure state bit to CPREG hash Added additional NS-bit to CPREG hash encoding. Updated hash lookup locations to specify hash bit currently set to non-secure. Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-7-git-send-email-greg.bellows@linaro.org [PMM: fix uses of ENCODE_CP_REG in kvm32.c to add extra argument] Signed-off-by: Peter Maydell --- target-arm/cpu.h | 25 ++++++++++++++++++++----- target-arm/helper.c | 7 ++++--- target-arm/kvm32.c | 6 +++--- target-arm/translate.c | 14 +++++++++----- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index dd7d229..532f698 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -879,6 +879,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?) + * non-secure/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; @@ -896,9 +897,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 29 +#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT) + +#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \ + ((ns) << CP_REG_NS_SHIFT | ((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 | \ @@ -917,8 +925,15 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid) uint32_t cpregid = kvmid; if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) { cpregid |= CP_REG_AA64_MASK; - } else if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { - cpregid |= (1 << 15); + } else { + if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { + cpregid |= (1 << 15); + } + + /* KVM is always non-secure so add the NS flag on AArch32 register + * entries. + */ + cpregid |= 1 << CP_REG_NS_SHIFT; } return cpregid; } diff --git a/target-arm/helper.c b/target-arm/helper.c index a4483d8..5fc8203 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3287,7 +3287,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) } static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, int state, + void *opaque, int state, int secstate, int crm, int opc1, int opc2) { /* Private utility function for define_one_arm_cp_reg_with_opaque(): @@ -3296,6 +3296,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, uint32_t *key = g_new(uint32_t, 1); ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; + int ns = (r->secure & ARM_CP_SECSTATE_NS) ? 1 : 0; if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) { /* The AArch32 view of a shared register sees the lower 32 bits * of a 64 bit backing field. It is not migratable as the AArch64 @@ -3327,7 +3328,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, ns, r2->crn, crm, opc1, opc2); } if (opaque) { r2->opaque = opaque; @@ -3477,7 +3478,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, continue; } add_cpreg_to_hashtable(cpu, r, opaque, state, - crm, opc1, opc2); + ARM_CP_SECSTATE_NS, crm, opc1, opc2); } } } diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index 5ec4eb1..a5e67da 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -51,17 +51,17 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) struct kvm_one_reg idregs[] = { { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 0, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 0, 0, 0), .addr = (uintptr_t)&midr, }, { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 1, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 1, 0, 0), .addr = (uintptr_t)&id_pfr0, }, { .id = KVM_REG_ARM | KVM_REG_SIZE_U32 - | ENCODE_CP_REG(15, 0, 0, 2, 0, 0), + | ENCODE_CP_REG(15, 0, 0, 0, 2, 0, 0), .addr = (uintptr_t)&id_isar0, }, { diff --git a/target-arm/translate.c b/target-arm/translate.c index 17c459a..b52c758 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7091,7 +7091,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) rt = (insn >> 12) & 0xf; ri = get_arm_cp_reginfo(s->cp_regs, - ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2)); + ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2)); if (ri) { /* Check access permissions */ if (!cp_access_ok(s->current_el, ri, isread)) { @@ -7281,12 +7281,16 @@ static int disas_coproc_insn(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, + s->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, + s->ns ? "non-secure" : "secure"); } return 1; -- cgit v1.1 From 3f3c82a57d128aa3ec823aa8032867c3a6e2e795 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: insert AArch32 cpregs twice into hashtable Prepare for cp register banking by inserting every cp register twice, once for secure world and once for non-secure world. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-8-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/helper.c | 98 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 5fc8203..96284f1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3296,23 +3296,59 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, uint32_t *key = g_new(uint32_t, 1); ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; - int ns = (r->secure & ARM_CP_SECSTATE_NS) ? 1 : 0; - if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) { - /* The AArch32 view of a shared register sees the lower 32 bits - * of a 64 bit backing field. It is not migratable as the AArch64 - * view handles that. AArch64 also handles reset. - * We assume it is a cp15 register if the .cp field is left unset. + int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0; + + /* Reset the secure state to the specific incoming state. This is + * necessary as the register may have been defined with both states. + */ + r2->secure = secstate; + + if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + /* Register is banked (using both entries in array). + * Overwriting fieldoffset as the array is only used to define + * banked registers but later only fieldoffset is used. */ - if (r2->cp == 0) { - r2->cp = 15; + r2->fieldoffset = r->bank_fieldoffsets[ns]; + } + + if (state == ARM_CP_STATE_AA32) { + if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) { + /* If the register is banked then we don't need to migrate or + * reset the 32-bit instance in certain cases: + * + * 1) If the register has both 32-bit and 64-bit instances then we + * can count on the 64-bit instance taking care of the + * non-secure bank. + * 2) If ARMv8 is enabled then we can count on a 64-bit version + * taking care of the secure bank. This requires that separate + * 32 and 64-bit definitions are provided. + */ + if ((r->state == ARM_CP_STATE_BOTH && ns) || + (arm_feature(&cpu->env, ARM_FEATURE_V8) && !ns)) { + r2->type |= ARM_CP_NO_MIGRATE; + r2->resetfn = arm_cp_reset_ignore; + } + } else if ((secstate != r->secure) && !ns) { + /* The register is not banked so we only want to allow migration of + * the non-secure instance. + */ + r2->type |= ARM_CP_NO_MIGRATE; + r2->resetfn = arm_cp_reset_ignore; } - r2->type |= ARM_CP_NO_MIGRATE; - r2->resetfn = arm_cp_reset_ignore; + + if (r->state == ARM_CP_STATE_BOTH) { + /* We assume it is a cp15 register if the .cp field is left unset. + */ + if (r2->cp == 0) { + r2->cp = 15; + } + #ifdef HOST_WORDS_BIGENDIAN - if (r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); - } + if (r2->fieldoffset) { + r2->fieldoffset += sizeof(uint32_t); + } #endif + } } if (state == ARM_CP_STATE_AA64) { /* To allow abbreviation of ARMCPRegInfo @@ -3461,10 +3497,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, */ if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) { if (r->access & PL3_R) { - assert(r->fieldoffset || r->readfn); + assert((r->fieldoffset || + (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || + r->readfn); } if (r->access & PL3_W) { - assert(r->fieldoffset || r->writefn); + assert((r->fieldoffset || + (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) || + r->writefn); } } /* Bad type field probably means missing sentinel at end of reg list */ @@ -3477,8 +3517,32 @@ 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, - ARM_CP_SECSTATE_NS, crm, opc1, opc2); + if (state == ARM_CP_STATE_AA32) { + /* Under AArch32 CP registers can be common + * (same for secure and non-secure world) or banked. + */ + switch (r->secure) { + case ARM_CP_SECSTATE_S: + case ARM_CP_SECSTATE_NS: + add_cpreg_to_hashtable(cpu, r, opaque, state, + r->secure, crm, opc1, opc2); + break; + default: + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_S, + crm, opc1, opc2); + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_NS, + crm, opc1, opc2); + break; + } + } else { + /* AArch64 registers get mapped to non-secure instance + * of AArch32 */ + add_cpreg_to_hashtable(cpu, r, opaque, state, + ARM_CP_SECSTATE_NS, + crm, opc1, opc2); + } } } } -- cgit v1.1 From 0f1a3b2470d798ad5335eb9d6236f02ff64e31a8 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: move AArch32 SCR into security reglist Define a new ARM CP register info list for the ARMv7 Security Extension feature. Register that list only for ARM cores with Security Extension/EL3 support. Moving AArch32 SCR into Security Extension register group. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-9-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/helper.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 96284f1..d3180dd 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -898,9 +898,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_RW, .writefn = vbar_write, .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[1]), .resetvalue = 0 }, - { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), - .resetvalue = 0, .writefn = scr_write }, { .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 }, @@ -2335,11 +2332,18 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { .access = PL3_RW, .writefn = vbar_write, .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[3]), .resetvalue = 0 }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo el3_cp_reginfo[] = { { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64, - .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0, .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3), - .writefn = scr_write }, + .resetvalue = 0, .writefn = scr_write }, + { .name = "SCR", .type = ARM_CP_NO_MIGRATE, + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0, + .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), + .resetfn = arm_cp_reset_ignore, .writefn = scr_write }, REGINFO_SENTINEL }; @@ -2960,7 +2964,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } if (arm_feature(env, ARM_FEATURE_EL3)) { - define_arm_cp_regs(cpu, v8_el3_cp_reginfo); + if (arm_feature(env, ARM_FEATURE_V8)) { + define_arm_cp_regs(cpu, v8_el3_cp_reginfo); + } + define_arm_cp_regs(cpu, el3_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_MPU)) { /* These are the MPU registers prior to PMSAv6. Any new -- cgit v1.1 From de38d23b542efca54108ef28bcc0efe96f378d2e Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: implement IRQ/FIQ routing to Monitor mode SCR.{IRQ/FIQ} bits allow 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 Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-10-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index d3180dd..973b5a9 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4233,12 +4233,21 @@ void arm_cpu_do_interrupt(CPUState *cs) /* Disable IRQ and imprecise data aborts. */ mask = CPSR_A | CPSR_I; offset = 4; + if (env->cp15.scr_el3 & 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.scr_el3 & SCR_FIQ) { + /* FIQ routed to monitor mode */ + new_mode = ARM_CPU_MODE_MON; + } offset = 4; break; case EXCP_SMC: -- cgit v1.1 From 770225764f831031d2e1453f69c365eb1b647d87 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:49 +0000 Subject: target-arm: add NSACR register Implements NSACR register with corresponding read/write functions for ARMv7 and ARMv8. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-11-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 532f698..2afe93a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -181,6 +181,7 @@ typedef struct CPUARMState { uint64_t c1_sys; /* System control register. */ uint64_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ + uint32_t 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 973b5a9..ace7ef9 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2344,6 +2344,10 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0, .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), .resetfn = arm_cp_reset_ignore, .writefn = scr_write }, + /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */ + { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, + .access = PL3_W | PL1_R, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.nsacr) }, REGINFO_SENTINEL }; -- cgit v1.1 From 144634ae6c1618dcee6aced9c0d4427844154091 Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Thu, 11 Dec 2014 12:07:50 +0000 Subject: target-arm: add SDER definition Added CP register defintions for SDER and SDER32_EL3 as well as cp15.sder for register storage. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-12-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2afe93a..12bd6ec 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -181,6 +181,7 @@ typedef struct CPUARMState { uint64_t c1_sys; /* System control register. */ uint64_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ + uint64_t sder; /* Secure debug enable register. */ uint32_t 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 ace7ef9..0d49489 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2344,6 +2344,14 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0, .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), .resetfn = arm_cp_reset_ignore, .writefn = scr_write }, + { .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL3_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.sder) }, + { .name = "SDER", + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL3_RW, .resetvalue = 0, + .fieldoffset = offsetoflow32(CPUARMState, cp15.sder) }, /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */ { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL3_W | PL1_R, .resetvalue = 0, -- cgit v1.1 From e89e51a17ea0d8aef9bf9b766c98f963e835fbf2 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:50 +0000 Subject: target-arm: add MVBAR support Use MVBAR register as exception vector base address for exceptions taken to CPU monitor mode. Signed-off-by: Sergey Fedorov Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-13-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 12bd6ec..cdf2dd7 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -211,6 +211,7 @@ typedef struct CPUARMState { uint32_t c9_pminten; /* perf monitor interrupt enables */ uint64_t mair_el1; uint64_t vbar_el[4]; /* vector base address register */ + uint32_t mvbar; /* (monitor) vector base address register */ uint32_t c13_fcse; /* FCSE PID. */ uint64_t contextidr_el1; /* Context ID. */ uint64_t tpidr_el0; /* User RW Thread register. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 0d49489..412c465 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2356,6 +2356,9 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, .access = PL3_W | PL1_R, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.nsacr) }, + { .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1, + .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.mvbar) }, REGINFO_SENTINEL }; @@ -4272,16 +4275,16 @@ 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 (env->cp15.c1_sys & SCTLR_V) { - /* when enabled, base address cannot be remapped. */ + + if (new_mode == ARM_CPU_MODE_MON) { + addr += env->cp15.mvbar; + } else if (env->cp15.c1_sys & 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 += env->cp15.vbar_el[1]; -- cgit v1.1 From 137feaa9a1622620adf19c0b707883dd990738e2 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:50 +0000 Subject: target-arm: add SCTLR_EL3 and make SCTLR banked Implements SCTLR_EL3 and uses secure/non-secure instance when needed. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-14-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 2 +- target-arm/cpu.c | 8 ++++-- target-arm/cpu.h | 10 ++++++- target-arm/helper.c | 72 +++++++++++++++++++++++++++++--------------------- target-arm/op_helper.c | 2 +- 5 files changed, 59 insertions(+), 35 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 693dfec..11d51af 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -273,7 +273,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.sctlr_ns = 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.c b/target-arm/cpu.c index 5ce7350..fdb7b35 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -109,7 +109,7 @@ static void arm_cpu_reset(CPUState *s) #if defined(CONFIG_USER_ONLY) env->pstate = PSTATE_MODE_EL0t; /* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */ - env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE; + env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE; /* and to the FP/Neon instructions */ env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3); #else @@ -167,7 +167,11 @@ static void arm_cpu_reset(CPUState *s) env->thumb = initial_pc & 1; } - if (env->cp15.c1_sys & SCTLR_V) { + /* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently + * executing as AArch32 then check if highvecs are enabled and + * adjust the PC accordingly. + */ + if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) { env->regs[15] = 0xFFFF0000; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index cdf2dd7..6559aa8 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -178,7 +178,15 @@ typedef struct CPUARMState { struct { uint32_t c0_cpuid; uint64_t c0_cssel; /* Cache size selection. */ - uint64_t c1_sys; /* System control register. */ + union { /* System control register. */ + struct { + uint64_t _unused_sctlr; + uint64_t sctlr_ns; + uint64_t hsctlr; + uint64_t sctlr_s; + }; + uint64_t sctlr_el[4]; + }; uint64_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ uint64_t sder; /* Secure debug enable register. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 412c465..769a182 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1908,7 +1908,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri, static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri) { - if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -1926,7 +1926,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_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCI)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -2003,7 +2003,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_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_DZE)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -2042,6 +2042,24 @@ static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) update_spsel(env, val); } +static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + + if (raw_read(env, ri) == value) { + /* Skip the TLB flush if nothing actually changed; Linux likes + * to do a lot of pointless SCTLR writes. + */ + return; + } + + 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); +} + static const ARMCPRegInfo v8_cp_reginfo[] = { /* Minimal set of EL0-visible registers. This will need to be expanded * significantly for system emulation of AArch64 CPUs. @@ -2311,6 +2329,10 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { }; static const ARMCPRegInfo v8_el3_cp_reginfo[] = { + { .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0, + .access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write, + .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1, @@ -2362,30 +2384,12 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { REGINFO_SENTINEL }; -static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - ARMCPU *cpu = arm_env_get_cpu(env); - - if (raw_read(env, ri) == value) { - /* Skip the TLB flush if nothing actually changed; Linux likes - * to do a lot of pointless SCTLR writes. - */ - return; - } - - 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); -} - 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_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCT)) { return CP_ACCESS_TRAP; } return CP_ACCESS_OK; @@ -3182,8 +3186,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) { 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), + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, + .access = PL1_RW, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), + offsetof(CPUARMState, cp15.sctlr_ns) }, .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr, .raw_writefn = raw_write, }; @@ -4278,7 +4284,7 @@ void arm_cpu_do_interrupt(CPUState *cs) if (new_mode == ARM_CPU_MODE_MON) { addr += env->cp15.mvbar; - } else if (env->cp15.c1_sys & SCTLR_V) { + } else if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) { /* High vectors. When enabled, base address cannot be remapped. */ addr += 0xffff0000; } else { @@ -4308,7 +4314,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 = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0; } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; @@ -4339,7 +4345,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 (A32_BANKED_CURRENT_REG_GET(env, sctlr) & (SCTLR_S | SCTLR_R)) { case SCTLR_S: return is_user ? 0 : PAGE_READ; case SCTLR_R: @@ -4588,7 +4594,8 @@ 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 ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_AFE) + && (ap & 1) == 0) { /* Access flag fault. */ code = (code == 15) ? 6 : 3; goto do_fault; @@ -4921,11 +4928,16 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address, hwaddr *phys_ptr, int *prot, target_ulong *page_size) { + /* This is not entirely correct as get_phys_addr() can also be called + * from ats_write() for an address translation of a specific regime. + */ + uint32_t sctlr = A32_BANKED_CURRENT_REG_GET(env, sctlr); + /* Fast Context Switch Extension. */ if (address < 0x02000000) address += env->cp15.c13_fcse; - if ((env->cp15.c1_sys & SCTLR_M) == 0) { + if ((sctlr & SCTLR_M) == 0) { /* MMU/MPU disabled. */ *phys_ptr = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -4938,7 +4950,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 (sctlr & 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 62012c3..a8dea5a 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -361,7 +361,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_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) { + if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { raise_exception(env, EXCP_UDEF); } -- cgit v1.1 From 6e8801f9dea9e10449f4fd7d85dbe8cab708a686 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:50 +0000 Subject: target-arm: respect SCR.FW, SCR.AW and SCTLR.NMFI Add checks of SCR AW/FW bits when performing writes of CPSR. These SCR bits are used to control whether the CPSR masking bits can be adjusted from non-secure state. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-15-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/helper.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index 769a182..d43d208 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3644,6 +3644,8 @@ uint32_t cpsr_read(CPUARMState *env) void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { + uint32_t changed_daif; + if (mask & CPSR_NZCV) { env->ZF = (~val) & CPSR_Z; env->NF = val; @@ -3666,6 +3668,58 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->GE = (val >> 16) & 0xf; } + /* In a V7 implementation that includes the security extensions but does + * not include Virtualization Extensions the SCR.FW and SCR.AW bits control + * whether non-secure software is allowed to change the CPSR_F and CPSR_A + * bits respectively. + * + * In a V8 implementation, it is permitted for privileged software to + * change the CPSR A/F bits regardless of the SCR.AW/FW bits. + */ + if (!arm_feature(env, ARM_FEATURE_V8) && + arm_feature(env, ARM_FEATURE_EL3) && + !arm_feature(env, ARM_FEATURE_EL2) && + !arm_is_secure(env)) { + + changed_daif = (env->daif ^ val) & mask; + + if (changed_daif & CPSR_A) { + /* Check to see if we are allowed to change the masking of async + * abort exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_AW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_A flag from " + "non-secure world with SCR.AW bit clear\n"); + mask &= ~CPSR_A; + } + } + + if (changed_daif & CPSR_F) { + /* Check to see if we are allowed to change the masking of FIQ + * exceptions from a non-secure state. + */ + if (!(env->cp15.scr_el3 & SCR_FW)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Ignoring attempt to switch CPSR_F flag from " + "non-secure world with SCR.FW bit clear\n"); + 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 ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & 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; + } + } + } + env->daif &= ~(CPSR_AIF & mask); env->daif |= val & CPSR_AIF & mask; -- cgit v1.1 From b85a1fd61c4d72c7928cd9b70f9f59fb2895936d Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:50 +0000 Subject: target-arm: make CSSELR banked Rename CSSELR (cache size selection register) and add secure instance (AArch32). Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-16-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 14 +++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 6559aa8..f06d209 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -177,7 +177,15 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; - uint64_t c0_cssel; /* Cache size selection. */ + union { /* Cache size selection */ + struct { + uint64_t _unused_csselr0; + uint64_t csselr_ns; + uint64_t _unused_csselr1; + uint64_t csselr_s; + }; + uint64_t csselr_el[4]; + }; union { /* System control register. */ struct { uint64_t _unused_sctlr; diff --git a/target-arm/helper.c b/target-arm/helper.c index d43d208..961dd37 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -776,7 +776,14 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = arm_env_get_cpu(env); - return cpu->ccsidr[env->cp15.c0_cssel]; + + /* Acquire the CSSELR index from the bank corresponding to the CCSIDR + * bank + */ + uint32_t index = A32_BANKED_REG_GET(env, csselr, + ri->secure & ARM_CP_SECSTATE_S); + + return cpu->ccsidr[index]; } static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -903,8 +910,9 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_MIGRATE }, { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c0_cssel), - .writefn = csselr_write, .resetvalue = 0 }, + .access = PL1_RW, .writefn = csselr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s), + offsetof(CPUARMState, cp15.csselr_ns) } }, /* Auxiliary ID register: this actually has an IMPDEF value but for now * just RAZ for all cores: */ -- cgit v1.1 From 7dd8c9af0d9d18fb3e54a4843b3bb1398bd330bc Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make TTBR0/1 banked Adds secure and non-secure bank register suport for TTBR0 and TTBR1. Changes include adding secure and non-secure instances of ttbr0 and ttbr1 as well as a CP register definition for TTBR0_EL3. Added a union containing both EL based array fields and secure and non-secure fields mapped to them. Updated accesses to use A32_BANKED_CURRENT_REG_GET macro. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-17-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 2 +- target-arm/cpu.h | 20 ++++++++++++++++++-- target-arm/helper.c | 37 +++++++++++++++++++++++++------------ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 11d51af..2b00b59 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -275,7 +275,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I; s->cpu->env.cp15.sctlr_ns = 0; s->cpu->env.cp15.c1_coproc = 0; - s->cpu->env.cp15.ttbr0_el1 = 0; + s->cpu->env.cp15.ttbr0_el[1] = 0; s->cpu->env.cp15.c3 = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index f06d209..efe7010 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -199,8 +199,24 @@ typedef struct CPUARMState { uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ uint64_t sder; /* Secure debug enable register. */ uint32_t nsacr; /* Non-secure access control register. */ - uint64_t ttbr0_el1; /* MMU translation table base 0. */ - uint64_t ttbr1_el1; /* MMU translation table base 1. */ + union { /* MMU translation table base 0. */ + struct { + uint64_t _unused_ttbr0_0; + uint64_t ttbr0_ns; + uint64_t _unused_ttbr0_1; + uint64_t ttbr0_s; + }; + uint64_t ttbr0_el[4]; + }; + union { /* MMU translation table base 1. */ + struct { + uint64_t _unused_ttbr1_0; + uint64_t ttbr1_ns; + uint64_t _unused_ttbr1_1; + uint64_t ttbr1_s; + }; + uint64_t ttbr1_el[4]; + }; uint64_t c2_control; /* MMU translation table base control. */ uint32_t c2_mask; /* MMU translation table base selection mask. */ uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 961dd37..171b841 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1646,13 +1646,15 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .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), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_ns) } }, { .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), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_ns) } }, { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .writefn = vmsa_tcr_el1_write, @@ -1883,11 +1885,13 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .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, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, REGINFO_SENTINEL }; @@ -2341,6 +2345,10 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0, .access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write, .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) }, + { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0, + .access = PL3_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1, @@ -4442,18 +4450,23 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, static bool get_level1_table_address(CPUARMState *env, uint32_t *table, uint32_t address) { + /* We only get here if EL1 is running in AArch32. If EL3 is running in + * AArch32 there is a secure and non-secure instance of the translation + * table registers. + */ if (address & env->cp15.c2_mask) { if ((env->cp15.c2_control & TTBCR_PD1)) { /* Translation table walk disabled for TTBR1 */ return false; } - *table = env->cp15.ttbr1_el1 & 0xffffc000; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000; } else { if ((env->cp15.c2_control & TTBCR_PD0)) { /* Translation table walk disabled for TTBR0 */ return false; } - *table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & + env->cp15.c2_base_mask; } *table |= (address >> 18) & 0x3ffc; return true; @@ -4758,7 +4771,7 @@ 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; + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); epd = extract32(env->cp15.c2_control, 7, 1); tsz = t0sz; @@ -4770,7 +4783,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, granule_sz = 11; } } else { - ttbr = env->cp15.ttbr1_el1; + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); epd = extract32(env->cp15.c2_control, 23, 1); tsz = t1sz; -- cgit v1.1 From 11f136ee25232a00f433cefe98ee33cd614ecccc Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make TTBCR banked Adds secure and non-secure bank register suport for TTBCR. Added new struct to compartmentalize the TCR data and masks. Removed old tcr/ttbcr data and added a 4 element array of the new structs in cp15. This allows for one entry per EL. Added a CP register definition for TCR_EL3. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-18-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 11 +++++--- target-arm/helper.c | 72 ++++++++++++++++++++++++++++++++------------------ target-arm/internals.h | 6 ++--- 3 files changed, 58 insertions(+), 31 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index efe7010..0eaf981 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -120,6 +120,12 @@ typedef struct ARMGenericTimer { #define GTIMER_VIRT 1 #define NUM_GTIMERS 2 +typedef struct { + uint64_t raw_tcr; + uint32_t mask; + uint32_t base_mask; +} TCR; + typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; @@ -217,9 +223,8 @@ typedef struct CPUARMState { }; uint64_t ttbr1_el[4]; }; - uint64_t c2_control; /* MMU translation table base control. */ - uint32_t c2_mask; /* MMU translation table base selection mask. */ - uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ + /* MMU translation table base control. */ + TCR tcr_el[4]; uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ uint32_t c3; /* MMU domain access control register diff --git a/target-arm/helper.c b/target-arm/helper.c index 171b841..b80608c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -136,6 +136,11 @@ static void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return (char *)env + ri->fieldoffset; +} + static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) { /* Raw read of a coprocessor register (as needed for migration, etc). */ @@ -1560,6 +1565,7 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + TCR *tcr = raw_ptr(env, ri); int maskshift = extract32(value, 0, 3); if (!arm_feature(env, ARM_FEATURE_V8)) { @@ -1578,14 +1584,15 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - /* Note that we always calculate c2_mask and c2_base_mask, but + /* Update the masks corresponding to the the TCR bank being written + * Note that we always calculate mask and base_mask, but * they are only used for short-descriptor tables (ie if EAE is 0); - * for long-descriptor tables the TTBCR fields are used differently - * and the c2_mask and c2_base_mask values are meaningless. + * for long-descriptor tables the TCR fields are used differently + * and the mask and base_mask values are meaningless. */ - raw_write(env, ri, value); - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift); + tcr->raw_tcr = value; + tcr->mask = ~(((uint32_t)0xffffffffu) >> maskshift); + tcr->base_mask = ~((uint32_t)0x3fffu >> maskshift); } static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1604,19 +1611,25 @@ static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void vmsa_ttbcr_reset(CPUARMState *env, const ARMCPRegInfo *ri) { - env->cp15.c2_base_mask = 0xffffc000u; - raw_write(env, ri, 0); - env->cp15.c2_mask = 0; + TCR *tcr = raw_ptr(env, ri); + + /* Reset both the TCR as well as the masks corresponding to the bank of + * the TCR being reset. + */ + tcr->raw_tcr = 0; + tcr->mask = 0; + tcr->base_mask = 0xffffc000u; } static void vmsa_tcr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = arm_env_get_cpu(env); + TCR *tcr = raw_ptr(env, ri); /* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */ tlb_flush(CPU(cpu), 1); - raw_write(env, ri, value); + tcr->raw_tcr = value; } static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1659,11 +1672,12 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .writefn = vmsa_tcr_el1_write, .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, - .fieldoffset = offsetof(CPUARMState, cp15.c2_control) }, + .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[1]) }, { .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, - .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) }, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), + offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, /* 64-bit FAR; this entry also gives us the AArch32 DFAR */ { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, @@ -2349,6 +2363,11 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0, .access = PL3_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) }, + { .name = "TCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2, + .access = PL3_RW, .writefn = vmsa_tcr_el1_write, + .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, + .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1, @@ -4450,23 +4469,25 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, static bool get_level1_table_address(CPUARMState *env, uint32_t *table, uint32_t address) { + /* Get the TCR bank based on our security state */ + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + /* We only get here if EL1 is running in AArch32. If EL3 is running in * AArch32 there is a secure and non-secure instance of the translation * table registers. */ - if (address & env->cp15.c2_mask) { - if ((env->cp15.c2_control & TTBCR_PD1)) { + if (address & tcr->mask) { + if (tcr->raw_tcr & TTBCR_PD1) { /* Translation table walk disabled for TTBR1 */ return false; } *table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000; } else { - if ((env->cp15.c2_control & TTBCR_PD0)) { + if (tcr->raw_tcr & TTBCR_PD0) { /* Translation table walk disabled for TTBR0 */ return false; } - *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & - env->cp15.c2_base_mask; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & tcr->base_mask; } *table |= (address >> 18) & 0x3ffc; return true; @@ -4720,13 +4741,14 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, int32_t granule_sz = 9; int32_t va_size = 32; int32_t tbi = 0; + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; if (arm_el_is_aa64(env, 1)) { va_size = 64; if (extract64(address, 55, 1)) - tbi = extract64(env->cp15.c2_control, 38, 1); + tbi = extract64(tcr->raw_tcr, 38, 1); else - tbi = extract64(env->cp15.c2_control, 37, 1); + tbi = extract64(tcr->raw_tcr, 37, 1); tbi *= 8; } @@ -4735,12 +4757,12 @@ 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(tcr->raw_tcr, 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(tcr->raw_tcr, 16, 6); if (arm_el_is_aa64(env, 1)) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); @@ -4772,10 +4794,10 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, */ if (ttbr_select == 0) { ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); - epd = extract32(env->cp15.c2_control, 7, 1); + epd = extract32(tcr->raw_tcr, 7, 1); tsz = t0sz; - tg = extract32(env->cp15.c2_control, 14, 2); + tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ granule_sz = 13; } @@ -4784,10 +4806,10 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, } } else { ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); - epd = extract32(env->cp15.c2_control, 23, 1); + epd = extract32(tcr->raw_tcr, 23, 1); tsz = t1sz; - tg = extract32(env->cp15.c2_control, 30, 2); + tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ granule_sz = 13; } diff --git a/target-arm/internals.h b/target-arm/internals.h index 2dff4ff..bb171a7 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -153,9 +153,9 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm) */ static inline bool extended_addresses_enabled(CPUARMState *env) { - return arm_el_is_aa64(env, 1) - || ((arm_feature(env, ARM_FEATURE_LPAE) - && (env->cp15.c2_control & TTBCR_EAE))); + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + return arm_el_is_aa64(env, 1) || + (arm_feature(env, ARM_FEATURE_LPAE) && (tcr->raw_tcr & TTBCR_EAE)); } /* Valid Syndrome Register EC field values */ -- cgit v1.1 From 0c17d68c1d3d6c35f37f5692042d2edb65c8bcc0 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make DACR banked When EL3 is running in AArch32 (or ARMv7 with Security Extensions) DACR has a secure and a non-secure instance. Adds definition for DACR32_EL2. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-19-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 2 +- target-arm/cpu.h | 13 +++++++++++-- target-arm/helper.c | 28 ++++++++++++++++++---------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 2b00b59..8967cc4 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -276,7 +276,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, s->cpu->env.cp15.sctlr_ns = 0; s->cpu->env.cp15.c1_coproc = 0; s->cpu->env.cp15.ttbr0_el[1] = 0; - s->cpu->env.cp15.c3 = 0; + s->cpu->env.cp15.dacr_ns = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0eaf981..1906fc1 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -227,8 +227,17 @@ typedef struct CPUARMState { TCR tcr_el[4]; 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. */ + union { /* MMU domain access control register + * MPU write buffer control. + */ + struct { + uint64_t dacr_ns; + uint64_t dacr_s; + }; + struct { + uint64_t dacr32_el2; + }; + }; uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */ uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */ uint64_t hcr_el2; /* Hypervisor configuration register */ diff --git a/target-arm/helper.c b/target-arm/helper.c index b80608c..ad9481c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -440,10 +440,12 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { * definitions that don't use CP_ANY wildcards (mostly in 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), - .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, }, + { .name = "DACR", + .cp = 15, .opc1 = CP_ANY, .crn = 3, .crm = CP_ANY, .opc2 = CP_ANY, + .access = PL1_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), + offsetoflow32(CPUARMState, cp15.dacr_ns) } }, /* ??? This covers not just the impdef TLB lockdown registers but also * some v7VMSA registers relating to TEX remap, so it is overly broad. */ @@ -2257,10 +2259,11 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W }, /* MMU Domain access control / MPU write buffer control */ - { .name = "DACR", .cp = 15, - .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c3), - .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, }, + { .name = "DACR", .cp = 15, .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), + offsetoflow32(CPUARMState, cp15.dacr_ns) } }, { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1, @@ -2330,6 +2333,11 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2), .writefn = hcr_write }, + { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0, + .access = PL2_RW, .resetvalue = 0, + .writefn = dacr_write, .raw_writefn = raw_write, + .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) }, { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1, @@ -4517,7 +4525,7 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, desc = ldl_phys(cs->as, table); type = (desc & 3); domain = (desc >> 5) & 0x0f; - domain_prot = (env->cp15.c3 >> (domain * 2)) & 3; + domain_prot = (A32_BANKED_CURRENT_REG_GET(env, dacr) >> (domain * 2)) & 3; if (type == 0) { /* Section translation fault. */ code = 5; @@ -4629,7 +4637,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, dacr) >> (domain * 2)) & 3; if (domain_prot == 0 || domain_prot == 2) { if (type != 1) { code = 9; /* Section domain fault. */ -- cgit v1.1 From 88ca1c2d70523486a952065f3ed7b8fc823b5863 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make IFSR banked When EL3 is running in AArch32 (or ARMv7 with Security Extensions) IFSR has a secure and a non-secure instance. Adds IFSR32_EL2 definition and storage. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-20-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 13 +++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1906fc1..e8bb057 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -242,7 +242,15 @@ typedef struct CPUARMState { uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */ uint64_t hcr_el2; /* Hypervisor configuration register */ uint64_t scr_el3; /* Secure configuration register. */ - uint32_t ifsr_el2; /* Fault status registers. */ + union { /* Fault status registers. */ + struct { + uint64_t ifsr_ns; + uint64_t ifsr_s; + }; + struct { + uint64_t ifsr32_el2; + }; + }; uint64_t esr_el[4]; uint32_t c6_region[8]; /* MPU base/size registers. */ uint64_t far_el[4]; /* Fault address registers. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index ad9481c..cfb267f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1654,8 +1654,9 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el[1]), .resetfn = arm_cp_reset_ignore, }, { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, }, + .access = PL1_RW, .resetvalue = 0, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s), + offsetoflow32(CPUARMState, cp15.ifsr_ns) } }, { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, @@ -2347,6 +2348,10 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = { .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) }, + { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1, + .access = PL2_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) }, { .name = "FAR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) }, @@ -4323,11 +4328,11 @@ 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; + A32_BANKED_CURRENT_REG_SET(env, ifsr, env->exception.fsr); env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 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); + env->exception.fsr, (uint32_t)env->exception.vaddress); new_mode = ARM_CPU_MODE_ABT; addr = 0x0c; mask = CPSR_A | CPSR_I; -- cgit v1.1 From 4a7e2d7315bd2ce28e49ccd0bde73eabdfd7437b Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make DFSR banked When EL3 is running in AArch32 (or ARMv7 with Security Extensions) DFSR has a secure and a non-secure instance. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-21-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 7 ++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index e8bb057..29870bd 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -251,7 +251,15 @@ typedef struct CPUARMState { uint64_t ifsr32_el2; }; }; - uint64_t esr_el[4]; + union { + struct { + uint64_t _unused_dfsr; + uint64_t dfsr_ns; + uint64_t hsr; + uint64_t dfsr_s; + }; + uint64_t esr_el[4]; + }; uint32_t c6_region[8]; /* MPU base/size registers. */ uint64_t far_el[4]; /* Fault address registers. */ uint64_t par_el1; /* Translation result. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index cfb267f..ebb6694 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1651,7 +1651,8 @@ 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, - .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el[1]), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s), + offsetoflow32(CPUARMState, cp15.dfsr_ns) }, .resetfn = arm_cp_reset_ignore, }, { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .resetvalue = 0, @@ -4339,11 +4340,11 @@ void arm_cpu_do_interrupt(CPUState *cs) offset = 4; break; case EXCP_DATA_ABORT: - env->cp15.esr_el[1] = env->exception.fsr; + A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32, env->exception.vaddress); qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n", - (uint32_t)env->cp15.esr_el[1], + env->exception.fsr, (uint32_t)env->exception.vaddress); new_mode = ARM_CPU_MODE_ABT; addr = 0x10; -- cgit v1.1 From b848ce2b9cbd38da3f2530fd93dba76dba0621c0 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:51 +0000 Subject: target-arm: make IFAR/DFAR banked When EL3 is running in AArch32 (or ARMv7 with Security Extensions) IFAR and DFAR have a secure and a non-secure instance. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-22-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 +- target-arm/cpu.h | 19 ++++++++++++++++++- target-arm/helper.c | 16 +++++++++------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index fdb7b35..d3db279 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -552,7 +552,7 @@ static void arm1026_initfn(Object *obj) ARMCPRegInfo ifar = { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]), + .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns), .resetvalue = 0 }; define_one_arm_cp_reg(cpu, &ifar); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 29870bd..52d5719 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -261,7 +261,24 @@ typedef struct CPUARMState { uint64_t esr_el[4]; }; uint32_t c6_region[8]; /* MPU base/size registers. */ - uint64_t far_el[4]; /* Fault address registers. */ + union { /* Fault address registers. */ + struct { + uint64_t _unused_far0; +#ifdef HOST_WORDS_BIGENDIAN + uint32_t ifar_ns; + uint32_t dfar_ns; + uint32_t ifar_s; + uint32_t dfar_s; +#else + uint32_t dfar_ns; + uint32_t ifar_ns; + uint32_t dfar_s; + uint32_t ifar_s; +#endif + uint64_t _unused_far3; + }; + uint64_t far_el[4]; + }; uint64_t par_el1; /* Translation result. */ uint32_t c9_insn; /* Cache lockdown registers. */ uint32_t c9_data; diff --git a/target-arm/helper.c b/target-arm/helper.c index ebb6694..0c8b532 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -559,7 +559,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .access = PL0_W, .type = ARM_CP_NOP }, { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ifar_s), + offsetof(CPUARMState, cp15.ifar_ns) }, .resetvalue = 0, }, /* Watchpoint Fault Address Register : should actually only be present * for 1136, 1176, 11MPCore. @@ -1682,11 +1683,14 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, - /* 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_AA64, .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, + { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s), + offsetof(CPUARMState, cp15.dfar_ns) } }, REGINFO_SENTINEL }; @@ -4330,8 +4334,7 @@ void arm_cpu_do_interrupt(CPUState *cs) /* Fall through to prefetch abort. */ case EXCP_PREFETCH_ABORT: A32_BANKED_CURRENT_REG_SET(env, ifsr, env->exception.fsr); - env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 32, 32, - env->exception.vaddress); + A32_BANKED_CURRENT_REG_SET(env, ifar, env->exception.vaddress); qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n", env->exception.fsr, (uint32_t)env->exception.vaddress); new_mode = ARM_CPU_MODE_ABT; @@ -4341,8 +4344,7 @@ void arm_cpu_do_interrupt(CPUState *cs) break; case EXCP_DATA_ABORT: A32_BANKED_CURRENT_REG_SET(env, dfsr, env->exception.fsr); - env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32, - env->exception.vaddress); + A32_BANKED_CURRENT_REG_SET(env, dfar, env->exception.vaddress); qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n", env->exception.fsr, (uint32_t)env->exception.vaddress); -- cgit v1.1 From 01c097f7960b330c4bf038d34bae17ad6c1ba499 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:52 +0000 Subject: target-arm: make PAR banked When EL3 is running in AArch32 (or ARMv7 with Security Extensions) PAR has a secure and a non-secure instance. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-23-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 23 +++++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 52d5719..2f8d607 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -279,7 +279,15 @@ typedef struct CPUARMState { }; uint64_t far_el[4]; }; - uint64_t par_el1; /* Translation result. */ + union { /* Translation result. */ + struct { + uint64_t _unused_par_0; + uint64_t par_ns; + uint64_t _unused_par_1; + uint64_t par_s; + }; + uint64_t par_el[4]; + }; uint32_t c9_insn; /* Cache lockdown registers. */ uint32_t c9_data; uint64_t c9_pmcr; /* performance monitor control register */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 0c8b532..d2e7652 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1404,6 +1404,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) int prot; int ret, is_user = ri->opc2 & 2; int access_type = ri->opc2 & 1; + uint64_t par64; ret = get_phys_addr(env, value, access_type, is_user, &phys_addr, &prot, &page_size); @@ -1412,7 +1413,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) * translation table format, but with WnR always clear. * Convert it to a 64-bit PAR. */ - uint64_t par64 = (1 << 11); /* LPAE bit always set */ + par64 = (1 << 11); /* LPAE bit always set */ if (ret == 0) { par64 |= phys_addr & ~0xfffULL; /* We don't set the ATTR or SH fields in the PAR. */ @@ -1424,7 +1425,6 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) * fault. */ } - env->cp15.par_el1 = par64; } else { /* ret is a DFSR/IFSR value for the short descriptor * translation table format (with WnR always clear). @@ -1434,23 +1434,25 @@ 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; + par64 = (phys_addr & 0xff000000) | (1 << 1); } else { - env->cp15.par_el1 = phys_addr & 0xfffff000; + par64 = phys_addr & 0xfffff000; } } else { - env->cp15.par_el1 = ((ret & (1 << 10)) >> 5) | - ((ret & (1 << 12)) >> 6) | - ((ret & 0xf) << 1) | 1; + par64 = ((ret & (1 << 10)) >> 5) | ((ret & (1 << 12)) >> 6) | + ((ret & 0xf) << 1) | 1; } } + + A32_BANKED_CURRENT_REG_SET(env, par, par64); } #endif static const ARMCPRegInfo vapa_cp_reginfo[] = { { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .resetvalue = 0, - .fieldoffset = offsetoflow32(CPUARMState, cp15.par_el1), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s), + offsetoflow32(CPUARMState, cp15.par_ns) }, .writefn = par_write }, #ifndef CONFIG_USER_ONLY { .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY, @@ -1903,8 +1905,9 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 }, { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0, - .access = PL1_RW, .type = ARM_CP_64BIT, - .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.par_s), + offsetof(CPUARMState, cp15.par_ns)} }, { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), -- cgit v1.1 From fb6c91ba2bb0b1c1b8662ceeeeb9474a025f9a6b Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Thu, 11 Dec 2014 12:07:52 +0000 Subject: target-arm: make VBAR banked When EL3 is running in Aarch32 (or ARMv7 with Security Extensions) VBAR has a secure and a non-secure instance, which are mapped to VBAR_EL1 and VBAR_EL3. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-24-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2f8d607..fc64497 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -297,7 +297,15 @@ 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 vbar_el[4]; /* vector base address register */ + union { /* vector base address register */ + struct { + uint64_t _unused_vbar; + uint64_t vbar_ns; + uint64_t hvbar; + uint64_t vbar_s; + }; + uint64_t vbar_el[4]; + }; uint32_t mvbar; /* (monitor) vector base address register */ uint32_t c13_fcse; /* FCSE PID. */ uint64_t contextidr_el1; /* Context ID. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index d2e7652..bc73c4f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -911,7 +911,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .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.vbar_el[1]), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), + offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, @@ -4401,7 +4402,7 @@ void arm_cpu_do_interrupt(CPUState *cs) * This register is only followed in non-monitor mode, and is banked. * Note: only bits 31:5 are valid. */ - addr += env->cp15.vbar_el[1]; + addr += A32_BANKED_CURRENT_REG_GET(env, vbar); } if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) { -- cgit v1.1 From 54bf36ed351c526cde0c853079f9ff1ab7e2ff89 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 11 Dec 2014 12:07:52 +0000 Subject: target-arm: make c13 cp regs banked (FCSEIDR, ...) When EL3 is running in AArch32 (or ARMv7 with Security Extensions) FCSEIDR, CONTEXTIDR, TPIDRURW, TPIDRURO and TPIDRPRW have a secure and a non-secure instance. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-25-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- linux-user/aarch64/target_cpu.h | 2 +- linux-user/arm/target_cpu.h | 2 +- linux-user/main.c | 2 +- target-arm/cpu.h | 36 +++++++++++++++++++++---- target-arm/helper.c | 58 ++++++++++++++++++++++++++++++++--------- target-arm/op_helper.c | 2 +- 6 files changed, 80 insertions(+), 22 deletions(-) diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h index 21560ef..b5593dc 100644 --- a/linux-user/aarch64/target_cpu.h +++ b/linux-user/aarch64/target_cpu.h @@ -32,7 +32,7 @@ static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is * different from AArch32 Linux, which uses TPIDRRO. */ - env->cp15.tpidr_el0 = newtls; + env->cp15.tpidr_el[0] = newtls; } #endif diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 39d65b6..d8a534d 100644 --- a/linux-user/arm/target_cpu.h +++ b/linux-user/arm/target_cpu.h @@ -29,7 +29,7 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) { - env->cp15.tpidrro_el0 = newtls; + env->cp15.tpidrro_el[0] = newtls; } #endif diff --git a/linux-user/main.c b/linux-user/main.c index 5c14c1e..186ee4d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -564,7 +564,7 @@ do_kernel_trap(CPUARMState *env) end_exclusive(); break; case 0xffff0fe0: /* __kernel_get_tls */ - env->regs[0] = env->cp15.tpidrro_el0; + env->regs[0] = env->cp15.tpidrro_el[0]; break; case 0xffff0f60: /* __kernel_cmpxchg64 */ arm_kernel_cmpxchg64_helper(env); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index fc64497..a1fefe4 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -307,11 +307,37 @@ typedef struct CPUARMState { uint64_t vbar_el[4]; }; uint32_t mvbar; /* (monitor) 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. */ + struct { /* FCSE PID. */ + uint32_t fcseidr_ns; + uint32_t fcseidr_s; + }; + union { /* Context ID. */ + struct { + uint64_t _unused_contextidr_0; + uint64_t contextidr_ns; + uint64_t _unused_contextidr_1; + uint64_t contextidr_s; + }; + uint64_t contextidr_el[4]; + }; + union { /* User RW Thread register. */ + struct { + uint64_t tpidrurw_ns; + uint64_t tpidrprw_ns; + uint64_t htpidr; + uint64_t _tpidr_el3; + }; + uint64_t tpidr_el[4]; + }; + /* The secure banks of these registers don't map anywhere */ + uint64_t tpidrurw_s; + uint64_t tpidrprw_s; + uint64_t tpidruro_s; + + union { /* User RO Thread register. */ + uint64_t tpidruro_ns; + uint64_t tpidrro_el[1]; + }; 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 bc73c4f..0357f41 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -424,13 +424,36 @@ static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri, } static const ARMCPRegInfo cp_reginfo[] = { - { .name = "FCSEIDR", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c13_fcse), + /* Define the secure and non-secure FCSE identifier CP registers + * separately because there is no secure bank in V8 (no _EL3). This allows + * the secure register to be properly reset and migrated. There is also no + * v8 EL1 version of the register so the non-secure instance stands alone. + */ + { .name = "FCSEIDR(NS)", + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 0, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_NS, + .fieldoffset = offsetof(CPUARMState, cp15.fcseidr_ns), + .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, }, + { .name = "FCSEIDR(S)", + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 0, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, + .fieldoffset = offsetof(CPUARMState, cp15.fcseidr_s), .resetvalue = 0, .writefn = fcse_write, .raw_writefn = raw_write, }, - { .name = "CONTEXTIDR", .state = ARM_CP_STATE_BOTH, + /* Define the secure and non-secure context identifier CP registers + * separately because there is no secure bank in V8 (no _EL3). This allows + * the secure register to be properly reset and migrated. In the + * non-secure case, the 32-bit register will have reset and migration + * disabled during registration as it is handled by the 64-bit instance. + */ + { .name = "CONTEXTIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el1), + .access = PL1_RW, .secure = ARM_CP_SECSTATE_NS, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), + .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, + { .name = "CONTEXTIDR(S)", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, + .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, + .fieldoffset = offsetof(CPUARMState, cp15.contextidr_s), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, REGINFO_SENTINEL }; @@ -1031,23 +1054,31 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { { .name = "TPIDR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 2, .crn = 13, .crm = 0, .access = PL0_RW, - .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el0), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[0]), .resetvalue = 0 }, { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL0_RW, - .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrurw_s), + offsetoflow32(CPUARMState, cp15.tpidrurw_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 3, .crn = 13, .crm = 0, .access = PL0_R|PL1_W, - .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el0), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el[0]), + .resetvalue = 0}, { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL0_R|PL1_W, - .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0), + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidruro_s), + offsetoflow32(CPUARMState, cp15.tpidruro_ns) }, .resetfn = arm_cp_reset_ignore }, - { .name = "TPIDR_EL1", .state = ARM_CP_STATE_BOTH, + { .name = "TPIDR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el1), .resetvalue = 0 }, + .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[1]), .resetvalue = 0 }, + { .name = "TPIDRPRW", .opc1 = 0, .cp = 15, .crn = 13, .crm = 0, .opc2 = 4, + .access = PL1_RW, + .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrprw_s), + offsetoflow32(CPUARMState, cp15.tpidrprw_ns) }, + .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -5051,8 +5082,9 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address, uint32_t sctlr = A32_BANKED_CURRENT_REG_GET(env, sctlr); /* Fast Context Switch Extension. */ - if (address < 0x02000000) - address += env->cp15.c13_fcse; + if (address < 0x02000000) { + address += A32_BANKED_CURRENT_REG_GET(env, fcseidr); + } if ((sctlr & SCTLR_M) == 0) { /* MMU/MPU disabled. */ diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a8dea5a..2bed914 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -575,7 +575,7 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) * short descriptor format (in which case it holds both PROCID and ASID), * since we don't implement the optional v7 context ID masking. */ - contextidr = extract64(env->cp15.contextidr_el1, 0, 32); + contextidr = extract64(env->cp15.contextidr_el[1], 0, 32); switch (bt) { case 3: /* linked context ID match */ -- cgit v1.1 From be693c87e440e671ed913784554384349ce8331d Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Thu, 11 Dec 2014 12:07:52 +0000 Subject: target-arm: make MAIR0/1 banked Added CP register info entries for the ARMv7 MAIR0/1 secure banks. Signed-off-by: Greg Bellows Reviewed-by: Peter Maydell Message-id: 1416242878-876-26-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu.h | 21 ++++++++++++++++++++- target-arm/helper.c | 12 +++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index a1fefe4..7ba55f0 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -296,7 +296,26 @@ typedef struct CPUARMState { 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; + union { /* Memory attribute redirection */ + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint64_t _unused_mair_0; + uint32_t mair1_ns; + uint32_t mair0_ns; + uint64_t _unused_mair_1; + uint32_t mair1_s; + uint32_t mair0_s; +#else + uint64_t _unused_mair_0; + uint32_t mair0_ns; + uint32_t mair1_ns; + uint64_t _unused_mair_1; + uint32_t mair0_s; + uint32_t mair1_s; +#endif + }; + uint64_t mair_el[4]; + }; union { /* vector base address register */ struct { uint64_t _unused_vbar; diff --git a/target-arm/helper.c b/target-arm/helper.c index 0357f41..96abbed 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -965,20 +965,26 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { */ { .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el1), + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), .resetvalue = 0 }, /* For non-long-descriptor page tables these are PRRR and NMRR; * regardless they still act as reads-as-written for QEMU. * The override is necessary because of the overly-broad TLB_LOCKDOWN * definition. */ + /* MAIR0/1 are defined seperately from their 64-bit counterpart which + * allows them to assign the correct fieldoffset based on the endianness + * handled in the field definitions. + */ { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE, .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW, - .fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair0_s), + offsetof(CPUARMState, cp15.mair0_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE, .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW, - .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair1_s), + offsetof(CPUARMState, cp15.mair1_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "ISR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0, -- cgit v1.1 From b1ab03af890b2b6c5bafc9344b7fe05b392180a5 Mon Sep 17 00:00:00 2001 From: Nikita Belov Date: Thu, 11 Dec 2014 12:07:52 +0000 Subject: hw/arm/realview.c: Fix memory leak in realview_init() Variable 'ram_lo' is allocated unconditionally, but used only in some cases. When it is unused pointer will be lost at function exit, resulting in a memory leak. Allocate memory for 'ram_lo' only if it is needed. Valgrind output: ==16879== 240 bytes in 1 blocks are definitely lost in loss record 6,033 of 7,018 ==16879== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==16879== by 0x33D2CE: malloc_and_trace (vl.c:2804) ==16879== by 0x509E610: g_malloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4000.0) ==16879== by 0x288836: realview_init (realview.c:55) ==16879== by 0x28988C: realview_pb_a8_init (realview.c:375) ==16879== by 0x341426: main (vl.c:4413) Signed-off-by: Nikita Belov Reviewed-by: Markus Armbruster Signed-off-by: Peter Maydell --- hw/arm/realview.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index af65aa4..d41ec97 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -52,7 +52,7 @@ static void realview_init(MachineState *machine, CPUARMState *env; ObjectClass *cpu_oc; MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram_lo = g_new(MemoryRegion, 1); + MemoryRegion *ram_lo; MemoryRegion *ram_hi = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); MemoryRegion *ram_hack = g_new(MemoryRegion, 1); @@ -135,6 +135,7 @@ static void realview_init(MachineState *machine, if (is_pb && ram_size > 0x20000000) { /* Core tile RAM. */ + ram_lo = g_new(MemoryRegion, 1); low_ram_size = ram_size - 0x20000000; ram_size = 0x20000000; memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size, -- cgit v1.1 From a554ecb49d0021fd8bb0fd4f2f6be807b3c8b54f Mon Sep 17 00:00:00 2001 From: zhanghailiang Date: Thu, 11 Dec 2014 12:07:53 +0000 Subject: hw/arm/boot: fix uninitialized scalar variable warning reported by coverity Coverity reports the 'size' may be used uninitialized, but that can't happen, because the caller has checked "if (binfo->dtb_filename || binfo->get_dtb)" before call 'load_dtb'. Here we simply remove the 'if (binfo->get_dtb)' to satisfy coverity. Signed-off-by: zhanghailiang Message-id: 1416826240-12368-1-git-send-email-zhang.zhanghailiang@huawei.com Signed-off-by: Peter Maydell --- hw/arm/boot.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 0014c34..e6a3c5b 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -329,6 +329,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info) * Returns: the size of the device tree image on success, * 0 if the image size exceeds the limit, * -1 on errors. + * + * Note: Must not be called unless have_dtb(binfo) is true. */ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, hwaddr addr_limit) @@ -352,7 +354,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, goto fail; } g_free(filename); - } else if (binfo->get_dtb) { + } else { fdt = binfo->get_dtb(binfo, &size); if (!fdt) { fprintf(stderr, "Board was unable to create a dtb blob\n"); -- cgit v1.1 From 72149414e25784de60b821fe67c56108a5b03ce1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Dec 2014 12:07:53 +0000 Subject: arm_gic_kvm: Tell kernel about number of IRQs Newer kernels support a device attribute on the GIC which allows us to tell it how many IRQs this GIC instance is configured with; use it, if it exists. Signed-off-by: Peter Maydell Reviewed-by: Christoffer Dall Message-id: 1417718679-1071-1-git-send-email-peter.maydell@linaro.org --- hw/intc/arm_gic_kvm.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 5038885..1ad3eb0 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -92,6 +92,21 @@ static bool kvm_arm_gic_can_save_restore(GICState *s) return s->dev_fd >= 0; } +static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum) +{ + struct kvm_device_attr attr = { + .group = group, + .attr = attrnum, + .flags = 0, + }; + + if (s->dev_fd == -1) { + return false; + } + + return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0; +} + static void kvm_gic_access(GICState *s, int group, int offset, int cpu, uint32_t *val, bool write) { @@ -553,6 +568,11 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { + uint32_t numirqs = s->num_irq; + kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1); + } + /* Distributor */ memory_region_init_reservation(&s->iomem, OBJECT(s), "kvm-gic_dist", 0x1000); -- cgit v1.1 From 38df27c8a7ef9877583a46e74d99181c3224e078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 11 Dec 2014 12:07:53 +0000 Subject: target-arm/kvm: make reg sync code common between kvm32/64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before we launch a guest we query KVM for the list of "co-processor" registers it knows about. This is used to synchronize system register state for the bulk of coprocessor/system registers. Move this code from the 32-bit specific vcpu init function into a common routine and call it also from the 64-bit vcpu init. This allows system registers to migrate correctly when using KVM, and also permits QEMU code to see the current KVM register state (which will be needed to support big-endian guests, since the virtio endianness callback must check for some system register settings). Since vcpu reset also has to sync registers, we move the 32 bit kvm_arm_reset_vcpu() into common code as well and share it with the 64 bit version. Signed-off-by: Alex Bennée [PMM: just copy the 32-bit code rather than improving it along the way; don't share reg_syncs_via_tuple_list() between 32 and 64 bit; tweak function names; move reset] Signed-off-by: Peter Maydell --- target-arm/kvm.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/kvm32.c | 94 ++----------------------------------------------- target-arm/kvm64.c | 24 +++++++------ target-arm/kvm_arm.h | 22 ++++++++++++ 4 files changed, 137 insertions(+), 101 deletions(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 319784d..191e759 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -21,6 +21,7 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "cpu.h" +#include "internals.h" #include "hw/arm/arm.h" const KVMCapabilityInfo kvm_arch_required_capabilities[] = { @@ -279,6 +280,94 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, memory_region_ref(kd->mr); } +static int compare_u64(const void *a, const void *b) +{ + if (*(uint64_t *)a > *(uint64_t *)b) { + return 1; + } + if (*(uint64_t *)a < *(uint64_t *)b) { + return -1; + } + return 0; +} + +/* Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu) +{ + struct kvm_reg_list rl; + struct kvm_reg_list *rlp; + int i, ret, arraylen; + CPUState *cs = CPU(cpu); + + rl.n = 0; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); + if (ret != -E2BIG) { + return ret; + } + rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); + rlp->n = rl.n; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); + if (ret) { + goto out; + } + /* Sort the list we get back from the kernel, since cpreg_tuples + * must be in strictly ascending order. + */ + qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + if (!kvm_arm_reg_syncs_via_cpreg_list(rlp->reg[i])) { + continue; + } + switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + case KVM_REG_SIZE_U64: + break; + default: + fprintf(stderr, "Can't handle size of register in kernel list\n"); + ret = -EINVAL; + goto out; + } + + arraylen++; + } + + cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); + cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); + cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, + arraylen); + cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, + arraylen); + cpu->cpreg_array_len = arraylen; + cpu->cpreg_vmstate_array_len = arraylen; + + for (i = 0, arraylen = 0; i < rlp->n; i++) { + uint64_t regidx = rlp->reg[i]; + if (!kvm_arm_reg_syncs_via_cpreg_list(regidx)) { + continue; + } + cpu->cpreg_indexes[arraylen] = regidx; + arraylen++; + } + assert(cpu->cpreg_array_len == arraylen); + + if (!write_kvmstate_to_list(cpu)) { + /* Shouldn't happen unless kernel is inconsistent about + * what registers exist. + */ + fprintf(stderr, "Initial read of kernel register state failed\n"); + ret = -EINVAL; + goto out; + } + +out: + g_free(rlp); + return ret; +} + bool write_kvmstate_to_list(ARMCPU *cpu) { CPUState *cs = CPU(cpu); @@ -351,6 +440,15 @@ bool write_list_to_kvmstate(ARMCPU *cpu) return ok; } +void kvm_arm_reset_vcpu(ARMCPU *cpu) +{ + /* Re-init VCPU so that all registers are set to + * their respective reset values. + */ + kvm_arm_vcpu_init(CPU(cpu)); + write_kvmstate_to_list(cpu); +} + void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { } diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index a5e67da..94030d1 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -138,7 +138,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return true; } -static bool reg_syncs_via_tuple_list(uint64_t regidx) +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) { /* Return true if the regidx is a register we should synchronize * via the cpreg_tuples array (ie is not a core reg we sync by @@ -153,24 +153,11 @@ static bool reg_syncs_via_tuple_list(uint64_t regidx) } } -static int compare_u64(const void *a, const void *b) -{ - if (*(uint64_t *)a > *(uint64_t *)b) { - return 1; - } - if (*(uint64_t *)a < *(uint64_t *)b) { - return -1; - } - return 0; -} - int kvm_arch_init_vcpu(CPUState *cs) { - int i, ret, arraylen; + int ret; uint64_t v; struct kvm_one_reg r; - struct kvm_reg_list rl; - struct kvm_reg_list *rlp; ARMCPU *cpu = ARM_CPU(cs); if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { @@ -206,73 +193,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } - /* Populate the cpreg list based on the kernel's idea - * of what registers exist (and throw away the TCG-created list). - */ - rl.n = 0; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl); - if (ret != -E2BIG) { - return ret; - } - rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t)); - rlp->n = rl.n; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp); - if (ret) { - goto out; - } - /* Sort the list we get back from the kernel, since cpreg_tuples - * must be in strictly ascending order. - */ - qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64); - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - if (!reg_syncs_via_tuple_list(rlp->reg[i])) { - continue; - } - switch (rlp->reg[i] & KVM_REG_SIZE_MASK) { - case KVM_REG_SIZE_U32: - case KVM_REG_SIZE_U64: - break; - default: - fprintf(stderr, "Can't handle size of register in kernel list\n"); - ret = -EINVAL; - goto out; - } - - arraylen++; - } - - cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen); - cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen); - cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes, - arraylen); - cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values, - arraylen); - cpu->cpreg_array_len = arraylen; - cpu->cpreg_vmstate_array_len = arraylen; - - for (i = 0, arraylen = 0; i < rlp->n; i++) { - uint64_t regidx = rlp->reg[i]; - if (!reg_syncs_via_tuple_list(regidx)) { - continue; - } - cpu->cpreg_indexes[arraylen] = regidx; - arraylen++; - } - assert(cpu->cpreg_array_len == arraylen); - - if (!write_kvmstate_to_list(cpu)) { - /* Shouldn't happen unless kernel is inconsistent about - * what registers exist. - */ - fprintf(stderr, "Initial read of kernel register state failed\n"); - ret = -EINVAL; - goto out; - } - -out: - g_free(rlp); - return ret; + return kvm_arm_init_cpreg_list(cpu); } typedef struct Reg { @@ -508,12 +429,3 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); - write_kvmstate_to_list(cpu); -} diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index c615286..ba16821 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -103,9 +103,21 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } - /* TODO : support for save/restore/reset of system regs via tuple list */ + return kvm_arm_init_cpreg_list(cpu); +} - return 0; +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) +{ + /* Return true if the regidx is a register we should synchronize + * via the cpreg_tuples array (ie is not a core reg we sync by + * hand in kvm_arch_get/put_registers()) + */ + switch (regidx & KVM_REG_ARM_COPROC_MASK) { + case KVM_REG_ARM_CORE: + return false; + default: + return true; + } } #define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ @@ -260,11 +272,3 @@ int kvm_arch_get_registers(CPUState *cs) /* TODO: other registers */ return ret; } - -void kvm_arm_reset_vcpu(ARMCPU *cpu) -{ - /* Re-init VCPU so that all registers are set to - * their respective reset values. - */ - kvm_arm_vcpu_init(CPU(cpu)); -} diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index af93105..455dea3 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -47,6 +47,28 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, uint64_t attr, int dev_fd); /** + * kvm_arm_init_cpreg_list: + * @cs: CPUState + * + * Initialize the CPUState's cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). + * + * Returns: 0 if success, else < 0 error code + */ +int kvm_arm_init_cpreg_list(ARMCPU *cpu); + +/** + * kvm_arm_reg_syncs_via_cpreg_list + * regidx: KVM register index + * + * Return true if this KVM register should be synchronized via the + * cpreg list of arbitrary system registers, false if it is synchronized + * by hand using code in kvm_arch_get/put_registers(). + */ +bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx); + +/** * write_list_to_kvmstate: * @cpu: ARMCPU * -- cgit v1.1 From a7130a3ef9b8dc3091a0700abb61e2926e89e916 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Dec 2014 12:07:53 +0000 Subject: target-arm: Support save/load for 64 bit CPUs For migration to work on 64 bit CPUs, we need to include both the 64-bit integer register file and the PSTATE. Everything else is either stored in the same place as existing 32-bit CPU state or handled by the generic sysreg mechanism. Signed-off-by: Peter Maydell Message-id: 1417788683-4038-3-git-send-email-peter.maydell@linaro.org --- target-arm/machine.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/target-arm/machine.c b/target-arm/machine.c index 6437690..c29e7a2 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -127,6 +127,13 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size) CPUARMState *env = &cpu->env; uint32_t val = qemu_get_be32(f); + env->aarch64 = ((val & PSTATE_nRW) == 0); + + if (is_a64(env)) { + pstate_write(env, val); + return 0; + } + /* Avoid mode switch when restoring CPSR */ env->uncached_cpsr = val & CPSR_M; cpsr_write(env, val, 0xffffffff); @@ -137,8 +144,15 @@ static void put_cpsr(QEMUFile *f, void *opaque, size_t size) { ARMCPU *cpu = opaque; CPUARMState *env = &cpu->env; + uint32_t val; + + if (is_a64(env)) { + val = pstate_read(env); + } else { + val = cpsr_read(env); + } - qemu_put_be32(f, cpsr_read(env)); + qemu_put_be32(f, val); } static const VMStateInfo vmstate_cpsr = { @@ -222,12 +236,14 @@ static int cpu_post_load(void *opaque, int version_id) const VMStateDescription vmstate_arm_cpu = { .name = "cpu", - .version_id = 21, - .minimum_version_id = 21, + .version_id = 22, + .minimum_version_id = 22, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16), + VMSTATE_UINT64_ARRAY(env.xregs, ARMCPU, 32), + VMSTATE_UINT64(env.pc, ARMCPU), { .name = "cpsr", .version_id = 0, -- cgit v1.1 From 25f2895e0e437a3548f9794846001fb5d5ab853d Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Thu, 11 Dec 2014 12:07:53 +0000 Subject: target-arm: Check error conditions on kvm_arm_reset_vcpu When resetting a VCPU we currently call both kvm_arm_vcpu_init() and write_kvmstate_to_list(), both of which can fail, but we never check the return value. The only choice here is to print an error an exit if the calls fail. Signed-off-by: Christoffer Dall Reviewed-by: Peter Maydell Message-id: 1418039630-11773-1-git-send-email-christoffer.dall@linaro.org Signed-off-by: Peter Maydell --- target-arm/kvm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 191e759..4d81f3d 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -442,11 +442,20 @@ bool write_list_to_kvmstate(ARMCPU *cpu) void kvm_arm_reset_vcpu(ARMCPU *cpu) { + int ret; + /* Re-init VCPU so that all registers are set to * their respective reset values. */ - kvm_arm_vcpu_init(CPU(cpu)); - write_kvmstate_to_list(cpu); + ret = kvm_arm_vcpu_init(CPU(cpu)); + if (ret < 0) { + fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } + if (!write_kvmstate_to_list(cpu)) { + fprintf(stderr, "write_kvmstate_to_list failed\n"); + abort(); + } } void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) -- cgit v1.1