aboutsummaryrefslogtreecommitdiff
path: root/target/ppc/excp_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc/excp_helper.c')
-rw-r--r--target/ppc/excp_helper.c1105
1 files changed, 152 insertions, 953 deletions
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0cd5426..1efdc40 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -19,22 +19,17 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "qemu/log.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/memory.h"
+#include "system/tcg.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "internal.h"
#include "helper_regs.h"
#include "hw/ppc/ppc.h"
#include "trace.h"
-#ifdef CONFIG_TCG
-#include "sysemu/tcg.h"
-#include "exec/helper-proto.h"
-#include "exec/cpu_ldst.h"
-#endif
-
/*****************************************************************************/
/* Exception processing */
#ifndef CONFIG_USER_ONLY
@@ -136,27 +131,6 @@ static void dump_hcall(CPUPPCState *env)
env->nip);
}
-#ifdef CONFIG_TCG
-/* Return true iff byteswap is needed to load instruction */
-static inline bool insn_need_byteswap(CPUArchState *env)
-{
- /* SYSTEM builds TARGET_BIG_ENDIAN. Need to swap when MSR[LE] is set */
- return !!(env->msr & ((target_ulong)1 << MSR_LE));
-}
-
-static uint32_t ppc_ldl_code(CPUArchState *env, target_ulong addr)
-{
- uint32_t insn = cpu_ldl_code(env, addr);
-
- if (insn_need_byteswap(env)) {
- insn = bswap32(insn);
- }
-
- return insn;
-}
-
-#endif
-
static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
{
const char *es;
@@ -324,10 +298,7 @@ static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp, target_ulong msr,
}
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
- if (ail == 0) {
- return;
- }
- if (ail == 1) {
+ if (ail == 0 || ail == 1) {
/* AIL=1 is reserved, treat it like AIL=0 */
return;
}
@@ -351,10 +322,7 @@ static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp, target_ulong msr,
} else {
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
}
- if (ail == 0) {
- return;
- }
- if (ail == 1 || ail == 2) {
+ if (ail == 0 || ail == 1 || ail == 2) {
/* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
return;
}
@@ -426,57 +394,14 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
env->reserve_addr = -1;
}
-#ifdef CONFIG_TCG
-/*
- * This stops the machine and logs CPU state without killing QEMU (like
- * cpu_abort()) because it is often a guest error as opposed to a QEMU error,
- * so the machine can still be debugged.
- */
-static G_NORETURN void powerpc_checkstop(CPUPPCState *env, const char *reason)
-{
- CPUState *cs = env_cpu(env);
- FILE *f;
-
- f = qemu_log_trylock();
- if (f) {
- fprintf(f, "Entering checkstop state: %s\n", reason);
- cpu_dump_state(cs, f, CPU_DUMP_FPU | CPU_DUMP_CCOP);
- qemu_log_unlock(f);
- }
-
- /*
- * This stops the machine and logs CPU state without killing QEMU
- * (like cpu_abort()) so the machine can still be debugged (because
- * it is often a guest error).
- */
- qemu_system_guest_panicked(NULL);
- cpu_loop_exit_noexc(cs);
-}
-
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-void helper_attn(CPUPPCState *env)
-{
- /* POWER attn is unprivileged when enabled by HID, otherwise illegal */
- if ((*env->check_attn)(env)) {
- powerpc_checkstop(env, "host executed attn");
- } else {
- raise_exception_err(env, POWERPC_EXCP_HV_EMU,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
- }
-}
-#endif
-#endif /* CONFIG_TCG */
-
static void powerpc_mcheck_checkstop(CPUPPCState *env)
{
/* KVM guests always have MSR[ME] enabled */
-#ifdef CONFIG_TCG
if (FIELD_EX64(env->msr, MSR, ME)) {
return;
}
-
+ assert(tcg_enabled());
powerpc_checkstop(env, "machine check with MSR[ME]=0");
-#endif
}
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
@@ -1626,7 +1551,7 @@ static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
}
#endif /* TARGET_PPC64 */
-static void powerpc_excp(PowerPCCPU *cpu, int excp)
+void powerpc_excp(PowerPCCPU *cpu, int excp)
{
CPUPPCState *env = &cpu->env;
@@ -1661,6 +1586,7 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_POWER8:
case POWERPC_EXCP_POWER9:
case POWERPC_EXCP_POWER10:
+ case POWERPC_EXCP_POWER11:
powerpc_excp_books(cpu, excp);
break;
default:
@@ -1682,51 +1608,54 @@ void ppc_cpu_do_interrupt(CPUState *cs)
PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
-static int p7_interrupt_powersave(CPUPPCState *env)
+static int p7_interrupt_powersave(uint32_t pending_interrupts,
+ target_ulong lpcr)
{
- if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
- (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+ if ((pending_interrupts & PPC_INTERRUPT_EXT) &&
+ (lpcr & LPCR_P7_PECE0)) {
return PPC_INTERRUPT_EXT;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
- (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+ if ((pending_interrupts & PPC_INTERRUPT_DECR) &&
+ (lpcr & LPCR_P7_PECE1)) {
return PPC_INTERRUPT_DECR;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
- (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+ if ((pending_interrupts & PPC_INTERRUPT_MCK) &&
+ (lpcr & LPCR_P7_PECE2)) {
return PPC_INTERRUPT_MCK;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
- (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+ if ((pending_interrupts & PPC_INTERRUPT_HMI) &&
+ (lpcr & LPCR_P7_PECE2)) {
return PPC_INTERRUPT_HMI;
}
- if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+ if (pending_interrupts & PPC_INTERRUPT_RESET) {
return PPC_INTERRUPT_RESET;
}
return 0;
}
-static int p7_next_unmasked_interrupt(CPUPPCState *env)
+static int p7_next_unmasked_interrupt(CPUPPCState *env,
+ uint32_t pending_interrupts,
+ target_ulong lpcr)
{
CPUState *cs = env_cpu(env);
/* Ignore MSR[EE] when coming out of some power management states */
bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
- assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
+ assert((pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
if (cs->halted) {
/* LPCR[PECE] controls which interrupts can exit power-saving mode */
- return p7_interrupt_powersave(env);
+ return p7_interrupt_powersave(pending_interrupts, lpcr);
}
/* Machine check exception */
- if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ if (pending_interrupts & PPC_INTERRUPT_MCK) {
return PPC_INTERRUPT_MCK;
}
/* Hypervisor decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+ if (pending_interrupts & PPC_INTERRUPT_HDECR) {
/* LPCR will be clear when not supported so this will work */
bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
@@ -1736,9 +1665,9 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
}
/* External interrupt can ignore MSR:EE under some circumstances */
- if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
- bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+ if (pending_interrupts & PPC_INTERRUPT_EXT) {
+ bool lpes0 = !!(lpcr & LPCR_LPES0);
+ bool heic = !!(lpcr & LPCR_HEIC);
/* HEIC blocks delivery to the hypervisor */
if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
!FIELD_EX64(env->msr, MSR, PR))) ||
@@ -1748,10 +1677,10 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
}
if (msr_ee != 0) {
/* Decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+ if (pending_interrupts & PPC_INTERRUPT_DECR) {
return PPC_INTERRUPT_DECR;
}
- if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+ if (pending_interrupts & PPC_INTERRUPT_PERFM) {
return PPC_INTERRUPT_PERFM;
}
}
@@ -1764,39 +1693,42 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \
PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
-static int p8_interrupt_powersave(CPUPPCState *env)
+static int p8_interrupt_powersave(uint32_t pending_interrupts,
+ target_ulong lpcr)
{
- if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+ if ((pending_interrupts & PPC_INTERRUPT_EXT) &&
+ (lpcr & LPCR_P8_PECE2)) {
return PPC_INTERRUPT_EXT;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+ if ((pending_interrupts & PPC_INTERRUPT_DECR) &&
+ (lpcr & LPCR_P8_PECE3)) {
return PPC_INTERRUPT_DECR;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+ if ((pending_interrupts & PPC_INTERRUPT_MCK) &&
+ (lpcr & LPCR_P8_PECE4)) {
return PPC_INTERRUPT_MCK;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+ if ((pending_interrupts & PPC_INTERRUPT_HMI) &&
+ (lpcr & LPCR_P8_PECE4)) {
return PPC_INTERRUPT_HMI;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+ if ((pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+ (lpcr & LPCR_P8_PECE0)) {
return PPC_INTERRUPT_DOORBELL;
}
- if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
- (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+ if ((pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+ (lpcr & LPCR_P8_PECE1)) {
return PPC_INTERRUPT_HDOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+ if (pending_interrupts & PPC_INTERRUPT_RESET) {
return PPC_INTERRUPT_RESET;
}
return 0;
}
-static int p8_next_unmasked_interrupt(CPUPPCState *env)
+static int p8_next_unmasked_interrupt(CPUPPCState *env,
+ uint32_t pending_interrupts,
+ target_ulong lpcr)
{
CPUState *cs = env_cpu(env);
@@ -1807,18 +1739,18 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
if (cs->halted) {
/* LPCR[PECE] controls which interrupts can exit power-saving mode */
- return p8_interrupt_powersave(env);
+ return p8_interrupt_powersave(pending_interrupts, lpcr);
}
/* Machine check exception */
- if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ if (pending_interrupts & PPC_INTERRUPT_MCK) {
return PPC_INTERRUPT_MCK;
}
/* Hypervisor decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+ if (pending_interrupts & PPC_INTERRUPT_HDECR) {
/* LPCR will be clear when not supported so this will work */
- bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+ bool hdice = !!(lpcr & LPCR_HDICE);
if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
/* HDEC clears on delivery */
return PPC_INTERRUPT_HDECR;
@@ -1826,9 +1758,9 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
}
/* External interrupt can ignore MSR:EE under some circumstances */
- if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
- bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+ if (pending_interrupts & PPC_INTERRUPT_EXT) {
+ bool lpes0 = !!(lpcr & LPCR_LPES0);
+ bool heic = !!(lpcr & LPCR_HEIC);
/* HEIC blocks delivery to the hypervisor */
if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
!FIELD_EX64(env->msr, MSR, PR))) ||
@@ -1838,20 +1770,20 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
}
if (msr_ee != 0) {
/* Decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+ if (pending_interrupts & PPC_INTERRUPT_DECR) {
return PPC_INTERRUPT_DECR;
}
- if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_DOORBELL) {
return PPC_INTERRUPT_DOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
return PPC_INTERRUPT_HDOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+ if (pending_interrupts & PPC_INTERRUPT_PERFM) {
return PPC_INTERRUPT_PERFM;
}
/* EBB exception */
- if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+ if (pending_interrupts & PPC_INTERRUPT_EBB) {
/*
* EBB exception must be taken in problem state and
* with BESCR_GE set.
@@ -1871,60 +1803,65 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \
PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
-static int p9_interrupt_powersave(CPUPPCState *env)
+static int p9_interrupt_powersave(CPUPPCState *env,
+ uint32_t pending_interrupts,
+ target_ulong lpcr)
{
+
/* External Exception */
- if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
- (env->spr[SPR_LPCR] & LPCR_EEE)) {
- bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+ if ((pending_interrupts & PPC_INTERRUPT_EXT) &&
+ (lpcr & LPCR_EEE)) {
+ bool heic = !!(lpcr & LPCR_HEIC);
if (!heic || !FIELD_EX64_HV(env->msr) ||
FIELD_EX64(env->msr, MSR, PR)) {
return PPC_INTERRUPT_EXT;
}
}
/* Decrementer Exception */
- if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
- (env->spr[SPR_LPCR] & LPCR_DEE)) {
+ if ((pending_interrupts & PPC_INTERRUPT_DECR) &&
+ (lpcr & LPCR_DEE)) {
return PPC_INTERRUPT_DECR;
}
/* Machine Check or Hypervisor Maintenance Exception */
- if (env->spr[SPR_LPCR] & LPCR_OEE) {
- if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ if (lpcr & LPCR_OEE) {
+ if (pending_interrupts & PPC_INTERRUPT_MCK) {
return PPC_INTERRUPT_MCK;
}
- if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+ if (pending_interrupts & PPC_INTERRUPT_HMI) {
return PPC_INTERRUPT_HMI;
}
}
/* Privileged Doorbell Exception */
- if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
- (env->spr[SPR_LPCR] & LPCR_PDEE)) {
+ if ((pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+ (lpcr & LPCR_PDEE)) {
return PPC_INTERRUPT_DOORBELL;
}
/* Hypervisor Doorbell Exception */
- if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
- (env->spr[SPR_LPCR] & LPCR_HDEE)) {
+ if ((pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+ (lpcr & LPCR_HDEE)) {
return PPC_INTERRUPT_HDOORBELL;
}
/* Hypervisor virtualization exception */
- if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
- (env->spr[SPR_LPCR] & LPCR_HVEE)) {
+ if ((pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+ (lpcr & LPCR_HVEE)) {
return PPC_INTERRUPT_HVIRT;
}
- if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+ if (pending_interrupts & PPC_INTERRUPT_RESET) {
return PPC_INTERRUPT_RESET;
}
return 0;
}
-static int p9_next_unmasked_interrupt(CPUPPCState *env)
+static int p9_next_unmasked_interrupt(CPUPPCState *env,
+ uint32_t pending_interrupts,
+ target_ulong lpcr)
{
CPUState *cs = env_cpu(env);
/* Ignore MSR[EE] when coming out of some power management states */
bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
- assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
+ assert((pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
if (cs->halted) {
if (env->spr[SPR_PSSCR] & PSSCR_EC) {
@@ -1932,7 +1869,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
* When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
* wakeup the processor
*/
- return p9_interrupt_powersave(env);
+ return p9_interrupt_powersave(env, pending_interrupts, lpcr);
} else {
/*
* When it's clear, any system-caused exception exits power-saving
@@ -1943,14 +1880,14 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
}
/* Machine check exception */
- if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ if (pending_interrupts & PPC_INTERRUPT_MCK) {
return PPC_INTERRUPT_MCK;
}
/* Hypervisor decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+ if (pending_interrupts & PPC_INTERRUPT_HDECR) {
/* LPCR will be clear when not supported so this will work */
- bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+ bool hdice = !!(lpcr & LPCR_HDICE);
if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
/* HDEC clears on delivery */
return PPC_INTERRUPT_HDECR;
@@ -1958,18 +1895,18 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
}
/* Hypervisor virtualization interrupt */
- if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+ if (pending_interrupts & PPC_INTERRUPT_HVIRT) {
/* LPCR will be clear when not supported so this will work */
- bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+ bool hvice = !!(lpcr & LPCR_HVICE);
if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
return PPC_INTERRUPT_HVIRT;
}
}
/* External interrupt can ignore MSR:EE under some circumstances */
- if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
- bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+ if (pending_interrupts & PPC_INTERRUPT_EXT) {
+ bool lpes0 = !!(lpcr & LPCR_LPES0);
+ bool heic = !!(lpcr & LPCR_HEIC);
/* HEIC blocks delivery to the hypervisor */
if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
!FIELD_EX64(env->msr, MSR, PR))) ||
@@ -1979,20 +1916,20 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
}
if (msr_ee != 0) {
/* Decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+ if (pending_interrupts & PPC_INTERRUPT_DECR) {
return PPC_INTERRUPT_DECR;
}
- if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_DOORBELL) {
return PPC_INTERRUPT_DOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
return PPC_INTERRUPT_HDOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+ if (pending_interrupts & PPC_INTERRUPT_PERFM) {
return PPC_INTERRUPT_PERFM;
}
/* EBB exception */
- if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+ if (pending_interrupts & PPC_INTERRUPT_EBB) {
/*
* EBB exception must be taken in problem state and
* with BESCR_GE set.
@@ -2010,27 +1947,35 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
static int ppc_next_unmasked_interrupt(CPUPPCState *env)
{
+ uint32_t pending_interrupts = env->pending_interrupts;
+ target_ulong lpcr = env->spr[SPR_LPCR];
+ bool async_deliver;
+
+ if (unlikely(env->quiesced)) {
+ return 0;
+ }
+
#ifdef TARGET_PPC64
switch (env->excp_model) {
case POWERPC_EXCP_POWER7:
- return p7_next_unmasked_interrupt(env);
+ return p7_next_unmasked_interrupt(env, pending_interrupts, lpcr);
case POWERPC_EXCP_POWER8:
- return p8_next_unmasked_interrupt(env);
+ return p8_next_unmasked_interrupt(env, pending_interrupts, lpcr);
case POWERPC_EXCP_POWER9:
case POWERPC_EXCP_POWER10:
- return p9_next_unmasked_interrupt(env);
+ case POWERPC_EXCP_POWER11:
+ return p9_next_unmasked_interrupt(env, pending_interrupts, lpcr);
default:
break;
}
#endif
- bool async_deliver;
/* External reset */
- if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+ if (pending_interrupts & PPC_INTERRUPT_RESET) {
return PPC_INTERRUPT_RESET;
}
/* Machine check exception */
- if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+ if (pending_interrupts & PPC_INTERRUPT_MCK) {
return PPC_INTERRUPT_MCK;
}
#if 0 /* TODO */
@@ -2049,9 +1994,9 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
/* Hypervisor decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+ if (pending_interrupts & PPC_INTERRUPT_HDECR) {
/* LPCR will be clear when not supported so this will work */
- bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+ bool hdice = !!(lpcr & LPCR_HDICE);
if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
/* HDEC clears on delivery */
return PPC_INTERRUPT_HDECR;
@@ -2059,18 +2004,18 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
}
/* Hypervisor virtualization interrupt */
- if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+ if (pending_interrupts & PPC_INTERRUPT_HVIRT) {
/* LPCR will be clear when not supported so this will work */
- bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+ bool hvice = !!(lpcr & LPCR_HVICE);
if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
return PPC_INTERRUPT_HVIRT;
}
}
/* External interrupt can ignore MSR:EE under some circumstances */
- if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
- bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+ if (pending_interrupts & PPC_INTERRUPT_EXT) {
+ bool lpes0 = !!(lpcr & LPCR_LPES0);
+ bool heic = !!(lpcr & LPCR_HEIC);
/* HEIC blocks delivery to the hypervisor */
if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
!FIELD_EX64(env->msr, MSR, PR))) ||
@@ -2080,45 +2025,45 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
}
if (FIELD_EX64(env->msr, MSR, CE)) {
/* External critical interrupt */
- if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+ if (pending_interrupts & PPC_INTERRUPT_CEXT) {
return PPC_INTERRUPT_CEXT;
}
}
if (async_deliver != 0) {
/* Watchdog timer on embedded PowerPC */
- if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+ if (pending_interrupts & PPC_INTERRUPT_WDT) {
return PPC_INTERRUPT_WDT;
}
- if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
return PPC_INTERRUPT_CDOORBELL;
}
/* Fixed interval timer on embedded PowerPC */
- if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+ if (pending_interrupts & PPC_INTERRUPT_FIT) {
return PPC_INTERRUPT_FIT;
}
/* Programmable interval timer on embedded PowerPC */
- if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+ if (pending_interrupts & PPC_INTERRUPT_PIT) {
return PPC_INTERRUPT_PIT;
}
/* Decrementer exception */
- if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+ if (pending_interrupts & PPC_INTERRUPT_DECR) {
return PPC_INTERRUPT_DECR;
}
- if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_DOORBELL) {
return PPC_INTERRUPT_DOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+ if (pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
return PPC_INTERRUPT_HDOORBELL;
}
- if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+ if (pending_interrupts & PPC_INTERRUPT_PERFM) {
return PPC_INTERRUPT_PERFM;
}
/* Thermal interrupt */
- if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+ if (pending_interrupts & PPC_INTERRUPT_THERM) {
return PPC_INTERRUPT_THERM;
}
/* EBB exception */
- if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+ if (pending_interrupts & PPC_INTERRUPT_EBB) {
/*
* EBB exception must be taken in problem state and
* with BESCR_GE set.
@@ -2187,7 +2132,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
powerpc_excp(cpu, POWERPC_EXCP_DECR);
break;
case PPC_INTERRUPT_PERFM:
- env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
powerpc_excp(cpu, POWERPC_EXCP_PERFM);
break;
case 0:
@@ -2238,7 +2182,9 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
powerpc_excp(cpu, POWERPC_EXCP_DECR);
break;
case PPC_INTERRUPT_DOORBELL:
- env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ if (!env->resume_as_sreset) {
+ env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ }
if (is_book3s_arch2x(env)) {
powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
} else {
@@ -2246,11 +2192,12 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
}
break;
case PPC_INTERRUPT_HDOORBELL:
- env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ if (!env->resume_as_sreset) {
+ env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ }
powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
break;
case PPC_INTERRUPT_PERFM:
- env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
powerpc_excp(cpu, POWERPC_EXCP_PERFM);
break;
case PPC_INTERRUPT_EBB: /* EBB exception */
@@ -2303,6 +2250,7 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
/* HDEC clears on delivery */
+ /* XXX: should not see an HDEC if resume_as_sreset. assert? */
env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
powerpc_excp(cpu, POWERPC_EXCP_HDECR);
break;
@@ -2322,15 +2270,18 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
powerpc_excp(cpu, POWERPC_EXCP_DECR);
break;
case PPC_INTERRUPT_DOORBELL:
- env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ if (!env->resume_as_sreset) {
+ env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ }
powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
break;
case PPC_INTERRUPT_HDOORBELL:
- env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ if (!env->resume_as_sreset) {
+ env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ }
powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
break;
case PPC_INTERRUPT_PERFM:
- env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
powerpc_excp(cpu, POWERPC_EXCP_PERFM);
break;
case PPC_INTERRUPT_EBB: /* EBB exception */
@@ -2372,6 +2323,7 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
return p8_deliver_interrupt(env, interrupt);
case POWERPC_EXCP_POWER9:
case POWERPC_EXCP_POWER10:
+ case POWERPC_EXCP_POWER11:
return p9_deliver_interrupt(env, interrupt);
default:
break;
@@ -2444,7 +2396,6 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
break;
case PPC_INTERRUPT_PERFM:
- env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
powerpc_excp(cpu, POWERPC_EXCP_PERFM);
break;
case PPC_INTERRUPT_THERM: /* Thermal interrupt */
@@ -2479,10 +2430,16 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
}
}
+/*
+ * system reset is not delivered via normal irq method, so have to set
+ * halted = 0 to resume CPU running if it was halted. Possibly we should
+ * move it over to using PPC_INTERRUPT_RESET rather than async_run_on_cpu.
+ */
void ppc_cpu_do_system_reset(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cs->halted = 0;
powerpc_excp(cpu, POWERPC_EXCP_RESET);
}
@@ -2504,6 +2461,7 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
/* Anything for nested required here? MSR[HV] bit? */
+ cs->halted = 0;
powerpc_set_excp_state(cpu, vector, msr);
}
@@ -2529,762 +2487,3 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
}
#endif /* !CONFIG_USER_ONLY */
-
-/*****************************************************************************/
-/* Exceptions processing helpers */
-
-void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
- uint32_t error_code, uintptr_t raddr)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = exception;
- env->error_code = error_code;
- cpu_loop_exit_restore(cs, raddr);
-}
-
-void raise_exception_err(CPUPPCState *env, uint32_t exception,
- uint32_t error_code)
-{
- raise_exception_err_ra(env, exception, error_code, 0);
-}
-
-void raise_exception(CPUPPCState *env, uint32_t exception)
-{
- raise_exception_err_ra(env, exception, 0, 0);
-}
-
-void raise_exception_ra(CPUPPCState *env, uint32_t exception,
- uintptr_t raddr)
-{
- raise_exception_err_ra(env, exception, 0, raddr);
-}
-
-#ifdef CONFIG_TCG
-void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
- uint32_t error_code)
-{
- raise_exception_err_ra(env, exception, error_code, 0);
-}
-
-void helper_raise_exception(CPUPPCState *env, uint32_t exception)
-{
- raise_exception_err_ra(env, exception, 0, 0);
-}
-
-#ifndef CONFIG_USER_ONLY
-void helper_store_msr(CPUPPCState *env, target_ulong val)
-{
- uint32_t excp = hreg_store_msr(env, val, 0);
-
- if (excp != 0) {
- cpu_interrupt_exittb(env_cpu(env));
- raise_exception(env, excp);
- }
-}
-
-void helper_ppc_maybe_interrupt(CPUPPCState *env)
-{
- ppc_maybe_interrupt(env);
-}
-
-#ifdef TARGET_PPC64
-void helper_scv(CPUPPCState *env, uint32_t lev)
-{
- if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) {
- raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev);
- } else {
- raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV);
- }
-}
-
-void helper_pminsn(CPUPPCState *env, uint32_t insn)
-{
- CPUState *cs = env_cpu(env);
-
- cs->halted = 1;
-
- /* Condition for waking up at 0x100 */
- env->resume_as_sreset = (insn != PPC_PM_STOP) ||
- (env->spr[SPR_PSSCR] & PSSCR_EC);
-
- /* HDECR is not to wake from PM state, it may have already fired */
- if (env->resume_as_sreset) {
- PowerPCCPU *cpu = env_archcpu(env);
- ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
- }
-
- ppc_maybe_interrupt(env);
-}
-#endif /* TARGET_PPC64 */
-
-static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
-{
- /* MSR:POW cannot be set by any form of rfi */
- msr &= ~(1ULL << MSR_POW);
-
- /* MSR:TGPR cannot be set by any form of rfi */
- if (env->flags & POWERPC_FLAG_TGPR)
- msr &= ~(1ULL << MSR_TGPR);
-
-#ifdef TARGET_PPC64
- /* Switching to 32-bit ? Crop the nip */
- if (!msr_is_64bit(env, msr)) {
- nip = (uint32_t)nip;
- }
-#else
- nip = (uint32_t)nip;
-#endif
- /* XXX: beware: this is false if VLE is supported */
- env->nip = nip & ~((target_ulong)0x00000003);
- hreg_store_msr(env, msr, 1);
- trace_ppc_excp_rfi(env->nip, env->msr);
- /*
- * No need to raise an exception here, as rfi is always the last
- * insn of a TB
- */
- cpu_interrupt_exittb(env_cpu(env));
- /* Reset the reservation */
- env->reserve_addr = -1;
-
- /* Context synchronizing: check if TCG TLB needs flush */
- check_tlb_flush(env, false);
-}
-
-void helper_rfi(CPUPPCState *env)
-{
- do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
-}
-
-#ifdef TARGET_PPC64
-void helper_rfid(CPUPPCState *env)
-{
- /*
- * The architecture defines a number of rules for which bits can
- * change but in practice, we handle this in hreg_store_msr()
- * which will be called by do_rfi(), so there is no need to filter
- * here
- */
- do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
-}
-
-void helper_rfscv(CPUPPCState *env)
-{
- do_rfi(env, env->lr, env->ctr);
-}
-
-void helper_hrfid(CPUPPCState *env)
-{
- do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
-}
-
-void helper_rfebb(CPUPPCState *env, target_ulong s)
-{
- target_ulong msr = env->msr;
-
- /*
- * Handling of BESCR bits 32:33 according to PowerISA v3.1:
- *
- * "If BESCR 32:33 != 0b00 the instruction is treated as if
- * the instruction form were invalid."
- */
- if (env->spr[SPR_BESCR] & BESCR_INVALID) {
- raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
- }
-
- env->nip = env->spr[SPR_EBBRR];
-
- /* Switching to 32-bit ? Crop the nip */
- if (!msr_is_64bit(env, msr)) {
- env->nip = (uint32_t)env->spr[SPR_EBBRR];
- }
-
- if (s) {
- env->spr[SPR_BESCR] |= BESCR_GE;
- } else {
- env->spr[SPR_BESCR] &= ~BESCR_GE;
- }
-}
-
-/*
- * Triggers or queues an 'ebb_excp' EBB exception. All checks
- * but FSCR, HFSCR and msr_pr must be done beforehand.
- *
- * PowerISA v3.1 isn't clear about whether an EBB should be
- * postponed or cancelled if the EBB facility is unavailable.
- * Our assumption here is that the EBB is cancelled if both
- * FSCR and HFSCR EBB facilities aren't available.
- */
-static void do_ebb(CPUPPCState *env, int ebb_excp)
-{
- PowerPCCPU *cpu = env_archcpu(env);
-
- /*
- * FSCR_EBB and FSCR_IC_EBB are the same bits used with
- * HFSCR.
- */
- helper_fscr_facility_check(env, FSCR_EBB, 0, FSCR_IC_EBB);
- helper_hfscr_facility_check(env, FSCR_EBB, "EBB", FSCR_IC_EBB);
-
- if (ebb_excp == POWERPC_EXCP_PERFM_EBB) {
- env->spr[SPR_BESCR] |= BESCR_PMEO;
- } else if (ebb_excp == POWERPC_EXCP_EXTERNAL_EBB) {
- env->spr[SPR_BESCR] |= BESCR_EEO;
- }
-
- if (FIELD_EX64(env->msr, MSR, PR)) {
- powerpc_excp(cpu, ebb_excp);
- } else {
- ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1);
- }
-}
-
-void raise_ebb_perfm_exception(CPUPPCState *env)
-{
- bool perfm_ebb_enabled = env->spr[SPR_POWER_MMCR0] & MMCR0_EBE &&
- env->spr[SPR_BESCR] & BESCR_PME &&
- env->spr[SPR_BESCR] & BESCR_GE;
-
- if (!perfm_ebb_enabled) {
- return;
- }
-
- do_ebb(env, POWERPC_EXCP_PERFM_EBB);
-}
-#endif /* TARGET_PPC64 */
-
-/*****************************************************************************/
-/* Embedded PowerPC specific helpers */
-void helper_40x_rfci(CPUPPCState *env)
-{
- do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
-}
-
-void helper_rfci(CPUPPCState *env)
-{
- do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
-}
-
-void helper_rfdi(CPUPPCState *env)
-{
- /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
- do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
-}
-
-void helper_rfmci(CPUPPCState *env)
-{
- /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
- do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
-}
-#endif /* !CONFIG_USER_ONLY */
-
-void helper_TW(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
- uint32_t flags)
-{
- if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
- ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
- ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
- ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
- ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
- raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_TRAP, GETPC());
- }
-}
-
-#ifdef TARGET_PPC64
-void helper_TD(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
- uint32_t flags)
-{
- if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
- ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
- ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
- ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
- ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
- raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_TRAP, GETPC());
- }
-}
-#endif /* TARGET_PPC64 */
-
-static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane)
-{
- const uint16_t c = 0xfffc;
- const uint64_t z0 = 0xfa2561cdf44ac398ULL;
- uint16_t z = 0, temp;
- uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32];
-
- for (int i = 3; i >= 0; i--) {
- k[i] = key & 0xffff;
- key >>= 16;
- }
- xleft[0] = x & 0xffff;
- xright[0] = (x >> 16) & 0xffff;
-
- for (int i = 0; i < 28; i++) {
- z = (z0 >> (63 - i)) & 1;
- temp = ror16(k[i + 3], 3) ^ k[i + 1];
- k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1);
- }
-
- for (int i = 0; i < 8; i++) {
- eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)];
- eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)];
- eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)];
- eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)];
- }
-
- for (int i = 0; i < 32; i++) {
- fxleft[i] = (rol16(xleft[i], 1) &
- rol16(xleft[i], 8)) ^ rol16(xleft[i], 2);
- xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i];
- xright[i + 1] = xleft[i];
- }
-
- return (((uint32_t)xright[32]) << 16) | xleft[32];
-}
-
-static uint64_t hash_digest(uint64_t ra, uint64_t rb, uint64_t key)
-{
- uint64_t stage0_h = 0ULL, stage0_l = 0ULL;
- uint64_t stage1_h, stage1_l;
-
- for (int i = 0; i < 4; i++) {
- stage0_h |= ror64(rb & 0xff, 8 * (2 * i + 1));
- stage0_h |= ((ra >> 32) & 0xff) << (8 * 2 * i);
- stage0_l |= ror64((rb >> 32) & 0xff, 8 * (2 * i + 1));
- stage0_l |= (ra & 0xff) << (8 * 2 * i);
- rb >>= 8;
- ra >>= 8;
- }
-
- stage1_h = (uint64_t)helper_SIMON_LIKE_32_64(stage0_h >> 32, key, 0) << 32;
- stage1_h |= helper_SIMON_LIKE_32_64(stage0_h, key, 1);
- stage1_l = (uint64_t)helper_SIMON_LIKE_32_64(stage0_l >> 32, key, 2) << 32;
- stage1_l |= helper_SIMON_LIKE_32_64(stage0_l, key, 3);
-
- return stage1_h ^ stage1_l;
-}
-
-static void do_hash(CPUPPCState *env, target_ulong ea, target_ulong ra,
- target_ulong rb, uint64_t key, bool store)
-{
- uint64_t calculated_hash = hash_digest(ra, rb, key), loaded_hash;
-
- if (store) {
- cpu_stq_data_ra(env, ea, calculated_hash, GETPC());
- } else {
- loaded_hash = cpu_ldq_data_ra(env, ea, GETPC());
- if (loaded_hash != calculated_hash) {
- raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_TRAP, GETPC());
- }
- }
-}
-
-#include "qemu/guest-random.h"
-
-#ifdef TARGET_PPC64
-#define HELPER_HASH(op, key, store, dexcr_aspect) \
-void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \
- target_ulong rb) \
-{ \
- if (env->msr & R_MSR_PR_MASK) { \
- if (!(env->spr[SPR_DEXCR] & R_DEXCR_PRO_##dexcr_aspect##_MASK || \
- env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \
- return; \
- } else if (!(env->msr & R_MSR_HV_MASK)) { \
- if (!(env->spr[SPR_DEXCR] & R_DEXCR_PNH_##dexcr_aspect##_MASK || \
- env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \
- return; \
- } else if (!(env->msr & R_MSR_S_MASK)) { \
- if (!(env->spr[SPR_HDEXCR] & R_HDEXCR_HNU_##dexcr_aspect##_MASK)) \
- return; \
- } \
- \
- do_hash(env, ea, ra, rb, key, store); \
-}
-#else
-#define HELPER_HASH(op, key, store, dexcr_aspect) \
-void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \
- target_ulong rb) \
-{ \
- do_hash(env, ea, ra, rb, key, store); \
-}
-#endif /* TARGET_PPC64 */
-
-HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true, NPHIE)
-HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false, NPHIE)
-HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true, PHIE)
-HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false, PHIE)
-
-#ifndef CONFIG_USER_ONLY
-/* Embedded.Processor Control */
-static int dbell2irq(target_ulong rb)
-{
- int msg = rb & DBELL_TYPE_MASK;
- int irq = -1;
-
- switch (msg) {
- case DBELL_TYPE_DBELL:
- irq = PPC_INTERRUPT_DOORBELL;
- break;
- case DBELL_TYPE_DBELL_CRIT:
- irq = PPC_INTERRUPT_CDOORBELL;
- break;
- case DBELL_TYPE_G_DBELL:
- case DBELL_TYPE_G_DBELL_CRIT:
- case DBELL_TYPE_G_DBELL_MC:
- /* XXX implement */
- default:
- break;
- }
-
- return irq;
-}
-
-void helper_msgclr(CPUPPCState *env, target_ulong rb)
-{
- int irq = dbell2irq(rb);
-
- if (irq < 0) {
- return;
- }
-
- ppc_set_irq(env_archcpu(env), irq, 0);
-}
-
-void helper_msgsnd(target_ulong rb)
-{
- int irq = dbell2irq(rb);
- int pir = rb & DBELL_PIRTAG_MASK;
- CPUState *cs;
-
- if (irq < 0) {
- return;
- }
-
- bql_lock();
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *cenv = &cpu->env;
-
- if ((rb & DBELL_BRDCAST_MASK) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
- ppc_set_irq(cpu, irq, 1);
- }
- }
- bql_unlock();
-}
-
-/* Server Processor Control */
-
-static bool dbell_type_server(target_ulong rb)
-{
- /*
- * A Directed Hypervisor Doorbell message is sent only if the
- * message type is 5. All other types are reserved and the
- * instruction is a no-op
- */
- return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER;
-}
-
-static inline bool dbell_bcast_core(target_ulong rb)
-{
- return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_CORE;
-}
-
-static inline bool dbell_bcast_subproc(target_ulong rb)
-{
- return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC;
-}
-
-void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
-{
- if (!dbell_type_server(rb)) {
- return;
- }
-
- ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
-}
-
-void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
-{
- int pir = rb & DBELL_PROCIDTAG_MASK;
- bool brdcast = false;
- CPUState *cs, *ccs;
- PowerPCCPU *cpu;
-
- if (!dbell_type_server(rb)) {
- return;
- }
-
- cpu = ppc_get_vcpu_by_pir(pir);
- if (!cpu) {
- return;
- }
- cs = CPU(cpu);
-
- if (dbell_bcast_core(rb) || (dbell_bcast_subproc(rb) &&
- (env->flags & POWERPC_FLAG_SMT_1LPAR))) {
- brdcast = true;
- }
-
- if (cs->nr_threads == 1 || !brdcast) {
- ppc_set_irq(cpu, PPC_INTERRUPT_HDOORBELL, 1);
- return;
- }
-
- /*
- * Why is bql needed for walking CPU list? Answer seems to be because ppc
- * irq handling needs it, but ppc_set_irq takes the lock itself if needed,
- * so could this be removed?
- */
- bql_lock();
- THREAD_SIBLING_FOREACH(cs, ccs) {
- ppc_set_irq(POWERPC_CPU(ccs), PPC_INTERRUPT_HDOORBELL, 1);
- }
- bql_unlock();
-}
-
-#ifdef TARGET_PPC64
-void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
-{
- helper_hfscr_facility_check(env, HFSCR_MSGP, "msgclrp", HFSCR_IC_MSGP);
-
- if (!dbell_type_server(rb)) {
- return;
- }
-
- ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_DOORBELL, 0);
-}
-
-/*
- * sends a message to another thread on the same
- * multi-threaded processor
- */
-void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
-{
- CPUState *cs = env_cpu(env);
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- int ttir = rb & PPC_BITMASK(57, 63);
-
- helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
-
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
- }
-
- if (!dbell_type_server(rb) || ttir >= nr_threads) {
- return;
- }
-
- if (nr_threads == 1) {
- ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1);
- return;
- }
-
- /* Does iothread need to be locked for walking CPU list? */
- bql_lock();
- THREAD_SIBLING_FOREACH(cs, ccs) {
- PowerPCCPU *ccpu = POWERPC_CPU(ccs);
- uint32_t thread_id = ppc_cpu_tir(ccpu);
-
- if (ttir == thread_id) {
- ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1);
- bql_unlock();
- return;
- }
- }
-
- g_assert_not_reached();
-}
-#endif /* TARGET_PPC64 */
-
-/* Single-step tracing */
-void helper_book3s_trace(CPUPPCState *env, target_ulong prev_ip)
-{
- uint32_t error_code = 0;
- if (env->insns_flags2 & PPC2_ISA207S) {
- /* Load/store reporting, SRR1[35, 36] and SDAR, are not implemented. */
- env->spr[SPR_POWER_SIAR] = prev_ip;
- error_code = PPC_BIT(33);
- }
- 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:
- /*
- * 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_TCG */