target-arm: Add 64 bit PAR, TTBR0, TTBR1 for LPAE
Under LPAE, the cp15 registers PAR, TTBR0 and TTBR1 are extended to 64 bits, with a 64 bit (MRRC/MCRR) access path to read the full width of the register. Add the state fields for the top half and the 64 bit access path. Actual use of the top half of the register will come with the addition of the long-descriptor translation table format support. For the PAR we also need to correct the masking applied for 32 bit writes (there are no bits reserved if LPAE is implemented) and clear the high half when doing a 32 bit result VA-to-PA lookup. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
f9fc619a0d
commit
891a2fe720
@ -113,7 +113,9 @@ typedef struct CPUARMState {
|
|||||||
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
|
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
|
||||||
uint32_t c1_scr; /* secure config register. */
|
uint32_t c1_scr; /* secure config register. */
|
||||||
uint32_t c2_base0; /* MMU translation table base 0. */
|
uint32_t c2_base0; /* MMU translation table base 0. */
|
||||||
uint32_t c2_base1; /* MMU translation table base 1. */
|
uint32_t c2_base0_hi; /* MMU translation table base 0, high 32 bits */
|
||||||
|
uint32_t c2_base1; /* MMU translation table base 0. */
|
||||||
|
uint32_t c2_base1_hi; /* MMU translation table base 1, high 32 bits */
|
||||||
uint32_t c2_control; /* MMU translation table base control. */
|
uint32_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. */
|
||||||
@ -127,6 +129,7 @@ typedef struct CPUARMState {
|
|||||||
uint32_t c6_insn; /* Fault address registers. */
|
uint32_t c6_insn; /* Fault address registers. */
|
||||||
uint32_t c6_data;
|
uint32_t c6_data;
|
||||||
uint32_t c7_par; /* Translation result. */
|
uint32_t c7_par; /* Translation result. */
|
||||||
|
uint32_t c7_par_hi; /* Translation result, high 32 bits */
|
||||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||||
uint32_t c9_data;
|
uint32_t c9_data;
|
||||||
uint32_t c9_pmcr; /* performance monitor control register */
|
uint32_t c9_pmcr; /* performance monitor control register */
|
||||||
@ -638,7 +641,7 @@ static inline CPUARMState *cpu_init(const char *cpu_model)
|
|||||||
#define cpu_signal_handler cpu_arm_signal_handler
|
#define cpu_signal_handler cpu_arm_signal_handler
|
||||||
#define cpu_list arm_cpu_list
|
#define cpu_list arm_cpu_list
|
||||||
|
|
||||||
#define CPU_SAVE_VERSION 8
|
#define CPU_SAVE_VERSION 9
|
||||||
|
|
||||||
/* MMU modes definitions */
|
/* MMU modes definitions */
|
||||||
#define MMU_MODE0_SUFFIX _kernel
|
#define MMU_MODE0_SUFFIX _kernel
|
||||||
|
@ -491,7 +491,9 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|||||||
|
|
||||||
static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||||
{
|
{
|
||||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
||||||
|
env->cp15.c7_par = value;
|
||||||
|
} else if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||||
env->cp15.c7_par = value & 0xfffff6ff;
|
env->cp15.c7_par = value & 0xfffff6ff;
|
||||||
} else {
|
} else {
|
||||||
env->cp15.c7_par = value & 0xfffff1ff;
|
env->cp15.c7_par = value & 0xfffff1ff;
|
||||||
@ -528,6 +530,7 @@ static int ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
|||||||
((ret & (12 << 1)) >> 6) |
|
((ret & (12 << 1)) >> 6) |
|
||||||
((ret & 0xf) << 1) | 1;
|
((ret & 0xf) << 1) | 1;
|
||||||
}
|
}
|
||||||
|
env->cp15.c7_par_hi = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -871,6 +874,69 @@ static const ARMCPRegInfo mpidr_cp_reginfo[] = {
|
|||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int par64_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value)
|
||||||
|
{
|
||||||
|
*value = ((uint64_t)env->cp15.c7_par_hi << 32) | env->cp15.c7_par;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int par64_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||||
|
{
|
||||||
|
env->cp15.c7_par_hi = value >> 32;
|
||||||
|
env->cp15.c7_par = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void par64_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
env->cp15.c7_par_hi = 0;
|
||||||
|
env->cp15.c7_par = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ttbr064_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
*value = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ttbr064_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->cp15.c2_base0_hi = value >> 32;
|
||||||
|
env->cp15.c2_base0 = value;
|
||||||
|
/* Writes to the 64 bit format TTBRs may change the ASID */
|
||||||
|
tlb_flush(env, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ttbr064_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
env->cp15.c2_base0_hi = 0;
|
||||||
|
env->cp15.c2_base0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ttbr164_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
*value = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ttbr164_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->cp15.c2_base1_hi = value >> 32;
|
||||||
|
env->cp15.c2_base1 = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ttbr164_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
env->cp15.c2_base1_hi = 0;
|
||||||
|
env->cp15.c2_base1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
||||||
/* NOP AMAIR0/1: the override is because these clash with tha rather
|
/* NOP AMAIR0/1: the override is because these clash with tha rather
|
||||||
* broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
|
* broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
|
||||||
@ -886,6 +952,15 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
|
|||||||
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
|
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
|
||||||
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
|
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
|
||||||
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
|
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
|
||||||
|
{ .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
|
||||||
|
.access = PL1_RW, .type = ARM_CP_64BIT,
|
||||||
|
.readfn = par64_read, .writefn = par64_write, .resetfn = par64_reset },
|
||||||
|
{ .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
|
||||||
|
.access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr064_read,
|
||||||
|
.writefn = ttbr064_write, .resetfn = ttbr064_reset },
|
||||||
|
{ .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
|
||||||
|
.access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr164_read,
|
||||||
|
.writefn = ttbr164_write, .resetfn = ttbr164_reset },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,7 +27,9 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||||||
qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
|
qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
|
||||||
qemu_put_be32(f, env->cp15.c1_scr);
|
qemu_put_be32(f, env->cp15.c1_scr);
|
||||||
qemu_put_be32(f, env->cp15.c2_base0);
|
qemu_put_be32(f, env->cp15.c2_base0);
|
||||||
|
qemu_put_be32(f, env->cp15.c2_base0_hi);
|
||||||
qemu_put_be32(f, env->cp15.c2_base1);
|
qemu_put_be32(f, env->cp15.c2_base1);
|
||||||
|
qemu_put_be32(f, env->cp15.c2_base1_hi);
|
||||||
qemu_put_be32(f, env->cp15.c2_control);
|
qemu_put_be32(f, env->cp15.c2_control);
|
||||||
qemu_put_be32(f, env->cp15.c2_mask);
|
qemu_put_be32(f, env->cp15.c2_mask);
|
||||||
qemu_put_be32(f, env->cp15.c2_base_mask);
|
qemu_put_be32(f, env->cp15.c2_base_mask);
|
||||||
@ -42,6 +44,7 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||||||
qemu_put_be32(f, env->cp15.c6_insn);
|
qemu_put_be32(f, env->cp15.c6_insn);
|
||||||
qemu_put_be32(f, env->cp15.c6_data);
|
qemu_put_be32(f, env->cp15.c6_data);
|
||||||
qemu_put_be32(f, env->cp15.c7_par);
|
qemu_put_be32(f, env->cp15.c7_par);
|
||||||
|
qemu_put_be32(f, env->cp15.c7_par_hi);
|
||||||
qemu_put_be32(f, env->cp15.c9_insn);
|
qemu_put_be32(f, env->cp15.c9_insn);
|
||||||
qemu_put_be32(f, env->cp15.c9_data);
|
qemu_put_be32(f, env->cp15.c9_data);
|
||||||
qemu_put_be32(f, env->cp15.c9_pmcr);
|
qemu_put_be32(f, env->cp15.c9_pmcr);
|
||||||
@ -144,7 +147,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
|
env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
|
||||||
env->cp15.c1_scr = qemu_get_be32(f);
|
env->cp15.c1_scr = qemu_get_be32(f);
|
||||||
env->cp15.c2_base0 = qemu_get_be32(f);
|
env->cp15.c2_base0 = qemu_get_be32(f);
|
||||||
|
env->cp15.c2_base0_hi = qemu_get_be32(f);
|
||||||
env->cp15.c2_base1 = qemu_get_be32(f);
|
env->cp15.c2_base1 = qemu_get_be32(f);
|
||||||
|
env->cp15.c2_base1_hi = qemu_get_be32(f);
|
||||||
env->cp15.c2_control = qemu_get_be32(f);
|
env->cp15.c2_control = qemu_get_be32(f);
|
||||||
env->cp15.c2_mask = qemu_get_be32(f);
|
env->cp15.c2_mask = qemu_get_be32(f);
|
||||||
env->cp15.c2_base_mask = qemu_get_be32(f);
|
env->cp15.c2_base_mask = qemu_get_be32(f);
|
||||||
@ -159,6 +164,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
env->cp15.c6_insn = qemu_get_be32(f);
|
env->cp15.c6_insn = qemu_get_be32(f);
|
||||||
env->cp15.c6_data = qemu_get_be32(f);
|
env->cp15.c6_data = qemu_get_be32(f);
|
||||||
env->cp15.c7_par = qemu_get_be32(f);
|
env->cp15.c7_par = qemu_get_be32(f);
|
||||||
|
env->cp15.c7_par_hi = qemu_get_be32(f);
|
||||||
env->cp15.c9_insn = qemu_get_be32(f);
|
env->cp15.c9_insn = qemu_get_be32(f);
|
||||||
env->cp15.c9_data = qemu_get_be32(f);
|
env->cp15.c9_data = qemu_get_be32(f);
|
||||||
env->cp15.c9_pmcr = qemu_get_be32(f);
|
env->cp15.c9_pmcr = qemu_get_be32(f);
|
||||||
|
Loading…
Reference in New Issue
Block a user