target-arm: Add support for A32 and T32 HVC and SMC insns
Add support for HVC and SMC instructions to the A32 and T32 decoder. Using these for real exceptions to EL2 or EL3 is currently not supported (the do_interrupt routine does not handle them) but we require the instruction support to implement PSCI. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1412865028-17725-6-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
3940433843
commit
37e6456ef5
@ -236,6 +236,16 @@ static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
|
||||
| (is_thumb ? 0 : ARM_EL_IL);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_hvc(uint32_t imm16)
|
||||
{
|
||||
return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_smc(void)
|
||||
{
|
||||
return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
|
||||
{
|
||||
return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
|
@ -941,6 +941,39 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
|
||||
tcg_gen_movi_i32(cpu_R[15], val);
|
||||
}
|
||||
|
||||
static inline void gen_hvc(DisasContext *s, int imm16)
|
||||
{
|
||||
/* The pre HVC helper handles cases when HVC gets trapped
|
||||
* as an undefined insn by runtime configuration (ie before
|
||||
* the insn really executes).
|
||||
*/
|
||||
gen_set_pc_im(s, s->pc - 4);
|
||||
gen_helper_pre_hvc(cpu_env);
|
||||
/* Otherwise we will treat this as a real exception which
|
||||
* happens after execution of the insn. (The distinction matters
|
||||
* for the PC value reported to the exception handler and also
|
||||
* for single stepping.)
|
||||
*/
|
||||
s->svc_imm = imm16;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_HVC;
|
||||
}
|
||||
|
||||
static inline void gen_smc(DisasContext *s)
|
||||
{
|
||||
/* As with HVC, we may take an exception either before or after
|
||||
* the insn executes.
|
||||
*/
|
||||
TCGv_i32 tmp;
|
||||
|
||||
gen_set_pc_im(s, s->pc - 4);
|
||||
tmp = tcg_const_i32(syn_aa32_smc());
|
||||
gen_helper_pre_smc(cpu_env, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_SMC;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gen_set_condexec (DisasContext *s)
|
||||
{
|
||||
@ -7872,15 +7905,32 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
|
||||
case 7:
|
||||
{
|
||||
int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
|
||||
/* SMC instruction (op1 == 3)
|
||||
and undefined instructions (op1 == 0 || op1 == 2)
|
||||
will trap */
|
||||
if (op1 != 1) {
|
||||
goto illegal_op;
|
||||
}
|
||||
switch (op1) {
|
||||
case 1:
|
||||
/* bkpt */
|
||||
ARCH(5);
|
||||
gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));
|
||||
gen_exception_insn(s, 4, EXCP_BKPT,
|
||||
syn_aa32_bkpt(imm16, false));
|
||||
break;
|
||||
case 2:
|
||||
/* Hypervisor call (v7) */
|
||||
ARCH(7);
|
||||
if (IS_USER(s)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_hvc(s, imm16);
|
||||
break;
|
||||
case 3:
|
||||
/* Secure monitor call (v6+) */
|
||||
ARCH(6K);
|
||||
if (IS_USER(s)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_smc(s);
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x8: /* signed multiply */
|
||||
@ -9710,10 +9760,23 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
goto illegal_op;
|
||||
|
||||
if (insn & (1 << 26)) {
|
||||
/* Secure monitor call (v6Z) */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"arm: unimplemented secure monitor call\n");
|
||||
goto illegal_op; /* not implemented. */
|
||||
if (!(insn & (1 << 20))) {
|
||||
/* Hypervisor call (v7) */
|
||||
int imm16 = extract32(insn, 16, 4) << 12
|
||||
| extract32(insn, 0, 12);
|
||||
ARCH(7);
|
||||
if (IS_USER(s)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_hvc(s, imm16);
|
||||
} else {
|
||||
/* Secure monitor call (v6+) */
|
||||
ARCH(6K);
|
||||
if (IS_USER(s)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_smc(s);
|
||||
}
|
||||
} else {
|
||||
op = (insn >> 20) & 7;
|
||||
switch (op) {
|
||||
@ -11148,6 +11211,12 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (dc->is_jmp == DISAS_SWI) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
} else if (dc->is_jmp == DISAS_HVC) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
|
||||
} else if (dc->is_jmp == DISAS_SMC) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_SMC, syn_aa32_smc());
|
||||
} else if (dc->ss_active) {
|
||||
gen_step_complete_exception(dc);
|
||||
} else {
|
||||
@ -11163,6 +11232,12 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
} else if (dc->is_jmp == DISAS_HVC && !dc->condjmp) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
|
||||
} else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_SMC, syn_aa32_smc());
|
||||
} else if (dc->ss_active) {
|
||||
gen_step_complete_exception(dc);
|
||||
} else {
|
||||
@ -11202,6 +11277,12 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
case DISAS_SWI:
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
break;
|
||||
case DISAS_HVC:
|
||||
gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
|
||||
break;
|
||||
case DISAS_SMC:
|
||||
gen_exception(EXCP_SMC, syn_aa32_smc());
|
||||
break;
|
||||
}
|
||||
if (dc->condjmp) {
|
||||
gen_set_label(dc->condlabel);
|
||||
|
@ -84,6 +84,8 @@ static inline int get_mem_index(DisasContext *s)
|
||||
#define DISAS_EXC 6
|
||||
/* WFE */
|
||||
#define DISAS_WFE 7
|
||||
#define DISAS_HVC 8
|
||||
#define DISAS_SMC 9
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
void a64_translate_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user