target/arm: Hyp mode R14 is shared with User and System

Hyp mode is an exception to the general rule that each AArch32
mode has its own r13, r14 and SPSR -- it has a banked r13 and
SPSR but shares its r14 with User and System mode. We were
incorrectly implementing it as banked, which meant that on
entry to Hyp mode r14 was 0 rather than the USR/SYS r14.

We provide a new function r14_bank_number() which is like
the existing bank_number() but provides the index into
env->banked_r14[]; bank_number() provides the index to use
for env->banked_r13[] and env->banked_cpsr[].

All the points in the code that were using bank_number()
to index into env->banked_r14[] are updated for consintency:
* switch_mode() -- this is the only place where we fix
an actual bug
* aarch64_sync_32_to_64() and aarch64_sync_64_to_32():
no behavioural change as we already special-cased Hyp R14
* kvm32.c: no behavioural change since the guest can't ever
be in Hyp mode, but conceptually the right thing to do
* msr_banked()/mrs_banked(): we can never get to the case
that accesses banked_r14[] with tgtmode == ARM_CPU_MODE_HYP,
so no behavioural change

Backports commit 593cfa2b637b92d37eef949653840dc065cdb960 from qemu
This commit is contained in:
Peter Maydell 2018-11-16 21:58:25 -05:00 committed by Lioncash
parent 92bf8ee620
commit 61c0f40ac3
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 33 additions and 16 deletions

View file

@ -5614,13 +5614,14 @@ static void switch_mode(CPUARMState *env, int mode)
i = bank_number(old_mode);
env->banked_r13[i] = env->regs[13];
env->banked_r14[i] = env->regs[14];
env->banked_spsr[i] = env->spsr;
i = bank_number(mode);
env->regs[13] = env->banked_r13[i];
env->regs[14] = env->banked_r14[i];
env->spsr = env->banked_spsr[i];
env->banked_r14[r14_bank_number(old_mode)] = env->regs[14];
env->regs[14] = env->banked_r14[r14_bank_number(mode)];
}
/* Physical Interrupt Target EL Lookup Table
@ -7212,7 +7213,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
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)];
env->xregs[14] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)];
}
}
@ -7226,7 +7227,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
env->xregs[16] = env->regs[14];
env->xregs[17] = env->regs[13];
} else {
env->xregs[16] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
env->xregs[16] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)];
env->xregs[17] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
}
@ -7234,7 +7235,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
env->xregs[18] = env->regs[14];
env->xregs[19] = env->regs[13];
} else {
env->xregs[18] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
env->xregs[18] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)];
env->xregs[19] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
}
@ -7242,7 +7243,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
env->xregs[20] = env->regs[14];
env->xregs[21] = env->regs[13];
} else {
env->xregs[20] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
env->xregs[20] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)];
env->xregs[21] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
}
@ -7250,7 +7251,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
env->xregs[22] = env->regs[14];
env->xregs[23] = env->regs[13];
} else {
env->xregs[22] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
env->xregs[22] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)];
env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
}
@ -7267,7 +7268,7 @@ void aarch64_sync_32_to_64(CPUARMState *env)
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->xregs[30] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)];
}
env->pc = env->regs[15];
@ -7317,7 +7318,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
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];
env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)] = env->xregs[14];
}
}
@ -7331,7 +7332,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[14] = env->xregs[16];
env->regs[13] = env->xregs[17];
} else {
env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
}
@ -7339,7 +7340,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[14] = env->xregs[18];
env->regs[13] = env->xregs[19];
} else {
env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
}
@ -7347,7 +7348,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[14] = env->xregs[20];
env->regs[13] = env->xregs[21];
} else {
env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
}
@ -7355,7 +7356,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[14] = env->xregs[22];
env->regs[13] = env->xregs[23];
} else {
env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
}
@ -7372,7 +7373,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
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->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[30];
}
env->regs[15] = env->pc;

View file

@ -147,6 +147,22 @@ static inline int bank_number(int mode)
g_assert_not_reached();
}
/**
* r14_bank_number: Map CPU mode onto register bank for r14
*
* Given an AArch32 CPU mode, return the index into the saved register
* banks to use for the R14 (LR) in that mode. This is the same as
* bank_number(), except for the special case of Hyp mode, where
* R14 is shared with USR and SYS, unlike its R13 and SPSR.
* This should be used as the index into env->banked_r14[], and
* bank_number() used for the index into env->banked_r13[] and
* env->banked_spsr[].
*/
static inline int r14_bank_number(int mode)
{
return (mode == ARM_CPU_MODE_HYP) ? BANK_USRSYS : bank_number(mode);
}
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
void arm_translate_init(struct uc_struct *uc);

View file

@ -696,7 +696,7 @@ void HELPER(msr_banked)(CPUARMState *env, uint32_t value, uint32_t tgtmode,
env->banked_r13[bank_number(tgtmode)] = value;
break;
case 14:
env->banked_r14[bank_number(tgtmode)] = value;
env->banked_r14[r14_bank_number(tgtmode)] = value;
break;
case 8:
case 9:
@ -731,7 +731,7 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
case 13:
return env->banked_r13[bank_number(tgtmode)];
case 14:
return env->banked_r14[bank_number(tgtmode)];
return env->banked_r14[r14_bank_number(tgtmode)];
case 8:
case 9:
case 10: