mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 17:53:56 -06:00
target/ppc: Move TCG specific exception handlers to tcg-excp_helper.c
Move the TCGCPUOps handlers to a new unit: tcg-excp_helper.c, only built when TCG is selected. See in target/ppc/cpu_init.c: #ifdef CONFIG_TCG static const TCGCPUOps ppc_tcg_ops = { ... .do_unaligned_access = ppc_cpu_do_unaligned_access, .do_transaction_failed = ppc_cpu_do_transaction_failed, .debug_excp_handler = ppc_cpu_debug_excp_handler, .debug_check_breakpoint = ppc_cpu_debug_check_breakpoint, .debug_check_watchpoint = ppc_cpu_debug_check_watchpoint, }; #endif /* CONFIG_TCG */ Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Harsh Prateek Bora <harshpb@linux.ibm.com> Message-ID: <20250127102620.39159-5-philmd@linaro.org> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
This commit is contained in:
parent
215b2ee8f1
commit
0fc76338fe
3 changed files with 203 additions and 173 deletions
|
@ -3144,178 +3144,5 @@ void helper_book3s_trace(CPUPPCState *env, target_ulong prev_ip)
|
||||||
raise_exception_err(env, POWERPC_EXCP_TRACE, error_code);
|
raise_exception_err(env, POWERPC_EXCP_TRACE, error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
|
||||||
MMUAccessType access_type,
|
|
||||||
int mmu_idx, uintptr_t retaddr)
|
|
||||||
{
|
|
||||||
CPUPPCState *env = cpu_env(cs);
|
|
||||||
uint32_t insn;
|
|
||||||
|
|
||||||
/* Restore state and reload the insn we executed, for filling in DSISR. */
|
|
||||||
cpu_restore_state(cs, retaddr);
|
|
||||||
insn = ppc_ldl_code(env, env->nip);
|
|
||||||
|
|
||||||
switch (env->mmu_model) {
|
|
||||||
case POWERPC_MMU_SOFT_4xx:
|
|
||||||
env->spr[SPR_40x_DEAR] = vaddr;
|
|
||||||
break;
|
|
||||||
case POWERPC_MMU_BOOKE:
|
|
||||||
case POWERPC_MMU_BOOKE206:
|
|
||||||
env->spr[SPR_BOOKE_DEAR] = vaddr;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
env->spr[SPR_DAR] = vaddr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs->exception_index = POWERPC_EXCP_ALIGN;
|
|
||||||
env->error_code = insn & 0x03FF0000;
|
|
||||||
cpu_loop_exit(cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
|
||||||
vaddr vaddr, unsigned size,
|
|
||||||
MMUAccessType access_type,
|
|
||||||
int mmu_idx, MemTxAttrs attrs,
|
|
||||||
MemTxResult response, uintptr_t retaddr)
|
|
||||||
{
|
|
||||||
CPUPPCState *env = cpu_env(cs);
|
|
||||||
|
|
||||||
switch (env->excp_model) {
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
case POWERPC_EXCP_POWER8:
|
|
||||||
case POWERPC_EXCP_POWER9:
|
|
||||||
case POWERPC_EXCP_POWER10:
|
|
||||||
case POWERPC_EXCP_POWER11:
|
|
||||||
/*
|
|
||||||
* Machine check codes can be found in processor User Manual or
|
|
||||||
* Linux or skiboot source.
|
|
||||||
*/
|
|
||||||
if (access_type == MMU_DATA_LOAD) {
|
|
||||||
env->spr[SPR_DAR] = vaddr;
|
|
||||||
env->spr[SPR_DSISR] = PPC_BIT(57);
|
|
||||||
env->error_code = PPC_BIT(42);
|
|
||||||
|
|
||||||
} else if (access_type == MMU_DATA_STORE) {
|
|
||||||
/*
|
|
||||||
* MCE for stores in POWER is asynchronous so hardware does
|
|
||||||
* not set DAR, but QEMU can do better.
|
|
||||||
*/
|
|
||||||
env->spr[SPR_DAR] = vaddr;
|
|
||||||
env->error_code = PPC_BIT(36) | PPC_BIT(43) | PPC_BIT(45);
|
|
||||||
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;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* TODO: Check behaviour for other CPUs, for now do nothing.
|
|
||||||
* Could add a basic MCE even if real hardware ignores.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs->exception_index = POWERPC_EXCP_MCHECK;
|
|
||||||
cpu_loop_exit_restore(cs, retaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ppc_cpu_debug_excp_handler(CPUState *cs)
|
|
||||||
{
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
CPUPPCState *env = cpu_env(cs);
|
|
||||||
|
|
||||||
if (env->insns_flags2 & PPC2_ISA207S) {
|
|
||||||
if (cs->watchpoint_hit) {
|
|
||||||
if (cs->watchpoint_hit->flags & BP_CPU) {
|
|
||||||
env->spr[SPR_DAR] = cs->watchpoint_hit->hitaddr;
|
|
||||||
env->spr[SPR_DSISR] = PPC_BIT(41);
|
|
||||||
cs->watchpoint_hit = NULL;
|
|
||||||
raise_exception(env, POWERPC_EXCP_DSI);
|
|
||||||
}
|
|
||||||
cs->watchpoint_hit = NULL;
|
|
||||||
} else if (cpu_breakpoint_test(cs, env->nip, BP_CPU)) {
|
|
||||||
raise_exception_err(env, POWERPC_EXCP_TRACE,
|
|
||||||
PPC_BIT(33) | PPC_BIT(43));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ppc_cpu_debug_check_breakpoint(CPUState *cs)
|
|
||||||
{
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
CPUPPCState *env = cpu_env(cs);
|
|
||||||
|
|
||||||
if (env->insns_flags2 & PPC2_ISA207S) {
|
|
||||||
target_ulong priv;
|
|
||||||
|
|
||||||
priv = env->spr[SPR_CIABR] & PPC_BITMASK(62, 63);
|
|
||||||
switch (priv) {
|
|
||||||
case 0x1: /* problem */
|
|
||||||
return env->msr & ((target_ulong)1 << MSR_PR);
|
|
||||||
case 0x2: /* supervisor */
|
|
||||||
return (!(env->msr & ((target_ulong)1 << MSR_PR)) &&
|
|
||||||
!(env->msr & ((target_ulong)1 << MSR_HV)));
|
|
||||||
case 0x3: /* hypervisor */
|
|
||||||
return (!(env->msr & ((target_ulong)1 << MSR_PR)) &&
|
|
||||||
(env->msr & ((target_ulong)1 << MSR_HV)));
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
|
|
||||||
{
|
|
||||||
#if defined(TARGET_PPC64)
|
|
||||||
CPUPPCState *env = cpu_env(cs);
|
|
||||||
|
|
||||||
if (env->insns_flags2 & PPC2_ISA207S) {
|
|
||||||
if (wp == env->dawr0_watchpoint) {
|
|
||||||
uint32_t dawrx = env->spr[SPR_DAWRX0];
|
|
||||||
bool wt = extract32(dawrx, PPC_BIT_NR(59), 1);
|
|
||||||
bool wti = extract32(dawrx, PPC_BIT_NR(60), 1);
|
|
||||||
bool hv = extract32(dawrx, PPC_BIT_NR(61), 1);
|
|
||||||
bool sv = extract32(dawrx, PPC_BIT_NR(62), 1);
|
|
||||||
bool pr = extract32(dawrx, PPC_BIT_NR(62), 1);
|
|
||||||
|
|
||||||
if ((env->msr & ((target_ulong)1 << MSR_PR)) && !pr) {
|
|
||||||
return false;
|
|
||||||
} else if ((env->msr & ((target_ulong)1 << MSR_HV)) && !hv) {
|
|
||||||
return false;
|
|
||||||
} else if (!sv) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wti) {
|
|
||||||
if (env->msr & ((target_ulong)1 << MSR_DR)) {
|
|
||||||
if (!wt) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (wt) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
#endif /* CONFIG_TCG */
|
#endif /* CONFIG_TCG */
|
||||||
|
|
|
@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
|
||||||
'int_helper.c',
|
'int_helper.c',
|
||||||
'mem_helper.c',
|
'mem_helper.c',
|
||||||
'misc_helper.c',
|
'misc_helper.c',
|
||||||
|
'tcg-excp_helper.c',
|
||||||
'timebase_helper.c',
|
'timebase_helper.c',
|
||||||
'translate.c',
|
'translate.c',
|
||||||
'power8-pmu.c',
|
'power8-pmu.c',
|
||||||
|
|
202
target/ppc/tcg-excp_helper.c
Normal file
202
target/ppc/tcg-excp_helper.c
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* PowerPC exception emulation helpers for QEMU (TCG specific)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2007 Jocelyn Mayer
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "exec/cpu_ldst.h"
|
||||||
|
|
||||||
|
#include "hw/ppc/ppc.h"
|
||||||
|
#include "internal.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
|
||||||
|
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||||
|
MMUAccessType access_type,
|
||||||
|
int mmu_idx, uintptr_t retaddr)
|
||||||
|
{
|
||||||
|
CPUPPCState *env = cpu_env(cs);
|
||||||
|
uint32_t insn;
|
||||||
|
|
||||||
|
/* Restore state and reload the insn we executed, for filling in DSISR. */
|
||||||
|
cpu_restore_state(cs, retaddr);
|
||||||
|
insn = ppc_ldl_code(env, env->nip);
|
||||||
|
|
||||||
|
switch (env->mmu_model) {
|
||||||
|
case POWERPC_MMU_SOFT_4xx:
|
||||||
|
env->spr[SPR_40x_DEAR] = vaddr;
|
||||||
|
break;
|
||||||
|
case POWERPC_MMU_BOOKE:
|
||||||
|
case POWERPC_MMU_BOOKE206:
|
||||||
|
env->spr[SPR_BOOKE_DEAR] = vaddr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
env->spr[SPR_DAR] = vaddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cs->exception_index = POWERPC_EXCP_ALIGN;
|
||||||
|
env->error_code = insn & 0x03FF0000;
|
||||||
|
cpu_loop_exit(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||||
|
vaddr vaddr, unsigned size,
|
||||||
|
MMUAccessType access_type,
|
||||||
|
int mmu_idx, MemTxAttrs attrs,
|
||||||
|
MemTxResult response, uintptr_t retaddr)
|
||||||
|
{
|
||||||
|
CPUPPCState *env = cpu_env(cs);
|
||||||
|
|
||||||
|
switch (env->excp_model) {
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
case POWERPC_EXCP_POWER8:
|
||||||
|
case POWERPC_EXCP_POWER9:
|
||||||
|
case POWERPC_EXCP_POWER10:
|
||||||
|
case POWERPC_EXCP_POWER11:
|
||||||
|
/*
|
||||||
|
* Machine check codes can be found in processor User Manual or
|
||||||
|
* Linux or skiboot source.
|
||||||
|
*/
|
||||||
|
if (access_type == MMU_DATA_LOAD) {
|
||||||
|
env->spr[SPR_DAR] = vaddr;
|
||||||
|
env->spr[SPR_DSISR] = PPC_BIT(57);
|
||||||
|
env->error_code = PPC_BIT(42);
|
||||||
|
|
||||||
|
} else if (access_type == MMU_DATA_STORE) {
|
||||||
|
/*
|
||||||
|
* MCE for stores in POWER is asynchronous so hardware does
|
||||||
|
* not set DAR, but QEMU can do better.
|
||||||
|
*/
|
||||||
|
env->spr[SPR_DAR] = vaddr;
|
||||||
|
env->error_code = PPC_BIT(36) | PPC_BIT(43) | PPC_BIT(45);
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* TODO: Check behaviour for other CPUs, for now do nothing.
|
||||||
|
* Could add a basic MCE even if real hardware ignores.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cs->exception_index = POWERPC_EXCP_MCHECK;
|
||||||
|
cpu_loop_exit_restore(cs, retaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppc_cpu_debug_excp_handler(CPUState *cs)
|
||||||
|
{
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
CPUPPCState *env = cpu_env(cs);
|
||||||
|
|
||||||
|
if (env->insns_flags2 & PPC2_ISA207S) {
|
||||||
|
if (cs->watchpoint_hit) {
|
||||||
|
if (cs->watchpoint_hit->flags & BP_CPU) {
|
||||||
|
env->spr[SPR_DAR] = cs->watchpoint_hit->hitaddr;
|
||||||
|
env->spr[SPR_DSISR] = PPC_BIT(41);
|
||||||
|
cs->watchpoint_hit = NULL;
|
||||||
|
raise_exception(env, POWERPC_EXCP_DSI);
|
||||||
|
}
|
||||||
|
cs->watchpoint_hit = NULL;
|
||||||
|
} else if (cpu_breakpoint_test(cs, env->nip, BP_CPU)) {
|
||||||
|
raise_exception_err(env, POWERPC_EXCP_TRACE,
|
||||||
|
PPC_BIT(33) | PPC_BIT(43));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ppc_cpu_debug_check_breakpoint(CPUState *cs)
|
||||||
|
{
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
CPUPPCState *env = cpu_env(cs);
|
||||||
|
|
||||||
|
if (env->insns_flags2 & PPC2_ISA207S) {
|
||||||
|
target_ulong priv;
|
||||||
|
|
||||||
|
priv = env->spr[SPR_CIABR] & PPC_BITMASK(62, 63);
|
||||||
|
switch (priv) {
|
||||||
|
case 0x1: /* problem */
|
||||||
|
return env->msr & ((target_ulong)1 << MSR_PR);
|
||||||
|
case 0x2: /* supervisor */
|
||||||
|
return (!(env->msr & ((target_ulong)1 << MSR_PR)) &&
|
||||||
|
!(env->msr & ((target_ulong)1 << MSR_HV)));
|
||||||
|
case 0x3: /* hypervisor */
|
||||||
|
return (!(env->msr & ((target_ulong)1 << MSR_PR)) &&
|
||||||
|
(env->msr & ((target_ulong)1 << MSR_HV)));
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
|
||||||
|
{
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
CPUPPCState *env = cpu_env(cs);
|
||||||
|
|
||||||
|
if (env->insns_flags2 & PPC2_ISA207S) {
|
||||||
|
if (wp == env->dawr0_watchpoint) {
|
||||||
|
uint32_t dawrx = env->spr[SPR_DAWRX0];
|
||||||
|
bool wt = extract32(dawrx, PPC_BIT_NR(59), 1);
|
||||||
|
bool wti = extract32(dawrx, PPC_BIT_NR(60), 1);
|
||||||
|
bool hv = extract32(dawrx, PPC_BIT_NR(61), 1);
|
||||||
|
bool sv = extract32(dawrx, PPC_BIT_NR(62), 1);
|
||||||
|
bool pr = extract32(dawrx, PPC_BIT_NR(62), 1);
|
||||||
|
|
||||||
|
if ((env->msr & ((target_ulong)1 << MSR_PR)) && !pr) {
|
||||||
|
return false;
|
||||||
|
} else if ((env->msr & ((target_ulong)1 << MSR_HV)) && !hv) {
|
||||||
|
return false;
|
||||||
|
} else if (!sv) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wti) {
|
||||||
|
if (env->msr & ((target_ulong)1 << MSR_DR)) {
|
||||||
|
if (!wt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !CONFIG_USER_ONLY */
|
Loading…
Add table
Add a link
Reference in a new issue