target/arm: Move some TLBI insns to their own source file

target/arm/helper.c is very large and unwieldy.  One subset of code
that we can pull out into its own file is the cpreg arrays and
corresponding functions for the TLBI instructions.

Because these are instructions they are only relevant for TCG and we
can make the new file only be built for CONFIG_TCG.

In this commit we move the AArch32 instructions from:
 not_v7_cp_reginfo[]
 v7_cp_reginfo[]
 v7mp_cp_reginfo[]
 v8_cp_reginfo[]
into a new file target/arm/tcg/tlb-insns.c.

A few small functions are used both by functions we haven't yet moved
across and by functions we have already moved.  We temporarily make
these global with a prototype in cpregs.h; when the move of all TLBI
insns is complete these will return to being file-local.

For CONFIG_TCG, this is just moving code around.  For a KVM only
build, these cpregs will no longer be added to the cpregs hashtable
for the CPU.  However this should not be a behaviour change, because:
 * we never try to migration sync or otherwise include
   ARM_CP_NO_RAW cpregs
 * for migration we treat the kernel's list of system registers
   as the authoritative one, so these TLBI insns were never
   in it anyway
The no-tcg stub of define_tlb_insn_regs() therefore does nothing.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20241210160452.2427965-2-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2024-12-10 16:04:43 +00:00
parent 08e199bbc6
commit 1e32ee23cd
6 changed files with 280 additions and 220 deletions

View file

@ -1134,4 +1134,18 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
return ri->opc1 == 4 || ri->opc1 == 5; return ri->opc1 == 4 || ri->opc1 == 5;
} }
/*
* Temporary declarations of functions until the move to tlb_insn_helper.c
* is complete and we can make the functions static again
*/
CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread);
CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread);
bool tlb_force_broadcast(CPUARMState *env);
void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value);
void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value);
#endif /* TARGET_ARM_CPREGS_H */ #endif /* TARGET_ARM_CPREGS_H */

View file

