diff --git a/qemu/target-arm/cpu.h b/qemu/target-arm/cpu.h index 20d15990..2d9926d4 100644 --- a/qemu/target-arm/cpu.h +++ b/qemu/target-arm/cpu.h @@ -122,6 +122,12 @@ typedef struct ARMGenericTimer { #define GTIMER_VIRT 1 #define NUM_GTIMERS 2 +typedef struct { + uint64_t raw_tcr; + uint32_t mask; + uint32_t base_mask; +} TCR; + typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; @@ -219,9 +225,8 @@ typedef struct CPUARMState { }; uint64_t ttbr1_el[4]; }; - uint64_t c2_control; /* MMU translation table base control. */ - uint32_t c2_mask; /* MMU translation table base selection mask. */ - uint32_t c2_base_mask; /* MMU translation table base 0 mask. */ + /* MMU translation table base control. */ + TCR tcr_el[4]; uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ uint32_t c3; /* MMU domain access control register diff --git a/qemu/target-arm/helper.c b/qemu/target-arm/helper.c index 1760daf6..10c92f84 100644 --- a/qemu/target-arm/helper.c +++ b/qemu/target-arm/helper.c @@ -39,6 +39,11 @@ static void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return (char *)env + ri->fieldoffset; +} + static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) { /* Raw read of a coprocessor register (as needed for migration, etc). */ @@ -1319,6 +1324,7 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + TCR *tcr = raw_ptr(env, ri); int maskshift = extract32(value, 0, 3); if (!arm_feature(env, ARM_FEATURE_V8)) { @@ -1337,14 +1343,15 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, } } - /* Note that we always calculate c2_mask and c2_base_mask, but + /* Update the masks corresponding to the the TCR bank being written + * Note that we always calculate mask and base_mask, but * they are only used for short-descriptor tables (ie if EAE is 0); - * for long-descriptor tables the TTBCR fields are used differently - * and the c2_mask and c2_base_mask values are meaningless. + * for long-descriptor tables the TCR fields are used differently + * and the mask and base_mask values are meaningless. */ - raw_write(env, ri, value); - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift); + tcr->raw_tcr = value; + tcr->mask = ~(((uint32_t)0xffffffffu) >> maskshift); + tcr->base_mask = ~((uint32_t)0x3fffu >> maskshift); } static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1363,19 +1370,25 @@ static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void vmsa_ttbcr_reset(CPUARMState *env, const ARMCPRegInfo *ri) { - env->cp15.c2_base_mask = 0xffffc000u; - raw_write(env, ri, 0); - env->cp15.c2_mask = 0; + TCR *tcr = raw_ptr(env, ri); + + /* Reset both the TCR as well as the masks corresponding to the bank of + * the TCR being reset. + */ + tcr->raw_tcr = 0; + tcr->mask = 0; + tcr->base_mask = 0xffffc000u; } static void vmsa_tcr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = arm_env_get_cpu(env); + TCR *tcr = raw_ptr(env, ri); /* For AArch64 the A1 bit could result in a change of ASID, so TLB flush. */ tlb_flush(CPU(cpu), 1); - raw_write(env, ri, value); + tcr->raw_tcr = value; } static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1409,10 +1422,11 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) }, NULL, NULL, vmsa_ttbr_write, }, { "TCR_EL1", 0,2,0, 3,0,2, ARM_CP_STATE_AA64, - 0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c2_control), {0, 0}, + 0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.tcr_el[1]), {0, 0}, NULL, NULL,vmsa_tcr_el1_write, NULL,raw_write, vmsa_ttbcr_reset, }, { "TTBCR", 15,2,0, 0,0,2, 0, - ARM_CP_NO_MIGRATE, PL1_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c2_control), {0, 0}, + ARM_CP_NO_MIGRATE, PL1_RW, 0, NULL, 0, 0, + { offsetoflow32(CPUARMState, cp15.tcr_el[3]), offsetoflow32(CPUARMState, cp15.tcr_el[1]) }, NULL, NULL, vmsa_ttbcr_write, NULL, vmsa_ttbcr_raw_write, arm_cp_reset_ignore, }, /* 64-bit FAR; this entry also gives us the AArch32 DFAR */ { "FAR_EL1", 0,6,0, 3,0,0, ARM_CP_STATE_BOTH, @@ -2009,6 +2023,9 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { { "TTBR0_EL3", 0,2,0, 3,6,0, ARM_CP_STATE_AA64,0, PL3_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.ttbr0_el[3]), {0, 0}, NULL, NULL, vmsa_ttbr_write }, + { "TCR_EL3", 0,2,0, 3,6,2, ARM_CP_STATE_AA64,0, + PL3_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.tcr_el[3]), {0, 0}, + NULL, NULL, vmsa_tcr_el1_write, NULL, raw_write, vmsa_ttbcr_reset }, { "ELR_EL3", 0,4,0, 3,6,1, ARM_CP_STATE_AA64, ARM_CP_NO_MIGRATE, PL3_RW, 0, NULL, 0, offsetof(CPUARMState, elr_el[3]) }, { "ESR_EL3", 0,5,2, 3,6,0, ARM_CP_STATE_AA64, @@ -3955,23 +3972,25 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, static bool get_level1_table_address(CPUARMState *env, uint32_t *table, uint32_t address) { + /* Get the TCR bank based on our security state */ + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + /* We only get here if EL1 is running in AArch32. If EL3 is running in * AArch32 there is a secure and non-secure instance of the translation * table registers. */ - if (address & env->cp15.c2_mask) { - if ((env->cp15.c2_control & TTBCR_PD1)) { + if (address & tcr->mask) { + if (tcr->raw_tcr & TTBCR_PD1) { /* Translation table walk disabled for TTBR1 */ return false; } *table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000; } else { - if ((env->cp15.c2_control & TTBCR_PD0)) { + if (tcr->raw_tcr & TTBCR_PD0) { /* Translation table walk disabled for TTBR0 */ return false; } - *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & - env->cp15.c2_base_mask; + *table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & tcr->base_mask; } *table |= (address >> 18) & 0x3ffc; return true; @@ -4225,15 +4244,14 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, int32_t granule_sz = 9; int32_t va_size = 32; int32_t tbi = 0; - uint32_t t0sz; - uint32_t t1sz; + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; if (arm_el_is_aa64(env, 1)) { va_size = 64; if (extract64(address, 55, 1)) - tbi = extract64(env->cp15.c2_control, 38, 1); + tbi = extract64(tcr->raw_tcr, 38, 1); else - tbi = extract64(env->cp15.c2_control, 37, 1); + tbi = extract64(tcr->raw_tcr, 37, 1); tbi *= 8; } @@ -4242,12 +4260,12 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - t0sz = extract32(env->cp15.c2_control, 0, 6); + uint32_t t0sz = extract32(tcr->raw_tcr, 0, 6); if (arm_el_is_aa64(env, 1)) { t0sz = MIN(t0sz, 39); t0sz = MAX(t0sz, 16); } - t1sz = extract32(env->cp15.c2_control, 16, 6); + uint32_t t1sz = extract32(tcr->raw_tcr, 16, 6); if (arm_el_is_aa64(env, 1)) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); @@ -4279,10 +4297,10 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, */ if (ttbr_select == 0) { ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); - epd = extract32(env->cp15.c2_control, 7, 1); + epd = extract32(tcr->raw_tcr, 7, 1); tsz = t0sz; - tg = extract32(env->cp15.c2_control, 14, 2); + tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ granule_sz = 13; } @@ -4291,10 +4309,10 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, } } else { ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); - epd = extract32(env->cp15.c2_control, 23, 1); + epd = extract32(tcr->raw_tcr, 23, 1); tsz = t1sz; - tg = extract32(env->cp15.c2_control, 30, 2); + tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ granule_sz = 13; } diff --git a/qemu/target-arm/internals.h b/qemu/target-arm/internals.h index 0b401fb0..3d3dec69 100644 --- a/qemu/target-arm/internals.h +++ b/qemu/target-arm/internals.h @@ -155,9 +155,9 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm) */ static inline bool extended_addresses_enabled(CPUARMState *env) { - return arm_el_is_aa64(env, 1) - || ((arm_feature(env, ARM_FEATURE_LPAE) - && (env->cp15.c2_control & TTBCR_EAE))); + TCR *tcr = &env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; + return arm_el_is_aa64(env, 1) || + (arm_feature(env, ARM_FEATURE_LPAE) && (tcr->raw_tcr & TTBCR_EAE)); } /* Valid Syndrome Register EC field values */