diff options
author | Edgar E. Iglesias <edgar.iglesias@xilinx.com> | 2014-09-29 18:48:50 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-09-29 18:48:50 +0100 |
commit | 35979d71c40180a33242bf396a16b302f025fb82 (patch) | |
tree | eef6d1ae9410d77d8be30e9a964eeebc8b5783a1 /target-arm/translate-a64.c | |
parent | 2dd081ae7642d54470225ea8c3f5cd4ef62fc732 (diff) |
target-arm: A64: Emulate the HVC insn
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 1411718914-6608-8-git-send-email-edgar.iglesias@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/translate-a64.c')
-rw-r--r-- | target-arm/translate-a64.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 8e66b6c972..f4cb56e8e6 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1473,20 +1473,33 @@ static void disas_exc(DisasContext *s, uint32_t insn) switch (opc) { case 0: - /* SVC, HVC, SMC; since we don't support the Virtualization - * or TrustZone extensions these all UNDEF except SVC. - */ - if (op2_ll != 1) { - unallocated_encoding(s); - break; - } /* For SVC, HVC and SMC we advance the single-step state * machine before taking the exception. This is architecturally * mandated, to ensure that single-stepping a system call * instruction works properly. */ - gen_ss_advance(s); - gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); + switch (op2_ll) { + case 1: + gen_ss_advance(s); + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); + break; + case 2: + if (!arm_dc_feature(s, ARM_FEATURE_EL2) || s->current_pl == 0) { + unallocated_encoding(s); + break; + } + /* The pre HVC helper handles cases when HVC gets trapped + * as an undefined insn by runtime configuration. + */ + gen_a64_set_pc_im(s->pc - 4); + gen_helper_pre_hvc(cpu_env); + gen_ss_advance(s); + gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16)); + break; + default: + unallocated_encoding(s); + break; + } break; case 1: if (op2_ll != 0) { |