mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 02:55:06 +00:00
target-arm: Add isread parameter to CPAccessFns
System registers might have access requirements which need to be described via a CPAccessFn and which differ for reads and writes. For this to be possible we need to pass the access function a parameter to tell it whether the access being checked is a read or a write. Backports commit 3f208fd76bcc91a8506681bb8472f2398fe6f487 from qemu
This commit is contained in:
parent
4838c1dfe9
commit
6dbc781ce3
|
@ -1332,7 +1332,9 @@ typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
|||
typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
|
||||
uint64_t value);
|
||||
/* Access permission check functions for coprocessor registers. */
|
||||
typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
typedef CPAccessResult CPAccessFn(CPUARMState *env,
|
||||
const ARMCPRegInfo *opaque,
|
||||
bool isread);
|
||||
/* Hook function for register reset */
|
||||
typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
|
||||
|
|
|
@ -251,7 +251,8 @@ void init_cpreg_list(ARMCPU *cpu)
|
|||
* access_el3_aa32ns_aa64any: Used to check both AArch32/64 register views.
|
||||
*/
|
||||
static CPAccessResult access_el3_aa32ns(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
bool secure = arm_is_secure_below_el3(env);
|
||||
|
||||
|
@ -263,10 +264,11 @@ static CPAccessResult access_el3_aa32ns(CPUARMState *env,
|
|||
}
|
||||
|
||||
static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (!arm_el_is_aa64(env, 3)) {
|
||||
return access_el3_aa32ns(env, ri);
|
||||
return access_el3_aa32ns(env, ri, isread);
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
@ -277,7 +279,8 @@ static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env,
|
|||
* We assume that the .access field is set to PL1_RW.
|
||||
*/
|
||||
static CPAccessResult access_trap_aa32s_el1(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 3) {
|
||||
return CP_ACCESS_OK;
|
||||
|
@ -540,7 +543,8 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
env->cp15.cpacr_el1 = value;
|
||||
}
|
||||
|
||||
static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* Check if CPACR accesses are to be trapped to EL2 */
|
||||
|
@ -557,7 +561,8 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Check if CPTR accesses are set to trap to EL3 */
|
||||
if (arm_current_el(env) == 2 && (env->cp15.cptr_el[3] & CPTR_TCPAC)) {
|
||||
|
@ -596,7 +601,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Performance monitor registers user accessibility is controlled
|
||||
* by PMUSERENR.
|
||||
|
@ -1010,7 +1016,8 @@ static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
env->teecr = value;
|
||||
}
|
||||
|
||||
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && (env->teecr & 1)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -1051,7 +1058,8 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
|
|||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
|
||||
if (arm_current_el(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
|
||||
|
@ -1060,7 +1068,8 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
|
||||
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
|
||||
bool isread)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
@ -1079,7 +1088,8 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
|
||||
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
|
||||
bool isread)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
@ -1101,29 +1111,34 @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
|
|||
}
|
||||
|
||||
static CPAccessResult gt_pct_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_counter_access(env, GTIMER_PHYS);
|
||||
return gt_counter_access(env, GTIMER_PHYS, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_vct_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_counter_access(env, GTIMER_VIRT);
|
||||
return gt_counter_access(env, GTIMER_VIRT, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_timer_access(env, GTIMER_PHYS);
|
||||
return gt_timer_access(env, GTIMER_PHYS, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_timer_access(env, GTIMER_VIRT);
|
||||
return gt_timer_access(env, GTIMER_VIRT, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* The AArch64 register view of the secure physical timer is
|
||||
* always accessible from EL3, and configurably accessible from
|
||||
|
@ -1523,7 +1538,8 @@ static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
/* get_phys_addr() isn't present for user-mode-only targets */
|
||||
|
||||
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (ri->opc2 & 4) {
|
||||
/* The ATS12NSO* operations must trap to EL3 if executed in
|
||||
|
@ -1668,7 +1684,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
A32_BANKED_CURRENT_REG_SET(env, par, par64);
|
||||
}
|
||||
|
||||
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 3 && !(env->cp15.scr_el3 & SCR_NS)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -2260,7 +2277,8 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
vfp_set_fpsr(env, value);
|
||||
}
|
||||
|
||||
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -2275,7 +2293,8 @@ static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
}
|
||||
|
||||
static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
|
||||
* SCTLR_EL1.UCI is set.
|
||||
|
@ -2548,7 +2567,8 @@ static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
*/
|
||||
}
|
||||
|
||||
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* We don't implement EL2, so the only control on DC ZVA is the
|
||||
* bit in the SCTLR which can prohibit access for EL0.
|
||||
|
@ -2565,13 +2585,14 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
int dzp_bit = 1 << 4;
|
||||
|
||||
/* DZP indicates whether DC ZVA access is allowed */
|
||||
if (aa64_zva_access(env, NULL) == CP_ACCESS_OK) {
|
||||
if (aa64_zva_access(env, NULL, false) == CP_ACCESS_OK) {
|
||||
dzp_bit = 0;
|
||||
}
|
||||
return cpu->dcz_blocksize | dzp_bit;
|
||||
}
|
||||
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (!(env->pstate & PSTATE_SP)) {
|
||||
/* Access to SP_EL0 is undefined if it's being used as
|
||||
|
@ -2610,7 +2631,8 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
tlb_flush(CPU(cpu), 1);
|
||||
}
|
||||
|
||||
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
|
@ -3149,7 +3171,8 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
|
||||
* but the AArch32 CTR has its own reginfo struct)
|
||||
|
|
|
@ -65,7 +65,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
|
|||
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
|
||||
DEF_HELPER_2(v7m_mrs, i32, env, i32)
|
||||
|
||||
DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
|
||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
||||
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
|
||||
|
|
|
@ -457,7 +457,8 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
|
||||
uint32_t isread)
|
||||
{
|
||||
const ARMCPRegInfo *ri = rip;
|
||||
int target_el;
|
||||
|
@ -471,7 +472,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (ri->accessfn(env, ri)) {
|
||||
switch (ri->accessfn(env, ri, isread)) {
|
||||
case CP_ACCESS_OK:
|
||||
return;
|
||||
case CP_ACCESS_TRAP:
|
||||
|
|
|
@ -1409,16 +1409,18 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
* runtime; this may result in an exception.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
TCGv_i32 tcg_syn;
|
||||
TCGv_i32 tcg_syn, tcg_isread;
|
||||
uint32_t syndrome;
|
||||
|
||||
gen_a64_set_pc_im(s, s->pc - 4);
|
||||
tmpptr = tcg_const_ptr(tcg_ctx, ri);
|
||||
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
|
||||
tcg_syn = tcg_const_i32(tcg_ctx, syndrome);
|
||||
gen_helper_access_check_cp_reg(tcg_ctx, tcg_ctx->cpu_env, tmpptr, tcg_syn);
|
||||
tcg_isread = tcg_const_i32(tcg_ctx, isread);
|
||||
gen_helper_access_check_cp_reg(tcg_ctx, tcg_ctx->cpu_env, tmpptr, tcg_syn, tcg_isread);
|
||||
tcg_temp_free_ptr(tcg_ctx, tmpptr);
|
||||
tcg_temp_free_i32(tcg_ctx, tcg_syn);
|
||||
tcg_temp_free_i32(tcg_ctx, tcg_isread);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
|
|
|
@ -7299,7 +7299,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
* call in order to handle c15_cpar.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
TCGv_i32 tcg_syn;
|
||||
TCGv_i32 tcg_syn, tcg_isread;
|
||||
uint32_t syndrome;
|
||||
|
||||
/* Note that since we are an implementation which takes an
|
||||
|
@ -7344,7 +7344,9 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
gen_set_pc_im(s, s->pc - 4);
|
||||
tmpptr = tcg_const_ptr(tcg_ctx, ri);
|
||||
tcg_syn = tcg_const_i32(tcg_ctx, syndrome);
|
||||
gen_helper_access_check_cp_reg(tcg_ctx, tcg_ctx->cpu_env, tmpptr, tcg_syn);
|
||||
tcg_isread = tcg_const_i32(tcg_ctx, isread);
|
||||
gen_helper_access_check_cp_reg(tcg_ctx, tcg_ctx->cpu_env, tmpptr, tcg_syn,
|
||||
tcg_isread);
|
||||
tcg_temp_free_ptr(tcg_ctx, tmpptr);
|
||||
tcg_temp_free_i32(tcg_ctx, tcg_syn);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue