diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2014-09-30 11:02:06 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2014-09-30 11:02:06 +0100 |
| commit | 29429c7244c73eefada3d0ec6dd30c5698782d08 (patch) | |
| tree | ca318448a3a953a6897001a4e04cb97f566f1456 /target-arm/op_helper.c | |
| parent | 70d3a7a7b8340d9f671c5aec4c6dd174fee2ef8e (diff) | |
| parent | 136e67e9b50b61fb03fedcea5c4fbe74cf44fdcc (diff) | |
| download | focaccia-qemu-29429c7244c73eefada3d0ec6dd30c5698782d08.tar.gz focaccia-qemu-29429c7244c73eefada3d0ec6dd30c5698782d08.zip | |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140929' into staging
target-arm: * more EL2/EL3 preparation work * don't handle c15_cpar changes via tb_flush() * fix some unused function warnings in ARM devices * build the GDB XML for 32 bit CPUs into qemu-*-aarch64 * implement guest breakpoint support # gpg: Signature made Mon 29 Sep 2014 19:25:37 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140929: target-arm: Add support for VIRQ and VFIQ target-arm: Add IRQ and FIQ routing to EL2 and 3 target-arm: A64: Emulate the SMC insn target-arm: Add a Hypervisor Trap exception type target-arm: A64: Emulate the HVC insn target-arm: A64: Correct updates to FAR and ESR on exceptions target-arm: Don't take interrupts targeting lower ELs target-arm: Break out exception masking to a separate func target-arm: A64: Refactor aarch64_cpu_do_interrupt target-arm: Add SCR_EL3 target-arm: Add HCR_EL2 target-arm: Don't handle c15_cpar changes via tb_flush() hw/input/tsc210x.c: Delete unused array tsc2101_rates hw/display/pxa2xx_lcd.c: Remove unused function pxa2xx_dma_rdst_set hw/intc/imx_avic.c: Remove unused function imx_avic_set_prio() hw/display/blizzard.c: Delete unused function blizzard_rgb2yuv configure: Build GDB XML for 32 bit ARM CPUs into qemu aarch64 binaries target-arm: Implement handling of breakpoint firing target-arm: Implement setting guest breakpoints Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/op_helper.c')
| -rw-r--r-- | target-arm/op_helper.c | 143 |
1 files changed, 128 insertions, 15 deletions
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index b956216c4b..03ac92afdc 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -301,6 +301,17 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val) void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome) { const ARMCPRegInfo *ri = rip; + + if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 + && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { + env->exception.syndrome = syndrome; + raise_exception(env, EXCP_UDEF); + } + + if (!ri->accessfn) { + return; + } + switch (ri->accessfn(env, ri)) { case CP_ACCESS_OK: return; @@ -374,6 +385,63 @@ void HELPER(clear_pstate_ss)(CPUARMState *env) env->pstate &= ~PSTATE_SS; } +void HELPER(pre_hvc)(CPUARMState *env) +{ + int cur_el = arm_current_pl(env); + /* FIXME: Use actual secure state. */ + bool secure = false; + bool undef; + + /* We've already checked that EL2 exists at translation time. + * EL3.HCE has priority over EL2.HCD. + */ + if (arm_feature(env, ARM_FEATURE_EL3)) { + undef = !(env->cp15.scr_el3 & SCR_HCE); + } else { + undef = env->cp15.hcr_el2 & HCR_HCD; + } + + /* In ARMv7 and ARMv8/AArch32, HVC is undef in secure state. + * For ARMv8/AArch64, HVC is allowed in EL3. + * Note that we've already trapped HVC from EL0 at translation + * time. + */ + if (secure && (!is_a64(env) || cur_el == 1)) { + undef = true; + } + + if (undef) { + env->exception.syndrome = syn_uncategorized(); + raise_exception(env, EXCP_UDEF); + } +} + +void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome) +{ + int cur_el = arm_current_pl(env); + /* FIXME: Use real secure state. */ + bool secure = false; + bool smd = env->cp15.scr_el3 & SCR_SMD; + /* On ARMv8 AArch32, SMD only applies to NS state. + * On ARMv7 SMD only applies to NS state and only if EL2 is available. + * For ARMv7 non EL2, we force SMD to zero so we don't need to re-check + * the EL2 condition here. + */ + bool undef = is_a64(env) ? smd : (!secure && smd); + + /* In NS EL1, HCR controlled routing to EL2 has priority over SMD. */ + if (!secure && cur_el == 1 && (env->cp15.hcr_el2 & HCR_TSC)) { + env->exception.syndrome = syndrome; + raise_exception(env, EXCP_HYP_TRAP); + } + + /* We've already checked that EL3 exists at translation time. */ + if (undef) { + env->exception.syndrome = syn_uncategorized(); + raise_exception(env, EXCP_UDEF); + } +} + void HELPER(exception_return)(CPUARMState *env) { int cur_el = arm_current_pl(env); @@ -511,32 +579,43 @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn) return false; } -static bool wp_matches(ARMCPU *cpu, int n) +static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) { CPUARMState *env = &cpu->env; - uint64_t wcr = env->cp15.dbgwcr[n]; + uint64_t cr; int pac, hmc, ssc, wt, lbn; /* TODO: check against CPU security state when we implement TrustZone */ bool is_secure = false; - if (!env->cpu_watchpoint[n] - || !(env->cpu_watchpoint[n]->flags & BP_WATCHPOINT_HIT)) { - return false; - } + if (is_wp) { + if (!env->cpu_watchpoint[n] + || !(env->cpu_watchpoint[n]->flags & BP_WATCHPOINT_HIT)) { + return false; + } + cr = env->cp15.dbgwcr[n]; + } else { + uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; + if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) { + return false; + } + cr = env->cp15.dbgbcr[n]; + } /* The WATCHPOINT_HIT flag guarantees us that the watchpoint is - * enabled and that the address and access type match; check the - * remaining fields, including linked breakpoints. - * Note that some combinations of {PAC, HMC SSC} are reserved and + * enabled and that the address and access type match; for breakpoints + * we know the address matched; check the remaining fields, including + * linked breakpoints. We rely on WCR and BCR having the same layout + * for the LBN, SSC, HMC, PAC/PMC and is-linked fields. + * Note that some combinations of {PAC, HMC, SSC} are reserved and * must act either like some valid combination or as if the watchpoint * were disabled. We choose the former, and use this together with * the fact that EL3 must always be Secure and EL2 must always be * Non-Secure to simplify the code slightly compared to the full * table in the ARM ARM. */ - pac = extract64(wcr, 1, 2); - hmc = extract64(wcr, 13, 1); - ssc = extract64(wcr, 14, 2); + pac = extract64(cr, 1, 2); + hmc = extract64(cr, 13, 1); + ssc = extract64(cr, 14, 2); switch (ssc) { case 0: @@ -560,6 +639,7 @@ static bool wp_matches(ARMCPU *cpu, int n) * Implementing this would require reworking the core watchpoint code * to plumb the mmu_idx through to this point. Luckily Linux does not * rely on this behaviour currently. + * For breakpoints we do want to use the current CPU state. */ switch (arm_current_pl(env)) { case 3: @@ -582,8 +662,8 @@ static bool wp_matches(ARMCPU *cpu, int n) g_assert_not_reached(); } - wt = extract64(wcr, 20, 1); - lbn = extract64(wcr, 16, 4); + wt = extract64(cr, 20, 1); + lbn = extract64(cr, 16, 4); if (wt && !linked_bp_matches(cpu, lbn)) { return false; @@ -606,7 +686,28 @@ static bool check_watchpoints(ARMCPU *cpu) } for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) { - if (wp_matches(cpu, n)) { + if (bp_wp_matches(cpu, n, true)) { + return true; + } + } + return false; +} + +static bool check_breakpoints(ARMCPU *cpu) +{ + CPUARMState *env = &cpu->env; + int n; + + /* If breakpoints are disabled globally or we can't take debug + * exceptions here then breakpoint firings are ignored. + */ + if (extract32(env->cp15.mdscr_el1, 15, 1) == 0 + || !arm_generate_debug_exceptions(env)) { + return false; + } + + for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) { + if (bp_wp_matches(cpu, n, false)) { return true; } } @@ -641,6 +742,18 @@ void arm_debug_excp_handler(CPUState *cs) cpu_resume_from_signal(cs, NULL); } } + } else { + if (check_breakpoints(cpu)) { + bool same_el = (arm_debug_target_el(env) == arm_current_pl(env)); + env->exception.syndrome = syn_breakpoint(same_el); + if (extended_addresses_enabled(env)) { + env->exception.fsr = (1 << 9) | 0x22; + } else { + env->exception.fsr = 0x2; + } + /* FAR is UNKNOWN, so doesn't need setting */ + raise_exception(env, EXCP_PREFETCH_ABORT); + } } } |