#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
static TCGv_i64 cpu_X[32];
static TCGv_i64 cpu_pc;
static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
+typedef void CryptoTwoOpEnvFn(TCGv_ptr, TCGv_i32, TCGv_i32);
+typedef void CryptoThreeOpEnvFn(TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32);
/* initialize TCG globals. */
void a64_translate_init(void)
#endif
}
+static inline ARMMMUIdx get_a64_user_mem_index(DisasContext *s)
+{
+ /* Return the mmu_idx to use for A64 "unprivileged load/store" insns:
+ * if EL1, access as if EL0; otherwise access at current EL
+ */
+ switch (s->mmu_idx) {
+ case ARMMMUIdx_S12NSE1:
+ return ARMMMUIdx_S12NSE0;
+ case ARMMMUIdx_S1SE1:
+ return ARMMMUIdx_S1SE0;
+ case ARMMMUIdx_S2NS:
+ g_assert_not_reached();
+ default:
+ return s->mmu_idx;
+ }
+}
+
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf, int flags)
{
tcg_temp_free_i32(tcg_excp);
}
-static void gen_exception(int excp, uint32_t syndrome)
+static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
{
TCGv_i32 tcg_excp = tcg_const_i32(excp);
TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
+ TCGv_i32 tcg_el = tcg_const_i32(target_el);
- gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
+ gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
+ tcg_syn, tcg_el);
+ tcg_temp_free_i32(tcg_el);
tcg_temp_free_i32(tcg_syn);
tcg_temp_free_i32(tcg_excp);
}
}
static void gen_exception_insn(DisasContext *s, int offset, int excp,
- uint32_t syndrome)
+ uint32_t syndrome, uint32_t target_el)
{
gen_a64_set_pc_im(s->pc - offset);
- gen_exception(excp, syndrome);
+ gen_exception(excp, syndrome, target_el);
+ s->is_jmp = DISAS_EXC;
+}
+
+static void gen_ss_advance(DisasContext *s)
+{
+ /* If the singlestep state is Active-not-pending, advance to
+ * Active-pending.
+ */
+ if (s->ss_active) {
+ s->pstate_ss = 0;
+ gen_helper_clear_pstate_ss(cpu_env);
+ }
+}
+
+static void gen_step_complete_exception(DisasContext *s)
+{
+ /* We just completed step of an insn. Move from Active-not-pending
+ * to Active-pending, and then also take the swstep exception.
+ * This corresponds to making the (IMPDEF) choice to prioritize
+ * swstep exceptions over asynchronous exceptions taken to an exception
+ * level where debug is disabled. This choice has the advantage that
+ * we do not need to maintain internal state corresponding to the
+ * ISV/EX syndrome bits between completion of the step and generation
+ * of the exception, and our syndrome information is always correct.
+ */
+ gen_ss_advance(s);
+ gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
+ default_exception_el(s));
s->is_jmp = DISAS_EXC;
}
static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
{
- /* No direct tb linking with singlestep or deterministic io */
- if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
+ /* No direct tb linking with singlestep (either QEMU's or the ARM
+ * debug architecture kind) or deterministic io
+ */
+ if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
return false;
}
s->is_jmp = DISAS_TB_JUMP;
} else {
gen_a64_set_pc_im(dest);
- if (s->singlestep_enabled) {
+ if (s->ss_active) {
+ gen_step_complete_exception(s);
+ } else if (s->singlestep_enabled) {
gen_exception_internal(EXCP_DEBUG);
+ } else {
+ tcg_gen_exit_tb(0);
+ s->is_jmp = DISAS_TB_JUMP;
}
- tcg_gen_exit_tb(0);
- s->is_jmp = DISAS_JUMP;
}
}
static void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */
- gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
+ default_exception_el(s));
}
#define unsupported_encoding(s, insn) \
static inline void assert_fp_access_checked(DisasContext *s)
{
#ifdef CONFIG_DEBUG_TCG
- if (unlikely(!s->fp_access_checked || !s->cpacr_fpen)) {
+ if (unlikely(!s->fp_access_checked || s->fp_excp_el)) {
fprintf(stderr, "target-arm: FP access check missing for "
"instruction 0x%08x\n", s->insn);
abort();
TCGv_i64 flag = tcg_temp_new_i64();
tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
- tcg_gen_trunc_i64_i32(cpu_ZF, flag);
+ tcg_gen_extrl_i64_i32(cpu_ZF, flag);
tcg_gen_shri_i64(flag, result, 32);
- tcg_gen_trunc_i64_i32(cpu_NF, flag);
+ tcg_gen_extrl_i64_i32(cpu_NF, flag);
tcg_temp_free_i64(flag);
}
if (sf) {
gen_set_NZ64(result);
} else {
- tcg_gen_trunc_i64_i32(cpu_ZF, result);
- tcg_gen_trunc_i64_i32(cpu_NF, result);
+ tcg_gen_extrl_i64_i32(cpu_ZF, result);
+ tcg_gen_extrl_i64_i32(cpu_NF, result);
}
tcg_gen_movi_i32(cpu_CF, 0);
tcg_gen_movi_i32(cpu_VF, 0);
tcg_gen_movi_i64(tmp, 0);
tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
- tcg_gen_trunc_i64_i32(cpu_CF, flag);
+ tcg_gen_extrl_i64_i32(cpu_CF, flag);
gen_set_NZ64(result);
tcg_gen_andc_i64(flag, flag, tmp);
tcg_temp_free_i64(tmp);
tcg_gen_shri_i64(flag, flag, 32);
- tcg_gen_trunc_i64_i32(cpu_VF, flag);
+ tcg_gen_extrl_i64_i32(cpu_VF, flag);
tcg_gen_mov_i64(dest, result);
tcg_temp_free_i64(result);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp, 0);
- tcg_gen_trunc_i64_i32(t0_32, t0);
- tcg_gen_trunc_i64_i32(t1_32, t1);
+ tcg_gen_extrl_i64_i32(t0_32, t0);
+ tcg_gen_extrl_i64_i32(t1_32, t1);
tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
tcg_gen_mov_i32(cpu_ZF, cpu_NF);
tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
gen_set_NZ64(result);
tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
- tcg_gen_trunc_i64_i32(cpu_CF, flag);
+ tcg_gen_extrl_i64_i32(cpu_CF, flag);
tcg_gen_xor_i64(flag, result, t0);
tmp = tcg_temp_new_i64();
tcg_gen_and_i64(flag, flag, tmp);
tcg_temp_free_i64(tmp);
tcg_gen_shri_i64(flag, flag, 32);
- tcg_gen_trunc_i64_i32(cpu_VF, flag);
+ tcg_gen_extrl_i64_i32(cpu_VF, flag);
tcg_gen_mov_i64(dest, result);
tcg_temp_free_i64(flag);
tcg_temp_free_i64(result);
TCGv_i32 t1_32 = tcg_temp_new_i32();
TCGv_i32 tmp;
- tcg_gen_trunc_i64_i32(t0_32, t0);
- tcg_gen_trunc_i64_i32(t1_32, t1);
+ tcg_gen_extrl_i64_i32(t0_32, t0);
+ tcg_gen_extrl_i64_i32(t1_32, t1);
tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
tcg_gen_mov_i32(cpu_ZF, cpu_NF);
tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
tcg_gen_extu_i32_i64(cf_64, cpu_CF);
tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp);
tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp);
- tcg_gen_trunc_i64_i32(cpu_CF, cf_64);
+ tcg_gen_extrl_i64_i32(cpu_CF, cf_64);
gen_set_NZ64(result);
tcg_gen_xor_i64(vf_64, result, t0);
tcg_gen_xor_i64(tmp, t0, t1);
tcg_gen_andc_i64(vf_64, vf_64, tmp);
tcg_gen_shri_i64(vf_64, vf_64, 32);
- tcg_gen_trunc_i64_i32(cpu_VF, vf_64);
+ tcg_gen_extrl_i64_i32(cpu_VF, vf_64);
tcg_gen_mov_i64(dest, result);
t1_32 = tcg_temp_new_i32();
tmp = tcg_const_i32(0);
- tcg_gen_trunc_i64_i32(t0_32, t0);
- tcg_gen_trunc_i64_i32(t1_32, t1);
+ tcg_gen_extrl_i64_i32(t0_32, t0);
+ tcg_gen_extrl_i64_i32(t1_32, t1);
tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp);
tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp);
} else {
TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
- tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx));
tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
assert(!s->fp_access_checked);
s->fp_access_checked = true;
- if (s->cpacr_fpen) {
+ if (!s->fp_excp_el) {
return true;
}
- gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false));
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false),
+ s->fp_excp_el);
return false;
}
{
uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
- if (insn & (1 << 31)) {
+ if (insn & (1U << 31)) {
/* C5.6.26 BL Branch with link */
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
}
{
unsigned int sf, op, rt;
uint64_t addr;
- int label_match;
+ TCGLabel *label_match;
TCGv_i64 tcg_cmp;
sf = extract32(insn, 31, 1);
{
unsigned int bit_pos, op, rt;
uint64_t addr;
- int label_match;
+ TCGLabel *label_match;
TCGv_i64 tcg_cmp;
bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
if (cond < 0x0e) {
/* genuinely conditional branches */
- int label_match = gen_new_label();
+ TCGLabel *label_match = gen_new_label();
arm_gen_test_cc(cond, label_match);
gen_goto_tb(s, 0, s->pc);
gen_set_label(label_match);
s->is_jmp = DISAS_WFI;
return;
case 1: /* YIELD */
+ s->is_jmp = DISAS_YIELD;
+ return;
case 2: /* WFE */
s->is_jmp = DISAS_WFE;
return;
int op = op1 << 3 | op2;
switch (op) {
case 0x05: /* SPSel */
- if (s->current_pl == 0) {
+ if (s->current_el == 0) {
unallocated_encoding(s);
return;
}
TCGv_i32 nzcv = tcg_temp_new_i32();
/* build bit 31, N */
- tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
+ tcg_gen_andi_i32(nzcv, cpu_NF, (1U << 31));
/* build bit 30, Z */
tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
TCGv_i32 nzcv = tcg_temp_new_i32();
/* take NZCV from R[t] */
- tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
+ tcg_gen_extrl_i64_i32(nzcv, tcg_rt);
/* bit 31, N */
- tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
+ tcg_gen_andi_i32(cpu_NF, nzcv, (1U << 31));
/* bit 30, Z */
tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
}
/* Check access permissions */
- if (!cp_access_ok(s->current_pl, ri, isread)) {
+ if (!cp_access_ok(s->current_el, ri, isread)) {
unallocated_encoding(s);
return;
}
* guaranteed to be constant by the tb flags.
*/
tcg_rt = cpu_reg(s, rt);
- tcg_gen_movi_i64(tcg_rt, s->current_pl << 2);
+ tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
return;
case ARM_CP_DC_ZVA:
/* Writes clear the aligned block of memory which rt points into. */
break;
}
- if (use_icount && (ri->type & ARM_CP_IO)) {
+ if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
gen_io_start();
}
}
}
- if (use_icount && (ri->type & ARM_CP_IO)) {
+ if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
gen_io_end();
s->is_jmp = DISAS_UPDATE;
int opc = extract32(insn, 21, 3);
int op2_ll = extract32(insn, 0, 5);
int imm16 = extract32(insn, 5, 16);
+ TCGv_i32 tmp;
switch (opc) {
case 0:
- /* SVC, HVC, SMC; since we don't support the Virtualization
- * or TrustZone extensions these all UNDEF except SVC.
+ /* 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.
*/
- if (op2_ll != 1) {
+ switch (op2_ll) {
+ case 1:
+ gen_ss_advance(s);
+ gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16),
+ default_exception_el(s));
+ break;
+ case 2:
+ if (s->current_el == 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), 2);
+ break;
+ case 3:
+ if (s->current_el == 0) {
+ unallocated_encoding(s);
+ break;
+ }
+ gen_a64_set_pc_im(s->pc - 4);
+ tmp = tcg_const_i32(syn_aa64_smc(imm16));
+ gen_helper_pre_smc(cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
+ gen_ss_advance(s);
+ gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16), 3);
+ break;
+ default:
unallocated_encoding(s);
break;
}
- gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16));
break;
case 1:
if (op2_ll != 0) {
break;
}
/* BRK */
- gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16));
+ gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16),
+ default_exception_el(s));
break;
case 2:
if (op2_ll != 0) {
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
break;
case 4: /* ERET */
- if (s->current_pl == 0) {
+ if (s->current_el == 0) {
unallocated_encoding(s);
return;
}
* }
* env->exclusive_addr = -1;
*/
- int fail_label = gen_new_label();
- int done_label = gen_new_label();
+ TCGLabel *fail_label = gen_new_label();
+ TCGLabel *done_label = gen_new_label();
TCGv_i64 addr = tcg_temp_local_new_i64();
TCGv_i64 tmp;
if (is_excl) {
if (!is_store) {
+ s->is_ldex = true;
gen_load_exclusive(s, rt, rt2, tcg_addr, size, is_pair);
} else {
gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, is_pair);
int rt = extract32(insn, 0, 5);
int rn = extract32(insn, 5, 5);
int rt2 = extract32(insn, 10, 5);
- int64_t offset = sextract32(insn, 15, 7);
+ uint64_t offset = sextract64(insn, 15, 7);
int index = extract32(insn, 23, 2);
bool is_vector = extract32(insn, 26, 1);
bool is_load = extract32(insn, 22, 1);
}
} else {
TCGv_i64 tcg_rt = cpu_reg(s, rt);
- int memidx = is_unpriv ? 1 : get_mem_index(s);
+ int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
if (is_store) {
do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx);
{
unsigned int page, rd;
uint64_t base;
- int64_t offset;
+ uint64_t offset;
page = extract32(insn, 31, 1);
/* SignExtend(immhi:immlo) -> offset */
- offset = ((int64_t)sextract32(insn, 5, 19) << 2) | extract32(insn, 29, 2);
+ offset = sextract64(insn, 5, 19);
+ offset = offset << 2 | extract32(insn, 29, 2);
rd = extract32(insn, 0, 5);
base = s->pc - 4;
* by r within the element (which is e bits wide)...
*/
mask = bitmask64(s + 1);
- mask = (mask >> r) | (mask << (e - r));
+ if (r) {
+ mask = (mask >> r) | (mask << (e - r));
+ mask &= bitmask64(e);
+ }
/* ...then replicate the element over the whole 64 bit value */
mask = bitfield_replicate(mask, e);
*result = mask;
TCGv_i32 t0, t1;
t0 = tcg_temp_new_i32();
t1 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(t0, src);
- tcg_gen_trunc_i64_i32(t1, shift_amount);
+ tcg_gen_extrl_i64_i32(t0, src);
+ tcg_gen_extrl_i64_i32(t1, shift_amount);
tcg_gen_rotr_i32(t0, t0, t1);
tcg_gen_extu_i32_i64(dst, t0);
tcg_temp_free_i32(t0);
static void disas_cc(DisasContext *s, uint32_t insn)
{
unsigned int sf, op, y, cond, rn, nzcv, is_imm;
- int label_continue = -1;
+ TCGLabel *label_continue = NULL;
TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
if (!extract32(insn, 29, 1)) {
nzcv = extract32(insn, 0, 4);
if (cond < 0x0e) { /* not always */
- int label_match = gen_new_label();
+ TCGLabel *label_match = gen_new_label();
label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
/* OPTME: we could use movcond here, at the cost of duplicating
* a lot of the arm_gen_test_cc() logic.
*/
- int label_match = gen_new_label();
- int label_continue = gen_new_label();
+ TCGLabel *label_match = gen_new_label();
+ TCGLabel *label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
gen_helper_clz64(tcg_rd, tcg_rn);
} else {
TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
gen_helper_clz(tcg_tmp32, tcg_tmp32);
tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
tcg_temp_free_i32(tcg_tmp32);
gen_helper_cls64(tcg_rd, tcg_rn);
} else {
TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
gen_helper_cls32(tcg_tmp32, tcg_tmp32);
tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
tcg_temp_free_i32(tcg_tmp32);
gen_helper_rbit64(tcg_rd, tcg_rn);
} else {
TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
gen_helper_rbit(tcg_tmp32, tcg_tmp32);
tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
tcg_temp_free_i32(tcg_tmp32);
{
unsigned int mos, type, rm, cond, rn, op, nzcv;
TCGv_i64 tcg_flags;
- int label_continue = -1;
+ TCGLabel *label_continue = NULL;
mos = extract32(insn, 29, 3);
type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
}
if (cond < 0x0e) { /* not always */
- int label_match = gen_new_label();
+ TCGLabel *label_match = gen_new_label();
label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
static void disas_fp_csel(DisasContext *s, uint32_t insn)
{
unsigned int mos, type, rm, cond, rn, rd;
- int label_continue = -1;
+ TCGLabel *label_continue = NULL;
mos = extract32(insn, 29, 3);
type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
}
if (cond < 0x0e) { /* not always */
- int label_match = gen_new_label();
+ TCGLabel *label_match = gen_new_label();
label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
assert(elements == 4);
read_vec_element(s, tcg_elt, rn, 0, MO_32);
- tcg_gen_trunc_i64_i32(tcg_elt1, tcg_elt);
+ tcg_gen_extrl_i64_i32(tcg_elt1, tcg_elt);
read_vec_element(s, tcg_elt, rn, 1, MO_32);
- tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
+ tcg_gen_extrl_i64_i32(tcg_elt2, tcg_elt);
do_minmaxop(s, tcg_elt1, tcg_elt2, opcode, is_min, fpst);
read_vec_element(s, tcg_elt, rn, 2, MO_32);
- tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
+ tcg_gen_extrl_i64_i32(tcg_elt2, tcg_elt);
read_vec_element(s, tcg_elt, rn, 3, MO_32);
- tcg_gen_trunc_i64_i32(tcg_elt3, tcg_elt);
+ tcg_gen_extrl_i64_i32(tcg_elt3, tcg_elt);
do_minmaxop(s, tcg_elt2, tcg_elt3, opcode, is_min, fpst);
tcg_shift = tcg_const_i32(fracbits);
if (is_double) {
- int maxpass = is_scalar ? 1 : is_q ? 2 : 1;
+ int maxpass = is_scalar ? 1 : 2;
for (pass = 0; pass < maxpass; pass++) {
TCGv_i64 tcg_op = tcg_temp_new_i64();
static NeonGenNarrowFn * const xtnfns[3] = {
gen_helper_neon_narrow_u8,
gen_helper_neon_narrow_u16,
- tcg_gen_trunc_i64_i32,
+ tcg_gen_extrl_i64_i32,
};
static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
gen_helper_neon_unarrow_sat8,
} else {
TCGv_i32 tcg_lo = tcg_temp_new_i32();
TCGv_i32 tcg_hi = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(tcg_lo, tcg_op);
+ tcg_gen_extrl_i64_i32(tcg_lo, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, cpu_env);
tcg_gen_shri_i64(tcg_op, tcg_op, 32);
- tcg_gen_trunc_i64_i32(tcg_hi, tcg_op);
+ tcg_gen_extrl_i64_i32(tcg_hi, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, cpu_env);
tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
tcg_temp_free_i32(tcg_lo);
static void do_narrow_high_u32(TCGv_i32 res, TCGv_i64 in)
{
tcg_gen_shri_i64(in, in, 32);
- tcg_gen_trunc_i64_i32(res, in);
+ tcg_gen_extrl_i64_i32(res, in);
}
static void do_narrow_round_high_u32(TCGv_i32 res, TCGv_i64 in)
}
if (size == 3) {
- for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
+ assert(is_q);
+ for (pass = 0; pass < 2; pass++) {
TCGv_i64 tcg_op1 = tcg_temp_new_i64();
TCGv_i64 tcg_op2 = tcg_temp_new_i64();
TCGv_i64 tcg_res = tcg_temp_new_i64();
*/
static void disas_crypto_aes(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ int size = extract32(insn, 22, 2);
+ int opcode = extract32(insn, 12, 5);
+ int rn = extract32(insn, 5, 5);
+ int rd = extract32(insn, 0, 5);
+ int decrypt;
+ TCGv_i32 tcg_rd_regno, tcg_rn_regno, tcg_decrypt;
+ CryptoThreeOpEnvFn *genfn;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
+ || size != 0) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opcode) {
+ case 0x4: /* AESE */
+ decrypt = 0;
+ genfn = gen_helper_crypto_aese;
+ break;
+ case 0x6: /* AESMC */
+ decrypt = 0;
+ genfn = gen_helper_crypto_aesmc;
+ break;
+ case 0x5: /* AESD */
+ decrypt = 1;
+ genfn = gen_helper_crypto_aese;
+ break;
+ case 0x7: /* AESIMC */
+ decrypt = 1;
+ genfn = gen_helper_crypto_aesmc;
+ break;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
+
+ /* Note that we convert the Vx register indexes into the
+ * index within the vfp.regs[] array, so we can share the
+ * helper with the AArch32 instructions.
+ */
+ tcg_rd_regno = tcg_const_i32(rd << 1);
+ tcg_rn_regno = tcg_const_i32(rn << 1);
+ tcg_decrypt = tcg_const_i32(decrypt);
+
+ genfn(cpu_env, tcg_rd_regno, tcg_rn_regno, tcg_decrypt);
+
+ tcg_temp_free_i32(tcg_rd_regno);
+ tcg_temp_free_i32(tcg_rn_regno);
+ tcg_temp_free_i32(tcg_decrypt);
}
/* C3.6.20 Crypto three-reg SHA
*/
static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ int size = extract32(insn, 22, 2);
+ int opcode = extract32(insn, 12, 3);
+ int rm = extract32(insn, 16, 5);
+ int rn = extract32(insn, 5, 5);
+ int rd = extract32(insn, 0, 5);
+ CryptoThreeOpEnvFn *genfn;
+ TCGv_i32 tcg_rd_regno, tcg_rn_regno, tcg_rm_regno;
+ int feature = ARM_FEATURE_V8_SHA256;
+
+ if (size != 0) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opcode) {
+ case 0: /* SHA1C */
+ case 1: /* SHA1P */
+ case 2: /* SHA1M */
+ case 3: /* SHA1SU0 */
+ genfn = NULL;
+ feature = ARM_FEATURE_V8_SHA1;
+ break;
+ case 4: /* SHA256H */
+ genfn = gen_helper_crypto_sha256h;
+ break;
+ case 5: /* SHA256H2 */
+ genfn = gen_helper_crypto_sha256h2;
+ break;
+ case 6: /* SHA256SU1 */
+ genfn = gen_helper_crypto_sha256su1;
+ break;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (!arm_dc_feature(s, feature)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_rd_regno = tcg_const_i32(rd << 1);
+ tcg_rn_regno = tcg_const_i32(rn << 1);
+ tcg_rm_regno = tcg_const_i32(rm << 1);
+
+ if (genfn) {
+ genfn(cpu_env, tcg_rd_regno, tcg_rn_regno, tcg_rm_regno);
+ } else {
+ TCGv_i32 tcg_opcode = tcg_const_i32(opcode);
+
+ gen_helper_crypto_sha1_3reg(cpu_env, tcg_rd_regno,
+ tcg_rn_regno, tcg_rm_regno, tcg_opcode);
+ tcg_temp_free_i32(tcg_opcode);
+ }
+
+ tcg_temp_free_i32(tcg_rd_regno);
+ tcg_temp_free_i32(tcg_rn_regno);
+ tcg_temp_free_i32(tcg_rm_regno);
}
/* C3.6.21 Crypto two-reg SHA
*/
static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ int size = extract32(insn, 22, 2);
+ int opcode = extract32(insn, 12, 5);
+ int rn = extract32(insn, 5, 5);
+ int rd = extract32(insn, 0, 5);
+ CryptoTwoOpEnvFn *genfn;
+ int feature;
+ TCGv_i32 tcg_rd_regno, tcg_rn_regno;
+
+ if (size != 0) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opcode) {
+ case 0: /* SHA1H */
+ feature = ARM_FEATURE_V8_SHA1;
+ genfn = gen_helper_crypto_sha1h;
+ break;
+ case 1: /* SHA1SU1 */
+ feature = ARM_FEATURE_V8_SHA1;
+ genfn = gen_helper_crypto_sha1su1;
+ break;
+ case 2: /* SHA256SU0 */
+ feature = ARM_FEATURE_V8_SHA256;
+ genfn = gen_helper_crypto_sha256su0;
+ break;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (!arm_dc_feature(s, feature)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_rd_regno = tcg_const_i32(rd << 1);
+ tcg_rn_regno = tcg_const_i32(rn << 1);
+
+ genfn(cpu_env, tcg_rd_regno, tcg_rn_regno);
+
+ tcg_temp_free_i32(tcg_rd_regno);
+ tcg_temp_free_i32(tcg_rn_regno);
}
/* C3.6 Data processing - SIMD, inc Crypto
CPUARMState *env = &cpu->env;
DisasContext dc1, *dc = &dc1;
CPUBreakpoint *bp;
- uint16_t *gen_opc_end;
int j, lj;
target_ulong pc_start;
target_ulong next_page_start;
dc->tb = tb;
- gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
-
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->singlestep_enabled = cs->singlestep_enabled;
dc->condjmp = 0;
dc->aarch64 = 1;
+ dc->el3_is_aa64 = arm_el_is_aa64(env, 3);
dc->thumb = 0;
dc->bswap_code = 0;
dc->condexec_mask = 0;
dc->condexec_cond = 0;
+ dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
+ dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
- dc->user = (ARM_TBFLAG_AA64_EL(tb->flags) == 0);
+ dc->user = (dc->current_el == 0);
#endif
- dc->cpacr_fpen = ARM_TBFLAG_AA64_FPEN(tb->flags);
+ dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = cpu->cp_regs;
- dc->current_pl = arm_current_pl(env);
dc->features = env->features;
+ /* Single step state. The code-generation logic here is:
+ * SS_ACTIVE == 0:
+ * generate code with no special handling for single-stepping (except
+ * that anything that can make us go to SS_ACTIVE == 1 must end the TB;
+ * this happens anyway because those changes are all system register or
+ * PSTATE writes).
+ * SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
+ * emit code for one insn
+ * emit code to clear PSTATE.SS
+ * emit code to generate software step exception for completed step
+ * end TB (as usual for having generated an exception)
+ * SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
+ * emit code to generate a software step exception
+ * end the TB
+ */
+ dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
+ dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
+ dc->is_ldex = false;
+ dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
+
init_tmp_a64_array(dc);
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
max_insns = CF_COUNT_MASK;
}
- gen_tb_start();
+ gen_tb_start(tb);
tcg_clear_temp_count();
}
if (search_pc) {
- j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
+ j = tcg_op_buf_count();
if (lj < j) {
lj++;
while (lj < j) {
tcg_gen_debug_insn_start(dc->pc);
}
+ if (dc->ss_active && !dc->pstate_ss) {
+ /* Singlestep state is Active-pending.
+ * If we're in this state at the start of a TB then either
+ * a) we just took an exception to an EL which is being debugged
+ * and this is the first insn in the exception handler
+ * b) debug exceptions were masked and we just unmasked them
+ * without changing EL (eg by clearing PSTATE.D)
+ * In either case we're going to take a swstep exception in the
+ * "did not step an insn" case, and so the syndrome ISV and EX
+ * bits should be zero.
+ */
+ assert(num_insns == 0);
+ gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
+ default_exception_el(dc));
+ dc->is_jmp = DISAS_EXC;
+ break;
+ }
+
disas_a64_insn(env, dc);
if (tcg_check_temp_count()) {
* ensures prefetch aborts occur at the right place.
*/
num_insns++;
- } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
+ } while (!dc->is_jmp && !tcg_op_buf_full() &&
!cs->singlestep_enabled &&
!singlestep &&
+ !dc->ss_active &&
dc->pc < next_page_start &&
num_insns < max_insns);
gen_io_end();
}
- if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
+ if (unlikely(cs->singlestep_enabled || dc->ss_active)
+ && dc->is_jmp != DISAS_EXC) {
/* Note that this means single stepping WFI doesn't halt the CPU.
* For conditional branch insns this is harmless unreachable code as
* gen_goto_tb() has already handled emitting the debug exception
if (dc->is_jmp != DISAS_JUMP) {
gen_a64_set_pc_im(dc->pc);
}
- gen_exception_internal(EXCP_DEBUG);
+ if (cs->singlestep_enabled) {
+ gen_exception_internal(EXCP_DEBUG);
+ } else {
+ gen_step_complete_exception(dc);
+ }
} else {
switch (dc->is_jmp) {
case DISAS_NEXT:
gen_a64_set_pc_im(dc->pc);
gen_helper_wfe(cpu_env);
break;
+ case DISAS_YIELD:
+ gen_a64_set_pc_im(dc->pc);
+ gen_helper_yield(cpu_env);
+ break;
case DISAS_WFI:
/* This is a special case because we don't want to just halt the CPU
* if trying to debug across a WFI.
*/
gen_a64_set_pc_im(dc->pc);
gen_helper_wfi(cpu_env);
+ /* The helper doesn't necessarily throw an exception, but we
+ * must go back to the main loop to check for interrupts anyway.
+ */
+ tcg_gen_exit_tb(0);
break;
}
}
done_generating:
gen_tb_end(tb, num_insns);
- *tcg_ctx.gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(env, pc_start, dc->pc - pc_start,
+ log_target_disas(cs, pc_start, dc->pc - pc_start,
4 | (dc->bswap_code << 1));
qemu_log("\n");
}
#endif
if (search_pc) {
- j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
+ j = tcg_op_buf_count();
lj++;
while (lj <= j) {
tcg_ctx.gen_opc_instr_start[lj++] = 0;