@ -366,8 +366,8 @@ static CPAccessResult access_tacr(CPUARMState *env, const ARMCPRegInfo *ri,
} }
/* Check for traps from EL1 due to HCR_EL2.TTLB. */ /* Check for traps from EL1 due to HCR_EL2.TTLB. */
static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri, CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread) bool isread)
{ {
if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TTLB)) { if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TTLB)) {
return CP_ACCESS_TRAP_EL2; return CP_ACCESS_TRAP_EL2;
@ -376,8 +376,8 @@ static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri,
} }
/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */ /* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */
static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri, CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread) bool isread)
{ {
if (arm_current_el(env) == 1 && if (arm_current_el(env) == 1 &&
(arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) { (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) {
@ -455,104 +455,16 @@ static int alle1_tlbmask(CPUARMState *env)
ARMMMUIdxBit_Stage2_S); ARMMMUIdxBit_Stage2_S);
} }
/* IS variants of TLB operations must affect all cores */
static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_all_cpus_synced(cs);
}
static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_all_cpus_synced(cs);
}
static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
/* /*
* Non-IS variants of TLB operations are upgraded to * Non-IS variants of TLB operations are upgraded to
* IS versions if we are at EL1 and HCR_EL2.FB is effectively set to * IS versions if we are at EL1 and HCR_EL2.FB is effectively set to
* force broadcast of these operations. * force broadcast of these operations.
*/ */
static bool tlb_force_broadcast(CPUARMState *env) bool tlb_force_broadcast(CPUARMState *env)
{ {
return arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_FB); return arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_FB);
} }
static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate all (TLBIALL) */
CPUState *cs = env_cpu(env);
if (tlb_force_broadcast(env)) {
tlb_flush_all_cpus_synced(cs);
} else {
tlb_flush(cs);
}
}
static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
CPUState *cs = env_cpu(env);
value &= TARGET_PAGE_MASK;
if (tlb_force_broadcast(env)) {
tlb_flush_page_all_cpus_synced(cs, value);
} else {
tlb_flush_page(cs, value);
}
}
static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate by ASID (TLBIASID) */
CPUState *cs = env_cpu(env);
if (tlb_force_broadcast(env)) {
tlb_flush_all_cpus_synced(cs);
} else {
tlb_flush(cs);
}
}
static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
CPUState *cs = env_cpu(env);
value &= TARGET_PAGE_MASK;
if (tlb_force_broadcast(env)) {
tlb_flush_page_all_cpus_synced(cs, value);
} else {
tlb_flush_page(cs, value);
}
}
static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri, static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
@ -586,8 +498,8 @@ static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E2); tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E2);
} }
static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12); uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
@ -595,8 +507,8 @@ static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E2); tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E2);
} }
static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12); uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
@ -605,24 +517,6 @@ static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
ARMMMUIdxBit_E2); ARMMMUIdxBit_E2);
} }
static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
}
static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2);
}
static const ARMCPRegInfo cp_reginfo[] = { static const ARMCPRegInfo cp_reginfo[] = {
/* /*
* Define the secure and non-secure FCSE identifier CP registers * Define the secure and non-secure FCSE identifier CP registers
@ -732,22 +626,6 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
*/ */
{ .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, { .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 }, .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
/*
* MMU TLB control. Note that the wildcarding means we cover not just
* the unified TLB ops but also the dside/iside/inner-shareable variants.
*/
{ .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 0, .access = PL1_W, .writefn = tlbiall_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIMVA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 1, .access = PL1_W, .writefn = tlbimva_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIASID", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
.type = ARM_CP_NO_RAW },
{ .name = "PRRR", .cp = 15, .crn = 10, .crm = 2, { .name = "PRRR", .cp = 15, .crn = 10, .crm = 2,
.opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP }, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "NMRR", .cp = 15, .crn = 10, .crm = 2, { .name = "NMRR", .cp = 15, .crn = 10, .crm = 2,
@ -2331,55 +2209,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0,
.fgt = FGT_ISR_EL1, .fgt = FGT_ISR_EL1,
.type = ARM_CP_NO_RAW, .access = PL1_R, .readfn = isr_read }, .type = ARM_CP_NO_RAW, .access = PL1_R, .readfn = isr_read },
/* 32 bit ITLB invalidates */
{ .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "ITLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "ITLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
/* 32 bit DTLB invalidates */
{ .name = "DTLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "DTLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "DTLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
/* 32 bit TLB invalidates */
{ .name = "TLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "TLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "TLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
{ .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimvaa_write },
};
static const ARMCPRegInfo v7mp_cp_reginfo[] = {
/* 32 bit TLB invalidates, Inner Shareable */
{ .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbiall_is_write },
{ .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimva_is_write },
{ .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbiasid_is_write },
{ .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimvaa_is_write },
}; };
static const ARMCPRegInfo pmovsset_cp_reginfo[] = { static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
@ -5833,42 +5662,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.par_el[1]), .fieldoffset = offsetof(CPUARMState, cp15.par_el[1]),
.writefn = par_write }, .writefn = par_write },
#endif #endif
/* TLB invalidate last level of translation table walk */
{ .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimva_is_write },
{ .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimvaa_is_write },
{ .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "TLBIMVAAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimvaa_write },
{ .name = "TLBIMVALH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbimva_hyp_write },
{ .name = "TLBIMVALHIS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbimva_hyp_is_write },
{ .name = "TLBIIPAS2",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2_hyp_write },
{ .name = "TLBIIPAS2IS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2is_hyp_write },
{ .name = "TLBIIPAS2L",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2_hyp_write },
{ .name = "TLBIIPAS2LIS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2is_hyp_write },
/* 32 bit cache operations */ /* 32 bit cache operations */
{ .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
.type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab }, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab },
@ -8734,6 +8527,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, not_v8_cp_reginfo); define_arm_cp_regs(cpu, not_v8_cp_reginfo);
} }
define_tlb_insn_regs(cpu);
if (arm_feature(env, ARM_FEATURE_V6)) { if (arm_feature(env, ARM_FEATURE_V6)) {
/* The ID registers all have impdef reset values */ /* The ID registers all have impdef reset values */
ARMCPRegInfo v6_idregs[] = { ARMCPRegInfo v6_idregs[] = {
@ -8839,10 +8634,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_V6K)) { if (arm_feature(env, ARM_FEATURE_V6K)) {
define_arm_cp_regs(cpu, v6k_cp_reginfo); define_arm_cp_regs(cpu, v6k_cp_reginfo);
} }
if (arm_feature(env, ARM_FEATURE_V7MP) &&
!arm_feature(env, ARM_FEATURE_PMSA)) {
define_arm_cp_regs(cpu, v7mp_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_V7VE)) { if (arm_feature(env, ARM_FEATURE_V7VE)) {
define_arm_cp_regs(cpu, pmovsset_cp_reginfo); define_arm_cp_regs(cpu, pmovsset_cp_reginfo);
} }

View file

@ -1727,6 +1727,9 @@ static inline uint64_t pauth_ptr_mask(ARMVAParameters param)
/* Add the cpreg definitions for debug related system registers */ /* Add the cpreg definitions for debug related system registers */
void define_debug_regs(ARMCPU *cpu); void define_debug_regs(ARMCPU *cpu);
/* Add the cpreg definitions for TLBI instructions */
void define_tlb_insn_regs(ARMCPU *cpu);
/* Effective value of MDCR_EL2 */ /* Effective value of MDCR_EL2 */
static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env) static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
{ {

View file

@ -25,3 +25,8 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
void assert_hflags_rebuild_correctly(CPUARMState *env) void assert_hflags_rebuild_correctly(CPUARMState *env)
{ {
} }
/* TLBI insns are only used by TCG, so we don't need to do anything for KVM */
void define_tlb_insn_regs(ARMCPU *cpu)
{
}

View file

@ -39,6 +39,7 @@ arm_ss.add(files(
'op_helper.c', 'op_helper.c',
'tlb_helper.c', 'tlb_helper.c',
'vec_helper.c', 'vec_helper.c',
'tlb-insns.c',
)) ))
arm_ss.add(when: 'TARGET_AARCH64', if_true: files( arm_ss.add(when: 'TARGET_AARCH64', if_true: files(

246
target/arm/tcg/tlb-insns.c Normal file
View file

@ -0,0 +1,246 @@
/*
* Helpers for TLBI insns
*
* This code is licensed under the GNU GPL v2 or later.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "exec/exec-all.h"
#include "cpu.h"
#include "internals.h"
#include "cpu-features.h"
#include "cpregs.h"
/* IS variants of TLB operations must affect all cores */
static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_all_cpus_synced(cs);
}
static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_all_cpus_synced(cs);
}
static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate all (TLBIALL) */
CPUState *cs = env_cpu(env);
if (tlb_force_broadcast(env)) {
tlb_flush_all_cpus_synced(cs);
} else {
tlb_flush(cs);
}
}
static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
CPUState *cs = env_cpu(env);
value &= TARGET_PAGE_MASK;
if (tlb_force_broadcast(env)) {
tlb_flush_page_all_cpus_synced(cs, value);
} else {
tlb_flush_page(cs, value);
}
}
static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate by ASID (TLBIASID) */
CPUState *cs = env_cpu(env);
if (tlb_force_broadcast(env)) {
tlb_flush_all_cpus_synced(cs);
} else {
tlb_flush(cs);
}
}
static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
CPUState *cs = env_cpu(env);
value &= TARGET_PAGE_MASK;
if (tlb_force_broadcast(env)) {
tlb_flush_page_all_cpus_synced(cs, value);
} else {
tlb_flush_page(cs, value);
}
}
static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
}
static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2);
}
static const ARMCPRegInfo tlbi_not_v7_cp_reginfo[] = {
/*
* MMU TLB control. Note that the wildcarding means we cover not just
* the unified TLB ops but also the dside/iside/inner-shareable variants.
*/
{ .name = "TLBIALL", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 0, .access = PL1_W, .writefn = tlbiall_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIMVA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 1, .access = PL1_W, .writefn = tlbimva_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIASID", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write,
.type = ARM_CP_NO_RAW },
{ .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
.type = ARM_CP_NO_RAW },
};
static const ARMCPRegInfo tlbi_v7_cp_reginfo[] = {
/* 32 bit ITLB invalidates */
{ .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "ITLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "ITLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
/* 32 bit DTLB invalidates */
{ .name = "DTLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "DTLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "DTLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
/* 32 bit TLB invalidates */
{ .name = "TLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiall_write },
{ .name = "TLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "TLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbiasid_write },
{ .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimvaa_write },
};
static const ARMCPRegInfo tlbi_v7mp_cp_reginfo[] = {
/* 32 bit TLB invalidates, Inner Shareable */
{ .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbiall_is_write },
{ .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimva_is_write },
{ .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbiasid_is_write },
{ .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimvaa_is_write },
};
static const ARMCPRegInfo tlbi_v8_cp_reginfo[] = {
/* AArch32 TLB invalidate last level of translation table walk */
{ .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimva_is_write },
{ .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis,
.writefn = tlbimvaa_is_write },
{ .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimva_write },
{ .name = "TLBIMVAAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
.writefn = tlbimvaa_write },
{ .name = "TLBIMVALH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbimva_hyp_write },
{ .name = "TLBIMVALHIS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbimva_hyp_is_write },
{ .name = "TLBIIPAS2",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2_hyp_write },
{ .name = "TLBIIPAS2IS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2is_hyp_write },
{ .name = "TLBIIPAS2L",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2_hyp_write },
{ .name = "TLBIIPAS2LIS",
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiipas2is_hyp_write },
};
void define_tlb_insn_regs(ARMCPU *cpu)
{
CPUARMState *env = &cpu->env;
if (!arm_feature(env, ARM_FEATURE_V7)) {
define_arm_cp_regs(cpu, tlbi_not_v7_cp_reginfo);
} else {
define_arm_cp_regs(cpu, tlbi_v7_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_V7MP) &&
!arm_feature(env, ARM_FEATURE_PMSA)) {
define_arm_cp_regs(cpu, tlbi_v7mp_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_V8)) {
define_arm_cp_regs(cpu, tlbi_v8_cp_reginfo);
}
}