aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/arch_dump.c28
-rw-r--r--target/ppc/compat.c17
-rw-r--r--target/ppc/cpu-models.c5
-rw-r--r--target/ppc/cpu-models.h3
-rw-r--r--target/ppc/cpu-param.h7
-rw-r--r--target/ppc/cpu.c48
-rw-r--r--target/ppc/cpu.h118
-rw-r--r--target/ppc/cpu_init.c525
-rw-r--r--target/ppc/cpu_init.h91
-rw-r--r--target/ppc/dfp_helper.c8
-rw-r--r--target/ppc/excp_helper.c1105
-rw-r--r--target/ppc/fpu_helper.c64
-rw-r--r--target/ppc/helper.h102
-rw-r--r--target/ppc/helper_regs.c44
-rw-r--r--target/ppc/helper_regs.h2
-rw-r--r--target/ppc/insn32.decode98
-rw-r--r--target/ppc/int_helper.c22
-rw-r--r--target/ppc/internal.h11
-rw-r--r--target/ppc/kvm.c86
-rw-r--r--target/ppc/kvm_ppc.h17
-rw-r--r--target/ppc/machine.c84
-rw-r--r--target/ppc/mem_helper.c66
-rw-r--r--target/ppc/meson.build1
-rw-r--r--target/ppc/misc_helper.c179
-rw-r--r--target/ppc/mmu-book3s-v3.c2
-rw-r--r--target/ppc/mmu-book3s-v3.h43
-rw-r--r--target/ppc/mmu-hash32.c73
-rw-r--r--target/ppc/mmu-hash32.h58
-rw-r--r--target/ppc/mmu-hash64.c63
-rw-r--r--target/ppc/mmu-hash64.h3
-rw-r--r--target/ppc/mmu-radix64.c68
-rw-r--r--target/ppc/mmu-radix64.h53
-rw-r--r--target/ppc/mmu_common.c337
-rw-r--r--target/ppc/mmu_helper.c9
-rw-r--r--target/ppc/power8-pmu.c1
-rw-r--r--target/ppc/ppc-qmp-cmds.c12
-rw-r--r--target/ppc/spr_common.h4
-rw-r--r--target/ppc/tcg-excp_helper.c851
-rw-r--r--target/ppc/timebase_helper.c90
-rw-r--r--target/ppc/translate.c116
-rw-r--r--target/ppc/translate/vmx-impl.c.inc292
-rw-r--r--target/ppc/translate/vmx-ops.c.inc19
-rw-r--r--target/ppc/translate/vsx-impl.c.inc594
-rw-r--r--target/ppc/translate/vsx-ops.c.inc82
-rw-r--r--target/ppc/user_only_helper.c1
45 files changed, 2924 insertions, 2578 deletions
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index a831565..80ac6c3 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -15,8 +15,8 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "elf.h"
-#include "sysemu/dump.h"
-#include "sysemu/kvm.h"
+#include "system/dump.h"
+#include "system/kvm.h"
#ifdef TARGET_PPC64
#define ELFCLASS ELFCLASS64
@@ -47,9 +47,14 @@ struct PPCUserRegStruct {
} QEMU_PACKED;
struct PPCElfPrstatus {
- char pad1[112];
+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pid;
+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
struct PPCUserRegStruct pr_reg;
- char pad2[40];
+ char pad3[40]; /* 40 == sizeof(struct elf_prstatus) -
+ offsetof(struct elf_prstatus, pr_reg) -
+ sizeof(struct user_pt_regs) */
} QEMU_PACKED;
@@ -96,7 +101,7 @@ typedef struct NoteFuncArg {
DumpState *state;
} NoteFuncArg;
-static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
reg_t cr;
@@ -109,6 +114,7 @@ static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
prstatus = &note->contents.prstatus;
memset(prstatus, 0, sizeof(*prstatus));
+ prstatus->pid = cpu_to_dump32(s, id);
reg = &prstatus->pr_reg;
for (i = 0; i < 32; i++) {
@@ -127,7 +133,7 @@ static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
reg->ccr = cpu_to_dump_reg(s, cr);
}
-static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfFpregset *fpregset;
@@ -146,7 +152,7 @@ static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr);
}
-static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfVmxregset *vmxregset;
@@ -178,7 +184,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
vmxregset->vscr.u32[3] = cpu_to_dump32(s, ppc_get_vscr(&cpu->env));
}
-static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfVsxregset *vsxregset;
@@ -195,7 +201,7 @@ static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
}
}
-static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
struct PPCElfSperegset *speregset;
Note *note = &arg->note;
@@ -211,7 +217,7 @@ static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
static const struct NoteFuncDescStruct {
int contents_size;
- void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu);
+ void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu, int id);
} note_func[] = {
{sizeof_field(Note, contents.prstatus), ppc_write_elf_prstatus},
{sizeof_field(Note, contents.fpregset), ppc_write_elf_fpregset},
@@ -282,7 +288,7 @@ static int ppc_write_all_elf_notes(const char *note_name,
arg.note.hdr.n_descsz = cpu_to_dump32(s, nf->contents_size);
strncpy(arg.note.name, note_name, sizeof(arg.note.name));
- (*nf->note_contents_func)(&arg, cpu);
+ (*nf->note_contents_func)(&arg, cpu, id);
note_size =
sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size;
diff --git a/target/ppc/compat.c b/target/ppc/compat.c
index ebef2cc..55de3bd 100644
--- a/target/ppc/compat.c
+++ b/target/ppc/compat.c
@@ -18,10 +18,10 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/kvm.h"
+#include "system/hw_accel.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
-#include "sysemu/cpus.h"
+#include "system/cpus.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
@@ -100,6 +100,13 @@ static const CompatInfo compat_table[] = {
.pcr_level = PCR_COMPAT_3_10,
.max_vthreads = 8,
},
+ { /* POWER11, ISA3.10 */
+ .name = "power11",
+ .pvr = CPU_POWERPC_LOGICAL_3_10_P11,
+ .pcr = PCR_COMPAT_3_10,
+ .pcr_level = PCR_COMPAT_3_10,
+ .max_vthreads = 8,
+ },
};
static const CompatInfo *compat_by_pvr(uint32_t pvr)
@@ -132,6 +139,10 @@ static bool pcc_compat(PowerPCCPUClass *pcc, uint32_t compat_pvr,
/* Outside specified range */
return false;
}
+ if (compat->pvr > pcc->spapr_logical_pvr) {
+ /* Older CPU cannot support a newer processor's compat mode */
+ return false;
+ }
if (!(pcc->pcr_supported & compat->pcr_level)) {
/* Not supported by this CPU */
return false;
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
index f2301b4..ea86ea2 100644
--- a/target/ppc/cpu-models.c
+++ b/target/ppc/cpu-models.c
@@ -35,7 +35,7 @@
#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \
static void \
glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \
- (ObjectClass *oc, void *data) \
+ (ObjectClass *oc, const void *data) \
{ \
DeviceClass *dc = DEVICE_CLASS(oc); \
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \
@@ -734,6 +734,8 @@
"POWER9 v2.2")
POWERPC_DEF("power10_v2.0", CPU_POWERPC_POWER10_DD20, POWER10,
"POWER10 v2.0")
+ POWERPC_DEF("power11_v2.0", CPU_POWERPC_POWER11_DD20, POWER11,
+ "POWER11_v2.0")
#endif /* defined (TARGET_PPC64) */
/***************************************************************************/
@@ -909,6 +911,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "power8nvl", "power8nvl_v1.0" },
{ "power9", "power9_v2.2" },
{ "power10", "power10_v2.0" },
+ { "power11", "power11_v2.0" },
#endif
/* Generic PowerPCs */
diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h
index 0229ef3..72ad31b 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -354,6 +354,8 @@ enum {
CPU_POWERPC_POWER10_BASE = 0x00800000,
CPU_POWERPC_POWER10_DD1 = 0x00801100,
CPU_POWERPC_POWER10_DD20 = 0x00801200,
+ CPU_POWERPC_POWER11_BASE = 0x00820000,
+ CPU_POWERPC_POWER11_DD20 = 0x00821200,
CPU_POWERPC_970_v22 = 0x00390202,
CPU_POWERPC_970FX_v10 = 0x00391100,
CPU_POWERPC_970FX_v20 = 0x003C0200,
@@ -391,6 +393,7 @@ enum {
CPU_POWERPC_LOGICAL_2_07 = 0x0F000004,
CPU_POWERPC_LOGICAL_3_00 = 0x0F000005,
CPU_POWERPC_LOGICAL_3_10 = 0x0F000006,
+ CPU_POWERPC_LOGICAL_3_10_P11 = 0x0F000007,
};
/* System version register (used on MPC 8xxx) */
diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h
index 77c5ed9..e4ed908 100644
--- a/target/ppc/cpu-param.h
+++ b/target/ppc/cpu-param.h
@@ -2,14 +2,13 @@
* PowerPC cpu parameters for qemu.
*
* Copyright (c) 2007 Jocelyn Mayer
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef PPC_CPU_PARAM_H
#define PPC_CPU_PARAM_H
#ifdef TARGET_PPC64
-# define TARGET_LONG_BITS 64
/*
* Note that the official physical address space bits is 62-M where M
* is implementation dependent. I've not looked up M for the set of
@@ -27,7 +26,6 @@
# define TARGET_VIRT_ADDR_SPACE_BITS 64
# endif
#else
-# define TARGET_LONG_BITS 32
# define TARGET_PHYS_ADDR_SPACE_BITS 36
# define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif
@@ -35,11 +33,10 @@
#ifdef CONFIG_USER_ONLY
/* Allow user-only to vary page size from 4k */
# define TARGET_PAGE_BITS_VARY
-# define TARGET_PAGE_BITS_MIN 12
#else
# define TARGET_PAGE_BITS 12
#endif
-#define TCG_GUEST_DEFAULT_MO 0
+#define TARGET_INSN_START_EXTRA_WORDS 0
#endif
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e3ad8e0..4d8faad 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -22,10 +22,11 @@
#include "cpu-models.h"
#include "cpu-qom.h"
#include "exec/log.h"
+#include "exec/watchpoint.h"
#include "fpu/softfloat-helpers.h"
#include "mmu-hash64.h"
#include "helper_regs.h"
-#include "sysemu/tcg.h"
+#include "system/tcg.h"
target_ulong cpu_read_xer(const CPUPPCState *env)
{
@@ -130,11 +131,13 @@ void ppc_store_ciabr(CPUPPCState *env, target_ulong val)
ppc_update_ciabr(env);
}
-void ppc_update_daw0(CPUPPCState *env)
+void ppc_update_daw(CPUPPCState *env, int rid)
{
CPUState *cs = env_cpu(env);
- target_ulong deaw = env->spr[SPR_DAWR0] & PPC_BITMASK(0, 60);
- uint32_t dawrx = env->spr[SPR_DAWRX0];
+ int spr_dawr = rid ? SPR_DAWR1 : SPR_DAWR0;
+ int spr_dawrx = rid ? SPR_DAWRX1 : SPR_DAWRX0;
+ target_ulong deaw = env->spr[spr_dawr] & PPC_BITMASK(0, 60);
+ uint32_t dawrx = env->spr[spr_dawrx];
int mrd = extract32(dawrx, PPC_BIT_NR(48), 54 - 48);
bool dw = extract32(dawrx, PPC_BIT_NR(57), 1);
bool dr = extract32(dawrx, PPC_BIT_NR(58), 1);
@@ -144,9 +147,9 @@ void ppc_update_daw0(CPUPPCState *env)
vaddr len;
int flags;
- if (env->dawr0_watchpoint) {
- cpu_watchpoint_remove_by_ref(cs, env->dawr0_watchpoint);
- env->dawr0_watchpoint = NULL;
+ if (env->dawr_watchpoint[rid]) {
+ cpu_watchpoint_remove_by_ref(cs, env->dawr_watchpoint[rid]);
+ env->dawr_watchpoint[rid] = NULL;
}
if (!dr && !dw) {
@@ -166,28 +169,45 @@ void ppc_update_daw0(CPUPPCState *env)
flags |= BP_MEM_WRITE;
}
- cpu_watchpoint_insert(cs, deaw, len, flags, &env->dawr0_watchpoint);
+ cpu_watchpoint_insert(cs, deaw, len, flags, &env->dawr_watchpoint[rid]);
}
void ppc_store_dawr0(CPUPPCState *env, target_ulong val)
{
env->spr[SPR_DAWR0] = val;
- ppc_update_daw0(env);
+ ppc_update_daw(env, 0);
}
-void ppc_store_dawrx0(CPUPPCState *env, uint32_t val)
+static void ppc_store_dawrx(CPUPPCState *env, uint32_t val, int rid)
{
int hrammc = extract32(val, PPC_BIT_NR(56), 1);
if (hrammc) {
/* This might be done with a second watchpoint at the xor of DEAW[0] */
- qemu_log_mask(LOG_UNIMP, "%s: DAWRX0[HRAMMC] is unimplemented\n",
- __func__);
+ qemu_log_mask(LOG_UNIMP, "%s: DAWRX%d[HRAMMC] is unimplemented\n",
+ __func__, rid);
}
- env->spr[SPR_DAWRX0] = val;
- ppc_update_daw0(env);
+ env->spr[rid ? SPR_DAWRX1 : SPR_DAWRX0] = val;
+ ppc_update_daw(env, rid);
+}
+
+void ppc_store_dawrx0(CPUPPCState *env, uint32_t val)
+{
+ ppc_store_dawrx(env, val, 0);
+}
+
+void ppc_store_dawr1(CPUPPCState *env, target_ulong val)
+{
+ env->spr[SPR_DAWR1] = val;
+ ppc_update_daw(env, 1);
+}
+
+void ppc_store_dawrx1(CPUPPCState *env, uint32_t val)
+{
+ ppc_store_dawrx(env, val, 1);
}
+
#endif
#endif
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2015e60..6b90543 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -22,7 +22,9 @@
#include "qemu/int128.h"
#include "qemu/cpu-float.h"
+#include "exec/cpu-common.h"
#include "exec/cpu-defs.h"
+#include "exec/cpu-interrupt.h"
#include "cpu-qom.h"
#include "qom/object.h"
#include "hw/registerfields.h"
@@ -40,6 +42,7 @@
#define PPC_BIT_NR(bit) (63 - (bit))
#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BIT32_NR(bit) (31 - (bit))
#define PPC_BIT32(bit) (0x80000000 >> (bit))
#define PPC_BIT8(bit) (0x80 >> (bit))
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
@@ -215,6 +218,8 @@ typedef enum powerpc_excp_t {
POWERPC_EXCP_POWER9,
/* POWER10 exception model */
POWERPC_EXCP_POWER10,
+ /* POWER11 exception model */
+ POWERPC_EXCP_POWER11,
} powerpc_excp_t;
/*****************************************************************************/
@@ -634,8 +639,8 @@ FIELD(MSR, LE, MSR_LE, 1)
#define PSSCR_EC PPC_BIT(43) /* Exit Criterion */
/* HFSCR bits */
-#define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */
-#define HFSCR_BHRB PPC_BIT(59) /* BHRB Instructions */
+#define HFSCR_MSGP PPC_BIT_NR(53) /* Privileged Message Send Facilities */
+#define HFSCR_BHRB PPC_BIT_NR(59) /* BHRB Instructions */
#define HFSCR_IC_MSGP 0xA
#define DBCR0_ICMP (1 << 27)
@@ -1197,21 +1202,6 @@ DEXCR_ASPECT(NPHIE, 5)
DEXCR_ASPECT(PHIE, 6)
/*****************************************************************************/
-/* PowerNV ChipTOD and TimeBase State Machine */
-struct pnv_tod_tbst {
- int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
- int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
-
- /*
- * "Timers" for async TBST events are simulated by mfTFAC because TFAC
- * is polled for such events. These are just used to ensure firmware
- * performs the polling at least a few times.
- */
- int tb_state_timer;
- int tb_sync_pulse_timer;
-};
-
-/*****************************************************************************/
/* The whole PowerPC CPU context */
/*
@@ -1262,15 +1252,17 @@ struct CPUArchState {
/* when a memory exception occurs, the access type is stored here */
int access_type;
+ /* For SMT processors */
+ bool has_smt_siblings;
+ int core_index;
+ int chip_index;
+
#if !defined(CONFIG_USER_ONLY)
/* MMU context, only relevant for full system emulation */
#if defined(TARGET_PPC64)
ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */
struct CPUBreakpoint *ciabr_breakpoint;
- struct CPUWatchpoint *dawr0_watchpoint;
-
- /* POWER CPU regs/state */
- target_ulong scratch[8]; /* SCRATCH registers (shared across core) */
+ struct CPUWatchpoint *dawr_watchpoint[2];
#endif
target_ulong sr[32]; /* segment registers */
uint32_t nb_BATs; /* number of BATs */
@@ -1291,12 +1283,6 @@ struct CPUArchState {
uint32_t tlb_need_flush; /* Delayed flush needed */
#define TLB_NEED_LOCAL_FLUSH 0x1
#define TLB_NEED_GLOBAL_FLUSH 0x2
-
-#if defined(TARGET_PPC64)
- /* PowerNV chiptod / timebase facility state. */
- /* Would be nice to put these into PnvCore */
- struct pnv_tod_tbst pnv_tod_tbst;
-#endif
#endif
/* Other registers */
@@ -1372,6 +1358,18 @@ struct CPUArchState {
* special way (such as routing some resume causes to 0x100, i.e. sreset).
*/
bool resume_as_sreset;
+
+ /*
+ * On powernv, quiesced means the CPU has been stopped using PC direct
+ * control xscom registers.
+ *
+ * On spapr, quiesced means it is in the "RTAS stopped" state.
+ *
+ * The core halted/stopped variables aren't sufficient for this, because
+ * they can be changed with various side-band operations like qmp cont,
+ * powersave interrupts, etc.
+ */
+ bool quiesced;
#endif
/* These resources are used only in TCG */
@@ -1426,12 +1424,12 @@ struct CPUArchState {
uint64_t pmu_base_time;
};
-#define _CORE_ID(cs) \
- (POWERPC_CPU(cs)->env.spr_cb[SPR_PIR].default_value & ~(cs->nr_threads - 1))
-
#define THREAD_SIBLING_FOREACH(cs, cs_sibling) \
CPU_FOREACH(cs_sibling) \
- if (_CORE_ID(cs) == _CORE_ID(cs_sibling))
+ if ((POWERPC_CPU(cs)->env.chip_index == \
+ POWERPC_CPU(cs_sibling)->env.chip_index) && \
+ (POWERPC_CPU(cs)->env.core_index == \
+ POWERPC_CPU(cs_sibling)->env.core_index))
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
do { \
@@ -1476,16 +1474,6 @@ struct ArchCPU {
/* Those resources are used only during code translation */
/* opcode handlers */
opc_handler_t *opcodes[PPC_CPU_OPCODES_LEN];
-
- /* Fields related to migration compatibility hacks */
- bool pre_2_8_migration;
- target_ulong mig_msr_mask;
- uint64_t mig_insns_flags;
- uint64_t mig_insns_flags2;
- uint32_t mig_nb_BATs;
- bool pre_2_10_migration;
- bool pre_3_0_migration;
- int32_t mig_slb_nr;
};
/**
@@ -1504,6 +1492,7 @@ struct PowerPCCPUClass {
void (*parent_parse_features)(const char *type, char *str, Error **errp);
uint32_t pvr;
+ uint32_t spapr_logical_pvr;
/*
* If @best is false, match if pcc is in the family of pvr
* Else match only if pcc is the best match for pvr in this family.
@@ -1535,6 +1524,17 @@ struct PowerPCCPUClass {
int (*check_attn)(CPUPPCState *env);
};
+static inline bool ppc_cpu_core_single_threaded(CPUState *cs)
+{
+ return !POWERPC_CPU(cs)->env.has_smt_siblings;
+}
+
+static inline bool ppc_cpu_lpar_single_threaded(CPUState *cs)
+{
+ return !(POWERPC_CPU(cs)->env.flags & POWERPC_FLAG_SMT_1LPAR) ||
+ ppc_cpu_core_single_threaded(cs);
+}
+
ObjectClass *ppc_cpu_class_by_name(const char *name);
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
@@ -1594,20 +1594,22 @@ extern const VMStateDescription vmstate_ppc_cpu;
/*****************************************************************************/
void ppc_translate_init(void);
+void ppc_translate_code(CPUState *cs, TranslationBlock *tb,
+ int *max_insns, vaddr pc, void *host_pc);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_update_ciabr(CPUPPCState *env);
void ppc_store_ciabr(CPUPPCState *env, target_ulong value);
-void ppc_update_daw0(CPUPPCState *env);
+void ppc_update_daw(CPUPPCState *env, int rid);
void ppc_store_dawr0(CPUPPCState *env, target_ulong value);
void ppc_store_dawrx0(CPUPPCState *env, uint32_t value);
+void ppc_store_dawr1(CPUPPCState *env, target_ulong value);
+void ppc_store_dawrx1(CPUPPCState *env, uint32_t value);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr(CPUPPCState *env, target_ulong value);
-void ppc_cpu_list(void);
-
/* Time-base and decrementer management */
uint64_t cpu_ppc_load_tbl(CPUPPCState *env);
uint32_t cpu_ppc_load_tbu(CPUPPCState *env);
@@ -1669,8 +1671,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
int ppc_dcr_read(ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
-#define cpu_list ppc_cpu_list
-
/* MMU modes definitions */
#define MMU_USER_IDX 0
static inline int ppc_env_mmu_index(CPUPPCState *env, bool ifetch)
@@ -1700,8 +1700,6 @@ void ppc_compat_add_property(Object *obj, const char *name,
uint32_t *compat_pvr, const char *basedesc);
#endif /* defined(TARGET_PPC64) */
-#include "exec/cpu-all.h"
-
/*****************************************************************************/
/* CRF definitions */
#define CRF_LT_BIT 3
@@ -2102,6 +2100,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_VTB (0x351)
#define SPR_LDBAR (0x352)
#define SPR_MMCRC (0x353)
+#define SPR_PMSR (0x355)
#define SPR_PSSCR (0x357)
#define SPR_440_INV0 (0x370)
#define SPR_440_INV1 (0x371)
@@ -2109,8 +2108,10 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_440_INV2 (0x372)
#define SPR_TRIG2 (0x372)
#define SPR_440_INV3 (0x373)
+#define SPR_PMCR (0x374)
#define SPR_440_ITV0 (0x374)
#define SPR_440_ITV1 (0x375)
+#define SPR_RWMR (0x375)
#define SPR_440_ITV2 (0x376)
#define SPR_440_ITV3 (0x377)
#define SPR_440_CCR1 (0x378)
@@ -2750,24 +2751,6 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer);
*/
#define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B))
-#ifdef CONFIG_DEBUG_TCG
-void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc,
- uint64_t *cs_base, uint32_t *flags);
-#else
-static inline void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc,
- uint64_t *cs_base, uint32_t *flags)
-{
- *pc = env->nip;
- *cs_base = 0;
- *flags = env->hflags;
-}
-#endif
-
-G_NORETURN void raise_exception(CPUPPCState *env, uint32_t exception);
-G_NORETURN void raise_exception_ra(CPUPPCState *env, uint32_t exception,
- uintptr_t raddr);
-G_NORETURN void raise_exception_err(CPUPPCState *env, uint32_t exception,
- uint32_t error_code);
G_NORETURN void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
uint32_t error_code, uintptr_t raddr);
@@ -3051,7 +3034,8 @@ static inline int check_attn_none(CPUPPCState *env)
#define POWERPC_FAMILY(_name) \
static void \
- glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, void *); \
+ glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, \
+ const void *); \
\
static const TypeInfo \
glue(glue(ppc_, _name), _cpu_family_type_info) = { \
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 01e358a..a0e77f2 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -1,3 +1,4 @@
+
/*
* PowerPC CPU initialization for qemu.
*
@@ -21,9 +22,9 @@
#include "qemu/osdep.h"
#include "disas/dis-asm.h"
#include "gdbstub/helpers.h"
-#include "sysemu/cpus.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/tcg.h"
+#include "system/cpus.h"
+#include "system/hw_accel.h"
+#include "system/tcg.h"
#include "cpu-models.h"
#include "mmu-hash32.h"
#include "mmu-hash64.h"
@@ -31,7 +32,7 @@
#include "qemu/module.h"
#include "qemu/qemu-print.h"
#include "qapi/error.h"
-#include "qapi/qmp/qnull.h"
+#include "qobject/qnull.h"
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/ppc.h"
@@ -39,18 +40,18 @@
#include "qemu/cutils.h"
#include "disas/capstone.h"
#include "fpu/softfloat.h"
-
+#include "exec/watchpoint.h"
#include "helper_regs.h"
#include "internal.h"
#include "spr_common.h"
#include "power8-pmu.h"
-
#ifndef CONFIG_USER_ONLY
#include "hw/boards.h"
#include "hw/intc/intc.h"
#include "kvm_ppc.h"
#endif
+#include "cpu_init.h"
/* #define PPC_DEBUG_SPR */
/* #define USE_APPLE_GDB */
@@ -920,6 +921,18 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask,
#endif
}
+static void register_atb_sprs(CPUPPCState *env)
+{
+ spr_register(env, SPR_ATBL, "ATBL",
+ &spr_read_atbl, SPR_NOACCESS,
+ &spr_read_atbl, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_ATBU, "ATBU",
+ &spr_read_atbu, SPR_NOACCESS,
+ &spr_read_atbu, SPR_NOACCESS,
+ 0x00000000);
+}
+
/* SPR specific to PowerPC 440 implementation */
static void register_440_sprs(CPUPPCState *env)
{
@@ -2153,7 +2166,7 @@ static void init_proc_405(CPUPPCState *env)
SET_WDT_PERIOD(16, 20, 24, 28);
}
-POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(405)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2221,7 +2234,7 @@ static void init_proc_440EP(CPUPPCState *env)
SET_WDT_PERIOD(20, 24, 28, 32);
}
-POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(440EP)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2260,7 +2273,7 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data)
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
}
-POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(460EX)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2315,7 +2328,7 @@ static void init_proc_440GP(CPUPPCState *env)
SET_WDT_PERIOD(20, 24, 28, 32);
}
-POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(440GP)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2385,7 +2398,7 @@ static void init_proc_440x5(CPUPPCState *env)
SET_WDT_PERIOD(20, 24, 28, 32);
}
-POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(440x5)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2421,7 +2434,7 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data)
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
}
-POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2470,7 +2483,7 @@ static void init_proc_MPC5xx(CPUPPCState *env)
/* XXX: TODO: allocate internal IRQ controller */
}
-POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2513,7 +2526,7 @@ static void init_proc_MPC8xx(CPUPPCState *env)
/* XXX: TODO: allocate internal IRQ controller */
}
-POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2564,7 +2577,7 @@ static void init_proc_G2(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(G2)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2603,7 +2616,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
}
-POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(G2LE)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2730,14 +2743,6 @@ static void init_proc_e200(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000); /* TOFIX */
- spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
init_tlbs_emb(env);
init_excp_e200(env, 0xFFFF0000UL);
@@ -2746,7 +2751,7 @@ static void init_proc_e200(CPUPPCState *env)
/* XXX: TODO: allocate internal IRQ controller */
}
-POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e200)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2909,6 +2914,11 @@ static void init_proc_e500(CPUPPCState *env, int version)
register_BookE206_sprs(env, 0x000000DF, tlbncfg, mmucfg);
register_usprgh_sprs(env);
+ if (version != fsl_e500v1) {
+ /* e500v1 has no support for alternate timebase */
+ register_atb_sprs(env);
+ }
+
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -3034,7 +3044,7 @@ static void init_proc_e500v1(CPUPPCState *env)
init_proc_e500(env, fsl_e500v1);
}
-POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e500v1)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3078,7 +3088,7 @@ static void init_proc_e500v2(CPUPPCState *env)
init_proc_e500(env, fsl_e500v2);
}
-POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e500v2)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3122,7 +3132,7 @@ static void init_proc_e500mc(CPUPPCState *env)
init_proc_e500(env, fsl_e500mc);
}
-POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e500mc)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3169,7 +3179,7 @@ static void init_proc_e5500(CPUPPCState *env)
init_proc_e500(env, fsl_e5500);
}
-POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e5500)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3218,7 +3228,7 @@ static void init_proc_e6500(CPUPPCState *env)
init_proc_e500(env, fsl_e6500);
}
-POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e6500)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3281,7 +3291,7 @@ static void init_proc_603(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(603)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3321,7 +3331,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
}
-POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(603E)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3367,7 +3377,7 @@ static void init_proc_e300(CPUPPCState *env)
register_e300_sprs(env);
}
-POWERPC_FAMILY(e300)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e300)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3423,7 +3433,7 @@ static void init_proc_604(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(604)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3469,7 +3479,7 @@ static void init_proc_604E(CPUPPCState *env)
register_604e_sprs(env);
}
-POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(604E)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3526,7 +3536,7 @@ static void init_proc_740(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(740)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3592,7 +3602,7 @@ static void init_proc_750(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(750)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3739,7 +3749,7 @@ static void init_proc_750cl(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(750cl)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3847,7 +3857,7 @@ static void init_proc_750cx(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(750cx)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3920,7 +3930,7 @@ static void init_proc_750fx(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(750fx)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -3993,7 +4003,7 @@ static void init_proc_750gx(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(750gx)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4053,7 +4063,7 @@ static void init_proc_745(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(745)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4099,7 +4109,7 @@ static void init_proc_755(CPUPPCState *env)
register_755_sprs(env);
}
-POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(755)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4166,7 +4176,7 @@ static void init_proc_7400(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7400)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4246,7 +4256,7 @@ static void init_proc_7410(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7410)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4347,7 +4357,7 @@ static void init_proc_7440(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7440)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4470,7 +4480,7 @@ static void init_proc_7450(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7450)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4600,7 +4610,7 @@ static void init_proc_7445(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7445)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4732,7 +4742,7 @@ static void init_proc_7455(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7455)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -4884,7 +4894,7 @@ static void init_proc_7457(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(7457)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -5019,7 +5029,7 @@ static void init_proc_e600(CPUPPCState *env)
ppc6xx_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(e600)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -5170,6 +5180,20 @@ static void register_book3s_207_dbg_sprs(CPUPPCState *env)
KVM_REG_PPC_CIABR, 0x00000000);
}
+static void register_book3s_310_dbg_sprs(CPUPPCState *env)
+{
+ spr_register_kvm_hv(env, SPR_DAWR1, "DAWR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_dawr1,
+ KVM_REG_PPC_DAWR1, 0x00000000);
+ spr_register_kvm_hv(env, SPR_DAWRX1, "DAWRX1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_dawrx1,
+ KVM_REG_PPC_DAWRX1, 0x00000000);
+}
+
static void register_970_dbg_sprs(CPUPPCState *env)
{
/* Breakpoints */
@@ -5759,16 +5783,6 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_core_write_generic,
0x00000000);
- spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_sprc,
- 0x00000000);
- spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_sprd, &spr_write_sprd,
- 0x00000000);
#endif
}
@@ -5781,6 +5795,23 @@ static void register_power9_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_WORT, 0);
+ spr_register_hv(env, SPR_RWMR, "RWMR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+
+ /* SPRC/SPRD exist in earlier CPUs but only tested on POWER9/10 */
+ spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_sprc,
+ 0x00000000);
+ spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_sprd, &spr_write_sprd,
+ 0x00000000);
#endif
}
@@ -5872,22 +5903,22 @@ static void register_power10_hash_sprs(CPUPPCState *env)
((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand);
g_rand_free(rand);
#endif
- spr_register(env, SPR_HASHKEYR, "HASHKEYR",
+ spr_register_kvm(env, SPR_HASHKEYR, "HASHKEYR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- hashkeyr_initial_value);
- spr_register_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
+ KVM_REG_PPC_HASHKEYR, hashkeyr_initial_value);
+ spr_register_kvm_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- hashpkeyr_initial_value);
+ KVM_REG_PPC_HASHPKEYR, hashpkeyr_initial_value);
}
static void register_power10_dexcr_sprs(CPUPPCState *env)
{
- spr_register(env, SPR_DEXCR, "DEXCR",
+ spr_register_kvm(env, SPR_DEXCR, "DEXCR",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic, KVM_REG_PPC_DEXCR,
0);
spr_register(env, SPR_UDEXCR, "UDEXCR",
@@ -5963,7 +5994,7 @@ static void init_proc_970(CPUPPCState *env)
ppc970_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(970)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -6038,7 +6069,7 @@ static void init_proc_power5plus(CPUPPCState *env)
ppc970_irq_init(env_archcpu(env));
}
-POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(POWER5P)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -6144,13 +6175,14 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
return true;
}
-POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(POWER7)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
+ pcc->spapr_logical_pvr = CPU_POWERPC_LOGICAL_2_06_PLUS;
pcc->pvr_match = ppc_pvr_match_power7;
pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -6307,13 +6339,14 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
return true;
}
-POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(POWER8)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
+ pcc->spapr_logical_pvr = CPU_POWERPC_LOGICAL_2_07;
pcc->pvr_match = ppc_pvr_match_power8;
pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -6405,7 +6438,7 @@ static struct ppc_radix_page_info POWER9_radix_page_info = {
#endif /* CONFIG_USER_ONLY */
#define POWER9_BHRB_ENTRIES_LOG2 5
-static void init_proc_POWER9(CPUPPCState *env)
+static void register_power9_common_sprs(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
@@ -6424,7 +6457,6 @@ static void init_proc_POWER9(CPUPPCState *env)
register_power5p_ear_sprs(env);
register_power5p_tb_sprs(env);
register_power6_common_sprs(env);
- register_HEIR32_spr(env);
register_power6_dbg_sprs(env);
register_power7_common_sprs(env);
register_power8_tce_address_control_sprs(env);
@@ -6442,16 +6474,32 @@ static void init_proc_POWER9(CPUPPCState *env)
register_power8_rpr_sprs(env);
register_power9_mmu_sprs(env);
- /* POWER9 Specific registers */
- spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL,
- spr_read_generic, spr_write_generic,
- KVM_REG_PPC_TIDR, 0);
-
/* FIXME: Filter fields properly based on privilege level */
spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL,
spr_read_generic, spr_write_generic,
KVM_REG_PPC_PSSCR, 0);
+ spr_register_hv(env, SPR_PMSR, "PMSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_pmsr, SPR_NOACCESS,
+ 0);
+ spr_register_hv(env, SPR_PMCR, "PMCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_pmcr,
+ PPC_BIT(63)); /* Version 1 (POWER9/10) */
+
+}
+
+static void init_proc_POWER9(CPUPPCState *env)
+{
+ register_power9_common_sprs(env);
+ register_HEIR32_spr(env);
+ /* POWER9 Specific registers */
+ spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL,
+ spr_read_generic, spr_write_generic,
+ KVM_REG_PPC_TIDR, 0);
/* env variables */
env->dcache_line_size = 128;
env->icache_line_size = 128;
@@ -6500,66 +6548,24 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
return false;
}
-POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(POWER9)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
+ pcc->spapr_logical_pvr = CPU_POWERPC_LOGICAL_3_00;
pcc->pvr_match = ppc_pvr_match_power9;
- pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
- pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
- PCR_COMPAT_2_05;
+ pcc->pcr_mask = PPC_PCR_MASK_POWER9;
+ pcc->pcr_supported = PPC_PCR_SUPPORTED_POWER9;
pcc->init_proc = init_proc_POWER9;
pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0_power9;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
- PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
- PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
- PPC_FLOAT_FRSQRTES |
- PPC_FLOAT_STFIWX |
- PPC_FLOAT_EXT |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO |
- PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
- PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
- PPC_SEGMENT_64B | PPC_SLBI |
- PPC_POPCNTB | PPC_POPCNTWD |
- PPC_CILDST;
- pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
- PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
- PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
- PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
- PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
- PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
- PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL | PPC2_MEM_LWSYNC |
- PPC2_BCDA_ISA206;
- pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_HV) |
- (1ull << MSR_TM) |
- (1ull << MSR_VR) |
- (1ull << MSR_VSX) |
- (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_DE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR) |
- (1ull << MSR_PMM) |
- (1ull << MSR_RI) |
- (1ull << MSR_LE);
- pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
- (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
- (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
- LPCR_DEE | LPCR_OEE))
- | LPCR_MER | LPCR_GTSE | LPCR_TC |
- LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->insns_flags = PPC_INSNS_FLAGS_POWER9;
+ pcc->insns_flags2 = PPC_INSNS_FLAGS2_POWER9;
+ pcc->msr_mask = PPC_MSR_MASK_POWER9;
+ pcc->lpcr_mask = PPC_LPCR_MASK_POWER9;
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if !defined(CONFIG_USER_ONLY)
@@ -6572,10 +6578,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->excp_model = POWERPC_EXCP_POWER9;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
pcc->bfd_mach = bfd_mach_ppc64;
- pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
- POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
- POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
- POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV;
+ pcc->flags = POWERPC_FLAGS_POWER9;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
}
@@ -6602,50 +6605,13 @@ static struct ppc_radix_page_info POWER10_radix_page_info = {
#define POWER10_BHRB_ENTRIES_LOG2 5
static void init_proc_POWER10(CPUPPCState *env)
{
- /* Common Registers */
- init_proc_book3s_common(env);
- register_book3s_207_dbg_sprs(env);
-
- /* Common TCG PMU */
- init_tcg_pmu_power8(env);
-
- /* POWER8 Specific Registers */
- register_book3s_ids_sprs(env);
- register_amr_sprs(env);
- register_iamr_sprs(env);
- register_book3s_purr_sprs(env);
- register_power5p_common_sprs(env);
- register_power5p_lpar_sprs(env);
- register_power5p_ear_sprs(env);
- register_power5p_tb_sprs(env);
- register_power6_common_sprs(env);
+ register_power9_common_sprs(env);
register_HEIR64_spr(env);
- register_power6_dbg_sprs(env);
- register_power7_common_sprs(env);
- register_power8_tce_address_control_sprs(env);
- register_power8_ids_sprs(env);
- register_power8_ebb_sprs(env);
- register_power8_fscr_sprs(env);
- register_power8_pmu_sup_sprs(env);
- register_power8_pmu_user_sprs(env);
- register_power8_tm_sprs(env);
- register_power8_pspb_sprs(env);
- register_power8_dpdes_sprs(env);
- register_vtb_sprs(env);
- register_power8_ic_sprs(env);
- register_power9_book4_sprs(env);
- register_power8_rpr_sprs(env);
- register_power9_mmu_sprs(env);
+ register_book3s_310_dbg_sprs(env);
register_power10_hash_sprs(env);
register_power10_dexcr_sprs(env);
register_power10_pmu_sup_sprs(env);
register_power10_pmu_user_sprs(env);
-
- /* FIXME: Filter fields properly based on privilege level */
- spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL,
- spr_read_generic, spr_write_generic,
- KVM_REG_PPC_PSSCR, 0);
-
/* env variables */
env->dcache_line_size = 128;
env->icache_line_size = 128;
@@ -6680,68 +6646,24 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
return false;
}
-POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
+POWERPC_FAMILY(POWER10)(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->fw_name = "PowerPC,POWER10";
dc->desc = "POWER10";
+ pcc->spapr_logical_pvr = CPU_POWERPC_LOGICAL_3_10;
pcc->pvr_match = ppc_pvr_match_power10;
- pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07 |
- PCR_COMPAT_3_00;
- pcc->pcr_supported = PCR_COMPAT_3_10 | PCR_COMPAT_3_00 | PCR_COMPAT_2_07 |
- PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
+ pcc->pcr_mask = PPC_PCR_MASK_POWER10;
+ pcc->pcr_supported = PPC_PCR_SUPPORTED_POWER10;
pcc->init_proc = init_proc_POWER10;
pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0_power9;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
- PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
- PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
- PPC_FLOAT_FRSQRTES |
- PPC_FLOAT_STFIWX |
- PPC_FLOAT_EXT |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO |
- PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
- PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
- PPC_SEGMENT_64B | PPC_SLBI |
- PPC_POPCNTB | PPC_POPCNTWD |
- PPC_CILDST;
- pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
- PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
- PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
- PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
- PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
- PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
- PPC2_ISA300 | PPC2_PRCNTL | PPC2_ISA310 |
- PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206;
- pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_HV) |
- (1ull << MSR_VR) |
- (1ull << MSR_VSX) |
- (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_DE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR) |
- (1ull << MSR_PMM) |
- (1ull << MSR_RI) |
- (1ull << MSR_LE);
- pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
- (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
- (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
- LPCR_DEE | LPCR_OEE))
- | LPCR_MER | LPCR_GTSE | LPCR_TC |
- LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
- /* DD2 adds an extra HAIL bit */
- pcc->lpcr_mask |= LPCR_HAIL;
+ pcc->insns_flags = PPC_INSNS_FLAGS_POWER10;
+ pcc->insns_flags2 = PPC_INSNS_FLAGS2_POWER10;
+ pcc->msr_mask = PPC_MSR_MASK_POWER10;
+ pcc->lpcr_mask = PPC_LPCR_MASK_POWER10;
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
@@ -6754,11 +6676,67 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
pcc->excp_model = POWERPC_EXCP_POWER10;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
pcc->bfd_mach = bfd_mach_ppc64;
- pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
- POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
- POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
- POWERPC_FLAG_VSX | POWERPC_FLAG_SCV |
- POWERPC_FLAG_BHRB;
+ pcc->flags = POWERPC_FLAGS_POWER10;
+ pcc->l1_dcache_size = 0x8000;
+ pcc->l1_icache_size = 0x8000;
+}
+
+static void init_proc_POWER11(CPUPPCState *env)
+{
+ init_proc_POWER10(env);
+}
+
+static bool ppc_pvr_match_power11(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
+{
+ uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK;
+ uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK;
+
+ if (!best && (base == CPU_POWERPC_POWER11_BASE)) {
+ return true;
+ }
+
+ if (base != pcc_base) {
+ return false;
+ }
+
+ if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) {
+ return true;
+ }
+
+ return false;
+}
+
+POWERPC_FAMILY(POWER11)(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+
+ dc->fw_name = "PowerPC,POWER11";
+ dc->desc = "POWER11";
+ pcc->spapr_logical_pvr = CPU_POWERPC_LOGICAL_3_10_P11;
+ pcc->pvr_match = ppc_pvr_match_power11;
+ pcc->pcr_mask = PPC_PCR_MASK_POWER11;
+ pcc->pcr_supported = PPC_PCR_SUPPORTED_POWER11;
+ pcc->init_proc = init_proc_POWER11;
+ pcc->check_pow = check_pow_nocheck;
+ pcc->check_attn = check_attn_hid0_power9;
+ pcc->insns_flags = PPC_INSNS_FLAGS_POWER11;
+ pcc->insns_flags2 = PPC_INSNS_FLAGS2_POWER11;
+ pcc->msr_mask = PPC_MSR_MASK_POWER11;
+ pcc->lpcr_mask = PPC_LPCR_MASK_POWER11;
+
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
+ pcc->mmu_model = POWERPC_MMU_3_00;
+#if !defined(CONFIG_USER_ONLY)
+ /* segment page size remain the same */
+ pcc->hash64_opts = &ppc_hash64_opts_POWER7;
+ pcc->radix_page_info = &POWER10_radix_page_info;
+ pcc->lrg_decr_bits = 56;
+#endif
+ pcc->excp_model = POWERPC_EXCP_POWER11;
+ pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
+ pcc->bfd_mach = bfd_mach_ppc64;
+ pcc->flags = POWERPC_FLAGS_POWER11;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
}
@@ -6784,7 +6762,8 @@ void cpu_ppc_set_1lpar(PowerPCCPU *cpu)
/*
* pseries SMT means "LPAR per core" mode, e.g., msgsndp is usable
- * between threads.
+ * between threads. powernv be in either mode, and it mostly affects
+ * supervisor visible registers and instructions.
*/
if (env->flags & POWERPC_FLAG_SMT) {
env->flags |= POWERPC_FLAG_SMT_1LPAR;
@@ -6974,7 +6953,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp)
pcc->parent_realize(dev, errp);
- if (env_cpu(env)->nr_threads > 1) {
+ if (!ppc_cpu_core_single_threaded(cs)) {
env->flags |= POWERPC_FLAG_SMT;
}
@@ -7102,7 +7081,7 @@ ObjectClass *ppc_cpu_class_by_name(const char *name)
if (strcmp(name, "max") == 0) {
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
if (mc) {
- return object_class_by_name(mc->default_cpu_type);
+ return object_class_by_name(machine_class_default_cpu_type(mc));
}
}
#endif
@@ -7135,7 +7114,7 @@ PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc)
}
/* Sort by PVR, ordering special case "host" last. */
-static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b)
+static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b, gpointer d)
{
ObjectClass *oc_a = (ObjectClass *)a;
ObjectClass *oc_b = (ObjectClass *)b;
@@ -7197,13 +7176,13 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
g_free(name);
}
-void ppc_cpu_list(void)
+static void ppc_cpu_list(void)
{
GSList *list;
qemu_printf("Available CPUs:\n");
list = object_class_get_list(TYPE_POWERPC_CPU, false);
- list = g_slist_sort(list, ppc_cpu_list_compare);
+ list = g_slist_sort_with_data(list, ppc_cpu_list_compare, NULL);
g_slist_foreach(list, ppc_cpu_list_entry, NULL);
g_slist_free(list);
@@ -7236,17 +7215,19 @@ static void ppc_restore_state_to_opc(CPUState *cs,
cpu->env.nip = data[0];
}
-#endif /* CONFIG_TCG */
-static bool ppc_cpu_has_work(CPUState *cs)
+static int ppc_cpu_mmu_index(CPUState *cs, bool ifetch)
{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
+ return ppc_env_mmu_index(cpu_env(cs), ifetch);
}
+#endif /* CONFIG_TCG */
-static int ppc_cpu_mmu_index(CPUState *cs, bool ifetch)
+#ifndef CONFIG_USER_ONLY
+static bool ppc_cpu_has_work(CPUState *cs)
{
- return ppc_env_mmu_index(cpu_env(cs), ifetch);
+ return cs->interrupt_request & CPU_INTERRUPT_HARD;
}
+#endif /* !CONFIG_USER_ONLY */
static void ppc_cpu_reset_hold(Object *obj, ResetType type)
{
@@ -7323,6 +7304,36 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
/* tininess for underflow is detected before rounding */
set_float_detect_tininess(float_tininess_before_rounding,
&env->fp_status);
+ /* Similarly for flush-to-zero */
+ set_float_ftz_detection(float_ftz_before_rounding, &env->fp_status);
+
+ /*
+ * PowerPC propagation rules:
+ * 1. A if it sNaN or qNaN
+ * 2. B if it sNaN or qNaN
+ * A signaling NaN is always silenced before returning it.
+ */
+ set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
+ set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
+ /*
+ * NaN propagation for fused multiply-add:
+ * if fRA is a NaN return it; otherwise if fRB is a NaN return it;
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
+ * whereas QEMU labels the operands as (a * b) + c.
+ */
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status);
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status);
+ /*
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
+ * to return an input NaN if we have one (ie c) rather than generating
+ * a default NaN
+ */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
+
+ /* Default NaN: sign bit clear, set frac msb */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
+ set_float_default_nan_pattern(0b01000000, &env->vec_status);
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
@@ -7375,6 +7386,12 @@ static void ppc_cpu_exec_exit(CPUState *cs)
cpu->vhyp_class->cpu_exec_exit(cpu->vhyp, cpu);
}
}
+
+static vaddr ppc_pointer_wrap(CPUState *cs, int mmu_idx,
+ vaddr result, vaddr base)
+{
+ return (cpu_env(cs)->hflags >> HFLAGS_64) & 1 ? result : (uint32_t)result;
+}
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */
@@ -7432,6 +7449,8 @@ static void ppc_disas_set_info(CPUState *cs, disassemble_info *info)
if ((env->hflags >> MSR_LE) & 1) {
info->endian = BFD_ENDIAN_LITTLE;
+ } else {
+ info->endian = BFD_ENDIAN_BIG;
}
info->mach = env->bfd_mach;
if (!env->bfd_mach) {
@@ -7448,19 +7467,11 @@ static void ppc_disas_set_info(CPUState *cs, disassemble_info *info)
#endif
}
-static Property ppc_cpu_properties[] = {
- DEFINE_PROP_BOOL("pre-2.8-migration", PowerPCCPU, pre_2_8_migration, false),
- DEFINE_PROP_BOOL("pre-2.10-migration", PowerPCCPU, pre_2_10_migration,
- false),
- DEFINE_PROP_BOOL("pre-3.0-migration", PowerPCCPU, pre_3_0_migration,
- false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
#ifndef CONFIG_USER_ONLY
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps ppc_sysemu_ops = {
+ .has_work = ppc_cpu_has_work,
.get_phys_page_debug = ppc_cpu_get_phys_page_debug,
.write_elf32_note = ppc32_cpu_write_elf32_note,
.write_elf64_note = ppc64_cpu_write_elf64_note,
@@ -7470,17 +7481,25 @@ static const struct SysemuCPUOps ppc_sysemu_ops = {
#endif
#ifdef CONFIG_TCG
-#include "hw/core/tcg-cpu-ops.h"
+#include "accel/tcg/cpu-ops.h"
static const TCGCPUOps ppc_tcg_ops = {
+ .mttcg_supported = TARGET_LONG_BITS == 64,
+ .guest_default_memory_order = 0,
.initialize = ppc_translate_init,
+ .translate_code = ppc_translate_code,
+ .get_tb_cpu_state = ppc_get_tb_cpu_state,
.restore_state_to_opc = ppc_restore_state_to_opc,
+ .mmu_index = ppc_cpu_mmu_index,
#ifdef CONFIG_USER_ONLY
.record_sigsegv = ppc_cpu_record_sigsegv,
#else
.tlb_fill = ppc_cpu_tlb_fill,
+ .pointer_wrap = ppc_pointer_wrap,
.cpu_exec_interrupt = ppc_cpu_exec_interrupt,
+ .cpu_exec_halt = ppc_cpu_has_work,
+ .cpu_exec_reset = cpu_reset,
.do_interrupt = ppc_cpu_do_interrupt,
.cpu_exec_enter = ppc_cpu_exec_enter,
.cpu_exec_exit = ppc_cpu_exec_exit,
@@ -7493,7 +7512,7 @@ static const TCGCPUOps ppc_tcg_ops = {
};
#endif /* CONFIG_TCG */
-static void ppc_cpu_class_init(ObjectClass *oc, void *data)
+static void ppc_cpu_class_init(ObjectClass *oc, const void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
@@ -7505,14 +7524,12 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
device_class_set_parent_unrealize(dc, ppc_cpu_unrealize,
&pcc->parent_unrealize);
pcc->pvr_match = ppc_pvr_match_default;
- device_class_set_props(dc, ppc_cpu_properties);
resettable_class_set_parent_phases(rc, NULL, ppc_cpu_reset_hold, NULL,
&pcc->parent_phases);
cc->class_by_name = ppc_cpu_class_by_name;
- cc->has_work = ppc_cpu_has_work;
- cc->mmu_index = ppc_cpu_mmu_index;
+ cc->list_cpus = ppc_cpu_list;
cc->dump_state = ppc_cpu_dump_state;
cc->set_pc = ppc_cpu_set_pc;
cc->get_pc = ppc_cpu_get_pc;
@@ -7561,7 +7578,7 @@ static const TypeInfo ppc_cpu_type_info = {
.class_size = sizeof(PowerPCCPUClass),
.class_init = ppc_cpu_class_init,
#ifndef CONFIG_USER_ONLY
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
diff --git a/target/ppc/cpu_init.h b/target/ppc/cpu_init.h
new file mode 100644
index 0000000..f8fd6ff
--- /dev/null
+++ b/target/ppc/cpu_init.h
@@ -0,0 +1,91 @@
+#ifndef TARGET_PPC_CPU_INIT_H
+#define TARGET_PPC_CPU_INIT_H
+
+#define PPC_INSNS_FLAGS_POWER9 \
+ (PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | \
+ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \
+ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES | \
+ PPC_FLOAT_STFIWX | PPC_FLOAT_EXT | PPC_CACHE | PPC_CACHE_ICBI | \
+ PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \
+ PPC_MEM_TLBSYNC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC | \
+ PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD | \
+ PPC_CILDST)
+
+#define PPC_INSNS_FLAGS_POWER10 PPC_INSNS_FLAGS_POWER9
+#define PPC_INSNS_FLAGS_POWER11 PPC_INSNS_FLAGS_POWER10
+
+#define PPC_INSNS_FLAGS2_POWER_COMMON \
+ (PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX | \
+ PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
+ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | \
+ PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | \
+ PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_ISA300 | PPC2_PRCNTL | \
+ PPC2_MEM_LWSYNC | PPC2_BCDA_ISA206)
+
+#define PPC_INSNS_FLAGS2_POWER9 \
+ (PPC_INSNS_FLAGS2_POWER_COMMON | PPC2_TM)
+#define PPC_INSNS_FLAGS2_POWER10 \
+ (PPC_INSNS_FLAGS2_POWER_COMMON | PPC2_ISA310)
+#define PPC_INSNS_FLAGS2_POWER11 PPC_INSNS_FLAGS2_POWER10
+
+#define PPC_MSR_MASK_POWER_COMMON \
+ ((1ull << MSR_SF) | \
+ (1ull << MSR_HV) | \
+ (1ull << MSR_VR) | \
+ (1ull << MSR_VSX) | \
+ (1ull << MSR_EE) | \
+ (1ull << MSR_PR) | \
+ (1ull << MSR_FP) | \
+ (1ull << MSR_ME) | \
+ (1ull << MSR_FE0) | \
+ (1ull << MSR_SE) | \
+ (1ull << MSR_DE) | \
+ (1ull << MSR_FE1) | \
+ (1ull << MSR_IR) | \
+ (1ull << MSR_DR) | \
+ (1ull << MSR_PMM) | \
+ (1ull << MSR_RI) | \
+ (1ull << MSR_LE))
+
+#define PPC_MSR_MASK_POWER9 \
+ (PPC_MSR_MASK_POWER_COMMON | (1ull << MSR_TM))
+#define PPC_MSR_MASK_POWER10 \
+ PPC_MSR_MASK_POWER_COMMON
+#define PPC_MSR_MASK_POWER11 PPC_MSR_MASK_POWER10
+
+#define PPC_PCR_MASK_POWER9 \
+ (PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07)
+#define PPC_PCR_MASK_POWER10 \
+ (PPC_PCR_MASK_POWER9 | PCR_COMPAT_3_00)
+#define PPC_PCR_MASK_POWER11 PPC_PCR_MASK_POWER10
+
+#define PPC_PCR_SUPPORTED_POWER9 \
+ (PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05)
+#define PPC_PCR_SUPPORTED_POWER10 \
+ (PPC_PCR_SUPPORTED_POWER9 | PCR_COMPAT_3_10)
+#define PPC_PCR_SUPPORTED_POWER11 PPC_PCR_SUPPORTED_POWER10
+
+#define PPC_LPCR_MASK_POWER9 \
+ (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD | \
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL | \
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD | \
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | \
+ LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC | \
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE)
+/* DD2 adds an extra HAIL bit */
+#define PPC_LPCR_MASK_POWER10 \
+ (PPC_LPCR_MASK_POWER9 | LPCR_HAIL)
+#define PPC_LPCR_MASK_POWER11 PPC_LPCR_MASK_POWER10
+
+#define POWERPC_FLAGS_POWER_COMMON \
+ (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | \
+ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | \
+ POWERPC_FLAG_VSX | POWERPC_FLAG_SCV)
+
+#define POWERPC_FLAGS_POWER9 \
+ (POWERPC_FLAGS_POWER_COMMON | POWERPC_FLAG_TM)
+#define POWERPC_FLAGS_POWER10 \
+ (POWERPC_FLAGS_POWER_COMMON | POWERPC_FLAG_BHRB)
+#define POWERPC_FLAGS_POWER11 POWERPC_FLAGS_POWER10
+
+#endif /* TARGET_PPC_CPU_INIT_H */
diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c
index 5967ea0..ecc3f79 100644
--- a/target/ppc/dfp_helper.c
+++ b/target/ppc/dfp_helper.c
@@ -249,7 +249,7 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
fprf = 0x05;
break;
default:
- assert(0); /* should never get here */
+ g_assert_not_reached();
}
dfp->env->fpscr &= ~FP_FPRF;
dfp->env->fpscr |= (fprf << FPSCR_FPRF);
@@ -1243,7 +1243,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
} else if (decNumberIsQNaN(&dfp.b)) { \
vt.VsrD(1) = -2; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
set_dfp64(t, &vt); \
} else { \
@@ -1252,7 +1252,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
} else if ((size) == 128) { \
vt.VsrD(1) = dfp.b.exponent + 6176; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
set_dfp64(t, &vt); \
} \
@@ -1300,7 +1300,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
raw_inf = 0x1e000; \
bias = 6176; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
\
if (unlikely((exp < 0) || (exp > max_exp))) { \
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 */
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 51bce99..07b782f 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -19,7 +19,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
#include "internal.h"
#include "fpu/softfloat.h"
@@ -155,8 +154,7 @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
} else if (tp##_is_infinity(arg)) { \
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
} else { \
- float_status dummy = { }; /* snan_bit_is_one = 0 */ \
- if (tp##_is_signaling_nan(arg, &dummy)) { \
+ if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
fprf = 0x00 << FPSCR_FPRF; \
} else { \
fprf = 0x11 << FPSCR_FPRF; \
@@ -1599,14 +1597,14 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
-VSX_ADD_SUB(xsaddsp, add, 1, float64, VsrD(0), 1, 1)
-VSX_ADD_SUB(xvadddp, add, 2, float64, VsrD(i), 0, 0)
-VSX_ADD_SUB(xvaddsp, add, 4, float32, VsrW(i), 0, 0)
-VSX_ADD_SUB(xssubdp, sub, 1, float64, VsrD(0), 1, 0)
-VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1)
-VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
-VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
+VSX_ADD_SUB(XSADDDP, add, 1, float64, VsrD(0), 1, 0)
+VSX_ADD_SUB(XSADDSP, add, 1, float64, VsrD(0), 1, 1)
+VSX_ADD_SUB(XVADDDP, add, 2, float64, VsrD(i), 0, 0)
+VSX_ADD_SUB(XVADDSP, add, 4, float32, VsrW(i), 0, 0)
+VSX_ADD_SUB(XSSUBDP, sub, 1, float64, VsrD(0), 1, 0)
+VSX_ADD_SUB(XSSUBSP, sub, 1, float64, VsrD(0), 1, 1)
+VSX_ADD_SUB(XVSUBDP, sub, 2, float64, VsrD(i), 0, 0)
+VSX_ADD_SUB(XVSUBSP, sub, 4, float32, VsrW(i), 0, 0)
void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -1676,10 +1674,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
-VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1)
-VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
-VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
+VSX_MUL(XSMULDP, 1, float64, VsrD(0), 1, 0)
+VSX_MUL(XSMULSP, 1, float64, VsrD(0), 1, 1)
+VSX_MUL(XVMULDP, 2, float64, VsrD(i), 0, 0)
+VSX_MUL(XVMULSP, 4, float32, VsrW(i), 0, 0)
void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -1750,10 +1748,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
-VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1)
-VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
-VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
+VSX_DIV(XSDIVDP, 1, float64, VsrD(0), 1, 0)
+VSX_DIV(XSDIVSP, 1, float64, VsrD(0), 1, 1)
+VSX_DIV(XVDIVDP, 2, float64, VsrD(i), 0, 0)
+VSX_DIV(XVDIVSP, 4, float32, VsrW(i), 0, 0)
void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -2383,12 +2381,12 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, false, GETPC()); \
}
-VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
-VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, VsrD(i))
-VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, VsrW(i))
-VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0))
-VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i))
-VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
+VSX_MAX_MIN(XSMAXDP, maxnum, 1, float64, VsrD(0))
+VSX_MAX_MIN(XVMAXDP, maxnum, 2, float64, VsrD(i))
+VSX_MAX_MIN(XVMAXSP, maxnum, 4, float32, VsrW(i))
+VSX_MAX_MIN(XSMINDP, minnum, 1, float64, VsrD(0))
+VSX_MAX_MIN(XVMINDP, minnum, 2, float64, VsrD(i))
+VSX_MAX_MIN(XVMINSP, minnum, 4, float32, VsrW(i))
#define VSX_MAX_MINC(name, max, tp, fld) \
void helper_##name(CPUPPCState *env, \
@@ -2527,14 +2525,14 @@ uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
return crf6; \
}
-VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1)
-VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1, 1)
-VSX_CMP(xvcmpgtdp, 2, float64, VsrD(i), lt, 1, 1)
-VSX_CMP(xvcmpnedp, 2, float64, VsrD(i), eq, 0, 0)
-VSX_CMP(xvcmpeqsp, 4, float32, VsrW(i), eq, 0, 1)
-VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1, 1)
-VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1, 1)
-VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0)
+VSX_CMP(XVCMPEQDP, 2, float64, VsrD(i), eq, 0, 1)
+VSX_CMP(XVCMPGEDP, 2, float64, VsrD(i), le, 1, 1)
+VSX_CMP(XVCMPGTDP, 2, float64, VsrD(i), lt, 1, 1)
+VSX_CMP(XVCMPNEDP, 2, float64, VsrD(i), eq, 0, 0)
+VSX_CMP(XVCMPEQSP, 4, float32, VsrW(i), eq, 0, 1)
+VSX_CMP(XVCMPGESP, 4, float32, VsrW(i), le, 1, 1)
+VSX_CMP(XVCMPGTSP, 4, float32, VsrW(i), lt, 1, 1)
+VSX_CMP(XVCMPNESP, 4, float32, VsrW(i), eq, 0, 0)
/*
* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 76b8f25..ca414f2 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -28,6 +28,8 @@ DEF_HELPER_2(store_pcr, void, env, tl)
DEF_HELPER_2(store_ciabr, void, env, tl)
DEF_HELPER_2(store_dawr0, void, env, tl)
DEF_HELPER_2(store_dawrx0, void, env, tl)
+DEF_HELPER_2(store_dawr1, void, env, tl)
+DEF_HELPER_2(store_dawrx1, void, env, tl)
DEF_HELPER_2(store_mmcr0, void, env, tl)
DEF_HELPER_2(store_mmcr1, void, env, tl)
DEF_HELPER_2(store_mmcrA, void, env, tl)
@@ -46,8 +48,10 @@ DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_4(lsw, void, env, tl, i32, i32)
DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32)
-DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32)
-DEF_HELPER_FLAGS_3(dcbzep, TCG_CALL_NO_WG, void, env, tl, i32)
+DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, int)
+#ifdef TARGET_PPC64
+DEF_HELPER_FLAGS_2(dcbzl, TCG_CALL_NO_WG, void, env, tl)
+#endif
DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_FLAGS_2(icbiep, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
@@ -201,18 +205,18 @@ DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(VPRTYBQ, TCG_CALL_NO_RWG, void, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddubs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vadduhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
@@ -275,10 +279,10 @@ DEF_HELPER_3(STVEBX, void, env, avr, tl)
DEF_HELPER_3(STVEHX, void, env, avr, tl)
DEF_HELPER_3(STVEWX, void, env, avr, tl)
#if defined(TARGET_PPC64)
-DEF_HELPER_4(lxvl, void, env, tl, vsr, tl)
-DEF_HELPER_4(lxvll, void, env, tl, vsr, tl)
-DEF_HELPER_4(stxvl, void, env, tl, vsr, tl)
-DEF_HELPER_4(stxvll, void, env, tl, vsr, tl)
+DEF_HELPER_4(LXVL, void, env, tl, vsr, tl)
+DEF_HELPER_4(LXVLL, void, env, tl, vsr, tl)
+DEF_HELPER_4(STXVL, void, env, tl, vsr, tl)
+DEF_HELPER_4(STXVLL, void, env, tl, vsr, tl)
#endif
DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
@@ -362,12 +366,12 @@ DEF_HELPER_FLAGS_4(bcdsr, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
DEF_HELPER_FLAGS_4(bcdtrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
DEF_HELPER_FLAGS_4(bcdutrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
-DEF_HELPER_4(xsadddp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSADDDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsaddqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xssubdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmuldp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSSUBDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMULDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsmulqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xsdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSDIVDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsdivqp, void, env, i32, vsr, vsr, vsr)
DEF_HELPER_3(xsredp, void, env, vsr, vsr)
DEF_HELPER_3(xssqrtdp, void, env, vsr, vsr)
@@ -390,8 +394,8 @@ DEF_HELPER_4(xscmpodp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpudp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpoqp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpuqp, void, env, i32, vsr, vsr)
-DEF_HELPER_4(xsmaxdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmindp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMAXDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMINDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMAXCDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMINCDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMAXJDP, void, env, vsr, vsr, vsr)
@@ -437,10 +441,10 @@ DEF_HELPER_4(xsrqpxp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xssqrtqp, void, env, i32, vsr, vsr)
DEF_HELPER_5(xssubqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xsaddsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xssubsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmulsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSADDSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSSUBSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMULSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSDIVSP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xsresp, void, env, vsr, vsr)
DEF_HELPER_2(xsrsp, i64, env, i64)
DEF_HELPER_3(xssqrtsp, void, env, vsr, vsr)
@@ -459,10 +463,10 @@ DEF_HELPER_5(XSNMADDQPO, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(XSNMSUBQP, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(XSNMSUBQPO, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvadddp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvsubdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmuldp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVADDDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVSUBDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMULDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVDIVDP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xvredp, void, env, vsr, vsr)
DEF_HELPER_3(xvsqrtdp, void, env, vsr, vsr)
DEF_HELPER_3(xvrsqrtedp, void, env, vsr, vsr)
@@ -472,12 +476,12 @@ DEF_HELPER_5(xvmadddp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvmsubdp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmadddp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmsubdp, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvmaxdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmindp, void, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpeqdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgtdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpnedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMAXDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMINDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPEQDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGEDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGTDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPNEDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
DEF_HELPER_3(xvcvdpsp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvdpsxds, void, env, vsr, vsr)
DEF_HELPER_3(xvcvdpsxws, void, env, vsr, vsr)
@@ -493,10 +497,10 @@ DEF_HELPER_3(xvrdpim, void, env, vsr, vsr)
DEF_HELPER_3(xvrdpip, void, env, vsr, vsr)
DEF_HELPER_3(xvrdpiz, void, env, vsr, vsr)
-DEF_HELPER_4(xvaddsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvsubsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmulsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVADDSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVSUBSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMULSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVDIVSP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xvresp, void, env, vsr, vsr)
DEF_HELPER_3(xvsqrtsp, void, env, vsr, vsr)
DEF_HELPER_3(xvrsqrtesp, void, env, vsr, vsr)
@@ -506,12 +510,12 @@ DEF_HELPER_5(xvmaddsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvmsubsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmaddsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmsubsp, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvmaxsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvminsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpeqsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgtsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpnesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMAXSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMINSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPEQSP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGESP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGTSP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPNESP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
DEF_HELPER_3(xvcvspdp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvsphp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvhpsp, void, env, vsr, vsr)
@@ -731,6 +735,8 @@ DEF_HELPER_2(store_tfmr, void, env, tl)
DEF_HELPER_FLAGS_2(store_sprc, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(load_sprd, TCG_CALL_NO_RWG_SE, tl, env)
DEF_HELPER_FLAGS_2(store_sprd, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_1(load_pmsr, TCG_CALL_NO_RWG_SE, tl, env)
+DEF_HELPER_FLAGS_2(store_pmcr, TCG_CALL_NO_RWG, void, env, tl)
#endif
DEF_HELPER_2(store_sdr1, void, env, tl)
DEF_HELPER_2(store_pidr, void, env, tl)
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 02076e9..7e57268 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -20,13 +20,15 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/main-loop.h"
-#include "exec/exec-all.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tcg.h"
+#include "exec/cputlb.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
#include "helper_regs.h"
#include "power8-pmu.h"
#include "cpu-models.h"
#include "spr_common.h"
+#include "accel/tcg/cpu-ops.h"
+#include "internal.h"
/* Swap temporary saved registers with GPRs */
void hreg_swap_gpr_tgpr(CPUPPCState *env)
@@ -83,15 +85,16 @@ static bool hreg_check_bhrb_enable(CPUPPCState *env)
static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
{
uint32_t hflags = 0;
-
#if defined(TARGET_PPC64)
- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
+ target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
+
+ if (mmcr0 & MMCR0_PMCC0) {
hflags |= 1 << HFLAGS_PMCC0;
}
- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
+ if (mmcr0 & MMCR0_PMCC1) {
hflags |= 1 << HFLAGS_PMCC1;
}
- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
+ if (mmcr0 & MMCR0_PMCjCE) {
hflags |= 1 << HFLAGS_PMCJCE;
}
if (hreg_check_bhrb_enable(env)) {
@@ -101,9 +104,9 @@ static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
#ifndef CONFIG_USER_ONLY
if (env->pmc_ins_cnt) {
hflags |= 1 << HFLAGS_INSN_CNT;
- }
- if (env->pmc_ins_cnt & 0x1e) {
- hflags |= 1 << HFLAGS_PMC_OTHER;
+ if (env->pmc_ins_cnt & 0x1e) {
+ hflags |= 1 << HFLAGS_PMC_OTHER;
+ }
}
#endif
#endif
@@ -143,10 +146,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
if (ppc_flags & POWERPC_FLAG_DE) {
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
- if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(env->msr, MSR, DE)) {
+ if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(msr, MSR, DE)) {
hflags |= 1 << HFLAGS_SE;
}
- if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(env->msr, MSR, DE)) {
+ if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(msr, MSR, DE)) {
hflags |= 1 << HFLAGS_BE;
}
} else {
@@ -254,26 +257,23 @@ void hreg_update_pmu_hflags(CPUPPCState *env)
env->hflags |= hreg_compute_pmu_hflags_value(env);
}
-#ifdef CONFIG_DEBUG_TCG
-void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc,
- uint64_t *cs_base, uint32_t *flags)
+TCGTBCPUState ppc_get_tb_cpu_state(CPUState *cs)
{
+ CPUPPCState *env = cpu_env(cs);
uint32_t hflags_current = env->hflags;
- uint32_t hflags_rebuilt;
- *pc = env->nip;
- *cs_base = 0;
- *flags = hflags_current;
-
- hflags_rebuilt = hreg_compute_hflags_value(env);
+#ifdef CONFIG_DEBUG_TCG
+ uint32_t hflags_rebuilt = hreg_compute_hflags_value(env);
if (unlikely(hflags_current != hflags_rebuilt)) {
cpu_abort(env_cpu(env),
"TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n",
hflags_current, hflags_rebuilt);
}
-}
#endif
+ return (TCGTBCPUState){ .pc = env->nip, .flags = hflags_current };
+}
+
void cpu_interrupt_exittb(CPUState *cs)
{
/*
diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h
index 8196c13..b928c2c 100644
--- a/target/ppc/helper_regs.h
+++ b/target/ppc/helper_regs.h
@@ -20,6 +20,8 @@
#ifndef HELPER_REGS_H
#define HELPER_REGS_H
+#include "target/ppc/cpu.h"
+
void hreg_swap_gpr_tgpr(CPUPPCState *env);
void hreg_compute_hflags(CPUPPCState *env);
void hreg_update_pmu_hflags(CPUPPCState *env);
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index ee33141..e53fd28 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -241,6 +241,9 @@
&XX3 xt xa xb
@XX3 ...... ..... ..... ..... ........ ... &XX3 xt=%xx_xt xa=%xx_xa xb=%xx_xb
+&XX3_rc xt xa xb rc:bool
+@XX3_rc ...... ..... ..... ..... rc:1 ....... ... &XX3_rc xt=%xx_xt xa=%xx_xa xb=%xx_xb
+
# 32 bit GER instructions have all mask bits considered 1
&MMIRR_XX3 xa xb xt pmsk xmsk ymsk
%xx_at 23:3
@@ -832,6 +835,14 @@ VADDCUW 000100 ..... ..... ..... 00110000000 @VX
VADDCUQ 000100 ..... ..... ..... 00101000000 @VX
VADDUQM 000100 ..... ..... ..... 00100000000 @VX
+VADDSBS 000100 ..... ..... ..... 01100000000 @VX
+VADDSHS 000100 ..... ..... ..... 01101000000 @VX
+VADDSWS 000100 ..... ..... ..... 01110000000 @VX
+
+VADDUBS 000100 ..... ..... ..... 01000000000 @VX
+VADDUHS 000100 ..... ..... ..... 01001000000 @VX
+VADDUWS 000100 ..... ..... ..... 01010000000 @VX
+
VADDEUQM 000100 ..... ..... ..... ..... 111100 @VA
VADDECUQ 000100 ..... ..... ..... ..... 111101 @VA
@@ -839,6 +850,14 @@ VSUBCUW 000100 ..... ..... ..... 10110000000 @VX
VSUBCUQ 000100 ..... ..... ..... 10101000000 @VX
VSUBUQM 000100 ..... ..... ..... 10100000000 @VX
+VSUBSBS 000100 ..... ..... ..... 11100000000 @VX
+VSUBSHS 000100 ..... ..... ..... 11101000000 @VX
+VSUBSWS 000100 ..... ..... ..... 11110000000 @VX
+
+VSUBUBS 000100 ..... ..... ..... 11000000000 @VX
+VSUBUHS 000100 ..... ..... ..... 11001000000 @VX
+VSUBUWS 000100 ..... ..... ..... 11010000000 @VX
+
VSUBECUQ 000100 ..... ..... ..... ..... 111111 @VA
VSUBEUQM 000100 ..... ..... ..... ..... 111110 @VA
@@ -977,6 +996,35 @@ STXVRHX 011111 ..... ..... ..... 0010101101 . @X_TSX
STXVRWX 011111 ..... ..... ..... 0011001101 . @X_TSX
STXVRDX 011111 ..... ..... ..... 0011101101 . @X_TSX
+LXSDX 011111 ..... ..... ..... 1001001100 . @X_TSX
+LXSIWAX 011111 ..... ..... ..... 0001001100 . @X_TSX
+LXSIBZX 011111 ..... ..... ..... 1100001101 . @X_TSX
+LXSIHZX 011111 ..... ..... ..... 1100101101 . @X_TSX
+LXSIWZX 011111 ..... ..... ..... 0000001100 . @X_TSX
+LXSSPX 011111 ..... ..... ..... 1000001100 . @X_TSX
+
+STXSDX 011111 ..... ..... ..... 1011001100 . @X_TSX
+STXSIBX 011111 ..... ..... ..... 1110001101 . @X_TSX
+STXSIHX 011111 ..... ..... ..... 1110101101 . @X_TSX
+STXSIWX 011111 ..... ..... ..... 0010001100 . @X_TSX
+STXSSPX 011111 ..... ..... ..... 1010001100 . @X_TSX
+
+LXVB16X 011111 ..... ..... ..... 1101101100 . @X_TSX
+LXVD2X 011111 ..... ..... ..... 1101001100 . @X_TSX
+LXVH8X 011111 ..... ..... ..... 1100101100 . @X_TSX
+LXVW4X 011111 ..... ..... ..... 1100001100 . @X_TSX
+LXVDSX 011111 ..... ..... ..... 0101001100 . @X_TSX
+LXVWSX 011111 ..... ..... ..... 0101101100 . @X_TSX
+LXVL 011111 ..... ..... ..... 0100001101 . @X_TSX
+LXVLL 011111 ..... ..... ..... 0100101101 . @X_TSX
+
+STXVB16X 011111 ..... ..... ..... 1111101100 . @X_TSX
+STXVD2X 011111 ..... ..... ..... 1111001100 . @X_TSX
+STXVH8X 011111 ..... ..... ..... 1110101100 . @X_TSX
+STXVW4X 011111 ..... ..... ..... 1110001100 . @X_TSX
+STXVL 011111 ..... ..... ..... 0110001101 . @X_TSX
+STXVLL 011111 ..... ..... ..... 0110101101 . @X_TSX
+
## VSX Vector Binary Floating-Point Sign Manipulation Instructions
XVABSDP 111100 ..... 00000 ..... 111011001 .. @XX2
@@ -988,6 +1036,28 @@ XVNEGSP 111100 ..... 00000 ..... 110111001 .. @XX2
XVCPSGNDP 111100 ..... ..... ..... 11110000 ... @XX3
XVCPSGNSP 111100 ..... ..... ..... 11010000 ... @XX3
+## VSX Binary Floating-Point Arithmetic Instructions
+
+XSADDSP 111100 ..... ..... ..... 00000000 ... @XX3
+XSSUBSP 111100 ..... ..... ..... 00001000 ... @XX3
+XSMULSP 111100 ..... ..... ..... 00010000 ... @XX3
+XSDIVSP 111100 ..... ..... ..... 00011000 ... @XX3
+
+XSADDDP 111100 ..... ..... ..... 00100000 ... @XX3
+XSSUBDP 111100 ..... ..... ..... 00101000 ... @XX3
+XSMULDP 111100 ..... ..... ..... 00110000 ... @XX3
+XSDIVDP 111100 ..... ..... ..... 00111000 ... @XX3
+
+XVADDSP 111100 ..... ..... ..... 01000000 ... @XX3
+XVSUBSP 111100 ..... ..... ..... 01001000 ... @XX3
+XVMULSP 111100 ..... ..... ..... 01010000 ... @XX3
+XVDIVSP 111100 ..... ..... ..... 01011000 ... @XX3
+
+XVADDDP 111100 ..... ..... ..... 01100000 ... @XX3
+XVSUBDP 111100 ..... ..... ..... 01101000 ... @XX3
+XVMULDP 111100 ..... ..... ..... 01110000 ... @XX3
+XVDIVDP 111100 ..... ..... ..... 01111000 ... @XX3
+
## VSX Scalar Multiply-Add Instructions
XSMADDADP 111100 ..... ..... ..... 00100001 . . . @XX3
@@ -1057,6 +1127,23 @@ XSCMPEQQP 111111 ..... ..... ..... 0001000100 - @X
XSCMPGEQP 111111 ..... ..... ..... 0011000100 - @X
XSCMPGTQP 111111 ..... ..... ..... 0011100100 - @X
+XVCMPEQSP 111100 ..... ..... ..... . 1000011 ... @XX3_rc
+XVCMPGTSP 111100 ..... ..... ..... . 1001011 ... @XX3_rc
+XVCMPGESP 111100 ..... ..... ..... . 1010011 ... @XX3_rc
+XVCMPNESP 111100 ..... ..... ..... . 1011011 ... @XX3_rc
+XVCMPEQDP 111100 ..... ..... ..... . 1100011 ... @XX3_rc
+XVCMPGTDP 111100 ..... ..... ..... . 1101011 ... @XX3_rc
+XVCMPGEDP 111100 ..... ..... ..... . 1110011 ... @XX3_rc
+XVCMPNEDP 111100 ..... ..... ..... . 1111011 ... @XX3_rc
+
+XSMAXDP 111100 ..... ..... ..... 10100000 ... @XX3
+XSMINDP 111100 ..... ..... ..... 10101000 ... @XX3
+
+XVMAXSP 111100 ..... ..... ..... 11000000 ... @XX3
+XVMINSP 111100 ..... ..... ..... 11001000 ... @XX3
+XVMAXDP 111100 ..... ..... ..... 11100000 ... @XX3
+XVMINDP 111100 ..... ..... ..... 11101000 ... @XX3
+
## VSX Binary Floating-Point Convert Instructions
XSCVQPDP 111111 ..... 10100 ..... 1101000100 . @X_tb_rc
@@ -1092,6 +1179,17 @@ XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a
XXMTACC 011111 ... -- 00001 ----- 0010110001 - @X_a
XXSETACCZ 011111 ... -- 00011 ----- 0010110001 - @X_a
+## VSX Vector Logical instructions
+
+XXLAND 111100 ..... ..... ..... 10000010 ... @XX3
+XXLANDC 111100 ..... ..... ..... 10001010 ... @XX3
+XXLOR 111100 ..... ..... ..... 10010010 ... @XX3
+XXLXOR 111100 ..... ..... ..... 10011010 ... @XX3
+XXLNOR 111100 ..... ..... ..... 10100010 ... @XX3
+XXLEQV 111100 ..... ..... ..... 10111010 ... @XX3
+XXLNAND 111100 ..... ..... ..... 10110010 ... @XX3
+XXLORC 111100 ..... ..... ..... 10101010 ... @XX3
+
## VSX GER instruction
XVI4GER8 111011 ... -- ..... ..... 00100011 ..- @XX3_at xa=%xx_xa
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 2c6b633..ef4b2e7 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -541,7 +541,7 @@ VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
}
#define VARITHSAT_DO(name, op, optype, cvt, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *vscr_sat, \
+ void helper_V##name(ppc_avr_t *r, ppc_avr_t *vscr_sat, \
ppc_avr_t *a, ppc_avr_t *b, uint32_t desc) \
{ \
int sat = 0; \
@@ -555,17 +555,17 @@ VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
} \
}
#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
+ VARITHSAT_DO(ADDS##suffix##S, +, optype, cvt, element) \
+ VARITHSAT_DO(SUBS##suffix##S, -, optype, cvt, element)
#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
-VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
-VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
-VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
-VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
-VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
-VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
+ VARITHSAT_DO(ADDU##suffix##S, +, optype, cvt, element) \
+ VARITHSAT_DO(SUBU##suffix##S, -, optype, cvt, element)
+VARITHSAT_SIGNED(B, s8, int16_t, cvtshsb)
+VARITHSAT_SIGNED(H, s16, int32_t, cvtswsh)
+VARITHSAT_SIGNED(W, s32, int64_t, cvtsdsw)
+VARITHSAT_UNSIGNED(B, u8, uint16_t, cvtshub)
+VARITHSAT_UNSIGNED(H, u16, uint32_t, cvtswuh)
+VARITHSAT_UNSIGNED(W, u32, uint64_t, cvtsduw)
#undef VARITHSAT_CASE
#undef VARITHSAT_DO
#undef VARITHSAT_SIGNED
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 20fb2ec..7723350 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -21,6 +21,7 @@
#include "exec/breakpoint.h"
#include "hw/registerfields.h"
#include "exec/page-protection.h"
+#include "accel/tcg/tb-cpu-state.h"
/* PM instructions */
typedef enum {
@@ -268,6 +269,8 @@ static inline void pte_invalidate(target_ulong *pte0)
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+uint32_t ppc_ldl_code(CPUArchState *env, target_ulong addr);
+
#ifdef CONFIG_USER_ONLY
void ppc_cpu_record_sigsegv(CPUState *cs, vaddr addr,
MMUAccessType access_type,
@@ -287,7 +290,11 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
void ppc_cpu_debug_excp_handler(CPUState *cs);
bool ppc_cpu_debug_check_breakpoint(CPUState *cs);
bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
-#endif
+
+G_NORETURN void powerpc_checkstop(CPUPPCState *env, const char *reason);
+void powerpc_excp(PowerPCCPU *cpu, int excp);
+
+#endif /* !CONFIG_USER_ONLY */
FIELD(GER_MSK, XMSK, 0, 4)
FIELD(GER_MSK, YMSK, 4, 4)
@@ -302,4 +309,6 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
return msk;
}
+TCGTBCPUState ppc_get_tb_cpu_state(CPUState *cs);
+
#endif /* PPC_INTERNAL_H */
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 2c39322..0156580 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -26,10 +26,10 @@
#include "cpu.h"
#include "cpu-models.h"
#include "qemu/timer.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
#include "kvm_ppc.h"
-#include "sysemu/cpus.h"
-#include "sysemu/device_tree.h"
+#include "system/cpus.h"
+#include "system/device_tree.h"
#include "mmu-hash64.h"
#include "hw/ppc/spapr.h"
@@ -37,17 +37,19 @@
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
#include "migration/qemu-file-types.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "trace.h"
#include "gdbstub/enums.h"
#include "exec/memattrs.h"
-#include "exec/ram_addr.h"
-#include "sysemu/hostmem.h"
+#include "system/ram_addr.h"
+#include "system/hostmem.h"
#include "qemu/cutils.h"
#include "qemu/main-loop.h"
#include "qemu/mmap-alloc.h"
#include "elf.h"
-#include "sysemu/kvm_int.h"
+#include "system/kvm_int.h"
+#include "system/kvm.h"
+#include "accel/accel-cpu-target.h"
#include CONFIG_DEVICES
@@ -90,6 +92,7 @@ static int cap_large_decr;
static int cap_fwnmi;
static int cap_rpt_invalidate;
static int cap_ail_mode_3;
+static int cap_dawr1;
#ifdef CONFIG_PSERIES
static int cap_papr;
@@ -150,6 +153,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
cap_large_decr = kvmppc_get_dec_bits();
cap_fwnmi = kvm_vm_check_extension(s, KVM_CAP_PPC_FWNMI);
+ cap_dawr1 = kvm_vm_check_extension(s, KVM_CAP_PPC_DAWR1);
/*
* Note: setting it to false because there is not such capability
* in KVM at this moment.
@@ -475,6 +479,11 @@ static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
}
}
+int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
+{
+ return 0;
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -898,7 +907,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu)
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
@@ -1203,7 +1212,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
return 0;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
@@ -1328,7 +1337,6 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
- return;
}
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
@@ -2112,6 +2120,16 @@ int kvmppc_set_fwnmi(PowerPCCPU *cpu)
return kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_FWNMI, 0);
}
+bool kvmppc_has_cap_dawr1(void)
+{
+ return !!cap_dawr1;
+}
+
+int kvmppc_set_cap_dawr1(int enable)
+{
+ return kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_DAWR1, 0, enable);
+}
+
int kvmppc_smt_threads(void)
{
return cap_ppc_smt ? cap_ppc_smt : 1;
@@ -2346,7 +2364,31 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on)
}
}
-static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
+static bool kvmppc_cpu_realize(CPUState *cs, Error **errp)
+{
+ int ret;
+ const char *vcpu_str = (cs->parent_obj.hotplugged == true) ?
+ "hotplug" : "create";
+ cs->cpu_index = cpu_get_free_index();
+
+ POWERPC_CPU(cs)->vcpu_id = cs->cpu_index;
+
+ /* create and park to fail gracefully in case vcpu hotplug fails */
+ ret = kvm_create_and_park_vcpu(cs);
+ if (ret) {
+ /*
+ * This causes QEMU to terminate if initial CPU creation
+ * fails, and only CPU hotplug failure if the error happens
+ * there.
+ */
+ error_setg(errp, "%s: vcpu %s failed with %d",
+ __func__, vcpu_str, ret);
+ return false;
+ }
+ return true;
+}
+
+static void kvmppc_host_cpu_class_init(ObjectClass *oc, const void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size");
@@ -2607,7 +2649,7 @@ static int kvm_ppc_register_host_cpu_type(void)
return -1;
}
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
- type_register(&type_info);
+ type_register_static(&type_info);
/* override TCG default cpu type with 'host' cpu model */
object_class_foreach(pseries_machine_class_fixup, TYPE_SPAPR_MACHINE,
false, NULL);
@@ -2966,3 +3008,23 @@ void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+ acc->cpu_target_realize = kvmppc_cpu_realize;
+}
+
+static const TypeInfo kvm_cpu_accel_type_info = {
+ .name = ACCEL_CPU_NAME("kvm"),
+
+ .parent = TYPE_ACCEL_CPU,
+ .class_init = kvm_cpu_accel_class_init,
+ .abstract = true,
+};
+static void kvm_cpu_accel_register_types(void)
+{
+ type_register_static(&kvm_cpu_accel_type_info);
+}
+type_init(kvm_cpu_accel_register_types);
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 1975fb5..a1d9ce9 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -9,7 +9,7 @@
#ifndef KVM_PPC_H
#define KVM_PPC_H
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "exec/hwaddr.h"
#include "cpu.h"
@@ -68,6 +68,8 @@ bool kvmppc_has_cap_htm(void);
bool kvmppc_has_cap_mmu_radix(void);
bool kvmppc_has_cap_mmu_hash_v3(void);
bool kvmppc_has_cap_xive(void);
+bool kvmppc_has_cap_dawr1(void);
+int kvmppc_set_cap_dawr1(int enable);
int kvmppc_get_cap_safe_cache(void);
int kvmppc_get_cap_safe_bounds_check(void);
int kvmppc_get_cap_safe_indirect_branch(void);
@@ -219,7 +221,6 @@ static inline int kvmppc_smt_threads(void)
static inline void kvmppc_error_append_smt_possible_hint(Error *const *errp)
{
- return;
}
static inline int kvmppc_set_smt_threads(int smt)
@@ -257,7 +258,6 @@ static inline target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
static inline void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu,
unsigned int online)
{
- return;
}
static inline void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
@@ -377,6 +377,16 @@ static inline bool kvmppc_has_cap_xive(void)
return false;
}
+static inline bool kvmppc_has_cap_dawr1(void)
+{
+ return false;
+}
+
+static inline int kvmppc_set_cap_dawr1(int enable)
+{
+ abort();
+}
+
static inline int kvmppc_get_cap_safe_cache(void)
{
return 0;
@@ -444,7 +454,6 @@ static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
static inline void kvmppc_check_papr_resize_hpt(Error **errp)
{
- return;
}
static inline int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu,
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 731dd8d..d72e5ec 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -1,15 +1,14 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tcg.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
#include "helper_regs.h"
#include "mmu-hash64.h"
#include "migration/cpu.h"
#include "qapi/error.h"
#include "kvm_ppc.h"
#include "power8-pmu.h"
-#include "sysemu/replay.h"
+#include "system/replay.h"
static void post_load_update_msr(CPUPPCState *env)
{
@@ -118,43 +117,11 @@ static const VMStateInfo vmstate_info_vsr = {
#define VMSTATE_VSR_ARRAY(_f, _s, _n) \
VMSTATE_VSR_ARRAY_V(_f, _s, _n, 0)
-static bool cpu_pre_2_8_migration(void *opaque, int version_id)
-{
- PowerPCCPU *cpu = opaque;
-
- return cpu->pre_2_8_migration;
-}
-
-#if defined(TARGET_PPC64)
-static bool cpu_pre_3_0_migration(void *opaque, int version_id)
-{
- PowerPCCPU *cpu = opaque;
-
- return cpu->pre_3_0_migration;
-}
-#endif
-
static int cpu_pre_save(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
int i;
- uint64_t insns_compat_mask =
- PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB
- | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES
- | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES
- | PPC_FLOAT_STFIWX | PPC_FLOAT_EXT
- | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ
- | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC
- | PPC_64B | PPC_64BX | PPC_ALTIVEC
- | PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD;
- uint64_t insns_compat_mask2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX
- | PPC2_PERM_ISA206 | PPC2_DIVE_ISA206
- | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206
- | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207
- | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207
- | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM
- | PPC2_MEM_LWSYNC;
env->spr[SPR_LR] = env->lr;
env->spr[SPR_CTR] = env->ctr;
@@ -177,35 +144,6 @@ static int cpu_pre_save(void *opaque)
env->spr[SPR_IBAT4U + 2 * i + 1] = env->IBAT[1][i + 4];
}
- /* Hacks for migration compatibility between 2.6, 2.7 & 2.8 */
- if (cpu->pre_2_8_migration) {
- /*
- * Mask out bits that got added to msr_mask since the versions
- * which stupidly included it in the migration stream.
- */
- target_ulong metamask = 0
-#if defined(TARGET_PPC64)
- | (1ULL << MSR_TS0)
- | (1ULL << MSR_TS1)
-#endif
- ;
- cpu->mig_msr_mask = env->msr_mask & ~metamask;
- cpu->mig_insns_flags = env->insns_flags & insns_compat_mask;
- /*
- * CPU models supported by old machines all have
- * PPC_MEM_TLBIE, so we set it unconditionally to allow
- * backward migration from a POWER9 host to a POWER8 host.
- */
- cpu->mig_insns_flags |= PPC_MEM_TLBIE;
- cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2;
- cpu->mig_nb_BATs = env->nb_BATs;
- }
- if (cpu->pre_3_0_migration) {
- if (cpu->hash64_opts) {
- cpu->mig_slb_nr = cpu->hash64_opts->slb_size;
- }
- }
-
/* Used to retain migration compatibility for pre 6.0 for 601 machines. */
env->hflags_compat_nmsr = 0;
@@ -325,7 +263,8 @@ static int cpu_post_load(void *opaque, int version_id)
/* Re-set breaks based on regs */
#if defined(TARGET_PPC64)
ppc_update_ciabr(env);
- ppc_update_daw0(env);
+ ppc_update_daw(env, 0);
+ ppc_update_daw(env, 1);
#endif
/*
* TCG needs to re-start the decrementer timer and/or raise the
@@ -549,12 +488,11 @@ static int slb_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_slb = {
.name = "cpu/slb",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.needed = slb_needed,
.post_load = slb_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_INT32_TEST(mig_slb_nr, PowerPCCPU, cpu_pre_3_0_migration),
VMSTATE_SLB_ARRAY(env.slb, PowerPCCPU, MAX_SLB_ENTRIES),
VMSTATE_END_OF_LIST()
}
@@ -621,7 +559,7 @@ static bool tlbemb_needed(void *opaque)
}
static const VMStateDescription vmstate_tlbemb = {
- .name = "cpu/tlb6xx",
+ .name = "cpu/tlbemb",
.version_id = 1,
.minimum_version_id = 1,
.needed = tlbemb_needed,
@@ -676,7 +614,7 @@ static bool compat_needed(void *opaque)
PowerPCCPU *cpu = opaque;
assert(!(cpu->compat_pvr && !cpu->vhyp));
- return !cpu->pre_2_10_migration && cpu->compat_pvr != 0;
+ return cpu->compat_pvr != 0;
}
static const VMStateDescription vmstate_compat = {
@@ -760,12 +698,6 @@ const VMStateDescription vmstate_ppc_cpu = {
/* Backward compatible internal state */
VMSTATE_UINTTL(env.hflags_compat_nmsr, PowerPCCPU),
- /* Sanity checking */
- VMSTATE_UINTTL_TEST(mig_msr_mask, PowerPCCPU, cpu_pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_insns_flags, PowerPCCPU, cpu_pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_insns_flags2, PowerPCCPU,
- cpu_pre_2_8_migration),
- VMSTATE_UINT32_TEST(mig_nb_BATs, PowerPCCPU, cpu_pre_2_8_migration),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c
index f88155a..6ab71a6 100644
--- a/target/ppc/mem_helper.c
+++ b/target/ppc/mem_helper.c
@@ -19,11 +19,13 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
+#include "exec/target_page.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "helper_regs.h"
-#include "exec/cpu_ldst.h"
+#include "accel/tcg/cpu-ldst.h"
+#include "accel/tcg/helper-retaddr.h"
+#include "accel/tcg/probe.h"
#include "internal.h"
#include "qemu/atomic128.h"
@@ -271,51 +273,59 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
}
static void dcbz_common(CPUPPCState *env, target_ulong addr,
- uint32_t opcode, bool epid, uintptr_t retaddr)
+ int mmu_idx, int dcbz_size, uintptr_t retaddr)
{
- target_ulong mask, dcbz_size = env->dcache_line_size;
- uint32_t i;
+ target_ulong mask = ~(target_ulong)(dcbz_size - 1);
void *haddr;
- int mmu_idx = epid ? PPC_TLB_EPID_STORE : ppc_env_mmu_index(env, false);
-
-#if defined(TARGET_PPC64)
- /* Check for dcbz vs dcbzl on 970 */
- if (env->excp_model == POWERPC_EXCP_970 &&
- !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
- dcbz_size = 32;
- }
-#endif
/* Align address */
- mask = ~(dcbz_size - 1);
addr &= mask;
/* Check reservation */
- if ((env->reserve_addr & mask) == addr) {
+ if (unlikely((env->reserve_addr & mask) == addr)) {
env->reserve_addr = (target_ulong)-1ULL;
}
/* Try fast path translate */
+#ifdef CONFIG_USER_ONLY
+ haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx);
+#else
haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr);
- if (haddr) {
- memset(haddr, 0, dcbz_size);
- } else {
+ if (unlikely(!haddr)) {
/* Slow path */
- for (i = 0; i < dcbz_size; i += 8) {
+ for (int i = 0; i < dcbz_size; i += 8) {
cpu_stq_mmuidx_ra(env, addr + i, 0, mmu_idx, retaddr);
}
+ return;
}
+#endif
+
+ set_helper_retaddr(retaddr);
+ memset(haddr, 0, dcbz_size);
+ clear_helper_retaddr();
}
-void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+void helper_dcbz(CPUPPCState *env, target_ulong addr, int mmu_idx)
{
- dcbz_common(env, addr, opcode, false, GETPC());
+ dcbz_common(env, addr, mmu_idx, env->dcache_line_size, GETPC());
}
-void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+#ifdef TARGET_PPC64
+void helper_dcbzl(CPUPPCState *env, target_ulong addr)
{
- dcbz_common(env, addr, opcode, true, GETPC());
+ int dcbz_size = env->dcache_line_size;
+
+ /*
+ * The translator checked for POWERPC_EXCP_970.
+ * All that's left is to check HID5.
+ */
+ if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+ dcbz_size = 32;
+ }
+
+ dcbz_common(env, addr, ppc_env_mmu_index(env, false), dcbz_size, GETPC());
}
+#endif
void helper_icbi(CPUPPCState *env, target_ulong addr)
{
@@ -467,8 +477,8 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \
*xt = t; \
}
-VSX_LXVL(lxvl, 0)
-VSX_LXVL(lxvll, 1)
+VSX_LXVL(LXVL, 0)
+VSX_LXVL(LXVLL, 1)
#undef VSX_LXVL
#define VSX_STXVL(name, lj) \
@@ -496,8 +506,8 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \
} \
}
-VSX_STXVL(stxvl, 0)
-VSX_STXVL(stxvll, 1)
+VSX_STXVL(STXVL, 0)
+VSX_STXVL(STXVLL, 1)
#undef VSX_STXVL
#undef GET_NB
#endif /* TARGET_PPC64 */
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index db3b7a0..8eed1fa 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -14,6 +14,7 @@ ppc_ss.add(when: 'CONFIG_TCG', if_true: files(
'int_helper.c',
'mem_helper.c',
'misc_helper.c',
+ 'tcg-excp_helper.c',
'timebase_helper.c',
'translate.c',
'power8-pmu.c',
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index fa47be2..e7d9462 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
-#include "exec/exec-all.h"
+#include "exec/cputlb.h"
#include "exec/helper-proto.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
@@ -48,9 +48,8 @@ void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[sprn] = val;
return;
}
@@ -195,7 +194,7 @@ void helper_store_ptcr(CPUPPCState *env, target_ulong val)
return;
}
- if (cs->nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
env->spr[SPR_PTCR] = val;
tlb_flush(cs);
} else {
@@ -234,6 +233,16 @@ void helper_store_dawrx0(CPUPPCState *env, target_ulong value)
ppc_store_dawrx0(env, value);
}
+void helper_store_dawr1(CPUPPCState *env, target_ulong value)
+{
+ ppc_store_dawr1(env, value);
+}
+
+void helper_store_dawrx1(CPUPPCState *env, target_ulong value)
+{
+ ppc_store_dawrx1(env, value);
+}
+
/*
* DPDES register is shared. Each bit reflects the state of the
* doorbell interrupt of a thread of the same core.
@@ -242,16 +251,12 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
target_ulong dpdes = 0;
helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes = 1;
}
@@ -278,21 +283,11 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (val & ~(nr_threads - 1)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value "
- TARGET_FMT_lx"\n", val);
- val &= (nr_threads - 1); /* Ignore the invalid bits */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
return;
}
@@ -303,11 +298,18 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
PowerPCCPU *ccpu = POWERPC_CPU(ccs);
uint32_t thread_id = ppc_cpu_tir(ccpu);
- ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id));
+ ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id));
}
bql_unlock();
}
+/*
+ * qemu-user breaks with pnv headers, so they go under ifdefs for now.
+ * A clean up may be to move powernv specific registers and helpers into
+ * target/ppc/pnv_helper.c
+ */
+#include "hw/ppc/pnv_core.h"
+
/* Indirect SCOM (SPRC/SPRD) access to SCRATCH0-7 are implemented. */
void helper_store_sprc(CPUPPCState *env, target_ulong val)
{
@@ -321,11 +323,39 @@ void helper_store_sprc(CPUPPCState *env, target_ulong val)
target_ulong helper_load_sprd(CPUPPCState *env)
{
+ /*
+ * SPRD is a HV-only register for Power CPUs, so this will only be
+ * accessed by powernv machines.
+ */
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
target_ulong sprc = env->spr[SPR_POWER_SPRC];
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- return env->scratch[(sprc >> 3) & 0x7];
+ if (pc->big_core) {
+ pc = pnv_chip_find_core(pc->chip, CPU_CORE(pc)->core_id & ~0x1);
+ }
+
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ return pc->scratch[(sprc >> 3) & 0x7];
+
+ case 0x1e0: /* core thread state */
+ if (env->excp_model == POWERPC_EXCP_POWER9) {
+ /*
+ * Only implement for POWER9 because skiboot uses it to check
+ * big-core mode. Other bits are unimplemented so we would
+ * prefer to get unimplemented message on POWER10 if it were
+ * used anywhere.
+ */
+ if (pc->big_core) {
+ return PPC_BIT(63);
+ } else {
+ return 0;
+ }
+ }
+ /* fallthru */
+
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
@@ -334,45 +364,88 @@ target_ulong helper_load_sprd(CPUPPCState *env)
return 0;
}
-static void do_store_scratch(CPUPPCState *env, int nr, target_ulong val)
+void helper_store_sprd(CPUPPCState *env, target_ulong val)
+{
+ target_ulong sprc = env->spr[SPR_POWER_SPRC];
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+ int nr;
+
+ if (pc->big_core) {
+ pc = pnv_chip_find_core(pc->chip, CPU_CORE(pc)->core_id & ~0x1);
+ }
+
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ /*
+ * Log stores to SCRATCH, because some firmware uses these for
+ * debugging and logging, but they would normally be read by the BMC,
+ * which is not implemented in QEMU yet. This gives a way to get at the
+ * information. Could also dump these upon checkstop.
+ */
+ nr = (sprc >> 3) & 0x7;
+ pc->scratch[nr] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "mtSPRD: Unimplemented SPRC:0x"
+ TARGET_FMT_lx"\n", sprc);
+ break;
+ }
+}
+
+target_ulong helper_load_pmsr(CPUPPCState *env)
+{
+ target_ulong lowerps = extract64(env->spr[SPR_PMCR], PPC_BIT_NR(15), 8);
+ target_ulong val = 0;
+
+ val |= PPC_BIT(63); /* verion 0x1 (POWER9/10) */
+ /* Pmin = 0 */
+ /* XXX: POWER9 should be 3 */
+ val |= 4ULL << PPC_BIT_NR(31); /* Pmax */
+ val |= lowerps << PPC_BIT_NR(15); /* Local actual Pstate */
+ val |= lowerps << PPC_BIT_NR(7); /* Global actual Pstate */
+
+ return val;
+}
+
+static void ppc_set_pmcr(PowerPCCPU *cpu, target_ulong val)
{
+ cpu->env.spr[SPR_PMCR] = val;
+}
+
+void helper_store_pmcr(CPUPPCState *env, target_ulong val)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- /*
- * Log stores to SCRATCH, because some firmware uses these for debugging
- * and logging, but they would normally be read by the BMC, which is
- * not implemented in QEMU yet. This gives a way to get at the information.
- * Could also dump these upon checkstop.
- */
- qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
+ /* Leave version field unchanged (0x1) */
+ val &= ~PPC_BITMASK(60, 63);
+ val |= PPC_BIT(63);
+
+ val &= ~PPC_BITMASK(0, 7); /* UpperPS ignored */
+ if (val & PPC_BITMASK(16, 59)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Non-zero PMCR reserved bits "
+ TARGET_FMT_lx"\n", val);
+ val &= ~PPC_BITMASK(16, 59);
+ }
- if (nr_threads == 1) {
- env->scratch[nr] = val;
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
+ ppc_set_pmcr(cpu, val);
return;
}
+ /* Does iothread need to be locked for walking CPU list? */
+ bql_lock();
THREAD_SIBLING_FOREACH(cs, ccs) {
- CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
- cenv->scratch[nr] = val;
+ PowerPCCPU *ccpu = POWERPC_CPU(ccs);
+ ppc_set_pmcr(ccpu, val);
}
+ bql_unlock();
}
-void helper_store_sprd(CPUPPCState *env, target_ulong val)
-{
- target_ulong sprc = env->spr[SPR_POWER_SPRC];
-
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- do_store_scratch(env, (sprc >> 3) & 0x7, val);
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
- TARGET_FMT_lx"\n", sprc);
- break;
- }
-}
#endif /* defined(TARGET_PPC64) */
void helper_store_pidr(CPUPPCState *env, target_ulong val)
diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c
index c8f69b3..3865556 100644
--- a/target/ppc/mmu-book3s-v3.c
+++ b/target/ppc/mmu-book3s-v3.c
@@ -18,10 +18,10 @@
*/
#include "qemu/osdep.h"
+#include "system/memory.h"
#include "cpu.h"
#include "mmu-hash64.h"
#include "mmu-book3s-v3.h"
-#include "mmu-radix64.h"
bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
{
diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h
index f3f7993..be66e26 100644
--- a/target/ppc/mmu-book3s-v3.h
+++ b/target/ppc/mmu-book3s-v3.h
@@ -20,9 +20,6 @@
#ifndef PPC_MMU_BOOK3S_V3_H
#define PPC_MMU_BOOK3S_V3_H
-#include "mmu-hash64.h"
-#include "mmu-books.h"
-
#ifndef CONFIG_USER_ONLY
/*
@@ -83,46 +80,6 @@ static inline bool ppc64_v3_radix(PowerPCCPU *cpu)
return !!(cpu->env.spr[SPR_LPCR] & LPCR_HR);
}
-static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
-{
- uint64_t base;
-
- if (cpu->vhyp) {
- return 0;
- }
- if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
- ppc_v3_pate_t pate;
-
- if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
- return 0;
- }
- base = pate.dw0;
- } else {
- base = cpu->env.spr[SPR_SDR1];
- }
- return base & SDR_64_HTABORG;
-}
-
-static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
-{
- uint64_t base;
-
- if (cpu->vhyp) {
- return cpu->vhyp_class->hpt_mask(cpu->vhyp);
- }
- if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
- ppc_v3_pate_t pate;
-
- if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
- return 0;
- }
- base = pate.dw0;
- } else {
- base = cpu->env.spr[SPR_SDR1];
- }
- return (1ULL << ((base & SDR_64_HTABSIZE) + 18 - 7)) - 1;
-}
-
#endif /* TARGET_PPC64 */
#endif /* CONFIG_USER_ONLY */
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index d5f2057..8b980a5 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -20,9 +20,9 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/page-protection.h"
-#include "sysemu/kvm.h"
+#include "exec/target_page.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
#include "internal.h"
#include "mmu-hash32.h"
@@ -37,17 +37,6 @@
# define LOG_BATS(...) do { } while (0)
#endif
-static int ppc_hash32_pte_prot(int mmu_idx,
- target_ulong sr, ppc_hash_pte32_t pte)
-{
- unsigned pp, key;
-
- key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
- pp = pte.pte1 & HPTE32_R_PP;
-
- return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
-}
-
static target_ulong hash32_bat_size(int mmu_idx,
target_ulong batu, target_ulong batl)
{
@@ -59,22 +48,6 @@ static target_ulong hash32_bat_size(int mmu_idx,
return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
}
-static int hash32_bat_prot(PowerPCCPU *cpu,
- target_ulong batu, target_ulong batl)
-{
- int pp, prot;
-
- prot = 0;
- pp = batl & BATL32_PP;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
- return prot;
-}
-
static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
MMUAccessType access_type, int *prot,
int mmu_idx)
@@ -106,7 +79,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
hwaddr raddr = (batl & mask) | (ea & ~mask);
- *prot = hash32_bat_prot(cpu, batu, batl);
+ *prot = ppc_hash32_bat_prot(batu, batl);
return raddr & TARGET_PAGE_MASK;
}
@@ -145,7 +118,6 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- int key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
@@ -206,7 +178,11 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
cpu_abort(cs, "ERROR: insn should not need address translation\n");
}
- *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
+ if (ppc_hash32_key(mmuidx_pr(mmu_idx), sr)) {
+ *prot = PAGE_READ | PAGE_WRITE;
+ } else {
+ *prot = PAGE_READ;
+ }
if (check_prot_access_type(*prot, access_type)) {
*raddr = eaddr;
return true;
@@ -225,13 +201,6 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
return false;
}
-hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
-{
- target_ulong mask = ppc_hash32_hpt_mask(cpu);
-
- return (hash * HASH_PTEG_SIZE_32) & mask;
-}
-
static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte32_t *pte)
@@ -322,15 +291,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
return pte_offset;
}
-static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
- target_ulong eaddr)
-{
- hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
- hwaddr mask = ~TARGET_PAGE_MASK;
-
- return (rpn & ~mask) | (eaddr & mask);
-}
-
bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible)
@@ -338,10 +298,10 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong sr;
- hwaddr pte_offset;
+ hwaddr pte_offset, raddr;
ppc_hash_pte32_t pte;
+ bool key;
int prot;
- hwaddr raddr;
/* There are no hash32 large pages. */
*psizep = TARGET_PAGE_BITS;
@@ -423,8 +383,8 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
"found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 7. Check access permissions */
-
- prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
+ key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
+ prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
if (!check_prot_access_type(prot, access_type)) {
/* Access right violation */
@@ -464,11 +424,12 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
*/
prot &= ~PAGE_WRITE;
}
- }
+ }
+ *protp = prot;
/* 9. Determine the real address from the PTE */
-
- *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr);
- *protp = prot;
+ *raddrp = pte.pte1 & HPTE32_R_RPN;
+ *raddrp &= TARGET_PAGE_MASK;
+ *raddrp |= eaddr & ~TARGET_PAGE_MASK;
return true;
}
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index f0ce695..04c23ea 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -3,7 +3,8 @@
#ifndef CONFIG_USER_ONLY
-hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash);
+#include "system/memory.h"
+
bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible);
@@ -102,48 +103,63 @@ static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
}
-static inline int ppc_hash32_pp_prot(bool key, int pp, bool nx)
+static inline hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
+{
+ return (hash * HASH_PTEG_SIZE_32) & ppc_hash32_hpt_mask(cpu);
+}
+
+static inline bool ppc_hash32_key(bool pr, target_ulong sr)
+{
+ return pr ? (sr & SR32_KP) : (sr & SR32_KS);
+}
+
+static inline int ppc_hash32_prot(bool key, int pp, bool nx)
{
int prot;
- if (key == 0) {
+ if (key) {
switch (pp) {
case 0x0:
- case 0x1:
- case 0x2:
- prot = PAGE_READ | PAGE_WRITE;
+ prot = 0;
break;
-
+ case 0x1:
case 0x3:
prot = PAGE_READ;
break;
-
+ case 0x2:
+ prot = PAGE_READ | PAGE_WRITE;
+ break;
default:
- abort();
+ g_assert_not_reached();
}
} else {
switch (pp) {
case 0x0:
- prot = 0;
- break;
-
case 0x1:
- case 0x3:
- prot = PAGE_READ;
- break;
-
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
-
+ case 0x3:
+ prot = PAGE_READ;
+ break;
default:
- abort();
+ g_assert_not_reached();
}
}
- if (nx == 0) {
- prot |= PAGE_EXEC;
- }
+ return nx ? prot : prot | PAGE_EXEC;
+}
+static inline int ppc_hash32_bat_prot(target_ulong batu, target_ulong batl)
+{
+ int prot = 0;
+ int pp = batl & BATL32_PP;
+
+ if (pp) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ }
return prot;
}
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index cbc8efa..dd33755 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -20,17 +20,18 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/page-protection.h"
#include "qemu/error-report.h"
#include "qemu/qemu-print.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
+#include "system/memory.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "exec/log.h"
#include "hw/hw.h"
#include "internal.h"
#include "mmu-book3s-v3.h"
+#include "mmu-books.h"
#include "helper_regs.h"
#ifdef CONFIG_TCG
@@ -508,6 +509,46 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
return prot;
}
+static hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
+{
+ uint64_t base;
+
+ if (cpu->vhyp) {
+ return 0;
+ }
+ if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
+ ppc_v3_pate_t pate;
+
+ if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
+ return 0;
+ }
+ base = pate.dw0;
+ } else {
+ base = cpu->env.spr[SPR_SDR1];
+ }
+ return base & SDR_64_HTABORG;
+}
+
+static hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
+{
+ uint64_t base;
+
+ if (cpu->vhyp) {
+ return cpu->vhyp_class->hpt_mask(cpu->vhyp);
+ }
+ if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
+ ppc_v3_pate_t pate;
+
+ if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
+ return 0;
+ }
+ base = pate.dw0;
+ } else {
+ base = cpu->env.spr[SPR_SDR1];
+ }
+ return (1ULL << ((base & SDR_64_HTABSIZE) + 18 - 7)) - 1;
+}
+
const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
hwaddr ptex, int n)
{
@@ -545,6 +586,15 @@ void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
false, n * HASH_PTE_SIZE_64);
}
+bool ppc_hash64_valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
+{
+ /* hash value/pteg group index is normalized by HPT mask */
+ if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
+ return false;
+ }
+ return true;
+}
+
static unsigned hpte_page_shift(const PPCHash64SegmentPageSizes *sps,
uint64_t pte0, uint64_t pte1)
{
@@ -943,6 +993,7 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
int exec_prot, pp_prot, amr_prot, prot;
int need_prot;
hwaddr raddr;
+ bool vrma = false;
/*
* Note on LPCR usage: 970 uses HID4, but our special variant of
@@ -972,6 +1023,7 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
}
} else if (ppc_hash64_use_vrma(env)) {
/* Emulated VRMA mode */
+ vrma = true;
slb = &vrma_slbe;
if (build_vrma_slbe(cpu, slb) != 0) {
/* Invalid VRMA setup, machine check */
@@ -1086,7 +1138,12 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
exec_prot = ppc_hash64_pte_noexec_guard(cpu, pte);
pp_prot = ppc_hash64_pte_prot(mmu_idx, slb, pte);
- amr_prot = ppc_hash64_amr_prot(cpu, pte);
+ if (vrma) {
+ /* VRMA does not check keys */
+ amr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ } else {
+ amr_prot = ppc_hash64_amr_prot(cpu, pte);
+ }
prot = exec_prot & pp_prot & amr_prot;
need_prot = check_prot_access_type(PAGE_RWX, access_type);
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index de653fc..b8fb12a 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -1,6 +1,8 @@
#ifndef MMU_HASH64_H
#define MMU_HASH64_H
+#include "exec/tswap.h"
+
#ifndef CONFIG_USER_ONLY
#ifdef TARGET_PPC64
@@ -120,6 +122,7 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
hwaddr ptex, int n);
void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
hwaddr ptex, int n);
+bool ppc_hash64_valid_ptex(PowerPCCPU *cpu, target_ulong ptex);
static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
const ppc_hash_pte64_t *hptes, int i)
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 5a02e49..33ac341 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -19,15 +19,47 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/page-protection.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
+#include "system/memory.h"
#include "kvm_ppc.h"
#include "exec/log.h"
#include "internal.h"
#include "mmu-radix64.h"
#include "mmu-book3s-v3.h"
+#include "mmu-books.h"
+
+/* Radix Partition Table Entry Fields */
+#define PATE1_R_PRTB 0x0FFFFFFFFFFFF000
+#define PATE1_R_PRTS 0x000000000000001F
+
+/* Radix Process Table Entry Fields */
+#define PRTBE_R_GET_RTS(rts) \
+ ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31)
+#define PRTBE_R_RPDB 0x0FFFFFFFFFFFFF00
+#define PRTBE_R_RPDS 0x000000000000001F
+
+/* Radix Page Directory/Table Entry Fields */
+#define R_PTE_VALID 0x8000000000000000
+#define R_PTE_LEAF 0x4000000000000000
+#define R_PTE_SW0 0x2000000000000000
+#define R_PTE_RPN 0x01FFFFFFFFFFF000
+#define R_PTE_SW1 0x0000000000000E00
+#define R_GET_SW(sw) (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7))
+#define R_PTE_R 0x0000000000000100
+#define R_PTE_C 0x0000000000000080
+#define R_PTE_ATT 0x0000000000000030
+#define R_PTE_ATT_NORMAL 0x0000000000000000
+#define R_PTE_ATT_SAO 0x0000000000000010
+#define R_PTE_ATT_NI_IO 0x0000000000000020
+#define R_PTE_ATT_TOLERANT_IO 0x0000000000000030
+#define R_PTE_EAA_PRIV 0x0000000000000008
+#define R_PTE_EAA_R 0x0000000000000004
+#define R_PTE_EAA_RW 0x0000000000000002
+#define R_PTE_EAA_X 0x0000000000000001
+#define R_PDE_NLB PRTBE_R_RPDB
+#define R_PDE_NLS PRTBE_R_RPDS
static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
vaddr eaddr,
@@ -180,6 +212,24 @@ static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
}
}
+static int ppc_radix64_get_prot_eaa(uint64_t pte)
+{
+ return (pte & R_PTE_EAA_R ? PAGE_READ : 0) |
+ (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) |
+ (pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
+}
+
+static int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
+{
+ const CPUPPCState *env = &cpu->env;
+ int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
+ int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
+
+ return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */
+ (amr & 0x1 ? 0 : PAGE_READ) |
+ (iamr & 0x1 ? 0 : PAGE_EXEC);
+}
+
static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
uint64_t pte, int *fault_cause, int *prot,
int mmu_idx, bool partition_scoped)
@@ -521,6 +571,20 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
prtbe0 = ldq_phys(cs->as, h_raddr);
}
+ /*
+ * Some Linux uses a zero process table entry in PID!=0 for kernel context
+ * without userspace in order to fault on NULL dereference, because using
+ * PIDR=0 for the kernel causes the Q0 page table to be used to translate
+ * Q3 as well. Check for that case here to avoid the invalid configuration
+ * message.
+ */
+ if (unlikely(!prtbe0)) {
+ if (guest_visible) {
+ ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
+ }
+ return 1;
+ }
+
/* Walk Radix Tree from Process Table Entry to Convert EA to RA */
*g_page_size = PRTBE_R_GET_RTS(prtbe0);
base_addr = prtbe0 & PRTBE_R_RPDB;
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index c5c04a1..6620b3d 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -3,7 +3,7 @@
#ifndef CONFIG_USER_ONLY
-#include "exec/page-protection.h"
+#ifdef TARGET_PPC64
/* Radix Quadrants */
#define R_EADDR_MASK 0x3FFFFFFFFFFFFFFF
@@ -14,61 +14,10 @@
#define R_EADDR_QUADRANT2 0x8000000000000000
#define R_EADDR_QUADRANT3 0xC000000000000000
-/* Radix Partition Table Entry Fields */
-#define PATE1_R_PRTB 0x0FFFFFFFFFFFF000
-#define PATE1_R_PRTS 0x000000000000001F
-
-/* Radix Process Table Entry Fields */
-#define PRTBE_R_GET_RTS(rts) \
- ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31)
-#define PRTBE_R_RPDB 0x0FFFFFFFFFFFFF00
-#define PRTBE_R_RPDS 0x000000000000001F
-
-/* Radix Page Directory/Table Entry Fields */
-#define R_PTE_VALID 0x8000000000000000
-#define R_PTE_LEAF 0x4000000000000000
-#define R_PTE_SW0 0x2000000000000000
-#define R_PTE_RPN 0x01FFFFFFFFFFF000
-#define R_PTE_SW1 0x0000000000000E00
-#define R_GET_SW(sw) (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7))
-#define R_PTE_R 0x0000000000000100
-#define R_PTE_C 0x0000000000000080
-#define R_PTE_ATT 0x0000000000000030
-#define R_PTE_ATT_NORMAL 0x0000000000000000
-#define R_PTE_ATT_SAO 0x0000000000000010
-#define R_PTE_ATT_NI_IO 0x0000000000000020
-#define R_PTE_ATT_TOLERANT_IO 0x0000000000000030
-#define R_PTE_EAA_PRIV 0x0000000000000008
-#define R_PTE_EAA_R 0x0000000000000004
-#define R_PTE_EAA_RW 0x0000000000000002
-#define R_PTE_EAA_X 0x0000000000000001
-#define R_PDE_NLB PRTBE_R_RPDB
-#define R_PDE_NLS PRTBE_R_RPDS
-
-#ifdef TARGET_PPC64
-
bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
bool guest_visible);
-static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
-{
- return (pte & R_PTE_EAA_R ? PAGE_READ : 0) |
- (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) |
- (pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
-}
-
-static inline int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
-{
- const CPUPPCState *env = &cpu->env;
- int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
- int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
-
- return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */
- (amr & 0x1 ? 0 : PAGE_READ) |
- (iamr & 0x1 ? 0 : PAGE_EXEC);
-}
-
#endif /* TARGET_PPC64 */
#endif /* CONFIG_USER_ONLY */
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index e254269..52d4861 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -20,12 +20,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "cpu.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "mmu-hash32.h"
-#include "exec/exec-all.h"
#include "exec/page-protection.h"
+#include "exec/target_page.h"
#include "exec/log.h"
#include "helper_regs.h"
#include "qemu/error-report.h"
@@ -37,17 +37,6 @@
/* #define DUMP_PAGE_TABLES */
-/* Context used internally during MMU translations */
-typedef struct {
- hwaddr raddr; /* Real address */
- hwaddr eaddr; /* Effective address */
- int prot; /* Protection bits */
- hwaddr hash[2]; /* Pagetable hash values */
- target_ulong ptem; /* Virtual segment ID | API */
- int key; /* Access key */
- int nx; /* Non-execute area */
-} mmu_ctx_t;
-
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = env_archcpu(env);
@@ -94,86 +83,23 @@ int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
return nr;
}
-static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h,
- MMUAccessType access_type)
-{
- target_ulong ptem, mmask;
- int ret, pteh, ptev, pp;
-
- ret = -1;
- /* Check validity and table match */
- ptev = pte_is_valid(pte0);
- pteh = (pte0 >> 6) & 1;
- if (ptev && h == pteh) {
- /* Check vsid & api */
- ptem = pte0 & PTE_PTEM_MASK;
- mmask = PTE_CHECK_MASK;
- pp = pte1 & 0x00000003;
- if (ptem == ctx->ptem) {
- if (ctx->raddr != (hwaddr)-1ULL) {
- /* all matches should have equal RPN, WIMG & PP */
- if ((ctx->raddr & mmask) != (pte1 & mmask)) {
- qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
- return -3;
- }
- }
- /* Keep the matching PTE information */
- ctx->raddr = pte1;
- ctx->prot = ppc_hash32_pp_prot(ctx->key, pp, ctx->nx);
- if (check_prot_access_type(ctx->prot, access_type)) {
- /* Access granted */
- qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
- ret = 0;
- } else {
- /* Access right violation */
- qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
- ret = -2;
- }
- }
- }
-
- return ret;
-}
-
-static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, MMUAccessType access_type)
-{
- int store = 0;
-
- /* Update page flags */
- if (!(*pte1p & 0x00000100)) {
- /* Update accessed flag */
- *pte1p |= 0x00000100;
- store = 1;
- }
- if (!(*pte1p & 0x00000080)) {
- if (access_type == MMU_DATA_STORE && ret == 0) {
- /* Update changed flag */
- *pte1p |= 0x00000080;
- store = 1;
- } else {
- /* Force page fault for first write access */
- ctx->prot &= ~PAGE_WRITE;
- }
- }
-
- return store;
-}
-
/* Software driven TLB helpers */
-static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, MMUAccessType access_type)
+static int ppc6xx_tlb_check(CPUPPCState *env, hwaddr *raddr, int *prot,
+ target_ulong eaddr, MMUAccessType access_type,
+ target_ulong ptem, bool key, bool nx)
{
ppc6xx_tlb_t *tlb;
- int nr, best, way;
- int ret;
+ target_ulong *pte1p;
+ int nr, best, way, ret;
+ bool is_code = (access_type == MMU_INST_FETCH);
+ /* Initialize real address with an invalid value */
+ *raddr = (hwaddr)-1ULL;
best = -1;
ret = -1; /* No TLB found */
for (way = 0; way < env->nb_ways; way++) {
- nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
tlb = &env->tlb.tlb6[nr];
/* This test "emulates" the PTE index match for hardware TLBs */
if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
@@ -191,37 +117,51 @@ static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
tlb->EPN, eaddr, tlb->pte1,
access_type == MMU_DATA_STORE ? 'S' : 'L',
access_type == MMU_INST_FETCH ? 'I' : 'D');
- switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
- 0, access_type)) {
- case -2:
- /* Access violation */
- ret = -2;
- best = nr;
- break;
- case -1: /* No match */
- case -3: /* TLB inconsistency */
- default:
- break;
- case 0:
- /* access granted */
- /*
- * XXX: we should go on looping to check all TLBs
- * consistency but we can speed-up the whole thing as
- * the result would be undefined if TLBs are not
- * consistent.
- */
+ /* Check validity and table match */
+ if (!pte_is_valid(tlb->pte0) || ((tlb->pte0 >> 6) & 1) != 0 ||
+ (tlb->pte0 & PTE_PTEM_MASK) != ptem) {
+ continue;
+ }
+ /* all matches should have equal RPN, WIMG & PP */
+ if (*raddr != (hwaddr)-1ULL &&
+ (*raddr & PTE_CHECK_MASK) != (tlb->pte1 & PTE_CHECK_MASK)) {
+ qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
+ /* TLB inconsistency */
+ continue;
+ }
+ /* Keep the matching PTE information */
+ best = nr;
+ *raddr = tlb->pte1;
+ *prot = ppc_hash32_prot(key, tlb->pte1 & HPTE32_R_PP, nx);
+ if (check_prot_access_type(*prot, access_type)) {
+ qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
ret = 0;
- best = nr;
- goto done;
+ break;
+ } else {
+ qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
+ ret = -2;
}
}
if (best != -1) {
-done:
qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
" prot=%01x ret=%d\n",
- ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ *raddr & TARGET_PAGE_MASK, *prot, ret);
/* Update page flags */
- pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
+ pte1p = &env->tlb.tlb6[best].pte1;
+ *pte1p |= 0x00000100; /* Update accessed flag */
+ if (!(*pte1p & 0x00000080)) {
+ if (access_type == MMU_DATA_STORE && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ } else {
+ /* Force page fault for first write access */
+ *prot &= ~PAGE_WRITE;
+ }
+ }
+ }
+ if (ret == -1) {
+ int r = is_code ? SPR_ICMP : SPR_DCMP;
+ env->spr[r] = ptem;
}
#if defined(DUMP_PAGE_TABLES)
if (qemu_loglevel_mask(CPU_LOG_MMU)) {
@@ -247,44 +187,17 @@ done:
return ret;
}
-/* Perform BAT hit & translation */
-static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp, target_ulong *BATu,
- target_ulong *BATl)
-{
- target_ulong bl;
- int pp, valid, prot;
-
- bl = (*BATu & 0x00001FFC) << 15;
- valid = 0;
- prot = 0;
- if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
- (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
- valid = 1;
- pp = *BATl & 0x00000003;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
- }
- *blp = bl;
- *validp = valid;
- *protp = prot;
-}
-
-static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, MMUAccessType access_type)
+static int get_bat_6xx_tlb(CPUPPCState *env, hwaddr *raddr, int *prot,
+ target_ulong eaddr, MMUAccessType access_type,
+ bool pr)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
- int i, valid, prot;
- int ret = -1;
+ int i, ret = -1;
bool ifetch = access_type == MMU_INST_FETCH;
qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', virtual);
+ ifetch ? 'I' : 'D', eaddr);
if (ifetch) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
@@ -295,27 +208,26 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
- if ((virtual & 0xF0000000) == BEPIu &&
- ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
- /* BAT matches */
- if (valid != 0) {
+ ifetch ? 'I' : 'D', i, eaddr, *BATu, *BATl);
+ bl = (*BATu & BATU32_BL) << 15;
+ if ((!pr && (*BATu & BATU32_VS)) || (pr && (*BATu & BATU32_VP))) {
+ if ((eaddr & BATU32_BEPIU) == BEPIu &&
+ ((eaddr & BATU32_BEPIL) & ~bl) == BEPIl) {
/* Get physical address */
- ctx->raddr = (*BATl & 0xF0000000) |
- ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
- (virtual & 0x0001F000);
+ *raddr = (*BATl & BATU32_BEPIU) |
+ ((eaddr & BATU32_BEPIL & bl) | (*BATl & BATU32_BEPIL)) |
+ (eaddr & 0x0001F000);
/* Compute access rights */
- ctx->prot = prot;
- if (check_prot_access_type(ctx->prot, access_type)) {
+ *prot = ppc_hash32_bat_prot(*BATu, *BATl);
+ if (check_prot_access_type(*prot, access_type)) {
qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
- " prot=%c%c\n", i, ctx->raddr,
- ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
+ " prot=%c%c\n", i, *raddr,
+ *prot & PAGE_READ ? 'R' : '-',
+ *prot & PAGE_WRITE ? 'W' : '-');
ret = 0;
} else {
ret = -2;
@@ -327,18 +239,18 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
if (ret < 0) {
if (qemu_log_enabled()) {
qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
- TARGET_FMT_lx ":\n", virtual);
+ TARGET_FMT_lx ":\n", eaddr);
for (i = 0; i < 4; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
+ bl = (*BATu & BATU32_BL) << 15;
qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx
" BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx
"\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " "
TARGET_FMT_lx "\n", __func__, ifetch ? 'I' : 'D',
- i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
+ i, eaddr, *BATu, *BATl, BEPIu, BEPIl, bl);
}
}
}
@@ -346,32 +258,30 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr,
+static int mmu6xx_get_physical_address(CPUPPCState *env, hwaddr *raddr,
+ int *prot, target_ulong eaddr,
+ hwaddr *hashp, bool *keyp,
MMUAccessType access_type, int type)
{
PowerPCCPU *cpu = env_archcpu(env);
hwaddr hash;
- target_ulong vsid, sr, pgidx;
- int ds, target_page_bits;
- bool pr;
+ target_ulong vsid, sr, pgidx, ptem;
+ bool key, ds, nx;
+ bool pr = FIELD_EX64(env->msr, MSR, PR);
/* First try to find a BAT entry if there are any */
- if (env->nb_BATs && get_bat_6xx_tlb(env, ctx, eaddr, access_type) == 0) {
+ if (env->nb_BATs &&
+ get_bat_6xx_tlb(env, raddr, prot, eaddr, access_type, pr) == 0) {
return 0;
}
/* Perform segment based translation when no BATs matched */
- pr = FIELD_EX64(env->msr, MSR, PR);
- ctx->eaddr = eaddr;
-
sr = env->sr[eaddr >> 28];
- ctx->key = (((sr & 0x20000000) && pr) ||
- ((sr & 0x40000000) && !pr)) ? 1 : 0;
- ds = sr & 0x80000000 ? 1 : 0;
- ctx->nx = sr & 0x10000000 ? 1 : 0;
- vsid = sr & 0x00FFFFFF;
- target_page_bits = TARGET_PAGE_BITS;
+ key = ppc_hash32_key(pr, sr);
+ *keyp = key;
+ ds = sr & SR32_T;
+ nx = sr & SR32_NX;
+ vsid = sr & SR32_VSID;
qemu_log_mask(CPU_LOG_MMU,
"Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
" nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
@@ -380,15 +290,15 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
(int)FIELD_EX64(env->msr, MSR, IR),
(int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
access_type == MMU_DATA_STORE, type);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
+ ptem = (vsid << 7) | (pgidx >> 10); /* Virtual segment ID | API */
qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
- TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
+ TARGET_FMT_lx "\n", key, ds, nx, vsid);
if (!ds) {
/* Check if instruction fetch is allowed, if needed */
- if (type == ACCESS_CODE && ctx->nx) {
+ if (type == ACCESS_CODE && nx) {
qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
return -3;
}
@@ -396,13 +306,11 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask "
HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n",
ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
+ *hashp = hash;
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
/* Software TLB search */
- return ppc6xx_tlb_check(env, ctx, eaddr, access_type);
+ return ppc6xx_tlb_check(env, raddr, prot, eaddr,
+ access_type, ptem, key, nx);
}
/* Direct-store segment : absolutely *BUGGY* for now */
@@ -411,15 +319,6 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
case ACCESS_INT:
/* Integer load/store : only access allowed */
break;
- case ACCESS_CODE:
- /* No code fetch is allowed in direct-store areas */
- return -4;
- case ACCESS_FLOAT:
- /* Floating point load/store */
- return -4;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- return -4;
case ACCESS_CACHE:
/*
* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
@@ -427,19 +326,17 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
* Should make the instruction do no-op. As it already do
* no-op, it's quite easy :-)
*/
- ctx->raddr = eaddr;
+ *raddr = eaddr;
return 0;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- return -4;
- default:
- qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need address"
- " translation\n");
+ case ACCESS_CODE: /* No code fetch is allowed in direct-store areas */
+ case ACCESS_FLOAT: /* Floating point load/store */
+ case ACCESS_RES: /* lwarx, ldarx or srwcx. */
+ case ACCESS_EXT: /* eciwx or ecowx */
return -4;
}
- if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
- (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
- ctx->raddr = eaddr;
+ if ((access_type == MMU_DATA_STORE || !key) &&
+ (access_type == MMU_DATA_LOAD || key)) {
+ *raddr = eaddr;
return 2;
}
return -2;
@@ -589,9 +486,9 @@ static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
+ bl = (*BATu & BATU32_BL) << 15;
qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
TARGET_FMT_lx " " TARGET_FMT_lx "\n",
@@ -777,9 +674,9 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- mmu_ctx_t ctx;
- int type;
- int ret;
+ hwaddr hash = 0; /* init to 0 to avoid used uninit warning */
+ bool key;
+ int type, ret;
if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
return true;
@@ -795,13 +692,9 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
type = ACCESS_INT;
}
- ctx.prot = 0;
- ctx.hash[0] = 0;
- ctx.hash[1] = 0;
- ret = mmu6xx_get_physical_address(env, &ctx, eaddr, access_type, type);
+ ret = mmu6xx_get_physical_address(env, raddrp, protp, eaddr, &hash, &key,
+ access_type, type);
if (ret == 0) {
- *raddrp = ctx.raddr;
- *protp = ctx.prot;
*psizep = TARGET_PAGE_BITS;
return true;
} else if (!guest_visible) {
@@ -816,7 +709,7 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
cs->exception_index = POWERPC_EXCP_IFTLB;
env->error_code = 1 << 18;
env->spr[SPR_IMISS] = eaddr;
- env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+ env->spr[SPR_ICMP] |= 0x80000000;
goto tlb_miss;
case -2:
/* Access rights violation */
@@ -847,13 +740,13 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
env->error_code = 0;
}
env->spr[SPR_DMISS] = eaddr;
- env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+ env->spr[SPR_DCMP] |= 0x80000000;
tlb_miss:
- env->error_code |= ctx.key << 19;
+ env->error_code |= key << 19;
env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
- get_pteg_offset32(cpu, ctx.hash[0]);
+ get_pteg_offset32(cpu, hash);
env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
- get_pteg_offset32(cpu, ctx.hash[1]);
+ get_pteg_offset32(cpu, ~hash);
break;
case -2:
/* Access rights violation */
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index b0a0676..ac60705 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -20,12 +20,13 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "cpu.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "mmu-hash32.h"
-#include "exec/exec-all.h"
+#include "exec/cputlb.h"
#include "exec/page-protection.h"
+#include "exec/target_page.h"
#include "exec/log.h"
#include "helper_regs.h"
#include "qemu/error-report.h"
@@ -35,7 +36,7 @@
#include "mmu-radix64.h"
#include "mmu-booke.h"
#include "exec/helper-proto.h"
-#include "exec/cpu_ldst.h"
+#include "accel/tcg/cpu-ldst.h"
/* #define FLUSH_ALL_TLBS */
@@ -316,7 +317,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
break;
default:
/* Should never reach here with other MMU models */
- assert(0);
+ g_assert_not_reached();
}
#else
ppc_tlb_invalidate_all(env);
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index db9ee8e..2a7a5b4 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -13,7 +13,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "helper_regs.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
diff --git a/target/ppc/ppc-qmp-cmds.c b/target/ppc/ppc-qmp-cmds.c
index a25d86a..7022564 100644
--- a/target/ppc/ppc-qmp-cmds.c
+++ b/target/ppc/ppc-qmp-cmds.c
@@ -28,7 +28,8 @@
#include "qemu/ctype.h"
#include "monitor/hmp-target.h"
#include "monitor/hmp.h"
-#include "qapi/qapi-commands-machine-target.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
#include "cpu-models.h"
#include "cpu-qom.h"
@@ -175,6 +176,15 @@ int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval)
return -EINVAL;
}
+CpuModelExpansionInfo *
+qmp_query_cpu_model_expansion(CpuModelExpansionType type,
+ CpuModelInfo *model,
+ Error **errp)
+{
+ error_setg(errp, "CPU model expansion is not supported on this target");
+ return NULL;
+}
+
static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
diff --git a/target/ppc/spr_common.h b/target/ppc/spr_common.h
index 01aff44..84c910c 100644
--- a/target/ppc/spr_common.h
+++ b/target/ppc/spr_common.h
@@ -165,6 +165,8 @@ void spr_write_cfar(DisasContext *ctx, int sprn, int gprn);
void spr_write_ciabr(DisasContext *ctx, int sprn, int gprn);
void spr_write_dawr0(DisasContext *ctx, int sprn, int gprn);
void spr_write_dawrx0(DisasContext *ctx, int sprn, int gprn);
+void spr_write_dawr1(DisasContext *ctx, int sprn, int gprn);
+void spr_write_dawrx1(DisasContext *ctx, int sprn, int gprn);
void spr_write_ureg(DisasContext *ctx, int sprn, int gprn);
void spr_read_purr(DisasContext *ctx, int gprn, int sprn);
void spr_write_purr(DisasContext *ctx, int sprn, int gprn);
@@ -204,6 +206,8 @@ void spr_write_hmer(DisasContext *ctx, int sprn, int gprn);
void spr_read_tfmr(DisasContext *ctx, int gprn, int sprn);
void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn);
void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_pmsr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_pmcr(DisasContext *ctx, int sprn, int gprn);
void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn);
void spr_read_ppr32(DisasContext *ctx, int sprn, int gprn);
void spr_write_ppr32(DisasContext *ctx, int sprn, int gprn);
diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
new file mode 100644
index 0000000..f835be5
--- /dev/null
+++ b/target/ppc/tcg-excp_helper.c
@@ -0,0 +1,851 @@
+/*
+ * 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 "qemu/main-loop.h"
+#include "qemu/log.h"
+#include "target/ppc/cpu.h"
+#include "accel/tcg/cpu-ldst.h"
+#include "exec/helper-proto.h"
+#include "system/runstate.h"
+
+#include "helper_regs.h"
+#include "hw/ppc/ppc.h"
+#include "internal.h"
+#include "cpu.h"
+#include "trace.h"
+
+/*****************************************************************************/
+/* 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 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
+
+static G_NORETURN void raise_exception_err(CPUPPCState *env, uint32_t exception,
+ uint32_t error_code)
+{
+ raise_exception_err_ra(env, exception, error_code, 0);
+}
+
+static G_NORETURN void raise_exception(CPUPPCState *env, uint32_t exception)
+{
+ raise_exception_err_ra(env, exception, 0, 0);
+}
+
+#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
+
+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);
+ bool wt, wti, hv, sv, pr;
+ uint32_t dawrx;
+
+ if ((env->insns_flags2 & PPC2_ISA207S) &&
+ (wp == env->dawr_watchpoint[0])) {
+ dawrx = env->spr[SPR_DAWRX0];
+ } else if ((env->insns_flags2 & PPC2_ISA310) &&
+ (wp == env->dawr_watchpoint[1])) {
+ dawrx = env->spr[SPR_DAWRX1];
+ } else {
+ return false;
+ }
+
+ wt = extract32(dawrx, PPC_BIT_NR(59), 1);
+ wti = extract32(dawrx, PPC_BIT_NR(60), 1);
+ hv = extract32(dawrx, PPC_BIT_NR(61), 1);
+ sv = extract32(dawrx, PPC_BIT_NR(62), 1);
+ 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)) {
+ return wt;
+ } else {
+ return !wt;
+ }
+ }
+
+ return true;
+#endif
+
+ return false;
+}
+
+/*
+ * 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.
+ */
+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);
+}
+
+/* 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));
+}
+
+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;
+}
+
+#if defined(TARGET_PPC64)
+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);
+ }
+}
+
+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 */
+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);
+}
+
+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]);
+}
+
+/* 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;
+}
+
+/*
+ * Send an interrupt to a thread in the same core as env).
+ */
+static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
+ CPUState *cs = env_cpu(env);
+
+ if (ppc_cpu_lpar_single_threaded(cs)) {
+ if (target_tir == 0) {
+ ppc_set_irq(cpu, irq, 1);
+ }
+ } else {
+ CPUState *ccs;
+
+ /* Does iothread need to be locked for walking CPU list? */
+ bql_lock();
+ THREAD_SIBLING_FOREACH(cs, ccs) {
+ PowerPCCPU *ccpu = POWERPC_CPU(ccs);
+ if (target_tir == ppc_cpu_tir(ccpu)) {
+ ppc_set_irq(ccpu, irq, 1);
+ break;
+ }
+ }
+ bql_unlock();
+ }
+}
+
+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;
+ }
+
+ /* POWER8 msgsnd is like msgsndp (targets a thread within core) */
+ if (!(env->insns_flags2 & PPC2_ISA300)) {
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL);
+ return;
+ }
+
+ /* POWER9 and later msgsnd is a global (targets any thread) */
+ 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 (ppc_cpu_core_single_threaded(cs) || !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)
+{
+ helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
+
+ if (!dbell_type_server(rb)) {
+ return;
+ }
+
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL);
+}
+#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);
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 39d3974..7209b41 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -20,7 +20,6 @@
#include "cpu.h"
#include "hw/ppc/ppc.h"
#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
@@ -62,9 +61,8 @@ void helper_store_purr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_purr(env, val);
return;
}
@@ -81,9 +79,8 @@ void helper_store_tbl(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbl(env, val);
return;
}
@@ -98,9 +95,8 @@ void helper_store_tbu(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu(env, val);
return;
}
@@ -140,9 +136,8 @@ void helper_store_hdecr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_hdecr(env, val);
return;
}
@@ -157,9 +152,8 @@ void helper_store_vtb(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_vtb(env, val);
return;
}
@@ -174,9 +168,8 @@ void helper_store_tbu40(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu40(env, val);
return;
}
@@ -217,7 +210,14 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong val)
store_booke_tsr(env, val);
}
-#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+/*
+ * qemu-user breaks with pnv headers, so they go under ifdefs for now.
+ * A clean up may be to move powernv specific registers and helpers into
+ * target/ppc/pnv_helper.c
+ */
+#include "hw/ppc/pnv_core.h"
+#include "hw/ppc/pnv_chip.h"
/*
* POWER processor Timebase Facility
*/
@@ -287,7 +287,7 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
- if (cs->nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[SPR_TFMR] = val;
} else {
CPUState *ccs;
@@ -298,8 +298,25 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
}
}
+static PnvCoreTODState *cpu_get_tbst(PowerPCCPU *cpu)
+{
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+
+ if (pc->big_core && pc->tod_state.big_core_quirk) {
+ /* Must operate on the even small core */
+ int core_id = CPU_CORE(pc)->core_id;
+ if (core_id & 1) {
+ pc = pc->chip->cores[core_id & ~1];
+ }
+ }
+
+ return &pc->tod_state;
+}
+
static void tb_state_machine_step(CPUPPCState *env)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -307,15 +324,15 @@ static void tb_state_machine_step(CPUPPCState *env)
return;
}
- if (env->pnv_tod_tbst.tb_sync_pulse_timer) {
- env->pnv_tod_tbst.tb_sync_pulse_timer--;
+ if (tod_state->tb_sync_pulse_timer) {
+ tod_state->tb_sync_pulse_timer--;
} else {
tfmr |= TFMR_TB_SYNC_OCCURED;
write_tfmr(env, tfmr);
}
- if (env->pnv_tod_tbst.tb_state_timer) {
- env->pnv_tod_tbst.tb_state_timer--;
+ if (tod_state->tb_state_timer) {
+ tod_state->tb_state_timer--;
return;
}
@@ -332,20 +349,20 @@ static void tb_state_machine_step(CPUPPCState *env)
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_SYNC_WAIT) {
tfmr = tfmr_new_tb_state(tfmr, TBST_GET_TOD);
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tbst == TBST_GET_TOD) {
- if (env->pnv_tod_tbst.tod_sent_to_tb) {
+ if (tod_state->tod_sent_to_tb) {
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_RUNNING);
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
}
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"state machine in invalid state 0x%x\n", tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
@@ -361,6 +378,8 @@ target_ulong helper_load_tfmr(CPUPPCState *env)
void helper_store_tfmr(CPUPPCState *env, target_ulong val)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
uint64_t clear_on_write;
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -384,14 +403,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
* after the second mfspr.
*/
tfmr &= ~TFMR_TB_SYNC_OCCURED;
- env->pnv_tod_tbst.tb_sync_pulse_timer = 1;
-
- if (ppc_cpu_tir(env_archcpu(env)) != 0 &&
- (val & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB))) {
- qemu_log_mask(LOG_UNIMP, "TFMR timebase state machine can only be "
- "driven by thread 0\n");
- goto out;
- }
+ tod_state->tb_sync_pulse_timer = 1;
if (((tfmr | val) & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) ==
(TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) {
@@ -399,7 +411,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
"MOVE_CHIP_TOD_TO_TB both set\n");
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
goto out;
}
@@ -413,8 +425,8 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
tfmr &= ~TFMR_LOAD_TOD_MOD;
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
tfmr &= ~TFMR_FIRMWARE_CONTROL_ERROR; /* XXX: should this be cleared? */
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
goto out;
}
@@ -427,19 +439,19 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
if (tfmr & TFMR_LOAD_TOD_MOD) {
/* Wait for an arbitrary 3 mfspr until the next state transition. */
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_NOT_SET) {
tfmr = tfmr_new_tb_state(tfmr, TBST_SYNC_WAIT);
- env->pnv_tod_tbst.tb_ready_for_tod = 1;
- env->pnv_tod_tbst.tb_state_timer = 3; /* arbitrary */
+ tod_state->tb_ready_for_tod = 1;
+ tod_state->tb_state_timer = 3; /* arbitrary */
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"not in TB not set state 0x%x\n",
tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 0bc16d7..27f90c3 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -21,7 +21,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
-#include "exec/exec-all.h"
+#include "exec/target_page.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "qemu/host-utils.h"
@@ -30,6 +30,7 @@
#include "exec/helper-gen.h"
#include "exec/translator.h"
+#include "exec/translation-block.h"
#include "exec/log.h"
#include "qemu/atomic128.h"
#include "spr_common.h"
@@ -178,6 +179,7 @@ struct DisasContext {
/* Translation flags */
MemOp default_tcg_memop_mask;
#if defined(TARGET_PPC64)
+ powerpc_excp_t excp_model;
bool sf_mode;
bool has_cfar;
bool has_bhrb;
@@ -635,6 +637,18 @@ void spr_write_dawrx0(DisasContext *ctx, int sprn, int gprn)
translator_io_start(&ctx->base);
gen_helper_store_dawrx0(tcg_env, cpu_gpr[gprn]);
}
+
+void spr_write_dawr1(DisasContext *ctx, int sprn, int gprn)
+{
+ translator_io_start(&ctx->base);
+ gen_helper_store_dawr1(tcg_env, cpu_gpr[gprn]);
+}
+
+void spr_write_dawrx1(DisasContext *ctx, int sprn, int gprn)
+{
+ translator_io_start(&ctx->base);
+ gen_helper_store_dawrx1(tcg_env, cpu_gpr[gprn]);
+}
#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
/* CTR */
@@ -1324,6 +1338,22 @@ void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
translator_io_start(&ctx->base);
gen_helper_store_lpcr(tcg_env, cpu_gpr[gprn]);
}
+
+void spr_read_pmsr(DisasContext *ctx, int gprn, int sprn)
+{
+ translator_io_start(&ctx->base);
+ gen_helper_load_pmsr(cpu_gpr[gprn], tcg_env);
+}
+
+void spr_write_pmcr(DisasContext *ctx, int sprn, int gprn)
+{
+ if (!gen_serialize_core_lpar(ctx)) {
+ return;
+ }
+ translator_io_start(&ctx->base);
+ gen_helper_store_pmcr(tcg_env, cpu_gpr[gprn]);
+}
+
#endif /* !defined(CONFIG_USER_ONLY) */
void spr_read_tar(DisasContext *ctx, int gprn, int sprn)
@@ -1587,16 +1617,13 @@ static opc_handler_t invalid_handler = {
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
{
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
TCGv_i32 t = tcg_temp_new_i32();
- tcg_gen_movi_tl(t0, CRF_EQ);
- tcg_gen_movi_tl(t1, CRF_LT);
tcg_gen_movcond_tl((s ? TCG_COND_LT : TCG_COND_LTU),
- t0, arg0, arg1, t1, t0);
- tcg_gen_movi_tl(t1, CRF_GT);
+ t0, arg0, arg1,
+ tcg_constant_tl(CRF_LT), tcg_constant_tl(CRF_EQ));
tcg_gen_movcond_tl((s ? TCG_COND_GT : TCG_COND_GTU),
- t0, arg0, arg1, t1, t0);
+ t0, arg0, arg1, tcg_constant_tl(CRF_GT), t0);
tcg_gen_trunc_tl_i32(t, t0);
tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so);
@@ -1718,11 +1745,10 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_mov_tl(ca32, ca);
}
} else {
- TCGv zero = tcg_constant_tl(0);
if (add_ca) {
- tcg_gen_add2_tl(t0, ca, arg1, zero, ca, zero);
- tcg_gen_add2_tl(t0, ca, t0, ca, arg2, zero);
+ tcg_gen_addcio_tl(t0, ca, arg1, arg2, ca);
} else {
+ TCGv zero = tcg_constant_tl(0);
tcg_gen_add2_tl(t0, ca, arg1, zero, arg2, zero);
}
gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, ca32, 0);
@@ -1822,7 +1848,7 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret,
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
- if (unlikely(Rc(ctx->opcode) != 0)) {
+ if (unlikely(compute_rc0)) {
gen_set_Rc0(ctx, ret);
}
}
@@ -1921,11 +1947,9 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_mov_tl(cpu_ca32, cpu_ca);
}
} else if (add_ca) {
- TCGv zero, inv1 = tcg_temp_new();
+ TCGv inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
- zero = tcg_constant_tl(0);
- tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
- tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
+ tcg_gen_addcio_tl(t0, cpu_ca, arg2, inv1, cpu_ca);
gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, cpu_ca32, 0);
} else {
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
@@ -2542,6 +2566,7 @@ static inline void gen_align_no_le(DisasContext *ctx)
(ctx->opcode & 0x03FF0000) | POWERPC_EXCP_ALIGN_LE);
}
+/* EA <- {(ra == 0) ? 0 : GPR[ra]} + displ */
static TCGv do_ea_calc(DisasContext *ctx, int ra, TCGv displ)
{
TCGv ea = tcg_temp_new();
@@ -2556,6 +2581,22 @@ static TCGv do_ea_calc(DisasContext *ctx, int ra, TCGv displ)
return ea;
}
+#if defined(TARGET_PPC64)
+/* EA <- (ra == 0) ? 0 : GPR[ra] */
+static TCGv do_ea_calc_ra(DisasContext *ctx, int ra)
+{
+ TCGv EA = tcg_temp_new();
+ if (!ra) {
+ tcg_gen_movi_tl(EA, 0);
+ } else if (NARROW_MODE(ctx)) {
+ tcg_gen_ext32u_tl(EA, cpu_gpr[ra]);
+ } else {
+ tcg_gen_mov_tl(EA, cpu_gpr[ra]);
+ }
+ return EA;
+}
+#endif
+
/*** Integer load ***/
#define DEF_MEMOP(op) ((op) | ctx->default_tcg_memop_mask)
#define BSWAP_MEMOP(op) ((op) | (ctx->default_tcg_memop_mask ^ MO_BSWAP))
@@ -2956,8 +2997,8 @@ static void gen_fetch_inc_conditional(DisasContext *ctx, MemOp memop,
tcg_gen_qemu_st_tl(u, EA, ctx->mem_idx, memop);
/* RT = (t != t2 ? t : u = 1<<(s*8-1)) */
- tcg_gen_movi_tl(u, 1 << (memop_size(memop) * 8 - 1));
- tcg_gen_movcond_tl(cond, cpu_gpr[rD(ctx->opcode)], t, t2, t, u);
+ tcg_gen_movcond_tl(cond, cpu_gpr[rD(ctx->opcode)], t, t2, t,
+ tcg_constant_tl(1 << (memop_size(memop) * 8 - 1)));
}
static void gen_ld_atomic(DisasContext *ctx, MemOp memop)
@@ -3583,7 +3624,6 @@ static void pmu_count_insns(DisasContext *ctx)
#else
static void pmu_count_insns(DisasContext *ctx)
{
- return;
}
#endif /* #if defined(TARGET_PPC64) */
@@ -4445,27 +4485,29 @@ static void gen_dcblc(DisasContext *ctx)
/* dcbz */
static void gen_dcbz(DisasContext *ctx)
{
- TCGv tcgv_addr;
- TCGv_i32 tcgv_op;
+ TCGv tcgv_addr = tcg_temp_new();
gen_set_access_type(ctx, ACCESS_CACHE);
- tcgv_addr = tcg_temp_new();
- tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000);
gen_addr_reg_index(ctx, tcgv_addr);
- gen_helper_dcbz(tcg_env, tcgv_addr, tcgv_op);
+
+#ifdef TARGET_PPC64
+ if (ctx->excp_model == POWERPC_EXCP_970 && !(ctx->opcode & 0x00200000)) {
+ gen_helper_dcbzl(tcg_env, tcgv_addr);
+ return;
+ }
+#endif
+
+ gen_helper_dcbz(tcg_env, tcgv_addr, tcg_constant_i32(ctx->mem_idx));
}
/* dcbzep */
static void gen_dcbzep(DisasContext *ctx)
{
- TCGv tcgv_addr;
- TCGv_i32 tcgv_op;
+ TCGv tcgv_addr = tcg_temp_new();
gen_set_access_type(ctx, ACCESS_CACHE);
- tcgv_addr = tcg_temp_new();
- tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000);
gen_addr_reg_index(ctx, tcgv_addr);
- gen_helper_dcbzep(tcg_env, tcgv_addr, tcgv_op);
+ gen_helper_dcbz(tcg_env, tcgv_addr, tcg_constant_i32(PPC_TLB_EPID_STORE));
}
/* dst / dstt */
@@ -5538,16 +5580,6 @@ static inline void set_fpr(int regno, TCGv_i64 src)
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env, vsr64_offset(regno, false));
}
-static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
-{
- tcg_gen_ld_i64(dst, tcg_env, avr64_offset(regno, high));
-}
-
-static inline void set_avr64(int regno, TCGv_i64 src, bool high)
-{
- tcg_gen_st_i64(src, tcg_env, avr64_offset(regno, high));
-}
-
/*
* Helpers for decodetree used by !function for decoding arguments.
*/
@@ -6416,8 +6448,6 @@ static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn)
opc_handler_t **table, *handler;
uint32_t inval;
- ctx->opcode = insn;
-
LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
insn, opc1(insn), opc2(insn), opc3(insn), opc4(insn),
ctx->le_mode ? "little" : "big");
@@ -6486,6 +6516,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#if defined(TARGET_PPC64)
+ ctx->excp_model = env->excp_model;
ctx->sf_mode = (hflags >> HFLAGS_64) & 1;
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
ctx->has_bhrb = !!(env->flags & POWERPC_FLAG_BHRB);
@@ -6550,6 +6581,7 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
ctx->base.pc_next = pc += 4;
if (!is_prefix_insn(ctx, insn)) {
+ ctx->opcode = insn;
ok = (decode_insn32(ctx, insn) ||
decode_legacy(cpu, ctx, insn));
} else if ((pc & 63) == 0) {
@@ -6661,8 +6693,8 @@ static const TranslatorOps ppc_tr_ops = {
.tb_stop = ppc_tr_tb_stop,
};
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
- vaddr pc, void *host_pc)
+void ppc_translate_code(CPUState *cs, TranslationBlock *tb,
+ int *max_insns, vaddr pc, void *host_pc)
{
DisasContext ctx;
diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
index 8084af7..92d6e8c 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -14,25 +14,39 @@ static inline TCGv_ptr gen_avr_ptr(int reg)
return r;
}
+static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
+{
+ tcg_gen_ld_i64(dst, tcg_env, avr64_offset(regno, high));
+}
+
+static inline void set_avr64(int regno, TCGv_i64 src, bool high)
+{
+ tcg_gen_st_i64(src, tcg_env, avr64_offset(regno, high));
+}
+
+static inline void get_avr_full(TCGv_i128 dst, int regno)
+{
+ tcg_gen_ld_i128(dst, tcg_env, avr_full_offset(regno));
+}
+
+static inline void set_avr_full(int regno, TCGv_i128 src)
+{
+ tcg_gen_st_i128(src, tcg_env, avr_full_offset(regno));
+}
+
static bool trans_LVX(DisasContext *ctx, arg_X *a)
{
TCGv EA;
- TCGv_i64 avr;
+ TCGv_i128 avr;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
- avr = tcg_temp_new_i64();
+ avr = tcg_temp_new_i128();
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_andi_tl(EA, EA, ~0xf);
- /*
- * We only need to swap high and low halves. gen_qemu_ld64_i64
- * does necessary 64-bit byteswap already.
- */
- gen_qemu_ld64_i64(ctx, avr, EA);
- set_avr64(a->rt, avr, !ctx->le_mode);
- tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, avr, EA);
- set_avr64(a->rt, avr, ctx->le_mode);
+ tcg_gen_qemu_ld_i128(avr, EA, ctx->mem_idx,
+ DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR));
+ set_avr_full(a->rt, avr);
return true;
}
@@ -46,22 +60,16 @@ static bool trans_LVXL(DisasContext *ctx, arg_LVXL *a)
static bool trans_STVX(DisasContext *ctx, arg_STVX *a)
{
TCGv EA;
- TCGv_i64 avr;
+ TCGv_i128 avr;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
- avr = tcg_temp_new_i64();
+ avr = tcg_temp_new_i128();
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_andi_tl(EA, EA, ~0xf);
- /*
- * We only need to swap high and low halves. gen_qemu_st64_i64
- * does necessary 64-bit byteswap already.
- */
- get_avr64(avr, a->rt, !ctx->le_mode);
- gen_qemu_st64_i64(ctx, avr, EA);
- tcg_gen_addi_tl(EA, EA, 8);
- get_avr64(avr, a->rt, ctx->le_mode);
- gen_qemu_st64_i64(ctx, avr, EA);
+ get_avr_full(avr, a->rt);
+ tcg_gen_qemu_st_i128(avr, EA, ctx->mem_idx,
+ DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR));
return true;
}
@@ -986,8 +994,8 @@ static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
{
TCGv_i64 ah, al, vrb, n, t0, t1, zero = tcg_constant_i64(0);
- REQUIRE_VECTOR(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA310);
+ REQUIRE_VECTOR(ctx);
ah = tcg_temp_new_i64();
al = tcg_temp_new_i64();
@@ -1047,58 +1055,6 @@ TRANS(VRLQ, do_vector_rotl_quad, false, false)
TRANS(VRLQNM, do_vector_rotl_quad, true, false)
TRANS(VRLQMI, do_vector_rotl_quad, false, true)
-#define GEN_VXFORM_SAT(NAME, VECE, NORM, SAT, OPC2, OPC3) \
-static void glue(glue(gen_, NAME), _vec)(unsigned vece, TCGv_vec t, \
- TCGv_vec sat, TCGv_vec a, \
- TCGv_vec b) \
-{ \
- TCGv_vec x = tcg_temp_new_vec_matching(t); \
- glue(glue(tcg_gen_, NORM), _vec)(VECE, x, a, b); \
- glue(glue(tcg_gen_, SAT), _vec)(VECE, t, a, b); \
- tcg_gen_cmp_vec(TCG_COND_NE, VECE, x, x, t); \
- tcg_gen_or_vec(VECE, sat, sat, x); \
-} \
-static void glue(gen_, NAME)(DisasContext *ctx) \
-{ \
- static const TCGOpcode vecop_list[] = { \
- glue(glue(INDEX_op_, NORM), _vec), \
- glue(glue(INDEX_op_, SAT), _vec), \
- INDEX_op_cmp_vec, 0 \
- }; \
- static const GVecGen4 g = { \
- .fniv = glue(glue(gen_, NAME), _vec), \
- .fno = glue(gen_helper_, NAME), \
- .opt_opc = vecop_list, \
- .write_aofs = true, \
- .vece = VECE, \
- }; \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- tcg_gen_gvec_4(avr_full_offset(rD(ctx->opcode)), \
- offsetof(CPUPPCState, vscr_sat), \
- avr_full_offset(rA(ctx->opcode)), \
- avr_full_offset(rB(ctx->opcode)), \
- 16, 16, &g); \
-}
-
-GEN_VXFORM_SAT(vaddubs, MO_8, add, usadd, 0, 8);
-GEN_VXFORM_DUAL_EXT(vaddubs, PPC_ALTIVEC, PPC_NONE, 0, \
- vmul10uq, PPC_NONE, PPC2_ISA300, 0x0000F800)
-GEN_VXFORM_SAT(vadduhs, MO_16, add, usadd, 0, 9);
-GEN_VXFORM_DUAL(vadduhs, PPC_ALTIVEC, PPC_NONE, \
- vmul10euq, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_SAT(vadduws, MO_32, add, usadd, 0, 10);
-GEN_VXFORM_SAT(vaddsbs, MO_8, add, ssadd, 0, 12);
-GEN_VXFORM_SAT(vaddshs, MO_16, add, ssadd, 0, 13);
-GEN_VXFORM_SAT(vaddsws, MO_32, add, ssadd, 0, 14);
-GEN_VXFORM_SAT(vsububs, MO_8, sub, ussub, 0, 24);
-GEN_VXFORM_SAT(vsubuhs, MO_16, sub, ussub, 0, 25);
-GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
-GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
-GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
-GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
GEN_VXFORM_TRANS(vsl, 2, 7);
GEN_VXFORM_TRANS(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
@@ -2641,26 +2597,14 @@ static void gen_xpnd04_2(DisasContext *ctx)
}
}
-
-GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \
- xpnd04_2, PPC_NONE, PPC2_ISA300)
-
GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
- bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
- bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vaddshs, PPC_ALTIVEC, PPC_NONE, \
- bcdcpsgn, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubudm, PPC2_ALTIVEC_207, PPC_NONE, \
bcds, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
bcdus, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
- bcdtrunc, PPC_NONE, PPC2_ISA300)
static void gen_vsbox(DisasContext *ctx)
{
@@ -2937,6 +2881,180 @@ static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add)
TRANS(VSUBCUW, do_vx_vaddsubcuw, 0)
TRANS(VADDCUW, do_vx_vaddsubcuw, 1)
+/* Integer Add/Sub Saturate Instructions */
+static inline void do_vadd_vsub_sat
+(
+ unsigned vece, TCGv_vec t, TCGv_vec qc, TCGv_vec a, TCGv_vec b,
+ void (*norm_op)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec),
+ void (*sat_op)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec))
+{
+ TCGv_vec x = tcg_temp_new_vec_matching(t);
+ norm_op(vece, x, a, b);
+ sat_op(vece, t, a, b);
+ tcg_gen_xor_vec(vece, x, x, t);
+ tcg_gen_or_vec(vece, qc, qc, x);
+}
+
+static void gen_vadd_sat_u(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_add_vec, tcg_gen_usadd_vec);
+}
+
+static void gen_vadd_sat_s(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_add_vec, tcg_gen_ssadd_vec);
+}
+
+static void gen_vsub_sat_u(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_sub_vec, tcg_gen_ussub_vec);
+}
+
+static void gen_vsub_sat_s(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_sub_vec, tcg_gen_sssub_vec);
+}
+
+/*
+ * Signed/Unsigned add/sub helper ops for byte/halfword/word
+ * GVecGen4 struct variants.
+ */
+static const TCGOpcode vecop_list_sub_u[] = {
+ INDEX_op_sub_vec, INDEX_op_ussub_vec, 0
+};
+static const TCGOpcode vecop_list_sub_s[] = {
+ INDEX_op_sub_vec, INDEX_op_sssub_vec, 0
+};
+static const TCGOpcode vecop_list_add_u[] = {
+ INDEX_op_add_vec, INDEX_op_usadd_vec, 0
+};
+static const TCGOpcode vecop_list_add_s[] = {
+ INDEX_op_add_vec, INDEX_op_ssadd_vec, 0
+};
+
+static const GVecGen4 op_vsububs = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUBS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vaddubs = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUBS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vsubuhs = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUHS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vadduhs = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUHS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vsubuws = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUWS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vadduws = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUWS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vsubsbs = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSBS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vaddsbs = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSBS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vsubshs = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSHS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vaddshs = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSHS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vsubsws = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSWS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vaddsws = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSWS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static bool do_vx_vadd_vsub_sat(DisasContext *ctx, arg_VX *a, const GVecGen4 *op)
+{
+ REQUIRE_VECTOR(ctx);
+ tcg_gen_gvec_4(avr_full_offset(a->vrt), offsetof(CPUPPCState, vscr_sat),
+ avr_full_offset(a->vra), avr_full_offset(a->vrb),
+ 16, 16, op);
+
+ return true;
+}
+
+TRANS_FLAGS(ALTIVEC, VSUBUBS, do_vx_vadd_vsub_sat, &op_vsububs)
+TRANS_FLAGS(ALTIVEC, VSUBUHS, do_vx_vadd_vsub_sat, &op_vsubuhs)
+TRANS_FLAGS(ALTIVEC, VSUBUWS, do_vx_vadd_vsub_sat, &op_vsubuws)
+TRANS_FLAGS(ALTIVEC, VSUBSBS, do_vx_vadd_vsub_sat, &op_vsubsbs)
+TRANS_FLAGS(ALTIVEC, VSUBSHS, do_vx_vadd_vsub_sat, &op_vsubshs)
+TRANS_FLAGS(ALTIVEC, VSUBSWS, do_vx_vadd_vsub_sat, &op_vsubsws)
+TRANS_FLAGS(ALTIVEC, VADDUBS, do_vx_vadd_vsub_sat, &op_vaddubs)
+TRANS_FLAGS(ALTIVEC, VADDUHS, do_vx_vadd_vsub_sat, &op_vadduhs)
+TRANS_FLAGS(ALTIVEC, VADDUWS, do_vx_vadd_vsub_sat, &op_vadduws)
+TRANS_FLAGS(ALTIVEC, VADDSBS, do_vx_vadd_vsub_sat, &op_vaddsbs)
+TRANS_FLAGS(ALTIVEC, VADDSHS, do_vx_vadd_vsub_sat, &op_vaddshs)
+TRANS_FLAGS(ALTIVEC, VADDSWS, do_vx_vadd_vsub_sat, &op_vaddsws)
+
static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc
index 7bb11b0..e28958a 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -54,18 +54,13 @@ GEN_VXFORM(vsro, 6, 17),
GEN_VXFORM(xpnd04_1, 0, 22),
GEN_VXFORM_300(bcdsr, 0, 23),
GEN_VXFORM_300(bcdsr, 0, 31),
-GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vadduws, 0, 10),
-GEN_VXFORM(vaddsbs, 0, 12),
-GEN_VXFORM_DUAL(vaddshs, bcdcpsgn, 0, 13, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vaddsws, 0, 14),
-GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vsubuws, 0, 26),
-GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
-GEN_VXFORM(vsubshs, 0, 29),
-GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_300_EXT(vmul10uq, 0, 8, 0x0000F800),
+GEN_VXFORM_300(vmul10euq, 0, 9),
+GEN_VXFORM_300(bcdcpsgn, 0, 13),
+GEN_VXFORM_207(bcdadd, 0, 24),
+GEN_VXFORM_207(bcdsub, 0, 25),
+GEN_VXFORM_300(bcdtrunc, 0, 28),
+GEN_VXFORM_300(xpnd04_2, 0, 30),
GEN_VXFORM_300(bcdtrunc, 0, 20),
GEN_VXFORM_300(bcdutrunc, 0, 21),
GEN_VXFORM(vsl, 2, 7),
diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc
index 0266f09..00ad57c 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -10,6 +10,16 @@ static inline void set_cpu_vsr(int n, TCGv_i64 src, bool high)
tcg_gen_st_i64(src, tcg_env, vsr64_offset(n, high));
}
+static inline void get_vsr_full(TCGv_i128 dst, int reg)
+{
+ tcg_gen_ld_i128(dst, tcg_env, vsr_full_offset(reg));
+}
+
+static inline void set_vsr_full(int reg, TCGv_i128 src)
+{
+ tcg_gen_st_i128(src, tcg_env, vsr_full_offset(reg));
+}
+
static inline TCGv_ptr gen_vsr_ptr(int reg)
{
TCGv_ptr r = tcg_temp_new_ptr();
@@ -24,66 +34,59 @@ static inline TCGv_ptr gen_acc_ptr(int reg)
return r;
}
-#define VSX_LOAD_SCALAR(name, operation) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_i64 t0; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- t0 = tcg_temp_new_i64(); \
- gen_set_access_type(ctx, ACCESS_INT); \
- EA = tcg_temp_new(); \
- gen_addr_reg_index(ctx, EA); \
- gen_qemu_##operation(ctx, t0, EA); \
- set_cpu_vsr(xT(ctx->opcode), t0, true); \
- /* NOTE: cpu_vsrl is undefined */ \
+static bool do_lxs(DisasContext *ctx, arg_X *a,
+ void (*op)(DisasContext *, TCGv_i64, TCGv))
+{
+ TCGv EA;
+ TCGv_i64 t0;
+ REQUIRE_VSX(ctx);
+ t0 = tcg_temp_new_i64();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ op(ctx, t0, EA);
+ set_cpu_vsr(a->rt, t0, true);
+ /* NOTE: cpu_vsrl is undefined */
+ return true;
}
-VSX_LOAD_SCALAR(lxsdx, ld64_i64)
-VSX_LOAD_SCALAR(lxsiwax, ld32s_i64)
-VSX_LOAD_SCALAR(lxsibzx, ld8u_i64)
-VSX_LOAD_SCALAR(lxsihzx, ld16u_i64)
-VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64)
-VSX_LOAD_SCALAR(lxsspx, ld32fs)
+TRANS_FLAGS2(VSX, LXSDX, do_lxs, gen_qemu_ld64_i64);
+TRANS_FLAGS2(VSX207, LXSIWAX, do_lxs, gen_qemu_ld32s_i64);
+TRANS_FLAGS2(ISA300, LXSIBZX, do_lxs, gen_qemu_ld8u_i64);
+TRANS_FLAGS2(ISA300, LXSIHZX, do_lxs, gen_qemu_ld16u_i64);
+TRANS_FLAGS2(VSX207, LXSIWZX, do_lxs, gen_qemu_ld32u_i64);
+TRANS_FLAGS2(VSX207, LXSSPX, do_lxs, gen_qemu_ld32fs);
-static void gen_lxvd2x(DisasContext *ctx)
+static bool trans_LXVD2X(DisasContext *ctx, arg_LXVD2X *a)
{
TCGv EA;
TCGv_i64 t0;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
+
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
gen_qemu_ld64_i64(ctx, t0, EA);
- set_cpu_vsr(xT(ctx->opcode), t0, true);
+ set_cpu_vsr(a->rt, t0, true);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64_i64(ctx, t0, EA);
- set_cpu_vsr(xT(ctx->opcode), t0, false);
+ set_cpu_vsr(a->rt, t0, false);
+ return true;
}
-static void gen_lxvw4x(DisasContext *ctx)
+static bool trans_LXVW4X(DisasContext *ctx, arg_LXVW4X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ TCGv_i64 xth, xtl;
+
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
+
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
-
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
@@ -100,55 +103,45 @@ static void gen_lxvw4x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
}
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ set_cpu_vsr(a->rt, xth, true);
+ set_cpu_vsr(a->rt, xtl, false);
+ return true;
}
-static void gen_lxvwsx(DisasContext *ctx)
+static bool trans_LXVWSX(DisasContext *ctx, arg_LXVWSX *a)
{
TCGv EA;
TCGv_i32 data;
- if (xT(ctx->opcode) < 32) {
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ if (a->rt < 32) {
+ REQUIRE_VSX(ctx);
} else {
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
+ REQUIRE_VECTOR(ctx);
}
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
-
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
data = tcg_temp_new_i32();
tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UL));
- tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
+ tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(a->rt), 16, 16, data);
+ return true;
}
-static void gen_lxvdsx(DisasContext *ctx)
+static bool trans_LXVDSX(DisasContext *ctx, arg_LXVDSX *a)
{
TCGv EA;
TCGv_i64 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
-
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
data = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UQ));
- tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
+ tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(a->rt), 16, 16, data);
+ return true;
}
static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl,
@@ -187,145 +180,166 @@ static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl,
tcg_gen_deposit_i64(outl, outl, lo, 32, 32);
}
-static void gen_lxvh8x(DisasContext *ctx)
+static bool trans_LXVH8X(DisasContext *ctx, arg_LXVH8X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
+ TCGv_i64 xth, xtl;
+
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
-
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
if (ctx->le_mode) {
gen_bswap16x8(xth, xtl, xth, xtl);
}
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ set_cpu_vsr(a->rt, xth, true);
+ set_cpu_vsr(a->rt, xtl, false);
+ return true;
}
-static void gen_lxvb16x(DisasContext *ctx)
+static bool trans_LXVB16X(DisasContext *ctx, arg_LXVB16X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
+ TCGv_i128 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
+
+ data = tcg_temp_new_i128();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ tcg_gen_qemu_ld_i128(data, EA, ctx->mem_idx,
+ MO_BE | MO_128 | MO_ATOM_IFALIGN_PAIR);
+ set_vsr_full(a->rt, data);
+ return true;
+}
+
+#if defined(TARGET_PPC64)
+static bool do_ld_st_vl(DisasContext *ctx, arg_X *a,
+ void (*helper)(TCGv_ptr, TCGv, TCGv_ptr, TCGv))
+{
+ TCGv EA;
+ TCGv_ptr xt;
+ if (a->rt < 32) {
+ REQUIRE_VSX(ctx);
+ } else {
+ REQUIRE_VECTOR(ctx);
}
- xth = tcg_temp_new_i64();
- xtl = tcg_temp_new_i64();
+ xt = gen_vsr_ptr(a->rt);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
- tcg_gen_addi_tl(EA, EA, 8);
- tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ EA = do_ea_calc_ra(ctx, a->ra);
+ helper(tcg_env, EA, xt, cpu_gpr[a->rb]);
+ return true;
}
+#endif
-#ifdef TARGET_PPC64
-#define VSX_VECTOR_LOAD_STORE_LENGTH(name) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_ptr xt; \
- \
- if (xT(ctx->opcode) < 32) { \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- } else { \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- } \
- EA = tcg_temp_new(); \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- gen_set_access_type(ctx, ACCESS_INT); \
- gen_addr_register(ctx, EA); \
- gen_helper_##name(tcg_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \
-}
-
-VSX_VECTOR_LOAD_STORE_LENGTH(lxvl)
-VSX_VECTOR_LOAD_STORE_LENGTH(lxvll)
-VSX_VECTOR_LOAD_STORE_LENGTH(stxvl)
-VSX_VECTOR_LOAD_STORE_LENGTH(stxvll)
+static bool trans_LXVL(DisasContext *ctx, arg_LXVL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_LXVL);
+#else
+ qemu_build_not_reached();
#endif
+ return true;
+}
-#define VSX_STORE_SCALAR(name, operation) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_i64 t0; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- t0 = tcg_temp_new_i64(); \
- gen_set_access_type(ctx, ACCESS_INT); \
- EA = tcg_temp_new(); \
- gen_addr_reg_index(ctx, EA); \
- get_cpu_vsr(t0, xS(ctx->opcode), true); \
- gen_qemu_##operation(ctx, t0, EA); \
+static bool trans_LXVLL(DisasContext *ctx, arg_LXVLL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_LXVLL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
}
-VSX_STORE_SCALAR(stxsdx, st64_i64)
+static bool trans_STXVL(DisasContext *ctx, arg_STXVL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_STXVL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
-VSX_STORE_SCALAR(stxsibx, st8_i64)
-VSX_STORE_SCALAR(stxsihx, st16_i64)
-VSX_STORE_SCALAR(stxsiwx, st32_i64)
-VSX_STORE_SCALAR(stxsspx, st32fs)
+static bool trans_STXVLL(DisasContext *ctx, arg_STXVLL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_STXVLL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
-static void gen_stxvd2x(DisasContext *ctx)
+static bool do_stxs(DisasContext *ctx, arg_X *a,
+ void (*op)(DisasContext *, TCGv_i64, TCGv))
{
TCGv EA;
TCGv_i64 t0;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ REQUIRE_VSX(ctx);
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- get_cpu_vsr(t0, xS(ctx->opcode), true);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_cpu_vsr(t0, a->rt, true);
+ op(ctx, t0, EA);
+ return true;
+}
+
+TRANS_FLAGS2(VSX, STXSDX, do_stxs, gen_qemu_st64_i64);
+TRANS_FLAGS2(ISA300, STXSIBX, do_stxs, gen_qemu_st8_i64);
+TRANS_FLAGS2(ISA300, STXSIHX, do_stxs, gen_qemu_st16_i64);
+TRANS_FLAGS2(VSX207, STXSIWX, do_stxs, gen_qemu_st32_i64);
+TRANS_FLAGS2(VSX207, STXSSPX, do_stxs, gen_qemu_st32fs);
+
+static bool trans_STXVD2X(DisasContext *ctx, arg_STXVD2X *a)
+{
+ TCGv EA;
+ TCGv_i64 t0;
+
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
+
+ t0 = tcg_temp_new_i64();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_cpu_vsr(t0, a->rt, true);
gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- get_cpu_vsr(t0, xS(ctx->opcode), false);
+ get_cpu_vsr(t0, a->rt, false);
gen_qemu_st64_i64(ctx, t0, EA);
+ return true;
}
-static void gen_stxvw4x(DisasContext *ctx)
+static bool trans_STXVW4X(DisasContext *ctx, arg_STXVW4X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i64 xsh, xsl;
+
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+ REQUIRE_VSX(ctx);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ get_cpu_vsr(xsh, a->rt, true);
+ get_cpu_vsr(xsl, a->rt, false);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
@@ -342,25 +356,23 @@ static void gen_stxvw4x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
}
+ return true;
}
-static void gen_stxvh8x(DisasContext *ctx)
+static bool trans_STXVH8X(DisasContext *ctx, arg_STXVH8X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i64 xsh, xsl;
+
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ get_cpu_vsr(xsh, a->rt, true);
+ get_cpu_vsr(xsl, a->rt, false);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 outh = tcg_temp_new_i64();
TCGv_i64 outl = tcg_temp_new_i64();
@@ -374,28 +386,24 @@ static void gen_stxvh8x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
}
+ return true;
}
-static void gen_stxvb16x(DisasContext *ctx)
+static bool trans_STXVB16X(DisasContext *ctx, arg_STXVB16X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i128 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
- xsh = tcg_temp_new_i64();
- xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+ REQUIRE_VSX(ctx);
+
+ data = tcg_temp_new_i128();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ);
- tcg_gen_addi_tl(EA, EA, 8);
- tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_vsr_full(data, a->rt);
+ tcg_gen_qemu_st_i128(data, EA, ctx->mem_idx,
+ MO_BE | MO_128 | MO_ATOM_IFALIGN_PAIR);
+ return true;
}
static void gen_mfvsrwz(DisasContext *ctx)
@@ -788,34 +796,28 @@ static bool do_xvcpsgn(DisasContext *ctx, arg_XX3 *a, unsigned vece)
TRANS(XVCPSGNSP, do_xvcpsgn, MO_32)
TRANS(XVCPSGNDP, do_xvcpsgn, MO_64)
-#define VSX_CMP(name, op1, op2, inval, type) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv_i32 ignored; \
- TCGv_ptr xt, xa, xb; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- xa = gen_vsr_ptr(xA(ctx->opcode)); \
- xb = gen_vsr_ptr(xB(ctx->opcode)); \
- if ((ctx->opcode >> (31 - 21)) & 1) { \
- gen_helper_##name(cpu_crf[6], tcg_env, xt, xa, xb); \
- } else { \
- ignored = tcg_temp_new_i32(); \
- gen_helper_##name(ignored, tcg_env, xt, xa, xb); \
- } \
+static bool do_cmp(DisasContext *ctx, arg_XX3_rc *a,
+ void (*helper)(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
+{
+ TCGv_i32 dest;
+ TCGv_ptr xt, xa, xb;
+ REQUIRE_VSX(ctx);
+ xt = gen_vsr_ptr(a->xt);
+ xa = gen_vsr_ptr(a->xa);
+ xb = gen_vsr_ptr(a->xb);
+ dest = a->rc ? cpu_crf[6] : tcg_temp_new_i32();
+ helper(dest, tcg_env, xt, xa, xb);
+ return true;
}
-VSX_CMP(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
-VSX_CMP(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
-VSX_CMP(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
-VSX_CMP(xvcmpnedp, 0x0C, 0x0F, 0, PPC2_ISA300)
-VSX_CMP(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
-VSX_CMP(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
-VSX_CMP(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
-VSX_CMP(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX)
+TRANS_FLAGS2(VSX, XVCMPEQSP, do_cmp, gen_helper_XVCMPEQSP);
+TRANS_FLAGS2(VSX, XVCMPGTSP, do_cmp, gen_helper_XVCMPGTSP);
+TRANS_FLAGS2(VSX, XVCMPGESP, do_cmp, gen_helper_XVCMPGESP);
+TRANS_FLAGS2(ISA300, XVCMPNESP, do_cmp, gen_helper_XVCMPNESP);
+TRANS_FLAGS2(VSX, XVCMPEQDP, do_cmp, gen_helper_XVCMPEQDP);
+TRANS_FLAGS2(VSX, XVCMPGTDP, do_cmp, gen_helper_XVCMPGTDP);
+TRANS_FLAGS2(VSX, XVCMPGEDP, do_cmp, gen_helper_XVCMPGEDP);
+TRANS_FLAGS2(ISA300, XVCMPNEDP, do_cmp, gen_helper_XVCMPNEDP);
static bool trans_XSCVQPDP(DisasContext *ctx, arg_X_tb_rc *a)
{
@@ -864,20 +866,6 @@ static void gen_##name(DisasContext *ctx) \
gen_helper_##name(tcg_env, opc); \
}
-#define GEN_VSX_HELPER_X3(name, op1, op2, inval, type) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv_ptr xt, xa, xb; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- xa = gen_vsr_ptr(xA(ctx->opcode)); \
- xb = gen_vsr_ptr(xB(ctx->opcode)); \
- gen_helper_##name(tcg_env, xt, xa, xb); \
-}
-
#define GEN_VSX_HELPER_X2(name, op1, op2, inval, type) \
static void gen_##name(DisasContext *ctx) \
{ \
@@ -983,12 +971,8 @@ static void gen_##name(DisasContext *ctx) \
set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
}
-GEN_VSX_HELPER_X3(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsaddqp, 0x04, 0x00, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsmulqp, 0x04, 0x01, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsdivqp, 0x04, 0x11, 0, PPC2_ISA300)
GEN_VSX_HELPER_X2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
@@ -1001,8 +985,6 @@ GEN_VSX_HELPER_X2_AB(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R2_AB(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R2_AB(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
GEN_VSX_HELPER_X2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
GEN_VSX_HELPER_R2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
@@ -1233,27 +1215,17 @@ GEN_VSX_HELPER_R2(xsrqpi, 0x05, 0x00, 0, PPC2_ISA300)
GEN_VSX_HELPER_R2(xsrqpxp, 0x05, 0x01, 0, PPC2_ISA300)
GEN_VSX_HELPER_R2(xssqrtqp, 0x04, 0x19, 0x1B, PPC2_ISA300)
GEN_VSX_HELPER_R3(xssubqp, 0x04, 0x10, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X1(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
@@ -1269,17 +1241,11 @@ GEN_VSX_HELPER_X2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_X1(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300)
GEN_VSX_HELPER_X2(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300)
@@ -1609,26 +1575,24 @@ static void gen_xxbrw(DisasContext *ctx)
set_cpu_vsr(xT(ctx->opcode), xtl, false);
}
-#define VSX_LOGICAL(name, vece, tcg_op) \
-static void glue(gen_, name)(DisasContext *ctx) \
- { \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- tcg_op(vece, vsr_full_offset(xT(ctx->opcode)), \
- vsr_full_offset(xA(ctx->opcode)), \
- vsr_full_offset(xB(ctx->opcode)), 16, 16); \
- }
+static bool do_logical_op(DisasContext *ctx, arg_XX3 *a, unsigned vece,
+ void (*helper)(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))
+{
+ REQUIRE_VSX(ctx);
+ helper(vece, vsr_full_offset(a->xt),
+ vsr_full_offset(a->xa),
+ vsr_full_offset(a->xb), 16, 16);
+ return true;
+}
-VSX_LOGICAL(xxland, MO_64, tcg_gen_gvec_and)
-VSX_LOGICAL(xxlandc, MO_64, tcg_gen_gvec_andc)
-VSX_LOGICAL(xxlor, MO_64, tcg_gen_gvec_or)
-VSX_LOGICAL(xxlxor, MO_64, tcg_gen_gvec_xor)
-VSX_LOGICAL(xxlnor, MO_64, tcg_gen_gvec_nor)
-VSX_LOGICAL(xxleqv, MO_64, tcg_gen_gvec_eqv)
-VSX_LOGICAL(xxlnand, MO_64, tcg_gen_gvec_nand)
-VSX_LOGICAL(xxlorc, MO_64, tcg_gen_gvec_orc)
+TRANS_FLAGS2(VSX, XXLAND, do_logical_op, MO_64, tcg_gen_gvec_and);
+TRANS_FLAGS2(VSX, XXLANDC, do_logical_op, MO_64, tcg_gen_gvec_andc);
+TRANS_FLAGS2(VSX, XXLOR, do_logical_op, MO_64, tcg_gen_gvec_or);
+TRANS_FLAGS2(VSX, XXLXOR, do_logical_op, MO_64, tcg_gen_gvec_xor);
+TRANS_FLAGS2(VSX, XXLNOR, do_logical_op, MO_64, tcg_gen_gvec_nor);
+TRANS_FLAGS2(VSX207, XXLEQV, do_logical_op, MO_64, tcg_gen_gvec_eqv);
+TRANS_FLAGS2(VSX207, XXLNAND, do_logical_op, MO_64, tcg_gen_gvec_nand);
+TRANS_FLAGS2(VSX207, XXLORC, do_logical_op, MO_64, tcg_gen_gvec_orc);
#define VSX_XXMRG(name, high) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -2215,13 +2179,13 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ,
int rt, bool store, bool paired)
{
TCGv ea;
- TCGv_i64 xt;
+ TCGv_i128 data;
MemOp mop;
int rt1, rt2;
- xt = tcg_temp_new_i64();
+ data = tcg_temp_new_i128();
- mop = DEF_MEMOP(MO_UQ);
+ mop = DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR);
gen_set_access_type(ctx, ACCESS_INT);
ea = do_ea_calc(ctx, ra, displ);
@@ -2235,32 +2199,20 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ,
}
if (store) {
- get_cpu_vsr(xt, rt1, !ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt1, ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
+ get_vsr_full(data, rt1);
+ tcg_gen_qemu_st_i128(data, ea, ctx->mem_idx, mop);
if (paired) {
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt2, !ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt2, ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
+ gen_addr_add(ctx, ea, ea, 16);
+ get_vsr_full(data, rt2);
+ tcg_gen_qemu_st_i128(data, ea, ctx->mem_idx, mop);
}
} else {
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt1, xt, !ctx->le_mode);
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt1, xt, ctx->le_mode);
+ tcg_gen_qemu_ld_i128(data, ea, ctx->mem_idx, mop);
+ set_vsr_full(rt1, data);
if (paired) {
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt2, xt, !ctx->le_mode);
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt2, xt, ctx->le_mode);
+ gen_addr_add(ctx, ea, ea, 16);
+ tcg_gen_qemu_ld_i128(data, ea, ctx->mem_idx, mop);
+ set_vsr_full(rt2, data);
}
}
return true;
@@ -2292,7 +2244,7 @@ static bool do_lstxv_PLS_D(DisasContext *ctx, arg_PLS_D *a,
static bool do_lstxv_X(DisasContext *ctx, arg_X *a, bool store, bool paired)
{
- if (paired || a->rt >= 32) {
+ if (paired || a->rt < 32) {
REQUIRE_VSX(ctx);
} else {
REQUIRE_VECTOR(ctx);
@@ -2712,8 +2664,6 @@ static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a,
void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
{
TCGv_ptr xt, xa, xb;
-
- REQUIRE_INSNS_FLAGS2(ctx, ISA300);
REQUIRE_VSX(ctx);
xt = gen_vsr_ptr(a->xt);
@@ -2724,13 +2674,40 @@ static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a,
return true;
}
-TRANS(XSCMPEQDP, do_helper_XX3, gen_helper_XSCMPEQDP)
-TRANS(XSCMPGEDP, do_helper_XX3, gen_helper_XSCMPGEDP)
-TRANS(XSCMPGTDP, do_helper_XX3, gen_helper_XSCMPGTDP)
-TRANS(XSMAXCDP, do_helper_XX3, gen_helper_XSMAXCDP)
-TRANS(XSMINCDP, do_helper_XX3, gen_helper_XSMINCDP)
-TRANS(XSMAXJDP, do_helper_XX3, gen_helper_XSMAXJDP)
-TRANS(XSMINJDP, do_helper_XX3, gen_helper_XSMINJDP)
+TRANS_FLAGS2(ISA300, XSCMPEQDP, do_helper_XX3, gen_helper_XSCMPEQDP)
+TRANS_FLAGS2(ISA300, XSCMPGEDP, do_helper_XX3, gen_helper_XSCMPGEDP)
+TRANS_FLAGS2(ISA300, XSCMPGTDP, do_helper_XX3, gen_helper_XSCMPGTDP)
+TRANS_FLAGS2(ISA300, XSMAXCDP, do_helper_XX3, gen_helper_XSMAXCDP)
+TRANS_FLAGS2(ISA300, XSMINCDP, do_helper_XX3, gen_helper_XSMINCDP)
+TRANS_FLAGS2(ISA300, XSMAXJDP, do_helper_XX3, gen_helper_XSMAXJDP)
+TRANS_FLAGS2(ISA300, XSMINJDP, do_helper_XX3, gen_helper_XSMINJDP)
+
+TRANS_FLAGS2(VSX207, XSADDSP, do_helper_XX3, gen_helper_XSADDSP)
+TRANS_FLAGS2(VSX207, XSSUBSP, do_helper_XX3, gen_helper_XSSUBSP)
+TRANS_FLAGS2(VSX207, XSMULSP, do_helper_XX3, gen_helper_XSMULSP)
+TRANS_FLAGS2(VSX207, XSDIVSP, do_helper_XX3, gen_helper_XSDIVSP)
+
+TRANS_FLAGS2(VSX, XSADDDP, do_helper_XX3, gen_helper_XSADDDP)
+TRANS_FLAGS2(VSX, XSSUBDP, do_helper_XX3, gen_helper_XSSUBDP)
+TRANS_FLAGS2(VSX, XSMULDP, do_helper_XX3, gen_helper_XSMULDP)
+TRANS_FLAGS2(VSX, XSDIVDP, do_helper_XX3, gen_helper_XSDIVDP)
+
+TRANS_FLAGS2(VSX, XVADDSP, do_helper_XX3, gen_helper_XVADDSP)
+TRANS_FLAGS2(VSX, XVSUBSP, do_helper_XX3, gen_helper_XVSUBSP)
+TRANS_FLAGS2(VSX, XVMULSP, do_helper_XX3, gen_helper_XVMULSP)
+TRANS_FLAGS2(VSX, XVDIVSP, do_helper_XX3, gen_helper_XVDIVSP)
+
+TRANS_FLAGS2(VSX, XVADDDP, do_helper_XX3, gen_helper_XVADDDP)
+TRANS_FLAGS2(VSX, XVSUBDP, do_helper_XX3, gen_helper_XVSUBDP)
+TRANS_FLAGS2(VSX, XVMULDP, do_helper_XX3, gen_helper_XVMULDP)
+TRANS_FLAGS2(VSX, XVDIVDP, do_helper_XX3, gen_helper_XVDIVDP)
+
+TRANS_FLAGS2(VSX, XSMAXDP, do_helper_XX3, gen_helper_XSMAXDP)
+TRANS_FLAGS2(VSX, XSMINDP, do_helper_XX3, gen_helper_XSMINDP)
+TRANS_FLAGS2(VSX, XVMAXSP, do_helper_XX3, gen_helper_XVMAXSP)
+TRANS_FLAGS2(VSX, XVMINSP, do_helper_XX3, gen_helper_XVMINSP)
+TRANS_FLAGS2(VSX, XVMAXDP, do_helper_XX3, gen_helper_XVMAXDP)
+TRANS_FLAGS2(VSX, XVMINDP, do_helper_XX3, gen_helper_XVMINDP)
static bool do_helper_X(arg_X *a,
void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
@@ -2910,4 +2887,3 @@ TRANS64(PMXVF64GERNN, do_ger, gen_helper_XVF64GERNN)
#undef GEN_XX2IFORM
#undef GEN_XX3_RC_FORM
#undef GEN_XX3FORM_DM
-#undef VSX_LOGICAL
diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc
index a3ba094..e553b5b 100644
--- a/target/ppc/translate/vsx-ops.c.inc
+++ b/target/ppc/translate/vsx-ops.c.inc
@@ -1,34 +1,3 @@
-GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsibzx, 0x1F, 0x0D, 0x18, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxsihzx, 0x1F, 0x0D, 0x19, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvwsx, 0x1F, 0x0C, 0x0B, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(lxvl, 0x1F, 0x0D, 0x08, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvll, 0x1F, 0x0D, 0x09, 0, PPC_NONE, PPC2_ISA300),
-#endif
-
-GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxsihx, 0x1F, 0xD, 0x1D, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(stxvl, 0x1F, 0x0D, 0x0C, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxvll, 0x1F, 0x0D, 0x0D, 0, PPC_NONE, PPC2_ISA300),
-#endif
-
GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207),
@@ -74,16 +43,6 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2)
-#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2)
-
#define GEN_XX3FORM_DM(name, opc2, opc3) \
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
@@ -153,12 +112,8 @@ GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300),
GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300),
GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300),
-GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0),
-GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
GEN_VSX_XFORM_300(xsmulqp, 0x04, 0x01, 0x0),
-GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX),
GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX),
GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX),
@@ -170,8 +125,6 @@ GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
GEN_VSX_XFORM_300(xscmpoqp, 0x04, 0x04, 0x00600001),
GEN_VSX_XFORM_300(xscmpuqp, 0x04, 0x14, 0x00600001),
-GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
-GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
GEN_XX2FORM_EO(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300),
GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
@@ -191,10 +144,6 @@ GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX),
GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX),
GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
-GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
-GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
GEN_VSX_XFORM_300(xsdivqp, 0x04, 0x11, 0x0),
GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207),
GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
@@ -203,10 +152,6 @@ GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207),
GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
-GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX),
GEN_XX2FORM(xvredp, 0x14, 0x0D, PPC2_VSX),
GEN_XX2FORM(xvsqrtdp, 0x16, 0x0C, PPC2_VSX),
GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX),
@@ -220,12 +165,6 @@ GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddadp", 0x04, 0x1C, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddmdp", 0x04, 0x1D, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubadp", 0x04, 0x1E, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubmdp", 0x04, 0x1F, PPC2_VSX),
-GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
-GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpnedp, 0x0C, 0x0F, PPC2_ISA300),
GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX),
GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX),
GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX),
@@ -241,10 +180,6 @@ GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX),
GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX),
GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX),
-GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX),
GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX),
GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX),
GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
@@ -258,12 +193,6 @@ GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddasp", 0x04, 0x18, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddmsp", 0x04, 0x19, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubasp", 0x04, 0x1A, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubmsp", 0x04, 0x1B, PPC2_VSX),
-GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
-GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpnesp, 0x0C, 0x0B, PPC2_ISA300),
GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX),
GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX),
GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX),
@@ -285,17 +214,6 @@ GEN_XX2FORM_EO(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300),
GEN_XX2FORM_EO(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300),
GEN_XX2FORM_EO(xxbrq, 0x16, 0x1D, 0x1F, PPC2_ISA300),
-#define VSX_LOGICAL(name, opc2, opc3, fl2) \
-GEN_XX3FORM(name, opc2, opc3, fl2)
-
-VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX),
-VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX),
-VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX),
-VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX),
-VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX),
-VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207),
-VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
-VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00),
diff --git a/target/ppc/user_only_helper.c b/target/ppc/user_only_helper.c
index a4d07a0..ae210eb 100644
--- a/target/ppc/user_only_helper.c
+++ b/target/ppc/user_only_helper.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "internal.h"
void ppc_cpu_record_sigsegv(CPUState *cs, vaddr address,