Skip to content

Commit

Permalink
target/ppc: Fix crash on machine check caused by ifetch
Browse files Browse the repository at this point in the history
is_prefix_insn_excp() loads the first word of the instruction address
which caused an exception, to determine whether or not it was prefixed
so the prefix bit can be set in [H]SRR1.

This works if the instruction image can be loaded, but if the exception
was caused by an ifetch, this load could fail and cause a recursive
exception and crash. Machine checks caused by ifetch are not excluded
from the prefix check and can crash (see issue 2108 for an example).

Fix this by excluding machine checks caused by ifetch from the prefix
check.

Cc: qemu-stable@nongnu.org
Acked-by: Cédric Le Goater <clg@kaod.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2108
Fixes: 55a7fa3 ("target/ppc: Machine check on invalid real address access on POWER9/10")
Fixes: 5a5d3b2 ("target/ppc: Add SRR1 prefix indication to interrupt handlers")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
  • Loading branch information
npiggin committed Feb 23, 2024
1 parent 2cc0e44 commit c8fd966
Showing 1 changed file with 25 additions and 11 deletions.
36 changes: 25 additions & 11 deletions target/ppc/excp_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,10 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;

if (!(env->insns_flags2 & PPC2_ISA310)) {
return false;
}

if (!tcg_enabled()) {
/*
* This does not load instructions and set the prefix bit correctly
Expand All @@ -1322,6 +1326,15 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp)
}

switch (excp) {
case POWERPC_EXCP_MCHECK:
if (!(env->error_code & PPC_BIT(42))) {
/*
* Fetch attempt caused a machine check, so attempting to fetch
* again would cause a recursive machine check.
*/
return false;
}
break;
case POWERPC_EXCP_HDSI:
/* HDSI PRTABLE_FAULT has the originating access type in error_code */
if ((env->spr[SPR_HDSISR] & DSISR_PRTABLE_FAULT) &&
Expand All @@ -1332,10 +1345,10 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp)
* instruction at NIP would cause recursive faults with the same
* translation).
*/
break;
return false;
}
/* fall through */
case POWERPC_EXCP_MCHECK:
break;

case POWERPC_EXCP_DSI:
case POWERPC_EXCP_DSEG:
case POWERPC_EXCP_ALIGN:
Expand All @@ -1346,17 +1359,13 @@ static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_VPU:
case POWERPC_EXCP_VSXU:
case POWERPC_EXCP_FU:
case POWERPC_EXCP_HV_FU: {
uint32_t insn = ppc_ldl_code(env, env->nip);
if (is_prefix_insn(env, insn)) {
return true;
}
case POWERPC_EXCP_HV_FU:
break;
}
default:
break;
return false;
}
return false;

return is_prefix_insn(env, ppc_ldl_code(env, env->nip));
}
#else
static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp)
Expand Down Expand Up @@ -3224,6 +3233,7 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,

switch (env->excp_model) {
#if defined(TARGET_PPC64)
case POWERPC_EXCP_POWER8:
case POWERPC_EXCP_POWER9:
case POWERPC_EXCP_POWER10:
/*
Expand All @@ -3245,6 +3255,10 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
env->error_code |= PPC_BIT(42);

} else { /* Fetch */
/*
* is_prefix_insn_excp() tests !PPC_BIT(42) to avoid fetching
* the instruction, so that must always be clear for fetches.
*/
env->error_code = PPC_BIT(36) | PPC_BIT(44) | PPC_BIT(45);
}
break;
Expand Down

0 comments on commit c8fd966

Please sign in to comment.