static void handle_sys(DisasContext *s, uint32_t insn, bool isread, unsigned int op0, unsigned int op1, unsigned int op2, unsigned int crn, unsigned int crm, unsigned int rt) { const ARMCPRegInfo *ri; TCGv_i64 tcg_rt; ri = get_arm_cp_reginfo(s->cp_regs, ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)); if (!ri) { /* Unknown register; this might be a guest error or a QEMU * unimplemented feature. */ qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 " "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n", isread ? "read" : "write", op0, op1, crn, crm, op2); unallocated_encoding(s); return; } /* Check access permissions */ if (!cp_access_ok(s->current_el, ri, isread)) { unallocated_encoding(s); return; } if (ri->accessfn) { /* Emit code to perform further access permissions checks at * runtime; this may result in an exception. */ TCGv_ptr tmpptr; TCGv_i32 tcg_syn; uint32_t syndrome; gen_a64_set_pc_im(s->pc - 4); tmpptr = tcg_const_ptr(ri); syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); tcg_syn = tcg_const_i32(syndrome); gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn); tcg_temp_free_ptr(tmpptr); tcg_temp_free_i32(tcg_syn); } /* Handle special cases first */ switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) { case ARM_CP_NOP: return; case ARM_CP_NZCV: tcg_rt = cpu_reg(s, rt); if (isread) { gen_get_nzcv(tcg_rt); } else { gen_set_nzcv(tcg_rt); } return; case ARM_CP_CURRENTEL: /* Reads as current EL value from pstate, which is * guaranteed to be constant by the tb flags. */ tcg_rt = cpu_reg(s, rt); 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. */ tcg_rt = cpu_reg(s, rt); gen_helper_dc_zva(cpu_env, tcg_rt); return; default: break; } if (use_icount && (ri->type & ARM_CP_IO)) { gen_io_start(); } tcg_rt = cpu_reg(s, rt); if (isread) { if (ri->type & ARM_CP_CONST) { tcg_gen_movi_i64(tcg_rt, ri->resetvalue); } else if (ri->readfn) { TCGv_ptr tmpptr; tmpptr = tcg_const_ptr(ri); gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr); tcg_temp_free_ptr(tmpptr); } else { tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset); } } else { if (ri->type & ARM_CP_CONST) { /* If not forbidden by access permissions, treat as WI */ return; } else if (ri->writefn) { TCGv_ptr tmpptr; tmpptr = tcg_const_ptr(ri); gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt); tcg_temp_free_ptr(tmpptr); } else { tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset); } } if (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; } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { /* We default to ending the TB on a coprocessor register write, * but allow this to be suppressed by the register definition * (usually only necessary to work around guest bugs). */ s->is_jmp = DISAS_UPDATE; } }