aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-05-27 22:23:13 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-05-27 22:23:13 +0100
commit8b92b9ef86077f9ec77998666cd7de137c33e9bf (patch)
tree8a2f2c64dc2f8f98e312f10ae273cd2c7d777bce
parent06539ebc76b8625587aa78d646a9d8d5fddf84f3 (diff)
parent9c7c0407028355ca83349b8a60fddfad46f2ebd8 (diff)
downloadqemu-8b92b9ef86077f9ec77998666cd7de137c33e9bf.zip
qemu-8b92b9ef86077f9ec77998666cd7de137c33e9bf.tar.gz
qemu-8b92b9ef86077f9ec77998666cd7de137c33e9bf.tar.bz2
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-5.1-20200527' into staging
ppc patch queue 2020-05-27 Here's the next pull request for qemu-5.1. It includes: * Support for the scv and rfscv POWER9 instructions in TCG * Support for the new SPAPR_LMB_FLAGS_HOTREMOVABLE flag, which provides a way for guests to know memory which should be removable (so the guest can avoid putting immovable allocations there). * Some fixes for the recently added partition scope radix translation in softmmu * Assorted minor fixes and cleanups It includes one patch to avoid a clash with SELinux when using NVLink VFIO devices. That's not technically within the files under my maintainership, but it is in a section of the VFIO quirks code that's specific to the POWER-only NVLink devices, and has an ack from Alex Williamson. # gpg: Signature made Wed 27 May 2020 06:36:59 BST # gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full] # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full] # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full] # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown] # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-5.1-20200527: vfio/nvlink: Remove exec permission to avoid SELinux AVCs target/ppc: Fix argument to ppc_radix64_partition_scoped_xlate() again hw/nvram/mac_nvram: Convert debug printf()s to trace events hw/pci-bridge/dec: Remove dead debug code target/ppc: Don't update radix PTE R/C bits with gdbstub target/ppc: Fix arguments to ppc_radix64_partition_scoped_xlate() target/ppc: Add missing braces in ppc_radix64_partition_scoped_xlate() target/ppc: Don't initialize some local variables in ppc_radix64_xlate() target/ppc: Pass const pointer to ppc_radix64_get_fully_qualified_addr() target/ppc: Pass const pointer to ppc_radix64_get_prot_amr() ppc/spapr: Add hotremovable flag on DIMM LMBs on drmem_v2 target/ppc: Add support for scv and rfscv instructions target/ppc: Untabify excp_helper.c ppc/spapr: add a POWER10 CPU model ppc/pnv: Fix NMI system reset SRR1 value Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/nvram/mac_nvram.c17
-rw-r--r--hw/nvram/trace-events4
-rw-r--r--hw/pci-bridge/dec.c10
-rw-r--r--hw/ppc/pnv.c26
-rw-r--r--hw/ppc/spapr.c3
-rw-r--r--hw/ppc/spapr_cpu_core.c1
-rw-r--r--hw/vfio/pci-quirks.c4
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--linux-user/ppc/cpu_loop.c1
-rw-r--r--target/ppc/cpu.h28
-rw-r--r--target/ppc/excp_helper.c130
-rw-r--r--target/ppc/helper.h1
-rw-r--r--target/ppc/mmu-radix64.c53
-rw-r--r--target/ppc/mmu-radix64.h4
-rw-r--r--target/ppc/translate.c53
-rw-r--r--target/ppc/translate_init.inc.c3
16 files changed, 237 insertions, 102 deletions
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index ff5db03..beec1c4 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -30,18 +30,9 @@
#include "migration/vmstate.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
+#include "trace.h"
#include <zlib.h>
-/* debug NVR */
-//#define DEBUG_NVR
-
-#ifdef DEBUG_NVR
-#define NVR_DPRINTF(fmt, ...) \
- do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVR_DPRINTF(fmt, ...)
-#endif
-
#define DEF_SYSTEM_SIZE 0xc10
/* macio style NVRAM device */
@@ -51,9 +42,8 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr,
MacIONVRAMState *s = opaque;
addr = (addr >> s->it_shift) & (s->size - 1);
+ trace_macio_nvram_write(addr, value);
s->data[addr] = value;
- NVR_DPRINTF("writeb addr %04" HWADDR_PRIx " val %" PRIx64 "\n",
- addr, value);
}
static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
@@ -64,8 +54,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
addr = (addr >> s->it_shift) & (s->size - 1);
value = s->data[addr];
- NVR_DPRINTF("readb addr %04" HWADDR_PRIx " val %" PRIx32 "\n",
- addr, value);
+ trace_macio_nvram_read(addr, value);
return value;
}
diff --git a/hw/nvram/trace-events b/hw/nvram/trace-events
index 0dea926..e023193 100644
--- a/hw/nvram/trace-events
+++ b/hw/nvram/trace-events
@@ -13,3 +13,7 @@ fw_cfg_add_string(uint16_t key_value, const char *key_name, const char *value) "
fw_cfg_add_i16(uint16_t key_value, const char *key_name, uint16_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx16
fw_cfg_add_i32(uint16_t key_value, const char *key_name, uint32_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx32
fw_cfg_add_i64(uint16_t key_value, const char *key_name, uint64_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx64
+
+# mac_nvram.c
+macio_nvram_read(uint32_t addr, uint8_t val) "read addr=0x%04"PRIx32" val=0x%02x"
+macio_nvram_write(uint32_t addr, uint8_t val) "write addr=0x%04"PRIx32" val=0x%02x"
diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c
index 3ae2f78..952bc71 100644
--- a/hw/pci-bridge/dec.c
+++ b/hw/pci-bridge/dec.c
@@ -32,16 +32,6 @@
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
-/* debug DEC */
-//#define DEBUG_DEC
-
-#ifdef DEBUG_DEC
-#define DEC_DPRINTF(fmt, ...) \
- do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DEC_DPRINTF(fmt, ...)
-#endif
-
#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
typedef struct DECState {
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index da63782..806a5d9 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1984,12 +1984,26 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
cpu_synchronize_state(cs);
ppc_cpu_do_system_reset(cs);
- /*
- * SRR1[42:45] is set to 0100 which the ISA defines as implementation
- * dependent. POWER processors use this for xscom triggered interrupts,
- * which come from the BMC or NMI IPIs.
- */
- env->spr[SPR_SRR1] |= PPC_BIT(43);
+ if (env->spr[SPR_SRR1] & SRR1_WAKESTATE) {
+ /*
+ * Power-save wakeups, as indicated by non-zero SRR1[46:47] put the
+ * wakeup reason in SRR1[42:45], system reset is indicated with 0b0100
+ * (PPC_BIT(43)).
+ */
+ if (!(env->spr[SPR_SRR1] & SRR1_WAKERESET)) {
+ warn_report("ppc_cpu_do_system_reset does not set system reset wakeup reason");
+ env->spr[SPR_SRR1] |= SRR1_WAKERESET;
+ }
+ } else {
+ /*
+ * For non-powersave system resets, SRR1[42:45] are defined to be
+ * implementation-dependent. The POWER9 User Manual specifies that
+ * an external (SCOM driven, which may come from a BMC nmi command or
+ * another CPU requesting a NMI IPI) system reset exception should be
+ * 0b0010 (PPC_BIT(44)).
+ */
+ env->spr[SPR_SRR1] |= SRR1_WAKESCOM;
+ }
}
static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 9b358fc..3b1a5ed 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -445,7 +445,8 @@ static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
g_assert(drc);
elem = spapr_get_drconf_cell(size / lmb_size, addr,
spapr_drc_index(drc), node,
- SPAPR_LMB_FLAGS_ASSIGNED);
+ (SPAPR_LMB_FLAGS_ASSIGNED |
+ SPAPR_LMB_FLAGS_HOTREMOVABLE));
QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
nr_entries++;
cur_addr = addr + size;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index e1f76c7..9c8c1b1 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -407,6 +407,7 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"),
+ DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"),
#ifdef CONFIG_KVM
DEFINE_SPAPR_CPU_CORE_TYPE("host"),
#endif
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 3bd05fe..f2155dd 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1620,7 +1620,7 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp)
}
cap = (void *) hdr;
- p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE,
MAP_SHARED, vdev->vbasedev.fd, nv2reg->offset);
if (p == MAP_FAILED) {
ret = -errno;
@@ -1680,7 +1680,7 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp)
/* Some NVLink bridges may not have assigned ATSD */
if (atsdreg->size) {
- p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE,
MAP_SHARED, vdev->vbasedev.fd, atsdreg->offset);
if (p == MAP_FAILED) {
ret = -errno;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index d2533e7..c421410 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -886,6 +886,7 @@ int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset);
#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008
#define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
#define SPAPR_LMB_FLAGS_RESERVED 0x00000080
+#define SPAPR_LMB_FLAGS_HOTREMOVABLE 0x00000100
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 5b27f86..df71e15 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -267,6 +267,7 @@ void cpu_loop(CPUPPCState *env)
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
+ case POWERPC_EXCP_SYSCALL_VECTORED:
cpu_abort(cs, "Syscall exception while in user mode. "
"Aborting\n");
break;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7db7882..1988b43 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -127,8 +127,9 @@ enum {
POWERPC_EXCP_SDOOR_HV = 100,
/* ISA 3.00 additions */
POWERPC_EXCP_HVIRT = 101,
+ POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception */
/* EOL */
- POWERPC_EXCP_NB = 102,
+ POWERPC_EXCP_NB = 103,
/* QEMU exceptions: used internally during code translation */
POWERPC_EXCP_STOP = 0x200, /* stop translation */
POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */
@@ -475,9 +476,31 @@ typedef struct ppc_v3_pate_t {
#define SRR1_PROTFAULT DSISR_PROTFAULT
#define SRR1_IAMR DSISR_AMR
+/* SRR1[42:45] wakeup fields for System Reset Interrupt */
+
+#define SRR1_WAKEMASK 0x003c0000 /* reason for wakeup */
+
+#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */
+#define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virt. Interrupt (P9) */
+#define SRR1_WAKEEE 0x00200000 /* External interrupt */
+#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
+#define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell */
+#define SRR1_WAKERESET 0x00100000 /* System reset */
+#define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell */
+#define SRR1_WAKESCOM 0x00080000 /* SCOM not in power-saving mode */
+
+/* SRR1[46:47] power-saving exit mode */
+
+#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask */
+
+#define SRR1_WS_HVLOSS 0x00030000 /* HV resources not maintained */
+#define SRR1_WS_GPRLOSS 0x00020000 /* GPRs not maintained */
+#define SRR1_WS_NOLOSS 0x00010000 /* All resources maintained */
+
/* Facility Status and Control (FSCR) bits */
#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
#define FSCR_TAR (63 - 55) /* Target Address Register */
+#define FSCR_SCV (63 - 51) /* System call vectored */
/* Interrupt cause mask and position in FSCR. HFSCR has the same format */
#define FSCR_IC_MASK (0xFFULL)
#define FSCR_IC_POS (63 - 7)
@@ -487,6 +510,7 @@ typedef struct ppc_v3_pate_t {
#define FSCR_IC_TM 5
#define FSCR_IC_EBB 7
#define FSCR_IC_TAR 8
+#define FSCR_IC_SCV 12
/* Exception state register bits definition */
#define ESR_PIL PPC_BIT(36) /* Illegal Instruction */
@@ -554,6 +578,8 @@ enum {
POWERPC_FLAG_VSX = 0x00080000,
/* Has Transaction Memory (ISA 2.07) */
POWERPC_FLAG_TM = 0x00100000,
+ /* Has SCV (ISA 3.00) */
+ POWERPC_FLAG_SCV = 0x00200000,
};
/*****************************************************************************/
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f052979..a988ba1 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -67,19 +67,31 @@ static inline void dump_syscall(CPUPPCState *env)
ppc_dump_gpr(env, 8), env->nip);
}
+static inline void dump_syscall_vectored(CPUPPCState *env)
+{
+ qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
+ " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
+ " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
+ " nip=" TARGET_FMT_lx "\n",
+ ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+ ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+ ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
+ ppc_dump_gpr(env, 8), env->nip);
+}
+
static inline void dump_hcall(CPUPPCState *env)
{
qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
- " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
- " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
- " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
+ " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+ " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
+ " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
" nip=" TARGET_FMT_lx "\n",
ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
- ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
- ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
- ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
- ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
- env->nip);
+ ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
+ ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
+ ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
+ ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
+ env->nip);
}
static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
@@ -89,7 +101,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
env->resume_as_sreset = false;
/* Pretend to be returning from doze always as we don't lose state */
- *msr |= (0x1ull << (63 - 47));
+ *msr |= SRR1_WS_NOLOSS;
/* Machine checks are sent normally */
if (excp == POWERPC_EXCP_MCHECK) {
@@ -97,25 +109,25 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
}
switch (excp) {
case POWERPC_EXCP_RESET:
- *msr |= 0x4ull << (63 - 45);
+ *msr |= SRR1_WAKERESET;
break;
case POWERPC_EXCP_EXTERNAL:
- *msr |= 0x8ull << (63 - 45);
+ *msr |= SRR1_WAKEEE;
break;
case POWERPC_EXCP_DECR:
- *msr |= 0x6ull << (63 - 45);
+ *msr |= SRR1_WAKEDEC;
break;
case POWERPC_EXCP_SDOOR:
- *msr |= 0x5ull << (63 - 45);
+ *msr |= SRR1_WAKEDBELL;
break;
case POWERPC_EXCP_SDOOR_HV:
- *msr |= 0x3ull << (63 - 45);
+ *msr |= SRR1_WAKEHDBELL;
break;
case POWERPC_EXCP_HV_MAINT:
- *msr |= 0xaull << (63 - 45);
+ *msr |= SRR1_WAKEHMI;
break;
case POWERPC_EXCP_HVIRT:
- *msr |= 0x9ull << (63 - 45);
+ *msr |= SRR1_WAKEHVI;
break;
default:
cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
@@ -185,7 +197,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
- int srr0, srr1, asrr0, asrr1, lev, ail;
+ int srr0, srr1, asrr0, asrr1, lev = -1, ail;
bool lpes0;
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
@@ -421,6 +433,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
new_msr |= (target_ulong)MSR_HVB;
}
break;
+ case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
+ lev = env->error_code;
+ dump_syscall_vectored(env);
+ env->nip += 4;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
case POWERPC_EXCP_DECR: /* Decrementer exception */
@@ -724,12 +743,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
break;
}
- /* Save PC */
- env->spr[srr0] = env->nip;
-
- /* Save MSR */
- env->spr[srr1] = msr;
-
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (new_msr & MSR_HVB) {
@@ -742,14 +755,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
}
- /* If any alternate SRR register are defined, duplicate saved values */
- if (asrr0 != -1) {
- env->spr[asrr0] = env->spr[srr0];
- }
- if (asrr1 != -1) {
- env->spr[asrr1] = env->spr[srr1];
- }
-
/*
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
@@ -784,14 +789,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
#endif
- /* Jump to handler */
- vector = env->excp_vectors[excp];
- if (vector == (target_ulong)-1ULL) {
- cpu_abort(cs, "Raised an exception without defined vector %d\n",
- excp);
- }
- vector |= env->excp_prefix;
-
/*
* AIL only works if there is no HV transition and we are running
* with translations enabled
@@ -800,10 +797,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
ail = 0;
}
- /* Handle AIL */
- if (ail) {
- new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
- vector |= ppc_excp_vector_offset(cs, ail);
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ /* If any alternate SRR register are defined, duplicate saved values */
+ if (asrr0 != -1) {
+ env->spr[asrr0] = env->nip;
+ }
+ if (asrr1 != -1) {
+ env->spr[asrr1] = msr;
}
#if defined(TARGET_PPC64)
@@ -823,6 +831,37 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
#endif
+ if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+ /* Save PC */
+ env->spr[srr0] = env->nip;
+
+ /* Save MSR */
+ env->spr[srr1] = msr;
+
+ /* Handle AIL */
+ if (ail) {
+ new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
+ vector |= ppc_excp_vector_offset(cs, ail);
+ }
+
+#if defined(TARGET_PPC64)
+ } else {
+ /* scv AIL is a little different */
+ if (ail) {
+ new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
+ }
+ if (ail == AIL_C000_0000_0000_4000) {
+ vector |= 0xc000000000003000ull;
+ } else {
+ vector |= 0x0000000000017000ull;
+ }
+ vector += lev * 0x20;
+
+ env->lr = env->nip;
+ env->ctr = msr;
+#endif
+ }
+
powerpc_set_excp_state(cpu, vector, new_msr);
}
@@ -1160,6 +1199,11 @@ void helper_rfid(CPUPPCState *env)
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]);
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index a95c010..2dfa1c6 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -15,6 +15,7 @@ DEF_HELPER_1(rfmci, void, env)
#if defined(TARGET_PPC64)
DEF_HELPER_2(pminsn, void, env, i32)
DEF_HELPER_1(rfid, void, env)
+DEF_HELPER_1(rfscv, void, env)
DEF_HELPER_1(hrfid, void, env)
DEF_HELPER_2(store_lpcr, void, env, tl)
DEF_HELPER_2(store_pcr, void, env, tl)
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 1404e53..c60bf31 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -28,7 +28,8 @@
#include "mmu-radix64.h"
#include "mmu-book3s-v3.h"
-static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
+static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
+ vaddr eaddr,
uint64_t *lpid, uint64_t *pid)
{
if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
@@ -49,6 +50,8 @@ static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
*lpid = 0;
*pid = 0;
break;
+ default:
+ g_assert_not_reached();
}
} else { /* !MSR[HV] -> Guest */
switch (eaddr & R_EADDR_QUADRANT) {
@@ -63,6 +66,8 @@ static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
*lpid = env->spr[SPR_LPIDR];
*pid = 0; /* pid set to 0 -> addresses guest operating system */
break;
+ default:
+ g_assert_not_reached();
}
}
@@ -269,7 +274,7 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
ppc_v3_pate_t pate,
hwaddr *h_raddr, int *h_prot,
int *h_page_size, bool pde_addr,
- bool cause_excp)
+ bool guest_visible)
{
int fault_cause = 0;
hwaddr pte_addr;
@@ -281,16 +286,18 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
&pte, &fault_cause, &pte_addr) ||
ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
- if (pde_addr) /* address being translated was that of a guest pde */
+ if (pde_addr) { /* address being translated was that of a guest pde */
fault_cause |= DSISR_PRTABLE_FAULT;
- if (cause_excp) {
+ }
+ if (guest_visible) {
ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
}
return 1;
}
- /* Update Reference and Change Bits */
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+ if (guest_visible) {
+ ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+ }
return 0;
}
@@ -299,7 +306,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
vaddr eaddr, uint64_t pid,
ppc_v3_pate_t pate, hwaddr *g_raddr,
int *g_prot, int *g_page_size,
- bool cause_excp)
+ bool guest_visible)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
@@ -313,7 +320,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
if (offset >= size) {
/* offset exceeds size of the process table */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
}
return 1;
@@ -333,7 +340,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
*/
ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
pate, &h_raddr, &h_prot,
- &h_page_size, 1, 1);
+ &h_page_size, true,
+ guest_visible);
if (ret) {
return ret;
}
@@ -353,7 +361,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
&fault_cause, &pte_addr);
if (ret) {
/* No valid PTE */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return ret;
@@ -372,7 +380,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
do {
ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
pate, &h_raddr, &h_prot,
- &h_page_size, 1, 1);
+ &h_page_size, true,
+ guest_visible);
if (ret) {
return ret;
}
@@ -381,7 +390,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
&nls, g_page_size, &pte, &fault_cause);
if (ret) {
/* No valid pte */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return ret;
@@ -398,13 +407,15 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
/* Access denied due to protection */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return 1;
}
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+ if (guest_visible) {
+ ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+ }
return 0;
}
@@ -429,17 +440,17 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
bool relocation,
hwaddr *raddr, int *psizep, int *protp,
- bool cause_excp)
+ bool guest_visible)
{
CPUPPCState *env = &cpu->env;
- uint64_t lpid = 0, pid = 0;
+ uint64_t lpid, pid;
ppc_v3_pate_t pate;
int psize, prot;
hwaddr g_raddr;
/* Virtual Mode Access - get the fully qualified address */
if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_segi(cpu, rwx, eaddr);
}
return 1;
@@ -452,13 +463,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
vhc->get_pate(cpu->vhyp, &pate);
} else {
if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
}
return 1;
}
if (!validate_pate(cpu, lpid, &pate)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
}
return 1;
@@ -479,7 +490,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
if (relocation) {
int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
pate, &g_raddr, &prot,
- &psize, cause_excp);
+ &psize, guest_visible);
if (ret) {
return ret;
}
@@ -502,7 +513,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
pate, raddr, &prot, &psize,
- 0, cause_excp);
+ false, guest_visible);
if (ret) {
return ret;
}
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index 9622854..f28c579 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -55,9 +55,9 @@ static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
(pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
}
-static inline int ppc_radix64_get_prot_amr(PowerPCCPU *cpu)
+static inline int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
{
- CPUPPCState *env = &cpu->env;
+ 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 */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 3385298..4ce3d66 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -173,6 +173,7 @@ struct DisasContext {
bool vsx_enabled;
bool spe_enabled;
bool tm_enabled;
+ bool scv_enabled;
bool gtse;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
@@ -4030,6 +4031,24 @@ static void gen_rfid(DisasContext *ctx)
#endif
}
+#if !defined(CONFIG_USER_ONLY)
+static void gen_rfscv(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ /* Restore CPU state */
+ CHK_SV;
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_helper_rfscv(cpu_env);
+ gen_sync_exception(ctx);
+#endif
+}
+#endif
+
static void gen_hrfid(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
@@ -4048,6 +4067,7 @@ static void gen_hrfid(DisasContext *ctx)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
+#define POWERPC_SYSCALL_VECTORED POWERPC_EXCP_SYSCALL_VECTORED
#endif
static void gen_sc(DisasContext *ctx)
{
@@ -4057,6 +4077,23 @@ static void gen_sc(DisasContext *ctx)
gen_exception_err(ctx, POWERPC_SYSCALL, lev);
}
+#if defined(TARGET_PPC64)
+#if !defined(CONFIG_USER_ONLY)
+static void gen_scv(DisasContext *ctx)
+{
+ uint32_t lev;
+
+ if (unlikely(!ctx->scv_enabled)) {
+ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV);
+ return;
+ }
+
+ lev = (ctx->opcode >> 5) & 0x7F;
+ gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev);
+}
+#endif
+#endif
+
/*** Trap ***/
/* Check for unconditional traps (always or never) */
@@ -7049,6 +7086,12 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
#if defined(TARGET_PPC64)
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
+#if !defined(CONFIG_USER_ONLY)
+/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */
+GEN_HANDLER_E(scv, 0x11, 0x10, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(scv, 0x11, 0x00, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(rfscv, 0x13, 0x12, 0x02, 0x03FF8001, PPC_NONE, PPC2_ISA300),
+#endif
GEN_HANDLER_E(stop, 0x13, 0x12, 0x0b, 0x03FFF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
@@ -7056,7 +7099,9 @@ GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H),
#endif
-GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW),
+/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */
+GEN_HANDLER(sc, 0x11, 0x11, 0xFF, 0x03FFF01D, PPC_FLOW),
+GEN_HANDLER(sc, 0x11, 0x01, 0xFF, 0x03FFF01D, PPC_FLOW),
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW),
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
#if defined(TARGET_PPC64)
@@ -7835,6 +7880,12 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
} else {
ctx->vsx_enabled = false;
}
+ if ((env->flags & POWERPC_FLAG_SCV)
+ && (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) {
+ ctx->scv_enabled = true;
+ } else {
+ ctx->scv_enabled = false;
+ }
#if defined(TARGET_PPC64)
if ((env->flags & POWERPC_FLAG_TM) && msr_tm) {
ctx->tm_enabled = !!msr_tm;
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index d8adc1b..38cb773 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -3382,6 +3382,7 @@ static void init_excp_POWER9(CPUPPCState *env)
#if !defined(CONFIG_USER_ONLY)
env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0;
+ env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000;
#endif
}
@@ -9030,7 +9031,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
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_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;