target/arm: Implement ESB instruction

Check for and defer any pending virtual SError.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220506180242.216785-17-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2022-05-06 13:02:34 -05:00 committed by Peter Maydell
parent 3c29632feb
commit 13954587ea
6 changed files with 103 additions and 15 deletions

View File

@ -187,6 +187,7 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn
{ {
{ {
[
YIELD ---- 0011 0010 0000 1111 ---- 0000 0001 YIELD ---- 0011 0010 0000 1111 ---- 0000 0001
WFE ---- 0011 0010 0000 1111 ---- 0000 0010 WFE ---- 0011 0010 0000 1111 ---- 0000 0010
WFI ---- 0011 0010 0000 1111 ---- 0000 0011 WFI ---- 0011 0010 0000 1111 ---- 0000 0011
@ -195,6 +196,9 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn
# SEV ---- 0011 0010 0000 1111 ---- 0000 0100 # SEV ---- 0011 0010 0000 1111 ---- 0000 0100
# SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101
ESB ---- 0011 0010 0000 1111 ---- 0001 0000
]
# The canonical nop ends in 00000000, but the whole of the # The canonical nop ends in 00000000, but the whole of the
# rest of the space executes as nop if otherwise unsupported. # rest of the space executes as nop if otherwise unsupported.
NOP ---- 0011 0010 0000 1111 ---- ---- ---- NOP ---- 0011 0010 0000 1111 ---- ---- ----

View File

@ -54,6 +54,7 @@ DEF_HELPER_1(wfe, void, env)
DEF_HELPER_1(yield, void, env) DEF_HELPER_1(yield, void, env)
DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_1(pre_hvc, void, env)
DEF_HELPER_2(pre_smc, void, env, i32) DEF_HELPER_2(pre_smc, void, env, i32)
DEF_HELPER_1(vesb, void, env)
DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_3(cpsr_write, void, env, i32, i32)
DEF_HELPER_2(cpsr_write_eret, void, env, i32) DEF_HELPER_2(cpsr_write_eret, void, env, i32)

View File

@ -960,3 +960,46 @@ void HELPER(probe_access)(CPUARMState *env, target_ulong ptr,
access_type, mmu_idx, ra); access_type, mmu_idx, ra);
} }
} }
/*
* This function corresponds to AArch64.vESBOperation().
* Note that the AArch32 version is not functionally different.
*/
void HELPER(vesb)(CPUARMState *env)
{
/*
* The EL2Enabled() check is done inside arm_hcr_el2_eff,
* and will return HCR_EL2.VSE == 0, so nothing happens.
*/
uint64_t hcr = arm_hcr_el2_eff(env);
bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO);
bool pending = enabled && (hcr & HCR_VSE);
bool masked = (env->daif & PSTATE_A);
/* If VSE pending and masked, defer the exception. */
if (pending && masked) {
uint32_t syndrome;
if (arm_el_is_aa64(env, 1)) {
/* Copy across IDS and ISS from VSESR. */
syndrome = env->cp15.vsesr_el2 & 0x1ffffff;
} else {
ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal };
if (extended_addresses_enabled(env)) {
syndrome = arm_fi_to_lfsc(&fi);
} else {
syndrome = arm_fi_to_sfsc(&fi);
}
/* Copy across AET and ExT from VSESR. */
syndrome |= env->cp15.vsesr_el2 & 0xd000;
}
/* Set VDISR_EL2.A along with the syndrome. */
env->cp15.vdisr_el2 = syndrome | (1u << 31);
/* Clear pending virtual SError */
env->cp15.hcr_el2 &= ~HCR_VSE;
cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR);
}
}

View File

@ -364,6 +364,7 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
[ [
# Hints, and CPS # Hints, and CPS
{ {
[
YIELD 1111 0011 1010 1111 1000 0000 0000 0001 YIELD 1111 0011 1010 1111 1000 0000 0000 0001
WFE 1111 0011 1010 1111 1000 0000 0000 0010 WFE 1111 0011 1010 1111 1000 0000 0000 0010
WFI 1111 0011 1010 1111 1000 0000 0000 0011 WFI 1111 0011 1010 1111 1000 0000 0000 0011
@ -372,9 +373,8 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
# SEV 1111 0011 1010 1111 1000 0000 0000 0100 # SEV 1111 0011 1010 1111 1000 0000 0000 0100
# SEVL 1111 0011 1010 1111 1000 0000 0000 0101 # SEVL 1111 0011 1010 1111 1000 0000 0000 0101
# For M-profile minimal-RAS ESB can be a NOP, which is the ESB 1111 0011 1010 1111 1000 0000 0001 0000
# default behaviour since it is in the hint space. ]
# ESB 1111 0011 1010 1111 1000 0000 0001 0000
# The canonical nop ends in 0000 0000, but the whole rest # The canonical nop ends in 0000 0000, but the whole rest
# of the space is "reserved hint, behaves as nop". # of the space is "reserved hint, behaves as nop".

View File

@ -1454,6 +1454,23 @@ static void handle_hint(DisasContext *s, uint32_t insn,
gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]); gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
} }
break; break;
case 0b10000: /* ESB */
/* Without RAS, we must implement this as NOP. */
if (dc_isar_feature(aa64_ras, s)) {
/*
* QEMU does not have a source of physical SErrors,
* so we are only concerned with virtual SErrors.
* The pseudocode in the ARM for this case is
* if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then
* AArch64.vESBOperation();
* Most of the condition can be evaluated at translation time.
* Test for EL2 present, and defer test for SEL2 to runtime.
*/
if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
gen_helper_vesb(cpu_env);
}
}
break;
case 0b11000: /* PACIAZ */ case 0b11000: /* PACIAZ */
if (s->pauth_active) { if (s->pauth_active) {
gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],

View File

@ -6239,6 +6239,29 @@ static bool trans_WFI(DisasContext *s, arg_WFI *a)
return true; return true;
} }
static bool trans_ESB(DisasContext *s, arg_ESB *a)
{
/*
* For M-profile, minimal-RAS ESB can be a NOP.
* Without RAS, we must implement this as NOP.
*/
if (!arm_dc_feature(s, ARM_FEATURE_M) && dc_isar_feature(aa32_ras, s)) {
/*
* QEMU does not have a source of physical SErrors,
* so we are only concerned with virtual SErrors.
* The pseudocode in the ARM for this case is
* if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then
* AArch32.vESBOperation();
* Most of the condition can be evaluated at translation time.
* Test for EL2 present, and defer test for SEL2 to runtime.
*/
if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
gen_helper_vesb(cpu_env);
}
}
return true;
}
static bool trans_NOP(DisasContext *s, arg_NOP *a) static bool trans_NOP(DisasContext *s, arg_NOP *a)
{ {
return true; return true;