Add TTBR0 and maps secure/non-secure instance of ttbr0 and ttbr1 accordingly (translation table base register).
Signed-off-by: Fabian Aggeler <aggel...@ethz.ch> --- target-arm/cpu.h | 21 +++++++++++++++++++-- target-arm/helper.c | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 6d3deb1..6890e82 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -203,8 +203,25 @@ typedef struct CPUARMState { uint32_t c1_scr; /* secure config register. */ uint32_t c1_sder; /* Secure debug enable register. */ uint32_t c1_nsacr; /* Non-secure access control register. */ - uint64_t ttbr0_el1; /* MMU translation table base 0. */ - uint64_t ttbr1_el1; /* MMU translation table base 1. */ + union { /* MMU translation table base 0. */ + struct { + uint64_t ttbr0_ns; + uint64_t ttbr0_s; + }; + struct { + uint64_t ttbr0_el1; + uint64_t ttbr0_el3; + }; + }; + union { /* MMU translation table base 1. */ + struct { + uint64_t ttbr1_ns; + uint64_t ttbr1_s; + }; + struct { + uint64_t ttbr1_el1; + }; + }; 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. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 69d9612..22609ed 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1498,12 +1498,14 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_el1) } }, { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1), - .writefn = vmsa_ttbr_write, .resetvalue = 0 }, + .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_el1) } }, { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .writefn = vmsa_tcr_el1_write, @@ -1744,11 +1746,13 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 }, { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), + offsetof(CPUARMState, cp15.ttbr0_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1, .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE, - .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1), + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), + offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore }, REGINFO_SENTINEL }; @@ -2270,6 +2274,10 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = { .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0, .access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write, .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el3) }, + { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 6, .opc2 = 0, + .access = PL3_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NO_MIGRATE, .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1, @@ -3966,10 +3974,14 @@ static uint32_t get_level1_table_address(CPUARMState *env, uint32_t address) { uint32_t table; + /* 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) - table = env->cp15.ttbr1_el1 & 0xffffc000; + table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000; else - table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask; + table = A32_BANKED_CURRENT_REG_GET(env, ttbr0) & env->cp15.c2_base_mask; table |= (address >> 18) & 0x3ffc; return table; @@ -4215,6 +4227,7 @@ 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 cur_el = arm_current_pl(env); if (arm_el_is_aa64(env, 1)) { va_size = 64; @@ -4266,7 +4279,19 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, * we will always flush the TLB any time the ASID is changed). */ if (ttbr_select == 0) { - ttbr = env->cp15.ttbr0_el1; + if (arm_el_is_aa64(env, 3)) { + switch (cur_el) { + case 3: + ttbr = env->cp15.ttbr0_el3; + break; + case 1: + case 0: + default: + ttbr = env->cp15.ttbr0_el1; + } + } else { + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); + } epd = extract32(env->cp15.c2_control, 7, 1); tsz = t0sz; @@ -4278,7 +4303,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, granule_sz = 11; } } else { - ttbr = env->cp15.ttbr1_el1; + ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); epd = extract32(env->cp15.c2_control, 23, 1); tsz = t1sz; -- 1.8.3.2