Skip to content

Commit

Permalink
target-arm: A64: Emulate the HVC insn
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
edgarigl authored and pm215 committed Sep 29, 2014
1 parent 2dd081a commit 35979d7
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 10 deletions.
1 change: 1 addition & 0 deletions target-arm/cpu.h
Expand Up @@ -51,6 +51,7 @@
#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */
#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */
#define EXCP_STREX 10
#define EXCP_HVC 11 /* HyperVisor Call */

#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
Expand Down
1 change: 1 addition & 0 deletions target-arm/helper-a64.c
Expand Up @@ -476,6 +476,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
case EXCP_BKPT:
case EXCP_UDEF:
case EXCP_SWI:
case EXCP_HVC:
env->cp15.esr_el[new_el] = env->exception.syndrome;
break;
case EXCP_IRQ:
Expand Down
20 changes: 19 additions & 1 deletion target-arm/helper.c
Expand Up @@ -3769,7 +3769,25 @@ void switch_mode(CPUARMState *env, int mode)
*/
unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx)
{
return 1;
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
unsigned int cur_el = arm_current_pl(env);
unsigned int target_el;

if (!env->aarch64) {
/* TODO: Add EL2 and 3 exception handling for AArch32. */
return 1;
}

switch (excp_idx) {
case EXCP_HVC:
target_el = 2;
break;
default:
target_el = MAX(cur_el, 1);
break;
}
return target_el;
}

static void v7m_push(CPUARMState *env, uint32_t val)
Expand Down
1 change: 1 addition & 0 deletions target-arm/helper.h
Expand Up @@ -50,6 +50,7 @@ DEF_HELPER_2(exception_internal, void, env, i32)
DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32)
DEF_HELPER_1(wfi, void, env)
DEF_HELPER_1(wfe, void, env)
DEF_HELPER_1(pre_hvc, void, env)

DEF_HELPER_3(cpsr_write, void, env, i32, i32)
DEF_HELPER_1(cpsr_read, i32, env)
Expand Down
6 changes: 6 additions & 0 deletions target-arm/internals.h
Expand Up @@ -53,6 +53,7 @@ static const char * const excnames[] = {
[EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
[EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
[EXCP_STREX] = "QEMU intercept of STREX",
[EXCP_HVC] = "Hypervisor Call",
};

static inline void arm_log_exception(int idx)
Expand Down Expand Up @@ -215,6 +216,11 @@ static inline uint32_t syn_aa64_svc(uint32_t imm16)
return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
}

static inline uint32_t syn_aa64_hvc(uint32_t imm16)
{
return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
}

static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
{
return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
Expand Down
31 changes: 31 additions & 0 deletions target-arm/op_helper.c
Expand Up @@ -385,6 +385,37 @@ 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(exception_return)(CPUARMState *env)
{
int cur_el = arm_current_pl(env);
Expand Down
31 changes: 22 additions & 9 deletions target-arm/translate-a64.c
Expand Up @@ -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) {
Expand Down

0 comments on commit 35979d7

Please sign in to comment.