diff options
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) { |