mirror of https://gitee.com/openkylin/qemu.git
target-arm: Add 32/64-bit register sync
Add AArch32 to AArch64 register sychronization functions. Replace manual register synchronization with new functions in aarch64_cpu_do_interrupt() and HELPER(exception_return)(). Signed-off-by: Greg Bellows <greg.bellows@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1423736974-14254-4-git-send-email-greg.bellows@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
f313369fdb
commit
ce02049dbf
|
@ -495,6 +495,8 @@ typedef struct CPUARMState {
|
|||
ARMCPU *cpu_arm_init(const char *cpu_model);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
uint32_t do_arm_semihosting(CPUARMState *env);
|
||||
void aarch64_sync_32_to_64(CPUARMState *env);
|
||||
void aarch64_sync_64_to_32(CPUARMState *env);
|
||||
|
||||
static inline bool is_a64(CPUARMState *env)
|
||||
{
|
||||
|
|
|
@ -466,7 +466,6 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
|||
unsigned int new_el = arm_excp_target_el(cs, cs->exception_index);
|
||||
target_ulong addr = env->cp15.vbar_el[new_el];
|
||||
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
|
||||
int i;
|
||||
|
||||
if (arm_current_el(env) < new_el) {
|
||||
if (env->aarch64) {
|
||||
|
@ -530,9 +529,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
|||
}
|
||||
env->elr_el[new_el] = env->regs[15];
|
||||
|
||||
for (i = 0; i < 15; i++) {
|
||||
env->xregs[i] = env->regs[i];
|
||||
}
|
||||
aarch64_sync_32_to_64(env);
|
||||
|
||||
env->condexec_bits = 0;
|
||||
}
|
||||
|
|
|
@ -4096,6 +4096,11 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void aarch64_sync_64_to_32(CPUARMState *env)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Map CPU modes onto saved register banks. */
|
||||
|
@ -4425,6 +4430,212 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
env->thumb = addr & 1;
|
||||
}
|
||||
|
||||
/* Function used to synchronize QEMU's AArch64 register set with AArch32
|
||||
* register set. This is necessary when switching between AArch32 and AArch64
|
||||
* execution state.
|
||||
*/
|
||||
void aarch64_sync_32_to_64(CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
uint32_t mode = env->uncached_cpsr & CPSR_M;
|
||||
|
||||
/* We can blanket copy R[0:7] to X[0:7] */
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->xregs[i] = env->regs[i];
|
||||
}
|
||||
|
||||
/* Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
|
||||
* Otherwise, they come from the banked user regs.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_FIQ) {
|
||||
for (i = 8; i < 13; i++) {
|
||||
env->xregs[i] = env->usr_regs[i - 8];
|
||||
}
|
||||
} else {
|
||||
for (i = 8; i < 13; i++) {
|
||||
env->xregs[i] = env->regs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers x13-x23 are the various mode SP and FP registers. Registers
|
||||
* r13 and r14 are only copied if we are in that mode, otherwise we copy
|
||||
* from the mode banked register.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
|
||||
env->xregs[13] = env->regs[13];
|
||||
env->xregs[14] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[13] = env->banked_r13[bank_number(ARM_CPU_MODE_USR)];
|
||||
/* HYP is an exception in that it is copied from r14 */
|
||||
if (mode == ARM_CPU_MODE_HYP) {
|
||||
env->xregs[14] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[14] = env->banked_r14[bank_number(ARM_CPU_MODE_USR)];
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_HYP) {
|
||||
env->xregs[15] = env->regs[13];
|
||||
} else {
|
||||
env->xregs[15] = env->banked_r13[bank_number(ARM_CPU_MODE_HYP)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_IRQ) {
|
||||
env->xregs[16] = env->regs[13];
|
||||
env->xregs[17] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[16] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
env->xregs[17] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_SVC) {
|
||||
env->xregs[18] = env->regs[13];
|
||||
env->xregs[19] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[18] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
|
||||
env->xregs[19] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_ABT) {
|
||||
env->xregs[20] = env->regs[13];
|
||||
env->xregs[21] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[20] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
|
||||
env->xregs[21] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_UND) {
|
||||
env->xregs[22] = env->regs[13];
|
||||
env->xregs[23] = env->regs[14];
|
||||
} else {
|
||||
env->xregs[22] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
|
||||
env->xregs[23] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
|
||||
}
|
||||
|
||||
/* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
|
||||
* mode, then we can copy from r8-r14. Otherwise, we copy from the
|
||||
* FIQ bank for r8-r14.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_FIQ) {
|
||||
for (i = 24; i < 31; i++) {
|
||||
env->xregs[i] = env->regs[i - 16]; /* X[24:30] <- R[8:14] */
|
||||
}
|
||||
} else {
|
||||
for (i = 24; i < 29; i++) {
|
||||
env->xregs[i] = env->fiq_regs[i - 24];
|
||||
}
|
||||
env->xregs[29] = env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)];
|
||||
env->xregs[30] = env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)];
|
||||
}
|
||||
|
||||
env->pc = env->regs[15];
|
||||
}
|
||||
|
||||
/* Function used to synchronize QEMU's AArch32 register set with AArch64
|
||||
* register set. This is necessary when switching between AArch32 and AArch64
|
||||
* execution state.
|
||||
*/
|
||||
void aarch64_sync_64_to_32(CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
uint32_t mode = env->uncached_cpsr & CPSR_M;
|
||||
|
||||
/* We can blanket copy X[0:7] to R[0:7] */
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->regs[i] = env->xregs[i];
|
||||
}
|
||||
|
||||
/* Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
|
||||
* Otherwise, we copy x8-x12 into the banked user regs.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_FIQ) {
|
||||
for (i = 8; i < 13; i++) {
|
||||
env->usr_regs[i - 8] = env->xregs[i];
|
||||
}
|
||||
} else {
|
||||
for (i = 8; i < 13; i++) {
|
||||
env->regs[i] = env->xregs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers r13 & r14 depend on the current mode.
|
||||
* If we are in a given mode, we copy the corresponding x registers to r13
|
||||
* and r14. Otherwise, we copy the x register to the banked r13 and r14
|
||||
* for the mode.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
|
||||
env->regs[13] = env->xregs[13];
|
||||
env->regs[14] = env->xregs[14];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_USR)] = env->xregs[13];
|
||||
|
||||
/* HYP is an exception in that it does not have its own banked r14 but
|
||||
* shares the USR r14
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_HYP) {
|
||||
env->regs[14] = env->xregs[14];
|
||||
} else {
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_USR)] = env->xregs[14];
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_HYP) {
|
||||
env->regs[13] = env->xregs[15];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_HYP)] = env->xregs[15];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_IRQ) {
|
||||
env->regs[13] = env->xregs[16];
|
||||
env->regs[14] = env->xregs[17];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_SVC) {
|
||||
env->regs[13] = env->xregs[18];
|
||||
env->regs[14] = env->xregs[19];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_ABT) {
|
||||
env->regs[13] = env->xregs[20];
|
||||
env->regs[14] = env->xregs[21];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_UND) {
|
||||
env->regs[13] = env->xregs[22];
|
||||
env->regs[14] = env->xregs[23];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
|
||||
}
|
||||
|
||||
/* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
|
||||
* mode, then we can copy to r8-r14. Otherwise, we copy to the
|
||||
* FIQ bank for r8-r14.
|
||||
*/
|
||||
if (mode == ARM_CPU_MODE_FIQ) {
|
||||
for (i = 24; i < 31; i++) {
|
||||
env->regs[i - 16] = env->xregs[i]; /* X[24:30] -> R[8:14] */
|
||||
}
|
||||
} else {
|
||||
for (i = 24; i < 29; i++) {
|
||||
env->fiq_regs[i - 24] = env->xregs[i];
|
||||
}
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[29];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[30];
|
||||
}
|
||||
|
||||
env->regs[15] = env->pc;
|
||||
}
|
||||
|
||||
/* Handle a CPU exception. */
|
||||
void arm_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
|
|
|
@ -465,7 +465,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
|||
int cur_el = arm_current_el(env);
|
||||
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
|
||||
uint32_t spsr = env->banked_spsr[spsr_idx];
|
||||
int new_el, i;
|
||||
int new_el;
|
||||
|
||||
aarch64_save_sp(env, cur_el);
|
||||
|
||||
|
@ -491,9 +491,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
|||
if (!arm_singlestep_active(env)) {
|
||||
env->uncached_cpsr &= ~PSTATE_SS;
|
||||
}
|
||||
for (i = 0; i < 15; i++) {
|
||||
env->regs[i] = env->xregs[i];
|
||||
}
|
||||
aarch64_sync_64_to_32(env);
|
||||
|
||||
env->regs[15] = env->elr_el[1] & ~0x1;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue