mirror of https://github.com/xqemu/xqemu.git
target-arm: make TTBR0/1 banked
Adds secure and non-secure bank register suport for TTBR0 and TTBR1. Changes include adding secure and non-secure instances of ttbr0 and ttbr1 as well as a CP register definition for TTBR0_EL3. Added a union containing both EL based array fields and secure and non-secure fields mapped to them. Updated accesses to use A32_BANKED_CURRENT_REG_GET macro. Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch> Signed-off-by: Greg Bellows <greg.bellows@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1416242878-876-17-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
b85a1fd61c
commit
7dd8c9af0d
|
@ -275,7 +275,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||||
s->cpu->env.cp15.sctlr_ns = 0;
|
s->cpu->env.cp15.sctlr_ns = 0;
|
||||||
s->cpu->env.cp15.c1_coproc = 0;
|
s->cpu->env.cp15.c1_coproc = 0;
|
||||||
s->cpu->env.cp15.ttbr0_el1 = 0;
|
s->cpu->env.cp15.ttbr0_el[1] = 0;
|
||||||
s->cpu->env.cp15.c3 = 0;
|
s->cpu->env.cp15.c3 = 0;
|
||||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||||
|
|
|
@ -199,8 +199,24 @@ typedef struct CPUARMState {
|
||||||
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
|
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
|
||||||
uint64_t sder; /* Secure debug enable register. */
|
uint64_t sder; /* Secure debug enable register. */
|
||||||
uint32_t nsacr; /* Non-secure access control register. */
|
uint32_t nsacr; /* Non-secure access control register. */
|
||||||
uint64_t ttbr0_el1; /* MMU translation table base 0. */
|
union { /* MMU translation table base 0. */
|
||||||
uint64_t ttbr1_el1; /* MMU translation table base 1. */
|
struct {
|
||||||
|
uint64_t _unused_ttbr0_0;
|
||||||
|
uint64_t ttbr0_ns;
|
||||||
|
uint64_t _unused_ttbr0_1;
|
||||||
|
uint64_t ttbr0_s;
|
||||||
|
};
|
||||||
|
uint64_t ttbr0_el[4];
|
||||||
|
};
|
||||||
|
union { /* MMU translation table base 1. */
|
||||||
|
struct {
|
||||||
|
uint64_t _unused_ttbr1_0;
|
||||||
|
uint64_t ttbr1_ns;
|
||||||
|
uint64_t _unused_ttbr1_1;
|
||||||
|
uint64_t ttbr1_s;
|
||||||
|
};
|
||||||
|
uint64_t ttbr1_el[4];
|
||||||
|
};
|
||||||
uint64_t c2_control; /* MMU translation table base control. */
|
uint64_t c2_control; /* MMU translation table base control. */
|
||||||
uint32_t c2_mask; /* MMU translation table base selection mask. */
|
uint32_t c2_mask; /* MMU translation table base selection mask. */
|
||||||
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
|
uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
|
||||||
|
|
|
@ -1646,13 +1646,15 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
|
||||||
.access = PL1_RW,
|
.access = PL1_RW,
|
||||||
.fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, },
|
.fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, },
|
||||||
{ .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
|
{ .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
|
||||||
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
|
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
|
||||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
|
.access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0,
|
||||||
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
|
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
|
||||||
|
offsetof(CPUARMState, cp15.ttbr0_ns) } },
|
||||||
{ .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
|
{ .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
|
||||||
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
|
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
|
||||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
|
.access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0,
|
||||||
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
|
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
|
||||||
|
offsetof(CPUARMState, cp15.ttbr1_ns) } },
|
||||||
{ .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
|
{ .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
|
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||||
.access = PL1_RW, .writefn = vmsa_tcr_el1_write,
|
.access = PL1_RW, .writefn = vmsa_tcr_el1_write,
|
||||||
|
@ -1883,11 +1885,13 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
||||||
.fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 },
|
.fieldoffset = offsetof(CPUARMState, cp15.par_el1), .resetvalue = 0 },
|
||||||
{ .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
|
{ .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
|
||||||
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
|
.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 },
|
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
|
||||||
{ .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
|
{ .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
|
||||||
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
|
.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 },
|
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
@ -2341,6 +2345,10 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0,
|
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0,
|
||||||
.access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
|
.access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
|
||||||
.fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) },
|
.fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]) },
|
||||||
|
{ .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0,
|
||||||
|
.access = PL3_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0,
|
||||||
|
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
|
||||||
{ .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
|
{ .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
|
||||||
.type = ARM_CP_NO_MIGRATE,
|
.type = ARM_CP_NO_MIGRATE,
|
||||||
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
|
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
|
||||||
|
@ -4442,18 +4450,23 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
|
||||||
static bool get_level1_table_address(CPUARMState *env, uint32_t *table,
|
static bool get_level1_table_address(CPUARMState *env, uint32_t *table,
|
||||||
uint32_t address)
|
uint32_t address)
|
||||||
{
|
{
|
||||||
|
/* 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 (address & env->cp15.c2_mask) {
|
||||||
if ((env->cp15.c2_control & TTBCR_PD1)) {
|
if ((env->cp15.c2_control & TTBCR_PD1)) {
|
||||||
/* Translation table walk disabled for TTBR1 */
|
/* Translation table walk disabled for TTBR1 */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*table = env->cp15.ttbr1_el1 & 0xffffc000;
|
*table = A32_BANKED_CURRENT_REG_GET(env, ttbr1) & 0xffffc000;
|
||||||
} else {
|
} else {
|
||||||
if ((env->cp15.c2_control & TTBCR_PD0)) {
|
if ((env->cp15.c2_control & TTBCR_PD0)) {
|
||||||
/* Translation table walk disabled for TTBR0 */
|
/* Translation table walk disabled for TTBR0 */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*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;
|
*table |= (address >> 18) & 0x3ffc;
|
||||||
return true;
|
return true;
|
||||||
|
@ -4758,7 +4771,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||||
* we will always flush the TLB any time the ASID is changed).
|
* we will always flush the TLB any time the ASID is changed).
|
||||||
*/
|
*/
|
||||||
if (ttbr_select == 0) {
|
if (ttbr_select == 0) {
|
||||||
ttbr = env->cp15.ttbr0_el1;
|
ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0);
|
||||||
epd = extract32(env->cp15.c2_control, 7, 1);
|
epd = extract32(env->cp15.c2_control, 7, 1);
|
||||||
tsz = t0sz;
|
tsz = t0sz;
|
||||||
|
|
||||||
|
@ -4770,7 +4783,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||||
granule_sz = 11;
|
granule_sz = 11;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ttbr = env->cp15.ttbr1_el1;
|
ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1);
|
||||||
epd = extract32(env->cp15.c2_control, 23, 1);
|
epd = extract32(env->cp15.c2_control, 23, 1);
|
||||||
tsz = t1sz;
|
tsz = t1sz;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue