target-arm: add SCTLR_EL3 and make SCTLR banked
Implements SCTLR_EL3 and uses secure/non-secure instance when needed. 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-14-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
e89e51a17e
commit
137feaa9a1
|
@ -273,7 +273,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
case 3:
|
case 3:
|
||||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||||
s->cpu->env.cp15.c1_sys = 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_el1 = 0;
|
||||||
s->cpu->env.cp15.c3 = 0;
|
s->cpu->env.cp15.c3 = 0;
|
||||||
|
|
|
@ -109,7 +109,7 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
env->pstate = PSTATE_MODE_EL0t;
|
env->pstate = PSTATE_MODE_EL0t;
|
||||||
/* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */
|
/* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */
|
||||||
env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE;
|
env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE;
|
||||||
/* and to the FP/Neon instructions */
|
/* and to the FP/Neon instructions */
|
||||||
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
|
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
|
||||||
#else
|
#else
|
||||||
|
@ -167,7 +167,11 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
env->thumb = initial_pc & 1;
|
env->thumb = initial_pc & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env->cp15.c1_sys & SCTLR_V) {
|
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
|
||||||
|
* executing as AArch32 then check if highvecs are enabled and
|
||||||
|
* adjust the PC accordingly.
|
||||||
|
*/
|
||||||
|
if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
|
||||||
env->regs[15] = 0xFFFF0000;
|
env->regs[15] = 0xFFFF0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,15 @@ typedef struct CPUARMState {
|
||||||
struct {
|
struct {
|
||||||
uint32_t c0_cpuid;
|
uint32_t c0_cpuid;
|
||||||
uint64_t c0_cssel; /* Cache size selection. */
|
uint64_t c0_cssel; /* Cache size selection. */
|
||||||
uint64_t c1_sys; /* System control register. */
|
union { /* System control register. */
|
||||||
|
struct {
|
||||||
|
uint64_t _unused_sctlr;
|
||||||
|
uint64_t sctlr_ns;
|
||||||
|
uint64_t hsctlr;
|
||||||
|
uint64_t sctlr_s;
|
||||||
|
};
|
||||||
|
uint64_t sctlr_el[4];
|
||||||
|
};
|
||||||
uint64_t c1_coproc; /* Coprocessor access register. */
|
uint64_t c1_coproc; /* Coprocessor access register. */
|
||||||
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. */
|
||||||
|
|
|
@ -1908,7 +1908,7 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
|
||||||
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
{
|
{
|
||||||
if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
|
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
|
||||||
return CP_ACCESS_TRAP;
|
return CP_ACCESS_TRAP;
|
||||||
}
|
}
|
||||||
return CP_ACCESS_OK;
|
return CP_ACCESS_OK;
|
||||||
|
@ -1926,7 +1926,7 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||||
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
|
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
|
||||||
* SCTLR_EL1.UCI is set.
|
* SCTLR_EL1.UCI is set.
|
||||||
*/
|
*/
|
||||||
if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
|
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCI)) {
|
||||||
return CP_ACCESS_TRAP;
|
return CP_ACCESS_TRAP;
|
||||||
}
|
}
|
||||||
return CP_ACCESS_OK;
|
return CP_ACCESS_OK;
|
||||||
|
@ -2003,7 +2003,7 @@ static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
/* We don't implement EL2, so the only control on DC ZVA is the
|
/* We don't implement EL2, so the only control on DC ZVA is the
|
||||||
* bit in the SCTLR which can prohibit access for EL0.
|
* bit in the SCTLR which can prohibit access for EL0.
|
||||||
*/
|
*/
|
||||||
if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
|
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_DZE)) {
|
||||||
return CP_ACCESS_TRAP;
|
return CP_ACCESS_TRAP;
|
||||||
}
|
}
|
||||||
return CP_ACCESS_OK;
|
return CP_ACCESS_OK;
|
||||||
|
@ -2042,6 +2042,24 @@ static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
|
||||||
update_spsel(env, val);
|
update_spsel(env, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||||
|
|
||||||
|
if (raw_read(env, ri) == value) {
|
||||||
|
/* Skip the TLB flush if nothing actually changed; Linux likes
|
||||||
|
* to do a lot of pointless SCTLR writes.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_write(env, ri, value);
|
||||||
|
/* ??? Lots of these bits are not implemented. */
|
||||||
|
/* This may enable/disable the MMU, so do a TLB flush. */
|
||||||
|
tlb_flush(CPU(cpu), 1);
|
||||||
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo v8_cp_reginfo[] = {
|
static const ARMCPRegInfo v8_cp_reginfo[] = {
|
||||||
/* Minimal set of EL0-visible registers. This will need to be expanded
|
/* Minimal set of EL0-visible registers. This will need to be expanded
|
||||||
* significantly for system emulation of AArch64 CPUs.
|
* significantly for system emulation of AArch64 CPUs.
|
||||||
|
@ -2311,6 +2329,10 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||||
|
{ .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0,
|
||||||
|
.access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
|
||||||
|
.fieldoffset = offsetof(CPUARMState, cp15.sctlr_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,
|
||||||
|
@ -2362,30 +2384,12 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
||||||
uint64_t value)
|
|
||||||
{
|
|
||||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
|
||||||
|
|
||||||
if (raw_read(env, ri) == value) {
|
|
||||||
/* Skip the TLB flush if nothing actually changed; Linux likes
|
|
||||||
* to do a lot of pointless SCTLR writes.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
raw_write(env, ri, value);
|
|
||||||
/* ??? Lots of these bits are not implemented. */
|
|
||||||
/* This may enable/disable the MMU, so do a TLB flush. */
|
|
||||||
tlb_flush(CPU(cpu), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
{
|
{
|
||||||
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
|
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
|
||||||
* but the AArch32 CTR has its own reginfo struct)
|
* but the AArch32 CTR has its own reginfo struct)
|
||||||
*/
|
*/
|
||||||
if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
|
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCT)) {
|
||||||
return CP_ACCESS_TRAP;
|
return CP_ACCESS_TRAP;
|
||||||
}
|
}
|
||||||
return CP_ACCESS_OK;
|
return CP_ACCESS_OK;
|
||||||
|
@ -3182,8 +3186,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
{
|
{
|
||||||
ARMCPRegInfo sctlr = {
|
ARMCPRegInfo sctlr = {
|
||||||
.name = "SCTLR", .state = ARM_CP_STATE_BOTH,
|
.name = "SCTLR", .state = ARM_CP_STATE_BOTH,
|
||||||
.opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
|
.opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
|
||||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sys),
|
.access = PL1_RW,
|
||||||
|
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s),
|
||||||
|
offsetof(CPUARMState, cp15.sctlr_ns) },
|
||||||
.writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
|
.writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
|
||||||
.raw_writefn = raw_write,
|
.raw_writefn = raw_write,
|
||||||
};
|
};
|
||||||
|
@ -4278,7 +4284,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||||
|
|
||||||
if (new_mode == ARM_CPU_MODE_MON) {
|
if (new_mode == ARM_CPU_MODE_MON) {
|
||||||
addr += env->cp15.mvbar;
|
addr += env->cp15.mvbar;
|
||||||
} else if (env->cp15.c1_sys & SCTLR_V) {
|
} else if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
|
||||||
/* High vectors. When enabled, base address cannot be remapped. */
|
/* High vectors. When enabled, base address cannot be remapped. */
|
||||||
addr += 0xffff0000;
|
addr += 0xffff0000;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4308,7 +4314,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||||
/* this is a lie, as the was no c1_sys on V4T/V5, but who cares
|
/* this is a lie, as the was no c1_sys on V4T/V5, but who cares
|
||||||
* and we should just guard the thumb mode on V4 */
|
* and we should just guard the thumb mode on V4 */
|
||||||
if (arm_feature(env, ARM_FEATURE_V4T)) {
|
if (arm_feature(env, ARM_FEATURE_V4T)) {
|
||||||
env->thumb = (env->cp15.c1_sys & SCTLR_TE) != 0;
|
env->thumb = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
|
||||||
}
|
}
|
||||||
env->regs[14] = env->regs[15] + offset;
|
env->regs[14] = env->regs[15] + offset;
|
||||||
env->regs[15] = addr;
|
env->regs[15] = addr;
|
||||||
|
@ -4339,7 +4345,7 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot,
|
||||||
}
|
}
|
||||||
if (access_type == 1)
|
if (access_type == 1)
|
||||||
return 0;
|
return 0;
|
||||||
switch (env->cp15.c1_sys & (SCTLR_S | SCTLR_R)) {
|
switch (A32_BANKED_CURRENT_REG_GET(env, sctlr) & (SCTLR_S | SCTLR_R)) {
|
||||||
case SCTLR_S:
|
case SCTLR_S:
|
||||||
return is_user ? 0 : PAGE_READ;
|
return is_user ? 0 : PAGE_READ;
|
||||||
case SCTLR_R:
|
case SCTLR_R:
|
||||||
|
@ -4588,7 +4594,8 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
|
||||||
goto do_fault;
|
goto do_fault;
|
||||||
|
|
||||||
/* The simplified model uses AP[0] as an access control bit. */
|
/* The simplified model uses AP[0] as an access control bit. */
|
||||||
if ((env->cp15.c1_sys & SCTLR_AFE) && (ap & 1) == 0) {
|
if ((A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_AFE)
|
||||||
|
&& (ap & 1) == 0) {
|
||||||
/* Access flag fault. */
|
/* Access flag fault. */
|
||||||
code = (code == 15) ? 6 : 3;
|
code = (code == 15) ? 6 : 3;
|
||||||
goto do_fault;
|
goto do_fault;
|
||||||
|
@ -4921,11 +4928,16 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
|
||||||
hwaddr *phys_ptr, int *prot,
|
hwaddr *phys_ptr, int *prot,
|
||||||
target_ulong *page_size)
|
target_ulong *page_size)
|
||||||
{
|
{
|
||||||
|
/* This is not entirely correct as get_phys_addr() can also be called
|
||||||
|
* from ats_write() for an address translation of a specific regime.
|
||||||
|
*/
|
||||||
|
uint32_t sctlr = A32_BANKED_CURRENT_REG_GET(env, sctlr);
|
||||||
|
|
||||||
/* Fast Context Switch Extension. */
|
/* Fast Context Switch Extension. */
|
||||||
if (address < 0x02000000)
|
if (address < 0x02000000)
|
||||||
address += env->cp15.c13_fcse;
|
address += env->cp15.c13_fcse;
|
||||||
|
|
||||||
if ((env->cp15.c1_sys & SCTLR_M) == 0) {
|
if ((sctlr & SCTLR_M) == 0) {
|
||||||
/* MMU/MPU disabled. */
|
/* MMU/MPU disabled. */
|
||||||
*phys_ptr = address;
|
*phys_ptr = address;
|
||||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||||
|
@ -4938,7 +4950,7 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
|
||||||
} else if (extended_addresses_enabled(env)) {
|
} else if (extended_addresses_enabled(env)) {
|
||||||
return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
|
return get_phys_addr_lpae(env, address, access_type, is_user, phys_ptr,
|
||||||
prot, page_size);
|
prot, page_size);
|
||||||
} else if (env->cp15.c1_sys & SCTLR_XP) {
|
} else if (sctlr & SCTLR_XP) {
|
||||||
return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
|
return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
|
||||||
prot, page_size);
|
prot, page_size);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -361,7 +361,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
|
||||||
* Note that SPSel is never OK from EL0; we rely on handle_msr_i()
|
* Note that SPSel is never OK from EL0; we rely on handle_msr_i()
|
||||||
* to catch that case at translate time.
|
* to catch that case at translate time.
|
||||||
*/
|
*/
|
||||||
if (arm_current_el(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
|
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
|
||||||
raise_exception(env, EXCP_UDEF);
|
raise_exception(env, EXCP_UDEF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue