aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-08-21 14:04:16 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-08-21 14:04:17 +0100
commite65472c7bc413d79faa61eb1d05c540b03945894 (patch)
tree9e5f998b666fee3579f6d57c229bbdd558d6ce14
parentf2cfa1229e539ee1bb1822912075cf25538ad6b9 (diff)
parentc0e6616b6685ffdb4c5e091bc152e46e14703dd1 (diff)
downloadqemu-e65472c7bc413d79faa61eb1d05c540b03945894.zip
qemu-e65472c7bc413d79faa61eb1d05c540b03945894.tar.gz
qemu-e65472c7bc413d79faa61eb1d05c540b03945894.tar.bz2
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20190821' into staging
ppc patch queue for 2019-08-21 First ppc and spapr pull request for qemu-4.2. Includes: * Some TCG emulation fixes and performance improvements * Support for the mffsl instruction in TCG * Added missing DPDES SPR * Some enhancements to the emulation of the XIVE interrupt controller * Cleanups to spapr MSI management * Some new suspend/resume infrastructure and a draft suspend implementation for spapr * New spapr hypercall for TPM communication (will be needed for secure guests under an Ultravisor) * Fix several memory leaks And a few other assorted fixes. # gpg: Signature made Wed 21 Aug 2019 08:24:44 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-4.2-20190821: (42 commits) ppc: Fix emulated single to double denormalized conversions ppc: Fix emulated INFINITY and NAN conversions ppc: conform to processor User's Manual for xscvdpspn ppc: Add support for 'mffsl' instruction target/ppc: Add Directed Privileged Door-bell Exception State (DPDES) SPR spapr/xive: Mask the EAS when allocating an IRQ spapr: Implement better workaround in spapr-vty device spapr/irq: Drop spapr_irq_msi_reset() spapr/pci: Free MSIs during reset spapr/pci: Consolidate de-allocation of MSIs ppc: remove idle_timer logic spapr: Implement ibm,suspend-me i386: use machine class ->wakeup method machine: Add wakeup method to MachineClass ppc/xive: Improve 'info pic' support ppc/xive: Provide silent escalation support ppc/xive: Provide unconditional escalation support ppc/xive: Provide escalation support ppc/xive: Provide backlog support ppc/xive: Implement TM_PULL_OS_CTX special command ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--disas/ppc.c5
-rw-r--r--docs/specs/ppc-spapr-uv-hcalls.txt76
-rw-r--r--hw/arm/virt.c9
-rw-r--r--hw/char/spapr_vty.c30
-rw-r--r--hw/core/machine.c3
-rw-r--r--hw/i386/pc.c11
-rw-r--r--hw/i386/pc_piix.c14
-rw-r--r--hw/i386/pc_q35.c13
-rw-r--r--hw/intc/pnv_xive.c9
-rw-r--r--hw/intc/spapr_xive.c6
-rw-r--r--hw/intc/xive.c206
-rw-r--r--hw/ppc/Makefile.objs1
-rw-r--r--hw/ppc/ppc.c13
-rw-r--r--hw/ppc/spapr.c115
-rw-r--r--hw/ppc/spapr_caps.c46
-rw-r--r--hw/ppc/spapr_drc.c7
-rw-r--r--hw/ppc/spapr_hcall.c167
-rw-r--r--hw/ppc/spapr_iommu.c2
-rw-r--r--hw/ppc/spapr_irq.c7
-rw-r--r--hw/ppc/spapr_pci.c29
-rw-r--r--hw/ppc/spapr_rtas.c32
-rw-r--r--hw/ppc/spapr_tpm_proxy.c178
-rw-r--r--hw/ppc/trace-events4
-rw-r--r--hw/s390x/s390-virtio-ccw.c14
-rw-r--r--include/hw/boards.h4
-rw-r--r--include/hw/i386/pc.h3
-rw-r--r--include/hw/ppc/spapr.h21
-rw-r--r--include/hw/ppc/spapr_cpu_core.h1
-rw-r--r--include/hw/ppc/spapr_irq.h1
-rw-r--r--include/hw/ppc/spapr_tpm_proxy.h31
-rw-r--r--include/hw/ppc/xive.h11
-rw-r--r--include/hw/ppc/xive_regs.h10
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin926432 -> 926784 bytes
m---------roms/SLOF0
-rw-r--r--target/ppc/cpu-qom.h1
-rw-r--r--target/ppc/cpu.h28
-rw-r--r--target/ppc/fpu_helper.c42
-rw-r--r--target/ppc/helper.h7
-rw-r--r--target/ppc/int_helper.c335
-rw-r--r--target/ppc/kvm.c75
-rw-r--r--target/ppc/translate.c3
-rw-r--r--target/ppc/translate/fp-impl.inc.c22
-rw-r--r--target/ppc/translate/fp-ops.inc.c4
-rw-r--r--target/ppc/translate/vmx-impl.inc.c355
-rw-r--r--target/ppc/translate_init.inc.c57
-rw-r--r--vl.c16
47 files changed, 1416 insertions, 610 deletions
diff --git a/disas/ppc.c b/disas/ppc.c
index a545437..63e97cf 100644
--- a/disas/ppc.c
+++ b/disas/ppc.c
@@ -1765,6 +1765,9 @@ extract_tbr (unsigned long insn,
/* An X_MASK with the RA and RB fields fixed. */
#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+/* An X form instruction with the RA field fixed. */
+#define XRA(op, xop, ra) (X((op), (xop)) | (((ra) << 16) & XRA_MASK))
+
/* An XRARB_MASK, but with the L bit clear. */
#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16))
@@ -4998,6 +5001,8 @@ const struct powerpc_opcode powerpc_opcodes[] = {
{ "ddivq", XRC(63,546,0), X_MASK, POWER6, { FRT, FRA, FRB } },
{ "ddivq.", XRC(63,546,1), X_MASK, POWER6, { FRT, FRA, FRB } },
+{ "mffsl", XRA(63,583,12), XRARB_MASK, POWER9, { FRT } },
+
{ "mffs", XRC(63,583,0), XRARB_MASK, COM, { FRT } },
{ "mffs.", XRC(63,583,1), XRARB_MASK, COM, { FRT } },
diff --git a/docs/specs/ppc-spapr-uv-hcalls.txt b/docs/specs/ppc-spapr-uv-hcalls.txt
new file mode 100644
index 0000000..389c274
--- /dev/null
+++ b/docs/specs/ppc-spapr-uv-hcalls.txt
@@ -0,0 +1,76 @@
+On PPC64 systems supporting Protected Execution Facility (PEF), system
+memory can be placed in a secured region where only an "ultravisor"
+running in firmware can provide to access it. pseries guests on such
+systems can communicate with the ultravisor (via ultracalls) to switch to a
+secure VM mode (SVM) where the guest's memory is relocated to this secured
+region, making its memory inaccessible to normal processes/guests running on
+the host.
+
+The various ultracalls/hypercalls relating to SVM mode are currently
+only documented internally, but are planned for direct inclusion into the
+public OpenPOWER version of the PAPR specification (LoPAPR/LoPAR). An internal
+ACR has been filed to reserve a hypercall number range specific to this
+use-case to avoid any future conflicts with the internally-maintained PAPR
+specification. This document summarizes some of these details as they relate
+to QEMU.
+
+== hypercalls needed by the ultravisor ==
+
+Switching to SVM mode involves a number of hcalls issued by the ultravisor
+to the hypervisor to orchestrate the movement of guest memory to secure
+memory and various other aspects SVM mode. Numbers are assigned for these
+hcalls within the reserved range 0xEF00-0xEF80. The below documents the
+hcalls relevant to QEMU.
+
+- H_TPM_COMM (0xef10)
+
+ For TPM_COMM_OP_EXECUTE operation:
+ Send a request to a TPM and receive a response, opening a new TPM session
+ if one has not already been opened.
+
+ For TPM_COMM_OP_CLOSE_SESSION operation:
+ Close the existing TPM session, if any.
+
+ Arguments:
+
+ r3 : H_TPM_COMM (0xef10)
+ r4 : TPM operation, one of:
+ TPM_COMM_OP_EXECUTE (0x1)
+ TPM_COMM_OP_CLOSE_SESSION (0x2)
+ r5 : in_buffer, guest physical address of buffer containing the request
+ - Caller may use the same address for both request and response
+ r6 : in_size, size of the in buffer
+ - Must be less than or equal to 4KB
+ r7 : out_buffer, guest physical address of buffer to store the response
+ - Caller may use the same address for both request and response
+ r8 : out_size, size of the out buffer
+ - Must be at least 4KB, as this is the maximum request/response size
+ supported by most TPM implementations, including the TPM Resource
+ Manager in the linux kernel.
+
+ Return values:
+
+ r3 : H_Success request processed successfully
+ H_PARAMETER invalid TPM operation
+ H_P2 in_buffer is invalid
+ H_P3 in_size is invalid
+ H_P4 out_buffer is invalid
+ H_P5 out_size is invalid
+ H_RESOURCE problem communicating with TPM
+ H_FUNCTION TPM access is not currently allowed/configured
+ r4 : For TPM_COMM_OP_EXECUTE, the size of the response will be stored here
+ upon success.
+
+ Use-case/notes:
+
+ SVM filesystems are encrypted using a symmetric key. This key is then
+ wrapped/encrypted using the public key of a trusted system which has the
+ private key stored in the system's TPM. An Ultravisor will use this
+ hcall to unwrap/unseal the symmetric key using the system's TPM device
+ or a TPM Resource Manager associated with the device.
+
+ The Ultravisor sets up a separate session key with the TPM in advance
+ during host system boot. All sensitive in and out values will be
+ encrypted using the session key. Though the hypervisor will see the 'in'
+ and 'out' buffers in raw form, any sensitive contents will generally be
+ encrypted using this session key.
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 02510ac..0d1629c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2050,10 +2050,17 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+static void virt_machine_4_2_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(4, 2)
+
static void virt_machine_4_1_options(MachineClass *mc)
{
+ virt_machine_4_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(4, 1)
+DEFINE_VIRT_MACHINE(4, 1)
static void virt_machine_4_0_options(MachineClass *mc)
{
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 7f860fc..087c93e 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -59,25 +59,19 @@ static int vty_getchars(SpaprVioDevice *sdev, uint8_t *buf, int max)
int n = 0;
while ((n < max) && (dev->out != dev->in)) {
- buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
-
- /* PowerVM's vty implementation has a bug where it inserts a
- * \0 after every \r going to the guest. Existing guests have
- * a workaround for this which removes every \0 immediately
- * following a \r, so here we make ourselves bug-for-bug
- * compatible, so that the guest won't drop a real \0-after-\r
- * that happens to occur in a binary stream. */
- if (buf[n - 1] == '\r') {
- if (n < max) {
- buf[n++] = '\0';
- } else {
- /* No room for the extra \0, roll back and try again
- * next time */
- dev->out--;
- n--;
- break;
- }
+ /*
+ * Long ago, PowerVM's vty implementation had a bug where it
+ * inserted a \0 after every \r going to the guest. Existing
+ * guests have a workaround for this which removes every \0
+ * immediately following a \r. To avoid triggering this
+ * workaround, we stop before inserting a \0 if the preceding
+ * character in the output buffer is a \r.
+ */
+ if (n > 0 && (buf[n - 1] == '\r') &&
+ (dev->buf[dev->out % VTERM_BUFSIZE] == '\0')) {
+ break;
}
+ buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
}
qemu_chr_fe_accept_input(&dev->chardev);
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 32d1ca9..83cd1bf 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -27,6 +27,9 @@
#include "hw/pci/pci.h"
#include "hw/mem/nvdimm.h"
+GlobalProperty hw_compat_4_1[] = {};
+const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
+
GlobalProperty hw_compat_4_0[] = {
{ "VGA", "edid", "false" },
{ "secondary-vga", "edid", "false" },
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 6b4f32e..697c336 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -119,6 +119,9 @@ struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
/* Physical Address of PVH entry point read from kernel ELF NOTE */
static size_t pvh_start_addr;
+GlobalProperty pc_compat_4_1[] = {};
+const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1);
+
GlobalProperty pc_compat_4_0[] = {};
const size_t pc_compat_4_0_len = G_N_ELEMENTS(pc_compat_4_0);
@@ -2840,6 +2843,13 @@ static void pc_machine_reset(MachineState *machine)
}
}
+static void pc_machine_wakeup(MachineState *machine)
+{
+ cpu_synchronize_all_states();
+ pc_machine_reset(machine);
+ cpu_synchronize_all_post_reset();
+}
+
static CpuInstanceProperties
pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
{
@@ -2952,6 +2962,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_IDE;
mc->max_cpus = 255;
mc->reset = pc_machine_reset;
+ mc->wakeup = pc_machine_wakeup;
hc->pre_plug = pc_machine_device_pre_plug_cb;
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9e187f8..a70cf0a 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -432,7 +432,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
}
-static void pc_i440fx_4_1_machine_options(MachineClass *m)
+static void pc_i440fx_4_2_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_options(m);
@@ -441,6 +441,18 @@ static void pc_i440fx_4_1_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_I440FX_MACHINE(v4_2, "pc-i440fx-4.2", NULL,
+ pc_i440fx_4_2_machine_options);
+
+static void pc_i440fx_4_1_machine_options(MachineClass *m)
+{
+ pc_i440fx_4_2_machine_options(m);
+ m->alias = NULL;
+ m->is_default = 0;
+ compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len);
+}
+
DEFINE_I440FX_MACHINE(v4_1, "pc-i440fx-4.1", NULL,
pc_i440fx_4_1_machine_options);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index be3464f..d4e8a1c 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -364,7 +364,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->max_cpus = 288;
}
-static void pc_q35_4_1_machine_options(MachineClass *m)
+static void pc_q35_4_2_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_options(m);
@@ -372,6 +372,17 @@ static void pc_q35_4_1_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_Q35_MACHINE(v4_2, "pc-q35-4.2", NULL,
+ pc_q35_4_2_machine_options);
+
+static void pc_q35_4_1_machine_options(MachineClass *m)
+{
+ pc_q35_4_2_machine_options(m);
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len);
+}
+
DEFINE_Q35_MACHINE(v4_1, "pc-q35-4.1", NULL,
pc_q35_4_1_machine_options);
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index a8caf25..ed6e9d7 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -1595,6 +1595,15 @@ void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
}
xive_end_pic_print_info(&end, i, mon);
}
+
+ monitor_printf(mon, "XIVE[%x] END Escalation %08x .. %08x\n", blk, 0,
+ nr_ends - 1);
+ for (i = 0; i < nr_ends; i++) {
+ if (xive_router_get_end(xrtr, blk, i, &end)) {
+ break;
+ }
+ xive_end_eas_pic_print_info(&end, i, mon);
+ }
}
static void pnv_xive_reset(void *dev)
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index aad981c..c1c9719 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -146,7 +146,6 @@ static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end,
priority, qindex, qentries, qaddr_base, qgen);
xive_end_queue_pic_print_info(end, 6, mon);
- monitor_printf(mon, "]");
}
void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
@@ -537,7 +536,10 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
return false;
}
- xive->eat[lisn].w |= cpu_to_be64(EAS_VALID);
+ /*
+ * Set default values when allocating an IRQ number
+ */
+ xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED);
if (lsi) {
xive_source_irq_set_lsi(xsrc, lisn);
}
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 7a6e4b7..b741721 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -337,6 +337,17 @@ static void xive_tm_set_os_pending(XiveTCTX *tctx, hwaddr offset,
xive_tctx_notify(tctx, TM_QW1_OS);
}
+static uint64_t xive_tm_pull_os_ctx(XiveTCTX *tctx, hwaddr offset,
+ unsigned size)
+{
+ uint32_t qw1w2_prev = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
+ uint32_t qw1w2;
+
+ qw1w2 = xive_set_field32(TM_QW1W2_VO, qw1w2_prev, 0);
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
+ return qw1w2;
+}
+
/*
* Define a mapping of "special" operations depending on the TIMA page
* offset and the size of the operation.
@@ -363,6 +374,8 @@ static const XiveTmOp xive_tm_operations[] = {
/* MMIOs above 2K : special operations with side effects */
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive_tm_pull_os_ctx },
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
@@ -406,7 +419,7 @@ void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
if (offset & 0x800) {
xto = xive_tm_find_op(offset, size, true);
if (!xto) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA"
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA "
"@%"HWADDR_PRIx"\n", offset);
} else {
xto->write_handler(tctx, offset, value, size);
@@ -1145,6 +1158,7 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
be32_to_cpu(qdata));
qindex = (qindex + 1) & (qentries - 1);
}
+ monitor_printf(mon, "]");
}
void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
@@ -1155,24 +1169,36 @@ void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
uint32_t qentries = 1 << (qsize + 10);
- uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6);
+ uint32_t nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end->w6);
+ uint32_t nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end->w6);
uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
+ uint8_t pq;
if (!xive_end_is_valid(end)) {
return;
}
- monitor_printf(mon, " %08x %c%c%c%c%c prio:%d nvt:%04x eq:@%08"PRIx64
- "% 6d/%5d ^%d", end_idx,
+ pq = xive_get_field32(END_W1_ESn, end->w1);
+
+ monitor_printf(mon, " %08x %c%c %c%c%c%c%c%c%c prio:%d nvt:%02x/%04x",
+ end_idx,
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
xive_end_is_valid(end) ? 'v' : '-',
xive_end_is_enqueue(end) ? 'q' : '-',
xive_end_is_notify(end) ? 'n' : '-',
xive_end_is_backlog(end) ? 'b' : '-',
xive_end_is_escalate(end) ? 'e' : '-',
- priority, nvt, qaddr_base, qindex, qentries, qgen);
+ xive_end_is_uncond_escalation(end) ? 'u' : '-',
+ xive_end_is_silent_escalation(end) ? 's' : '-',
+ priority, nvt_blk, nvt_idx);
- xive_end_queue_pic_print_info(end, 6, mon);
- monitor_printf(mon, "]\n");
+ if (qaddr_base) {
+ monitor_printf(mon, " eq:@%08"PRIx64"% 6d/%5d ^%d",
+ qaddr_base, qindex, qentries, qgen);
+ xive_end_queue_pic_print_info(end, 6, mon);
+ }
+ monitor_printf(mon, "\n");
}
static void xive_end_enqueue(XiveEND *end, uint32_t data)
@@ -1200,6 +1226,29 @@ static void xive_end_enqueue(XiveEND *end, uint32_t data)
end->w1 = xive_set_field32(END_W1_PAGE_OFF, end->w1, qindex);
}
+void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx,
+ Monitor *mon)
+{
+ XiveEAS *eas = (XiveEAS *) &end->w4;
+ uint8_t pq;
+
+ if (!xive_end_is_escalate(end)) {
+ return;
+ }
+
+ pq = xive_get_field32(END_W1_ESe, end->w1);
+
+ monitor_printf(mon, " %08x %c%c %c%c end:%02x/%04x data:%08x\n",
+ end_idx,
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
+ xive_eas_is_valid(eas) ? 'V' : ' ',
+ xive_eas_is_masked(eas) ? 'M' : ' ',
+ (uint8_t) xive_get_field64(EAS_END_BLOCK, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_INDEX, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_DATA, eas->w));
+}
+
/*
* XIVE Router (aka. Virtualization Controller or IVRE)
*/
@@ -1398,46 +1447,43 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
*
* The parameters represent what is sent on the PowerBus
*/
-static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
+static bool xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
bool cam_ignore, uint8_t priority,
uint32_t logic_serv)
{
- XiveNVT nvt;
XiveTCTXMatch match = { .tctx = NULL, .ring = 0 };
bool found;
- /* NVT cache lookup */
- if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
- nvt_blk, nvt_idx);
- return;
- }
-
- if (!xive_nvt_is_valid(&nvt)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
- nvt_blk, nvt_idx);
- return;
- }
-
found = xive_presenter_match(xrtr, format, nvt_blk, nvt_idx, cam_ignore,
priority, logic_serv, &match);
if (found) {
ipb_update(&match.tctx->regs[match.ring], priority);
xive_tctx_notify(match.tctx, match.ring);
- return;
}
- /* Record the IPB in the associated NVT structure */
- ipb_update((uint8_t *) &nvt.w4, priority);
- xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+ return found;
+}
- /*
- * If no matching NVT is dispatched on a HW thread :
- * - update the NVT structure if backlog is activated
- * - escalate (ESe PQ bits and EAS in w4-5) if escalation is
- * activated
- */
+/*
+ * Notification using the END ESe/ESn bit (Event State Buffer for
+ * escalation and notification). Profide futher coalescing in the
+ * Router.
+ */
+static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ uint32_t end_esmask)
+{
+ uint8_t pq = xive_get_field32(end_esmask, end->w1);
+ bool notify = xive_esb_trigger(&pq);
+
+ if (pq != xive_get_field32(end_esmask, end->w1)) {
+ end->w1 = xive_set_field32(end_esmask, end->w1, pq);
+ xive_router_write_end(xrtr, end_blk, end_idx, end, 1);
+ }
+
+ /* ESe/n[Q]=1 : end of notification */
+ return notify;
}
/*
@@ -1451,6 +1497,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
XiveEND end;
uint8_t priority;
uint8_t format;
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+ XiveNVT nvt;
+ bool found;
/* END cache lookup */
if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
@@ -1472,6 +1522,13 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
}
/*
+ * When the END is silent, we skip the notification part.
+ */
+ if (xive_end_is_silent_escalation(&end)) {
+ goto do_escalation;
+ }
+
+ /*
* The W7 format depends on the F bit in W6. It defines the type
* of the notification :
*
@@ -1492,16 +1549,9 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
* even futher coalescing in the Router
*/
if (!xive_end_is_notify(&end)) {
- uint8_t pq = xive_get_field32(END_W1_ESn, end.w1);
- bool notify = xive_esb_trigger(&pq);
-
- if (pq != xive_get_field32(END_W1_ESn, end.w1)) {
- end.w1 = xive_set_field32(END_W1_ESn, end.w1, pq);
- xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
- }
-
/* ESn[Q]=1 : end of notification */
- if (!notify) {
+ if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+ &end, END_W1_ESn)) {
return;
}
}
@@ -1509,14 +1559,82 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
/*
* Follows IVPE notification
*/
- xive_presenter_notify(xrtr, format,
- xive_get_field32(END_W6_NVT_BLOCK, end.w6),
- xive_get_field32(END_W6_NVT_INDEX, end.w6),
+ nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end.w6);
+ nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end.w6);
+
+ /* NVT cache lookup */
+ if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ if (!xive_nvt_is_valid(&nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ found = xive_presenter_notify(xrtr, format, nvt_blk, nvt_idx,
xive_get_field32(END_W7_F0_IGNORE, end.w7),
priority,
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
/* TODO: Auto EOI. */
+
+ if (found) {
+ return;
+ }
+
+ /*
+ * If no matching NVT is dispatched on a HW thread :
+ * - specific VP: update the NVT structure if backlog is activated
+ * - logical server : forward request to IVPE (not supported)
+ */
+ if (xive_end_is_backlog(&end)) {
+ if (format == 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: END %x/%x invalid config: F1 & backlog\n",
+ end_blk, end_idx);
+ return;
+ }
+ /* Record the IPB in the associated NVT structure */
+ ipb_update((uint8_t *) &nvt.w4, priority);
+ xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+
+ /*
+ * On HW, follows a "Broadcast Backlog" to IVPEs
+ */
+ }
+
+do_escalation:
+ /*
+ * If activated, escalate notification using the ESe PQ bits and
+ * the EAS in w4-5
+ */
+ if (!xive_end_is_escalate(&end)) {
+ return;
+ }
+
+ /*
+ * Check the END ESe (Event State Buffer for escalation) for even
+ * futher coalescing in the Router
+ */
+ if (!xive_end_is_uncond_escalation(&end)) {
+ /* ESe[Q]=1 : end of notification */
+ if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+ &end, END_W1_ESe)) {
+ return;
+ }
+ }
+
+ /*
+ * The END trigger becomes an Escalation trigger
+ */
+ xive_router_end_notify(xrtr,
+ xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
+ xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
+ xive_get_field32(END_W5_ESC_END_DATA, end.w5));
}
void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 9da93af..2c4e1c8 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -5,6 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o
+obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o
obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o
# IBM PowerNV
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 7963fee..52a18eb 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1011,6 +1011,8 @@ static void timebase_save(PPCTimebase *tb)
* there is no need to update it from KVM here
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
+
+ tb->runstate_paused = runstate_check(RUN_STATE_PAUSED);
}
static void timebase_load(PPCTimebase *tb)
@@ -1054,9 +1056,9 @@ void cpu_ppc_clock_vm_state_change(void *opaque, int running,
}
/*
- * When migrating, read the clock just before migration,
- * so that the guest clock counts during the events
- * between:
+ * When migrating a running guest, read the clock just
+ * before migration, so that the guest clock counts
+ * during the events between:
*
* * vm_stop()
* *
@@ -1071,7 +1073,10 @@ static int timebase_pre_save(void *opaque)
{
PPCTimebase *tb = opaque;
- timebase_save(tb);
+ /* guest_timebase won't be overridden in case of paused guest */
+ if (!tb->runstate_paused) {
+ timebase_save(tb);
+ }
return 0;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index e09c67e..64fc225 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -79,6 +79,7 @@
#include "qemu/cutils.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/mem/memory-device.h"
+#include "hw/ppc/spapr_tpm_proxy.h"
#include <libfdt.h>
@@ -1070,6 +1071,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
add_str(hypertas, "hcall-tce");
add_str(hypertas, "hcall-vio");
add_str(hypertas, "hcall-splpar");
+ add_str(hypertas, "hcall-join");
add_str(hypertas, "hcall-bulk");
add_str(hypertas, "hcall-set-mode");
add_str(hypertas, "hcall-sprg0");
@@ -1753,10 +1755,6 @@ static void spapr_machine_reset(MachineState *machine)
ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
}
- if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
- spapr_irq_msi_reset(spapr);
- }
-
/*
* This is fixing some of the default configuration of the XIVE
* devices. To be called after the reset of the machine devices.
@@ -3081,6 +3079,13 @@ static void spapr_machine_init(MachineState *machine)
qemu_register_boot_set(spapr_boot_set, spapr);
+ /*
+ * Nothing needs to be done to resume a suspended guest because
+ * suspending does not change the machine state, so no need for
+ * a ->wakeup method.
+ */
+ qemu_register_wakeup_support();
+
if (kvm_enabled()) {
/* to stop and start vmclock */
qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
@@ -4035,6 +4040,29 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
}
}
+static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
+
+ if (spapr->tpm_proxy != NULL) {
+ error_setg(errp, "Only one TPM proxy can be specified for this machine");
+ return;
+ }
+
+ spapr->tpm_proxy = tpm_proxy;
+}
+
+static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+
+ object_property_set_bool(OBJECT(dev), false, "realized", NULL);
+ object_unparent(OBJECT(dev));
+ spapr->tpm_proxy = NULL;
+}
+
static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -4044,6 +4072,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
spapr_core_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
spapr_phb_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
}
}
@@ -4056,6 +4086,8 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
spapr_core_unplug(hotplug_dev, dev);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
spapr_phb_unplug(hotplug_dev, dev);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_unplug(hotplug_dev, dev);
}
}
@@ -4090,6 +4122,8 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
return;
}
spapr_phb_unplug_request(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_unplug(hotplug_dev, dev);
}
}
@@ -4110,7 +4144,8 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
- object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
+ object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
return HOTPLUG_HANDLER(machine);
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
@@ -4306,6 +4341,53 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id)
return NULL;
}
+static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ /* These are only called by TCG, KVM maintains dispatch state */
+
+ spapr_cpu->prod = false;
+ if (spapr_cpu->vpa_addr) {
+ CPUState *cs = CPU(cpu);
+ uint32_t dispatch;
+
+ dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ dispatch++;
+ if ((dispatch & 1) != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "VPA: incorrect dispatch counter value for "
+ "dispatched partition %u, correcting.\n", dispatch);
+ dispatch++;
+ }
+ stl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
+ }
+}
+
+static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ if (spapr_cpu->vpa_addr) {
+ CPUState *cs = CPU(cpu);
+ uint32_t dispatch;
+
+ dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ dispatch++;
+ if ((dispatch & 1) != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "VPA: incorrect dispatch counter value for "
+ "preempted partition %u, correcting.\n", dispatch);
+ dispatch++;
+ }
+ stl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
+ }
+}
+
static void spapr_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -4362,6 +4444,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
vhc->hpte_set_r = spapr_hpte_set_r;
vhc->get_pate = spapr_get_pate;
vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
+ vhc->cpu_exec_enter = spapr_cpu_exec_enter;
+ vhc->cpu_exec_exit = spapr_cpu_exec_exit;
xic->ics_get = spapr_ics_get;
xic->ics_resend = spapr_ics_resend;
xic->icp_get = spapr_icp_get;
@@ -4431,14 +4515,31 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
+ * pseries-4.2
+ */
+static void spapr_machine_4_2_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
+
+/*
* pseries-4.1
*/
static void spapr_machine_4_1_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ static GlobalProperty compat[] = {
+ /* Only allow 4kiB and 64kiB IOMMU pagesizes */
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
+ };
+
+ spapr_machine_4_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
-DEFINE_SPAPR_MACHINE(4_1, "4.1", true);
+DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
/*
* pseries-4.0
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 7830d66..481dfd2 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -195,10 +195,12 @@ static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
}
if (tcg_enabled()) {
error_setg(errp,
- "No Transactional Memory support in TCG, try cap-htm=off");
+ "No Transactional Memory support in TCG,"
+ " try appending -machine cap-htm=off");
} else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
error_setg(errp,
-"KVM implementation does not support Transactional Memory, try cap-htm=off"
+"KVM implementation does not support Transactional Memory,"
+ " try appending -machine cap-htm=off"
);
}
}
@@ -216,7 +218,8 @@ static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
* rid of anything that doesn't do VMX */
g_assert(env->insns_flags & PPC_ALTIVEC);
if (!(env->insns_flags2 & PPC2_VSX)) {
- error_setg(errp, "VSX support not available, try cap-vsx=off");
+ error_setg(errp, "VSX support not available,"
+ " try appending -machine cap-vsx=off");
}
}
@@ -230,7 +233,8 @@ static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
return;
}
if (!(env->insns_flags2 & PPC2_DFP)) {
- error_setg(errp, "DFP support not available, try cap-dfp=off");
+ error_setg(errp, "DFP support not available,"
+ " try appending -machine cap-dfp=off");
}
}
@@ -254,7 +258,8 @@ static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val,
cap_cfpc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
+ "Requested safe cache capability level not supported by kvm,"
+ " try appending -machine cap-cfpc=%s",
cap_cfpc_possible.vals[kvm_val]);
}
@@ -282,7 +287,8 @@ static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val,
cap_sbbc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
+"Requested safe bounds check capability level not supported by kvm,"
+ " try appending -machine cap-sbbc=%s",
cap_sbbc_possible.vals[kvm_val]);
}
@@ -313,7 +319,8 @@ static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr,
cap_ibs_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
+"Requested safe indirect branch capability level not supported by kvm,"
+ " try appending -machine cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
}
@@ -402,11 +409,13 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr,
if (tcg_enabled()) {
error_setg(errp,
- "No Nested KVM-HV support in tcg, try cap-nested-hv=off");
+ "No Nested KVM-HV support in tcg,"
+ " try appending -machine cap-nested-hv=off");
} else if (kvm_enabled()) {
if (!kvmppc_has_cap_nested_kvm_hv()) {
error_setg(errp,
-"KVM implementation does not support Nested KVM-HV, try cap-nested-hv=off");
+"KVM implementation does not support Nested KVM-HV,"
+ " try appending -machine cap-nested-hv=off");
} else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) {
error_setg(errp,
"Error enabling cap-nested-hv with KVM, try cap-nested-hv=off");
@@ -436,10 +445,12 @@ static void cap_large_decr_apply(SpaprMachineState *spapr,
if (!kvm_nr_bits) {
error_setg(errp,
- "No large decrementer support, try cap-large-decr=off");
+ "No large decrementer support,"
+ " try appending -machine cap-large-decr=off");
} else if (pcc->lrg_decr_bits != kvm_nr_bits) {
error_setg(errp,
-"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off",
+"KVM large decrementer size (%d) differs to model (%d),"
+ " try appending -machine cap-large-decr=off",
kvm_nr_bits, pcc->lrg_decr_bits);
}
}
@@ -455,7 +466,8 @@ static void cap_large_decr_cpu_apply(SpaprMachineState *spapr,
if (kvm_enabled()) {
if (kvmppc_enable_cap_large_decr(cpu, val)) {
error_setg(errp,
- "No large decrementer support, try cap-large-decr=off");
+ "No large decrementer support,"
+ " try appending -machine cap-large-decr=off");
}
}
@@ -475,10 +487,12 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val,
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
error_setg(errp,
-"Requested count cache flush assist capability level not supported by tcg, try cap-ccf-assist=off");
+"Requested count cache flush assist capability level not supported by tcg,"
+ " try appending -machine cap-ccf-assist=off");
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested count cache flush assist capability level not supported by kvm, try cap-ccf-assist=off");
+"Requested count cache flush assist capability level not supported by kvm,"
+ " try appending -machine cap-ccf-assist=off");
}
}
@@ -779,7 +793,7 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp)
for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
SpaprCapabilityInfo *cap = &capability_table[i];
- const char *name = g_strdup_printf("cap-%s", cap->name);
+ char *name = g_strdup_printf("cap-%s", cap->name);
char *desc;
object_class_property_add(klass, name, cap->type,
@@ -787,11 +801,13 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp)
NULL, cap, &local_err);
if (local_err) {
error_propagate(errp, local_err);
+ g_free(name);
return;
}
desc = g_strdup_printf("%s", cap->description);
object_class_property_set_description(klass, name, desc, &local_err);
+ g_free(name);
g_free(desc);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 09255f4..62f1a42 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -227,7 +227,7 @@ static uint32_t drc_set_unusable(SpaprDrc *drc)
return RTAS_OUT_SUCCESS;
}
-static const char *spapr_drc_name(SpaprDrc *drc)
+static char *spapr_drc_name(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
@@ -828,6 +828,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
Object *obj;
SpaprDrc *drc;
SpaprDrcClass *drck;
+ char *drc_name = NULL;
uint32_t drc_index, drc_power_domain;
if (!strstart(prop->type, "link<", NULL)) {
@@ -857,8 +858,10 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
g_array_append_val(drc_power_domains, drc_power_domain);
/* ibm,drc-names */
- drc_names = g_string_append(drc_names, spapr_drc_name(drc));
+ drc_name = spapr_drc_name(drc);
+ drc_names = g_string_append(drc_names, drc_name);
drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
+ g_free(drc_name);
/* ibm,drc-types */
drc_types = g_string_append(drc_types, drck->typename);
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 225c60a..e20a946 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -875,11 +875,6 @@ unmap_out:
#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
-#define VPA_MIN_SIZE 640
-#define VPA_SIZE_OFFSET 0x4
-#define VPA_SHARED_PROC_OFFSET 0x9
-#define VPA_SHARED_PROC_VAL 0x2
-
static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
CPUState *cs = CPU(cpu);
@@ -1056,14 +1051,155 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
{
CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
env->msr |= (1ULL << MSR_EE);
hreg_compute_hflags(env);
+
+ if (spapr_cpu->prod) {
+ spapr_cpu->prod = false;
+ return H_SUCCESS;
+ }
+
if (!cpu_has_work(cs)) {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
cs->exit_request = 1;
}
+
+ return H_SUCCESS;
+}
+
+/*
+ * Confer to self, aka join. Cede could use the same pattern as well, if
+ * EXCP_HLT can be changed to ECXP_HALTED.
+ */
+static target_ulong h_confer_self(PowerPCCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ if (spapr_cpu->prod) {
+ spapr_cpu->prod = false;
+ return H_SUCCESS;
+ }
+ cs->halted = 1;
+ cs->exception_index = EXCP_HALTED;
+ cs->exit_request = 1;
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_join(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUPPCState *env = &cpu->env;
+ CPUState *cs;
+ bool last_unjoined = true;
+
+ if (env->msr & (1ULL << MSR_EE)) {
+ return H_BAD_MODE;
+ }
+
+ /*
+ * Must not join the last CPU running. Interestingly, no such restriction
+ * for H_CONFER-to-self, but that is probably not intended to be used
+ * when H_JOIN is available.
+ */
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
+ CPUPPCState *e = &c->env;
+ if (c == cpu) {
+ continue;
+ }
+
+ /* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */
+ if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+ last_unjoined = false;
+ break;
+ }
+ }
+ if (last_unjoined) {
+ return H_CONTINUE;
+ }
+
+ return h_confer_self(cpu);
+}
+
+static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_long target = args[0];
+ uint32_t dispatch = args[1];
+ CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu;
+
+ /*
+ * -1 means confer to all other CPUs without dispatch counter check,
+ * otherwise it's a targeted confer.
+ */
+ if (target != -1) {
+ PowerPCCPU *target_cpu = spapr_find_cpu(target);
+ uint32_t target_dispatch;
+
+ if (!target_cpu) {
+ return H_PARAMETER;
+ }
+
+ /*
+ * target == self is a special case, we wait until prodded, without
+ * dispatch counter check.
+ */
+ if (cpu == target_cpu) {
+ return h_confer_self(cpu);
+ }
+
+ spapr_cpu = spapr_cpu_state(target_cpu);
+ if (!spapr_cpu->vpa_addr || ((dispatch & 1) == 0)) {
+ return H_SUCCESS;
+ }
+
+ target_dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ if (target_dispatch != dispatch) {
+ return H_SUCCESS;
+ }
+
+ /*
+ * The targeted confer does not do anything special beyond yielding
+ * the current vCPU, but even this should be better than nothing.
+ * At least for single-threaded tcg, it gives the target a chance to
+ * run before we run again. Multi-threaded tcg does not really do
+ * anything with EXCP_YIELD yet.
+ */
+ }
+
+ cs->exception_index = EXCP_YIELD;
+ cs->exit_request = 1;
+ cpu_loop_exit(cs);
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_long target = args[0];
+ PowerPCCPU *tcpu;
+ CPUState *cs;
+ SpaprCpuState *spapr_cpu;
+
+ tcpu = spapr_find_cpu(target);
+ cs = CPU(tcpu);
+ if (!cs) {
+ return H_PARAMETER;
+ }
+
+ spapr_cpu = spapr_cpu_state(tcpu);
+ spapr_cpu->prod = true;
+ cs->halted = 0;
+ qemu_cpu_kick(cs);
+
return H_SUCCESS;
}
@@ -1613,6 +1749,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
ov5_updates = spapr_ovec_new();
spapr->cas_reboot = spapr_ovec_diff(ov5_updates,
ov5_cas_old, spapr->ov5_cas);
+ spapr_ovec_cleanup(ov5_cas_old);
/* Now that processing is finished, set the radix/hash bit for the
* guest if it requested a valid mode; otherwise terminate the boot. */
if (guest_radix) {
@@ -1630,6 +1767,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
}
spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest,
OV1_PPC_3_00);
+ spapr_ovec_cleanup(ov1_guest);
if (!spapr->cas_reboot) {
/* If spapr_machine_reset() did not set up a HPT but one is necessary
* (because the guest isn't going to use radix) then set it up here. */
@@ -1825,6 +1963,7 @@ static target_ulong h_update_dt(PowerPCCPU *cpu, SpaprMachineState *spapr,
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
+static spapr_hcall_fn svm_hypercall_table[(SVM_HCALL_MAX - SVM_HCALL_BASE) / 4 + 1];
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
{
@@ -1834,6 +1973,11 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
assert((opcode & 0x3) == 0);
slot = &papr_hypercall_table[opcode / 4];
+ } else if (opcode >= SVM_HCALL_BASE && opcode <= SVM_HCALL_MAX) {
+ /* we only have SVM-related hcall numbers assigned in multiples of 4 */
+ assert((opcode & 0x3) == 0);
+
+ slot = &svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4];
} else {
assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
@@ -1856,6 +2000,13 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
if (fn) {
return fn(cpu, spapr, opcode, args);
}
+ } else if ((opcode >= SVM_HCALL_BASE) &&
+ (opcode <= SVM_HCALL_MAX)) {
+ spapr_hcall_fn fn = svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4];
+
+ if (fn) {
+ return fn(cpu, spapr, opcode, args);
+ }
} else if ((opcode >= KVMPPC_HCALL_BASE) &&
(opcode <= KVMPPC_HCALL_MAX)) {
spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
@@ -1888,6 +2039,12 @@ static void hypercall_register_types(void)
/* hcall-splpar */
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
spapr_register_hypercall(H_CEDE, h_cede);
+ spapr_register_hypercall(H_CONFER, h_confer);
+ spapr_register_hypercall(H_PROD, h_prod);
+
+ /* hcall-join */
+ spapr_register_hypercall(H_JOIN, h_join);
+
spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
/* processor register resource access h-calls */
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index ce85f8a..e87b3d5 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -136,7 +136,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
ret.addr_mask = ~page_mask;
ret.perm = spapr_tce_iommu_access_flags(tce);
}
- trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
+ trace_spapr_iommu_xlate(tcet->liobn, addr, ret.translated_addr, ret.perm,
ret.addr_mask);
return ret;
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 2f87fe0..06fe243 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -59,11 +59,6 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num)
bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
}
-void spapr_irq_msi_reset(SpaprMachineState *spapr)
-{
- bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
-}
-
static void spapr_irq_init_kvm(SpaprMachineState *spapr,
SpaprIrq *irq, Error **errp)
{
@@ -731,6 +726,8 @@ int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
{
+ assert(!spapr->irq_map || bitmap_empty(spapr->irq_map, spapr->irq_map_nr));
+
if (spapr->irq->reset) {
spapr->irq->reset(spapr, errp);
}
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index bf31fd8..deb0b0c 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -338,10 +338,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
return;
}
- if (!smc->legacy_irq_allocation) {
- spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
- }
- spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
}
@@ -411,10 +407,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
/* Release previous MSIs */
if (msi) {
- if (!smc->legacy_irq_allocation) {
- spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
- }
- spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@@ -1808,6 +1800,19 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
memory_region_del_subregion(get_system_memory(), &sphb->mem32window);
}
+static void spapr_phb_destroy_msi(gpointer opaque)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ spapr_pci_msi *msi = opaque;
+
+ if (!smc->legacy_irq_allocation) {
+ spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
+ }
+ spapr_irq_free(spapr, msi->first_irq, msi->num);
+ g_free(msi);
+}
+
static void spapr_phb_realize(DeviceState *dev, Error **errp)
{
/* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
@@ -2019,7 +2024,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
spapr_tce_get_iommu(tcet));
}
- sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
+ sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free,
+ spapr_phb_destroy_msi);
return;
unrealize:
@@ -2074,6 +2080,8 @@ static void spapr_phb_reset(DeviceState *qdev)
if (spapr_phb_eeh_available(SPAPR_PCI_HOST_BRIDGE(qdev))) {
spapr_phb_vfio_reset(qdev);
}
+
+ g_hash_table_remove_all(sphb->msi);
}
static Property spapr_phb_properties[] = {
@@ -2093,7 +2101,8 @@ static Property spapr_phb_properties[] = {
0x800000000000000ULL),
DEFINE_PROP_BOOL("ddw", SpaprPhbState, ddw_enabled, true),
DEFINE_PROP_UINT64("pgsz", SpaprPhbState, page_size_mask,
- (1ULL << 12) | (1ULL << 16)),
+ (1ULL << 12) | (1ULL << 16)
+ | (1ULL << 21) | (1ULL << 24)),
DEFINE_PROP_UINT32("numa_node", SpaprPhbState, numa_node, -1),
DEFINE_PROP_BOOL("pre-2.8-migration", SpaprPhbState,
pre_2_8_migration, false),
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d3f9a69..526b489 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -217,6 +217,36 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
qemu_cpu_kick(cs);
}
+static void rtas_ibm_suspend_me(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ CPUState *cs;
+
+ if (nargs != 0 || nret != 1) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
+ CPUPPCState *e = &c->env;
+ if (c == cpu) {
+ continue;
+ }
+
+ /* See h_join */
+ if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+ rtas_st(rets, 0, H_MULTI_THREADS_ACTIVE);
+ return;
+ }
+ }
+
+ qemu_system_suspend_request();
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
+}
+
static inline int sysparm_st(target_ulong addr, target_ulong len,
const void *val, uint16_t vallen)
{
@@ -484,6 +514,8 @@ static void core_rtas_register_types(void)
rtas_query_cpu_stopped_state);
spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
+ spapr_rtas_register(RTAS_IBM_SUSPEND_ME, "ibm,suspend-me",
+ rtas_ibm_suspend_me);
spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
"ibm,get-system-parameter",
rtas_ibm_get_system_parameter);
diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c
new file mode 100644
index 0000000..b835d25
--- /dev/null
+++ b/hw/ppc/spapr_tpm_proxy.c
@@ -0,0 +1,178 @@
+/*
+ * SPAPR TPM Proxy/Hypercall
+ *
+ * Copyright IBM Corp. 2019
+ *
+ * Authors:
+ * Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "cpu.h"
+#include "hw/ppc/spapr.h"
+#include "hw/qdev-properties.h"
+#include "trace.h"
+
+#define TPM_SPAPR_BUFSIZE 4096
+
+enum {
+ TPM_COMM_OP_EXECUTE = 1,
+ TPM_COMM_OP_CLOSE_SESSION = 2,
+};
+
+static void spapr_tpm_proxy_reset(void *opaque)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(opaque);
+
+ if (tpm_proxy->host_fd != -1) {
+ close(tpm_proxy->host_fd);
+ tpm_proxy->host_fd = -1;
+ }
+}
+
+static ssize_t tpm_execute(SpaprTpmProxy *tpm_proxy, target_ulong *args)
+{
+ uint64_t data_in = ppc64_phys_to_real(args[1]);
+ target_ulong data_in_size = args[2];
+ uint64_t data_out = ppc64_phys_to_real(args[3]);
+ target_ulong data_out_size = args[4];
+ uint8_t buf_in[TPM_SPAPR_BUFSIZE];
+ uint8_t buf_out[TPM_SPAPR_BUFSIZE];
+ ssize_t ret;
+
+ trace_spapr_tpm_execute(data_in, data_in_size, data_out, data_out_size);
+
+ if (data_in_size > TPM_SPAPR_BUFSIZE) {
+ error_report("invalid TPM input buffer size: " TARGET_FMT_lu,
+ data_in_size);
+ return H_P3;
+ }
+
+ if (data_out_size < TPM_SPAPR_BUFSIZE) {
+ error_report("invalid TPM output buffer size: " TARGET_FMT_lu,
+ data_out_size);
+ return H_P5;
+ }
+
+ if (tpm_proxy->host_fd == -1) {
+ tpm_proxy->host_fd = open(tpm_proxy->host_path, O_RDWR);
+ if (tpm_proxy->host_fd == -1) {
+ error_report("failed to open TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+ }
+
+ cpu_physical_memory_read(data_in, buf_in, data_in_size);
+
+ do {
+ ret = write(tpm_proxy->host_fd, buf_in, data_in_size);
+ if (ret > 0) {
+ data_in_size -= ret;
+ }
+ } while ((ret >= 0 && data_in_size > 0) || (ret == -1 && errno == EINTR));
+
+ if (ret == -1) {
+ error_report("failed to write to TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+
+ do {
+ ret = read(tpm_proxy->host_fd, buf_out, data_out_size);
+ } while (ret == 0 || (ret == -1 && errno == EINTR));
+
+ if (ret == -1) {
+ error_report("failed to read from TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+
+ cpu_physical_memory_write(data_out, buf_out, ret);
+ args[0] = ret;
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_tpm_comm(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong op = args[0];
+ SpaprTpmProxy *tpm_proxy = spapr->tpm_proxy;
+
+ if (!tpm_proxy) {
+ error_report("TPM proxy not available");
+ return H_FUNCTION;
+ }
+
+ trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op);
+
+ switch (op) {
+ case TPM_COMM_OP_EXECUTE:
+ return tpm_execute(tpm_proxy, args);
+ case TPM_COMM_OP_CLOSE_SESSION:
+ spapr_tpm_proxy_reset(tpm_proxy);
+ return H_SUCCESS;
+ default:
+ return H_PARAMETER;
+ }
+}
+
+static void spapr_tpm_proxy_realize(DeviceState *d, Error **errp)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
+
+ if (tpm_proxy->host_path == NULL) {
+ error_setg(errp, "must specify 'host-path' option for device");
+ return;
+ }
+
+ tpm_proxy->host_fd = -1;
+ qemu_register_reset(spapr_tpm_proxy_reset, tpm_proxy);
+}
+
+static void spapr_tpm_proxy_unrealize(DeviceState *d, Error **errp)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
+
+ qemu_unregister_reset(spapr_tpm_proxy_reset, tpm_proxy);
+}
+
+static Property spapr_tpm_proxy_properties[] = {
+ DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data)
+{
+ DeviceClass *dk = DEVICE_CLASS(k);
+
+ dk->realize = spapr_tpm_proxy_realize;
+ dk->unrealize = spapr_tpm_proxy_unrealize;
+ dk->user_creatable = true;
+ dk->props = spapr_tpm_proxy_properties;
+}
+
+static const TypeInfo spapr_tpm_proxy_info = {
+ .name = TYPE_SPAPR_TPM_PROXY,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SpaprTpmProxy),
+ .class_init = spapr_tpm_proxy_class_init,
+};
+
+static void spapr_tpm_proxy_register_types(void)
+{
+ type_register_static(&spapr_tpm_proxy_info);
+ spapr_register_hypercall(SVM_H_TPM_COMM, h_tpm_comm);
+}
+
+type_init(spapr_tpm_proxy_register_types)
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index f76448f..96dad76 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -25,6 +25,10 @@ spapr_update_dt(unsigned cb) "New blob %u bytes"
spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
+# spapr_hcall_tpm.c
+spapr_h_tpm_comm(const char *device_path, uint64_t operation) "tpm_device_path=%s operation=0x%"PRIu64
+spapr_tpm_execute(uint64_t data_in, uint64_t data_in_sz, uint64_t data_out, uint64_t data_out_sz) "data_in=0x%"PRIx64", data_in_sz=%"PRIu64", data_out=0x%"PRIx64", data_out_sz=%"PRIu64
+
# spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 434d933..8bfb668 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -663,14 +663,26 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
+static void ccw_machine_4_2_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_4_2_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(4_2, "4.2", true);
+
static void ccw_machine_4_1_instance_options(MachineState *machine)
{
+ ccw_machine_4_2_instance_options(machine);
}
static void ccw_machine_4_1_class_options(MachineClass *mc)
{
+ ccw_machine_4_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
}
-DEFINE_CCW_MACHINE(4_1, "4.1", true);
+DEFINE_CCW_MACHINE(4_1, "4.1", false);
static void ccw_machine_4_0_instance_options(MachineState *machine)
{
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 739d109..60d6921 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -180,6 +180,7 @@ struct MachineClass {
void (*init)(MachineState *state);
void (*reset)(MachineState *state);
+ void (*wakeup)(MachineState *state);
void (*hot_add_cpu)(MachineState *state, const int64_t id, Error **errp);
int (*kvm_type)(MachineState *machine, const char *arg);
void (*smp_parse)(MachineState *ms, QemuOpts *opts);
@@ -317,6 +318,9 @@ struct MachineState {
} \
type_init(machine_initfn##_register_types)
+extern GlobalProperty hw_compat_4_1[];
+extern const size_t hw_compat_4_1_len;
+
extern GlobalProperty hw_compat_4_0[];
extern const size_t hw_compat_4_0_len;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 2afe285..19a8378 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -302,6 +302,9 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
+extern GlobalProperty pc_compat_4_1[];
+extern const size_t pc_compat_4_1_len;
+
extern GlobalProperty pc_compat_4_0[];
extern const size_t pc_compat_4_0_len;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 60553d3..fa7c380 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -10,6 +10,7 @@
#include "hw/ppc/spapr_irq.h"
#include "hw/ppc/spapr_xive.h" /* For SpaprXive */
#include "hw/ppc/xics.h" /* For ICSState */
+#include "hw/ppc/spapr_tpm_proxy.h"
struct SpaprVioBus;
struct SpaprPhbState;
@@ -203,6 +204,7 @@ struct SpaprMachineState {
SpaprCapabilities def, eff, mig;
unsigned gpu_numa_id;
+ SpaprTpmProxy *tpm_proxy;
};
#define H_SUCCESS 0
@@ -508,6 +510,15 @@ struct SpaprMachineState {
#define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3)
#define KVMPPC_HCALL_MAX KVMPPC_H_UPDATE_DT
+/*
+ * The hcall range 0xEF00 to 0xEF80 is reserved for use in facilitating
+ * Secure VM mode via an Ultravisor / Protected Execution Facility
+ */
+#define SVM_HCALL_BASE 0xEF00
+#define SVM_H_TPM_COMM 0xEF10
+#define SVM_HCALL_MAX SVM_H_TPM_COMM
+
+
typedef struct SpaprDeviceTreeUpdateHeader {
uint32_t version_id;
} SpaprDeviceTreeUpdateHeader;
@@ -525,6 +536,13 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args);
+/* Virtual Processor Area structure constants */
+#define VPA_MIN_SIZE 640
+#define VPA_SIZE_OFFSET 0x4
+#define VPA_SHARED_PROC_OFFSET 0x9
+#define VPA_SHARED_PROC_VAL 0x2
+#define VPA_DISPATCH_COUNTER 0x100
+
/* ibm,set-eeh-option */
#define RTAS_EEH_DISABLE 0
#define RTAS_EEH_ENABLE 1
@@ -624,8 +642,9 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
#define RTAS_IBM_CREATE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x27)
#define RTAS_IBM_REMOVE_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x28)
#define RTAS_IBM_RESET_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x29)
+#define RTAS_IBM_SUSPEND_ME (RTAS_TOKEN_BASE + 0x2A)
-#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2A)
+#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2B)
/* RTAS ibm,get-system-parameter token values */
#define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 35e0a7e..1c4cc65 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -46,6 +46,7 @@ typedef struct SpaprCpuState {
uint64_t vpa_addr;
uint64_t slb_shadow_addr, slb_shadow_size;
uint64_t dtl_addr, dtl_size;
+ bool prod; /* not migrated, only used to improve dispatch latencies */
struct ICPState *icp;
struct XiveTCTX *tctx;
} SpaprCpuState;
diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h
index 8132e00..5db3051 100644
--- a/include/hw/ppc/spapr_irq.h
+++ b/include/hw/ppc/spapr_irq.h
@@ -30,7 +30,6 @@ void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis);
int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align,
Error **errp);
void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num);
-void spapr_irq_msi_reset(SpaprMachineState *spapr);
typedef struct SpaprIrq {
uint32_t nr_irqs;
diff --git a/include/hw/ppc/spapr_tpm_proxy.h b/include/hw/ppc/spapr_tpm_proxy.h
new file mode 100644
index 0000000..c574e22
--- /dev/null
+++ b/include/hw/ppc/spapr_tpm_proxy.h
@@ -0,0 +1,31 @@
+/*
+ * SPAPR TPM Proxy/Hypercall
+ *
+ * Copyright IBM Corp. 2019
+ *
+ * Authors:
+ * Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_SPAPR_TPM_PROXY_H
+#define HW_SPAPR_TPM_PROXY_H
+
+#include "qom/object.h"
+#include "hw/qdev-core.h"
+
+#define TYPE_SPAPR_TPM_PROXY "spapr-tpm-proxy"
+#define SPAPR_TPM_PROXY(obj) OBJECT_CHECK(SpaprTpmProxy, (obj), \
+ TYPE_SPAPR_TPM_PROXY)
+
+typedef struct SpaprTpmProxy {
+ /*< private >*/
+ DeviceState parent;
+
+ char *host_path;
+ int host_fd;
+} SpaprTpmProxy;
+
+#endif /* HW_SPAPR_TPM_PROXY_H */
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 9399c77..6d38755 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -148,13 +148,11 @@
* XIVE Notifier (Interface between Source and Router)
*/
-typedef struct XiveNotifier {
- Object parent;
-} XiveNotifier;
+typedef struct XiveNotifier XiveNotifier;
#define TYPE_XIVE_NOTIFIER "xive-notifier"
#define XIVE_NOTIFIER(obj) \
- OBJECT_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER)
+ INTERFACE_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER)
#define XIVE_NOTIFIER_CLASS(klass) \
OBJECT_CLASS_CHECK(XiveNotifierClass, (klass), TYPE_XIVE_NOTIFIER)
#define XIVE_NOTIFIER_GET_CLASS(obj) \
@@ -356,8 +354,6 @@ typedef struct XiveRouterClass {
XiveTCTX *(*get_tctx)(XiveRouter *xrtr, CPUState *cs);
} XiveRouterClass;
-void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
-
int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
XiveEAS *eas);
int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
@@ -399,9 +395,6 @@ typedef struct XiveENDSource {
*/
#define XIVE_PRIORITY_MAX 7
-void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
-void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
-
/*
* XIVE Thread Interrupt Management Aera (TIMA)
*
diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
index b0c68ab..08c8bf7 100644
--- a/include/hw/ppc/xive_regs.h
+++ b/include/hw/ppc/xive_regs.h
@@ -131,6 +131,8 @@ typedef struct XiveEAS {
#define xive_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS_VALID)
#define xive_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS_MASKED)
+void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
+
static inline uint64_t xive_get_field64(uint64_t mask, uint64_t word)
{
return (be64_to_cpu(word) & mask) >> ctz64(mask);
@@ -210,6 +212,10 @@ typedef struct XiveEND {
#define xive_end_is_notify(end) (be32_to_cpu((end)->w0) & END_W0_UCOND_NOTIFY)
#define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG)
#define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & END_W0_ESCALATE_CTL)
+#define xive_end_is_uncond_escalation(end) \
+ (be32_to_cpu((end)->w0) & END_W0_UNCOND_ESCALATE)
+#define xive_end_is_silent_escalation(end) \
+ (be32_to_cpu((end)->w0) & END_W0_SILENT_ESCALATE)
static inline uint64_t xive_end_qaddr(XiveEND *end)
{
@@ -217,6 +223,10 @@ static inline uint64_t xive_end_qaddr(XiveEND *end)
be32_to_cpu(end->w3);
}
+void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
+void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
+void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
+
/* Notification Virtual Target (NVT) */
typedef struct XiveNVT {
uint32_t w0;
diff --git a/pc-bios/README b/pc-bios/README
index 68b4a81..d59cd25 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20190703.
+ built from git tag qemu-slof-20190719.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 2def514..fb08375 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/roms/SLOF b/roms/SLOF
-Subproject ba1ab360eebe6338bb8d7d83a9220ccf7e213af
+Subproject 7bfe584e321946771692711ff83ad2b5850daca
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index a2f202f..5769fb7 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -201,6 +201,7 @@ typedef struct PowerPCCPUClass {
typedef struct PPCTimebase {
uint64_t guest_timebase;
int64_t time_of_the_day_ns;
+ bool runstate_paused;
} PPCTimebase;
extern const VMStateDescription vmstate_ppc_timebase;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 4ea33cf..eaee1a5 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -591,7 +591,7 @@ enum {
#define FPSCR_XE 3 /* Floating-point inexact exception enable */
#define FPSCR_NI 2 /* Floating-point non-IEEE mode */
#define FPSCR_RN1 1
-#define FPSCR_RN 0 /* Floating-point rounding control */
+#define FPSCR_RN0 0 /* Floating-point rounding control */
#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1)
#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1)
#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1)
@@ -614,7 +614,7 @@ enum {
#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1)
#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1)
#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1)
-#define fpscr_rn (((env->fpscr) >> FPSCR_RN) & 0x3)
+#define fpscr_rn (((env->fpscr) >> FPSCR_RN0) & 0x3)
/* Invalid operation exception summary */
#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \
(1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \
@@ -640,7 +640,7 @@ enum {
#define FP_VXZDZ (1ull << FPSCR_VXZDZ)
#define FP_VXIMZ (1ull << FPSCR_VXIMZ)
#define FP_VXVC (1ull << FPSCR_VXVC)
-#define FP_FR (1ull << FSPCR_FR)
+#define FP_FR (1ull << FPSCR_FR)
#define FP_FI (1ull << FPSCR_FI)
#define FP_C (1ull << FPSCR_C)
#define FP_FL (1ull << FPSCR_FL)
@@ -648,7 +648,7 @@ enum {
#define FP_FE (1ull << FPSCR_FE)
#define FP_FU (1ull << FPSCR_FU)
#define FP_FPCC (FP_FL | FP_FG | FP_FE | FP_FU)
-#define FP_FPRF (FP_C | FP_FL | FP_FG | FP_FE | FP_FU)
+#define FP_FPRF (FP_C | FP_FPCC)
#define FP_VXSOFT (1ull << FPSCR_VXSOFT)
#define FP_VXSQRT (1ull << FPSCR_VXSQRT)
#define FP_VXCVI (1ull << FPSCR_VXCVI)
@@ -659,7 +659,12 @@ enum {
#define FP_XE (1ull << FPSCR_XE)
#define FP_NI (1ull << FPSCR_NI)
#define FP_RN1 (1ull << FPSCR_RN1)
-#define FP_RN (1ull << FPSCR_RN)
+#define FP_RN0 (1ull << FPSCR_RN0)
+#define FP_RN (FP_RN1 | FP_RN0)
+
+#define FP_MODE FP_RN
+#define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE)
+#define FP_STATUS (FP_FR | FP_FI | FP_FPRF)
/* the exception bits which can be cleared by mcrfs - includes FX */
#define FP_EX_CLEAR_BITS (FP_FX | FP_OX | FP_UX | FP_ZX | \
@@ -1104,10 +1109,6 @@ struct CPUPPCState {
bool resume_as_sreset;
#endif
- /* Those resources are used only during code translation */
- /* opcode handlers */
- opc_handler_t *opcodes[PPC_CPU_OPCODES_LEN];
-
/* Those resources are used only in QEMU core */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */
@@ -1191,6 +1192,10 @@ struct PowerPCCPU {
int32_t node_id; /* NUMA node this CPU belongs to */
PPCHash64Options *hash64_opts;
+ /* 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;
@@ -1224,6 +1229,10 @@ struct PPCVirtualHypervisorClass {
void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1);
void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry);
target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp);
+#ifndef CONFIG_USER_ONLY
+ void (*cpu_exec_enter)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+ void (*cpu_exec_exit)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+#endif
};
#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
@@ -1462,6 +1471,7 @@ typedef PowerPCCPU ArchCPU;
#define SPR_MPC_ICTRL (0x09E)
#define SPR_MPC_BAR (0x09F)
#define SPR_PSPB (0x09F)
+#define SPR_DPDES (0x0B0)
#define SPR_DAWR (0x0B4)
#define SPR_RPR (0x0BA)
#define SPR_CIABR (0x0BB)
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index f437c88..07bc905 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -58,19 +58,35 @@ uint64_t helper_todouble(uint32_t arg)
uint64_t ret;
if (likely(abs_arg >= 0x00800000)) {
- /* Normalized operand, or Inf, or NaN. */
- ret = (uint64_t)extract32(arg, 30, 2) << 62;
- ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59;
- ret |= (uint64_t)extract32(arg, 0, 30) << 29;
+ if (unlikely(extract32(arg, 23, 8) == 0xff)) {
+ /* Inf or NAN. */
+ ret = (uint64_t)extract32(arg, 31, 1) << 63;
+ ret |= (uint64_t)0x7ff << 52;
+ ret |= (uint64_t)extract32(arg, 0, 23) << 29;
+ } else {
+ /* Normalized operand. */
+ ret = (uint64_t)extract32(arg, 30, 2) << 62;
+ ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59;
+ ret |= (uint64_t)extract32(arg, 0, 30) << 29;
+ }
} else {
/* Zero or Denormalized operand. */
ret = (uint64_t)extract32(arg, 31, 1) << 63;
if (unlikely(abs_arg != 0)) {
- /* Denormalized operand. */
- int shift = clz32(abs_arg) - 9;
- int exp = -126 - shift + 1023;
+ /*
+ * Denormalized operand.
+ * Shift fraction so that the msb is in the implicit bit position.
+ * Thus, shift is in the range [1:23].
+ */
+ int shift = clz32(abs_arg) - 8;
+ /*
+ * The first 3 terms compute the float64 exponent. We then bias
+ * this result by -1 so that we can swallow the implicit bit below.
+ */
+ int exp = -126 - shift + 1023 - 1;
+
ret |= (uint64_t)exp << 52;
- ret |= abs_arg << (shift + 29);
+ ret += (uint64_t)abs_arg << (52 - 23 + shift);
}
}
return ret;
@@ -403,7 +419,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
if (prev == 1) {
switch (bit) {
case FPSCR_RN1:
- case FPSCR_RN:
+ case FPSCR_RN0:
fpscr_set_rounding_mode(env);
break;
case FPSCR_VXSNAN:
@@ -557,7 +573,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
}
break;
case FPSCR_RN1:
- case FPSCR_RN:
+ case FPSCR_RN0:
fpscr_set_rounding_mode(env);
break;
default:
@@ -2871,10 +2887,14 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode,
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
{
+ uint64_t result;
+
float_status tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
- return (uint64_t)float64_to_float32(xb, &tstat) << 32;
+ result = (uint64_t)float64_to_float32(xb, &tstat);
+ /* hardware replicates result to both words of the doubleword result. */
+ return (result << 32) | result;
}
uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb)
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 380c9b1..54ea9b9 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -193,8 +193,6 @@ DEF_HELPER_2(vprtybw, void, avr, avr)
DEF_HELPER_2(vprtybd, void, avr, avr)
DEF_HELPER_2(vprtybq, void, avr, avr)
DEF_HELPER_3(vsubcuw, void, avr, avr, avr)
-DEF_HELPER_2(lvsl, void, avr, tl)
-DEF_HELPER_2(lvsr, void, avr, tl)
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)
@@ -219,8 +217,6 @@ DEF_HELPER_3(vrlb, void, avr, avr, avr)
DEF_HELPER_3(vrlh, void, avr, avr, avr)
DEF_HELPER_3(vrlw, void, avr, avr, avr)
DEF_HELPER_3(vrld, void, avr, avr, avr)
-DEF_HELPER_3(vsl, void, avr, avr, avr)
-DEF_HELPER_3(vsr, void, avr, avr, avr)
DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32)
DEF_HELPER_3(vextractub, void, avr, avr, i32)
DEF_HELPER_3(vextractuh, void, avr, avr, i32)
@@ -314,8 +310,6 @@ DEF_HELPER_4(vctsxs, void, env, avr, avr, i32)
DEF_HELPER_2(vclzb, void, avr, avr)
DEF_HELPER_2(vclzh, void, avr, avr)
-DEF_HELPER_2(vclzw, void, avr, avr)
-DEF_HELPER_2(vclzd, void, avr, avr)
DEF_HELPER_2(vctzb, void, avr, avr)
DEF_HELPER_2(vctzh, void, avr, avr)
DEF_HELPER_2(vctzw, void, avr, avr)
@@ -328,7 +322,6 @@ DEF_HELPER_1(vclzlsbb, tl, avr)
DEF_HELPER_1(vctzlsbb, tl, avr)
DEF_HELPER_3(vbpermd, void, avr, avr, avr)
DEF_HELPER_3(vbpermq, void, avr, avr, avr)
-DEF_HELPER_2(vgbbd, void, avr, avr)
DEF_HELPER_3(vpmsumb, void, avr, avr, avr)
DEF_HELPER_3(vpmsumh, void, avr, avr, avr)
DEF_HELPER_3(vpmsumw, void, avr, avr, avr)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 8f037af..46deb57 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -459,24 +459,6 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
#undef SATCVT
#undef SATCVTU
-void helper_lvsl(ppc_avr_t *r, target_ulong sh)
-{
- int i, j = (sh & 0xf);
-
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
- r->VsrB(i) = j++;
- }
-}
-
-void helper_lvsr(ppc_avr_t *r, target_ulong sh)
-{
- int i, j = 0x10 - (sh & 0xf);
-
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
- r->VsrB(i) = j++;
- }
-}
-
void helper_mtvscr(CPUPPCState *env, uint32_t vscr)
{
env->vscr = vscr & ~(1u << VSCR_SAT);
@@ -1205,282 +1187,6 @@ void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
#undef VBPERMQ_INDEX
#undef VBPERMQ_DW
-static const uint64_t VGBBD_MASKS[256] = {
- 0x0000000000000000ull, /* 00 */
- 0x0000000000000080ull, /* 01 */
- 0x0000000000008000ull, /* 02 */
- 0x0000000000008080ull, /* 03 */
- 0x0000000000800000ull, /* 04 */
- 0x0000000000800080ull, /* 05 */
- 0x0000000000808000ull, /* 06 */
- 0x0000000000808080ull, /* 07 */
- 0x0000000080000000ull, /* 08 */
- 0x0000000080000080ull, /* 09 */
- 0x0000000080008000ull, /* 0A */
- 0x0000000080008080ull, /* 0B */
- 0x0000000080800000ull, /* 0C */
- 0x0000000080800080ull, /* 0D */
- 0x0000000080808000ull, /* 0E */
- 0x0000000080808080ull, /* 0F */
- 0x0000008000000000ull, /* 10 */
- 0x0000008000000080ull, /* 11 */
- 0x0000008000008000ull, /* 12 */
- 0x0000008000008080ull, /* 13 */
- 0x0000008000800000ull, /* 14 */
- 0x0000008000800080ull, /* 15 */
- 0x0000008000808000ull, /* 16 */
- 0x0000008000808080ull, /* 17 */
- 0x0000008080000000ull, /* 18 */
- 0x0000008080000080ull, /* 19 */
- 0x0000008080008000ull, /* 1A */
- 0x0000008080008080ull, /* 1B */
- 0x0000008080800000ull, /* 1C */
- 0x0000008080800080ull, /* 1D */
- 0x0000008080808000ull, /* 1E */
- 0x0000008080808080ull, /* 1F */
- 0x0000800000000000ull, /* 20 */
- 0x0000800000000080ull, /* 21 */
- 0x0000800000008000ull, /* 22 */
- 0x0000800000008080ull, /* 23 */
- 0x0000800000800000ull, /* 24 */
- 0x0000800000800080ull, /* 25 */
- 0x0000800000808000ull, /* 26 */
- 0x0000800000808080ull, /* 27 */
- 0x0000800080000000ull, /* 28 */
- 0x0000800080000080ull, /* 29 */
- 0x0000800080008000ull, /* 2A */
- 0x0000800080008080ull, /* 2B */
- 0x0000800080800000ull, /* 2C */
- 0x0000800080800080ull, /* 2D */
- 0x0000800080808000ull, /* 2E */
- 0x0000800080808080ull, /* 2F */
- 0x0000808000000000ull, /* 30 */
- 0x0000808000000080ull, /* 31 */
- 0x0000808000008000ull, /* 32 */
- 0x0000808000008080ull, /* 33 */
- 0x0000808000800000ull, /* 34 */
- 0x0000808000800080ull, /* 35 */
- 0x0000808000808000ull, /* 36 */
- 0x0000808000808080ull, /* 37 */
- 0x0000808080000000ull, /* 38 */
- 0x0000808080000080ull, /* 39 */
- 0x0000808080008000ull, /* 3A */
- 0x0000808080008080ull, /* 3B */
- 0x0000808080800000ull, /* 3C */
- 0x0000808080800080ull, /* 3D */
- 0x0000808080808000ull, /* 3E */
- 0x0000808080808080ull, /* 3F */
- 0x0080000000000000ull, /* 40 */
- 0x0080000000000080ull, /* 41 */
- 0x0080000000008000ull, /* 42 */
- 0x0080000000008080ull, /* 43 */
- 0x0080000000800000ull, /* 44 */
- 0x0080000000800080ull, /* 45 */
- 0x0080000000808000ull, /* 46 */
- 0x0080000000808080ull, /* 47 */
- 0x0080000080000000ull, /* 48 */
- 0x0080000080000080ull, /* 49 */
- 0x0080000080008000ull, /* 4A */
- 0x0080000080008080ull, /* 4B */
- 0x0080000080800000ull, /* 4C */
- 0x0080000080800080ull, /* 4D */
- 0x0080000080808000ull, /* 4E */
- 0x0080000080808080ull, /* 4F */
- 0x0080008000000000ull, /* 50 */
- 0x0080008000000080ull, /* 51 */
- 0x0080008000008000ull, /* 52 */
- 0x0080008000008080ull, /* 53 */
- 0x0080008000800000ull, /* 54 */
- 0x0080008000800080ull, /* 55 */
- 0x0080008000808000ull, /* 56 */
- 0x0080008000808080ull, /* 57 */
- 0x0080008080000000ull, /* 58 */
- 0x0080008080000080ull, /* 59 */
- 0x0080008080008000ull, /* 5A */
- 0x0080008080008080ull, /* 5B */
- 0x0080008080800000ull, /* 5C */
- 0x0080008080800080ull, /* 5D */
- 0x0080008080808000ull, /* 5E */
- 0x0080008080808080ull, /* 5F */
- 0x0080800000000000ull, /* 60 */
- 0x0080800000000080ull, /* 61 */
- 0x0080800000008000ull, /* 62 */
- 0x0080800000008080ull, /* 63 */
- 0x0080800000800000ull, /* 64 */
- 0x0080800000800080ull, /* 65 */
- 0x0080800000808000ull, /* 66 */
- 0x0080800000808080ull, /* 67 */
- 0x0080800080000000ull, /* 68 */
- 0x0080800080000080ull, /* 69 */
- 0x0080800080008000ull, /* 6A */
- 0x0080800080008080ull, /* 6B */
- 0x0080800080800000ull, /* 6C */
- 0x0080800080800080ull, /* 6D */
- 0x0080800080808000ull, /* 6E */
- 0x0080800080808080ull, /* 6F */
- 0x0080808000000000ull, /* 70 */
- 0x0080808000000080ull, /* 71 */
- 0x0080808000008000ull, /* 72 */
- 0x0080808000008080ull, /* 73 */
- 0x0080808000800000ull, /* 74 */
- 0x0080808000800080ull, /* 75 */
- 0x0080808000808000ull, /* 76 */
- 0x0080808000808080ull, /* 77 */
- 0x0080808080000000ull, /* 78 */
- 0x0080808080000080ull, /* 79 */
- 0x0080808080008000ull, /* 7A */
- 0x0080808080008080ull, /* 7B */
- 0x0080808080800000ull, /* 7C */
- 0x0080808080800080ull, /* 7D */
- 0x0080808080808000ull, /* 7E */
- 0x0080808080808080ull, /* 7F */
- 0x8000000000000000ull, /* 80 */
- 0x8000000000000080ull, /* 81 */
- 0x8000000000008000ull, /* 82 */
- 0x8000000000008080ull, /* 83 */
- 0x8000000000800000ull, /* 84 */
- 0x8000000000800080ull, /* 85 */
- 0x8000000000808000ull, /* 86 */
- 0x8000000000808080ull, /* 87 */
- 0x8000000080000000ull, /* 88 */
- 0x8000000080000080ull, /* 89 */
- 0x8000000080008000ull, /* 8A */
- 0x8000000080008080ull, /* 8B */
- 0x8000000080800000ull, /* 8C */
- 0x8000000080800080ull, /* 8D */
- 0x8000000080808000ull, /* 8E */
- 0x8000000080808080ull, /* 8F */
- 0x8000008000000000ull, /* 90 */
- 0x8000008000000080ull, /* 91 */
- 0x8000008000008000ull, /* 92 */
- 0x8000008000008080ull, /* 93 */
- 0x8000008000800000ull, /* 94 */
- 0x8000008000800080ull, /* 95 */
- 0x8000008000808000ull, /* 96 */
- 0x8000008000808080ull, /* 97 */
- 0x8000008080000000ull, /* 98 */
- 0x8000008080000080ull, /* 99 */
- 0x8000008080008000ull, /* 9A */
- 0x8000008080008080ull, /* 9B */
- 0x8000008080800000ull, /* 9C */
- 0x8000008080800080ull, /* 9D */
- 0x8000008080808000ull, /* 9E */
- 0x8000008080808080ull, /* 9F */
- 0x8000800000000000ull, /* A0 */
- 0x8000800000000080ull, /* A1 */
- 0x8000800000008000ull, /* A2 */
- 0x8000800000008080ull, /* A3 */
- 0x8000800000800000ull, /* A4 */
- 0x8000800000800080ull, /* A5 */
- 0x8000800000808000ull, /* A6 */
- 0x8000800000808080ull, /* A7 */
- 0x8000800080000000ull, /* A8 */
- 0x8000800080000080ull, /* A9 */
- 0x8000800080008000ull, /* AA */
- 0x8000800080008080ull, /* AB */
- 0x8000800080800000ull, /* AC */
- 0x8000800080800080ull, /* AD */
- 0x8000800080808000ull, /* AE */
- 0x8000800080808080ull, /* AF */
- 0x8000808000000000ull, /* B0 */
- 0x8000808000000080ull, /* B1 */
- 0x8000808000008000ull, /* B2 */
- 0x8000808000008080ull, /* B3 */
- 0x8000808000800000ull, /* B4 */
- 0x8000808000800080ull, /* B5 */
- 0x8000808000808000ull, /* B6 */
- 0x8000808000808080ull, /* B7 */
- 0x8000808080000000ull, /* B8 */
- 0x8000808080000080ull, /* B9 */
- 0x8000808080008000ull, /* BA */
- 0x8000808080008080ull, /* BB */
- 0x8000808080800000ull, /* BC */
- 0x8000808080800080ull, /* BD */
- 0x8000808080808000ull, /* BE */
- 0x8000808080808080ull, /* BF */
- 0x8080000000000000ull, /* C0 */
- 0x8080000000000080ull, /* C1 */
- 0x8080000000008000ull, /* C2 */
- 0x8080000000008080ull, /* C3 */
- 0x8080000000800000ull, /* C4 */
- 0x8080000000800080ull, /* C5 */
- 0x8080000000808000ull, /* C6 */
- 0x8080000000808080ull, /* C7 */
- 0x8080000080000000ull, /* C8 */
- 0x8080000080000080ull, /* C9 */
- 0x8080000080008000ull, /* CA */
- 0x8080000080008080ull, /* CB */
- 0x8080000080800000ull, /* CC */
- 0x8080000080800080ull, /* CD */
- 0x8080000080808000ull, /* CE */
- 0x8080000080808080ull, /* CF */
- 0x8080008000000000ull, /* D0 */
- 0x8080008000000080ull, /* D1 */
- 0x8080008000008000ull, /* D2 */
- 0x8080008000008080ull, /* D3 */
- 0x8080008000800000ull, /* D4 */
- 0x8080008000800080ull, /* D5 */
- 0x8080008000808000ull, /* D6 */
- 0x8080008000808080ull, /* D7 */
- 0x8080008080000000ull, /* D8 */
- 0x8080008080000080ull, /* D9 */
- 0x8080008080008000ull, /* DA */
- 0x8080008080008080ull, /* DB */
- 0x8080008080800000ull, /* DC */
- 0x8080008080800080ull, /* DD */
- 0x8080008080808000ull, /* DE */
- 0x8080008080808080ull, /* DF */
- 0x8080800000000000ull, /* E0 */
- 0x8080800000000080ull, /* E1 */
- 0x8080800000008000ull, /* E2 */
- 0x8080800000008080ull, /* E3 */
- 0x8080800000800000ull, /* E4 */
- 0x8080800000800080ull, /* E5 */
- 0x8080800000808000ull, /* E6 */
- 0x8080800000808080ull, /* E7 */
- 0x8080800080000000ull, /* E8 */
- 0x8080800080000080ull, /* E9 */
- 0x8080800080008000ull, /* EA */
- 0x8080800080008080ull, /* EB */
- 0x8080800080800000ull, /* EC */
- 0x8080800080800080ull, /* ED */
- 0x8080800080808000ull, /* EE */
- 0x8080800080808080ull, /* EF */
- 0x8080808000000000ull, /* F0 */
- 0x8080808000000080ull, /* F1 */
- 0x8080808000008000ull, /* F2 */
- 0x8080808000008080ull, /* F3 */
- 0x8080808000800000ull, /* F4 */
- 0x8080808000800080ull, /* F5 */
- 0x8080808000808000ull, /* F6 */
- 0x8080808000808080ull, /* F7 */
- 0x8080808080000000ull, /* F8 */
- 0x8080808080000080ull, /* F9 */
- 0x8080808080008000ull, /* FA */
- 0x8080808080008080ull, /* FB */
- 0x8080808080800000ull, /* FC */
- 0x8080808080800080ull, /* FD */
- 0x8080808080808000ull, /* FE */
- 0x8080808080808080ull, /* FF */
-};
-
-void helper_vgbbd(ppc_avr_t *r, ppc_avr_t *b)
-{
- int i;
- uint64_t t[2] = { 0, 0 };
-
- VECTOR_FOR_INORDER_I(i, u8) {
-#if defined(HOST_WORDS_BIGENDIAN)
- t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (i & 7);
-#else
- t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (7 - (i & 7));
-#endif
- }
-
- r->u64[0] = t[0];
- r->u64[1] = t[1];
-}
-
#define PMSUM(name, srcfld, trgfld, trgtyp) \
void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
@@ -1758,41 +1464,6 @@ VEXTU_X_DO(vextuhrx, 16, 0)
VEXTU_X_DO(vextuwrx, 32, 0)
#undef VEXTU_X_DO
-/*
- * The specification says that the results are undefined if all of the
- * shift counts are not identical. We check to make sure that they
- * are to conform to what real hardware appears to do.
- */
-#define VSHIFT(suffix, leftp) \
- void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int shift = b->VsrB(15) & 0x7; \
- int doit = 1; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
- doit = doit && ((b->u8[i] & 0x7) == shift); \
- } \
- if (doit) { \
- if (shift == 0) { \
- *r = *a; \
- } else if (leftp) { \
- uint64_t carry = a->VsrD(1) >> (64 - shift); \
- \
- r->VsrD(0) = (a->VsrD(0) << shift) | carry; \
- r->VsrD(1) = a->VsrD(1) << shift; \
- } else { \
- uint64_t carry = a->VsrD(0) << (64 - shift); \
- \
- r->VsrD(1) = (a->VsrD(1) >> shift) | carry; \
- r->VsrD(0) = a->VsrD(0) >> shift; \
- } \
- } \
- }
-VSHIFT(l, 1)
-VSHIFT(r, 0)
-#undef VSHIFT
-
void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i;
@@ -2148,18 +1819,12 @@ VUPK(lsw, s64, s32, UPKLO)
#define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8)
#define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16)
-#define clzw(v) clz32((v))
-#define clzd(v) clz64((v))
VGENERIC_DO(clzb, u8)
VGENERIC_DO(clzh, u16)
-VGENERIC_DO(clzw, u32)
-VGENERIC_DO(clzd, u64)
#undef clzb
#undef clzh
-#undef clzw
-#undef clzd
#define ctzb(v) ((v) ? ctz32(v) : 8)
#define ctzh(v) ((v) ? ctz32(v) : 16)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 6162a90..8c5b1f2 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -58,7 +58,6 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
};
static int cap_interrupt_unset;
-static int cap_interrupt_level;
static int cap_segstate;
static int cap_booke_sregs;
static int cap_ppc_smt;
@@ -90,25 +89,6 @@ static int cap_large_decr;
static uint32_t debug_inst_opcode;
/*
- * XXX We have a race condition where we actually have a level triggered
- * interrupt, but the infrastructure can't expose that yet, so the guest
- * takes but ignores it, goes to sleep and never gets notified that there's
- * still an interrupt pending.
- *
- * As a quick workaround, let's just wake up again 20 ms after we injected
- * an interrupt. That way we can assure that we're always reinjecting
- * interrupts in case the guest swallowed them.
- */
-static QEMUTimer *idle_timer;
-
-static void kvm_kick_cpu(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
-
- qemu_cpu_kick(CPU(cpu));
-}
-
-/*
* Check whether we are running with KVM-PR (instead of KVM-HV). This
* should only be used for fallback tests - generally we should use
* explicit capabilities for the features we want, rather than
@@ -127,7 +107,6 @@ static int kvmppc_get_dec_bits(void);
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
- cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE);
@@ -163,9 +142,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
*/
cap_ppc_pvr_compat = false;
- if (!cap_interrupt_level) {
- fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
- "VM to stall at times!\n");
+ if (!kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL)) {
+ error_report("KVM: Host kernel doesn't have level irq capability");
+ exit(1);
}
kvm_ppc_register_host_cpu_type(ms);
@@ -493,8 +472,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
return ret;
}
- idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu);
-
switch (cenv->mmu_model) {
case POWERPC_MMU_BOOKE206:
/* This target supports access to KVM's guest TLB */
@@ -1334,7 +1311,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
return 0;
}
- if (!kvm_enabled() || !cap_interrupt_unset || !cap_interrupt_level) {
+ if (!kvm_enabled() || !cap_interrupt_unset) {
return 0;
}
@@ -1351,49 +1328,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- int r;
- unsigned irq;
-
- qemu_mutex_lock_iothread();
-
- /*
- * PowerPC QEMU tracks the various core input pins (interrupt,
- * critical interrupt, reset, etc) in PPC-specific
- * env->irq_input_state.
- */
- if (!cap_interrupt_level &&
- run->ready_for_interrupt_injection &&
- (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->irq_input_state & (1 << PPC_INPUT_INT)))
- {
- /*
- * For now KVM disregards the 'irq' argument. However, in the
- * future KVM could cache it in-kernel to avoid a heavyweight
- * exit when reading the UIC.
- */
- irq = KVM_INTERRUPT_SET;
-
- trace_kvm_injected_interrupt(irq);
- r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq);
- if (r < 0) {
- printf("cpu %d fail inject %x\n", cs->cpu_index, irq);
- }
-
- /* Always wake up soon in case the interrupt was level based */
- timer_mod(idle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / 50));
- }
-
- /*
- * We don't know if there are more interrupts pending after
- * this. However, the guest will return to userspace in the course
- * of handling this one anyways, so we will get a chance to
- * deliver the rest.
- */
-
- qemu_mutex_unlock_iothread();
+ return;
}
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 2a9d13f..0cf3f97 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7845,6 +7845,7 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = cs->env_ptr;
opc_handler_t **table, *handler;
@@ -7862,7 +7863,7 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
opc3(ctx->opcode), opc4(ctx->opcode),
ctx->le_mode ? "little" : "big");
ctx->base.pc_next += 4;
- table = env->opcodes;
+ table = cpu->opcodes;
handler = table[opc1(ctx->opcode)];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c
index 9dcff94..7cd9d8d 100644
--- a/target/ppc/translate/fp-impl.inc.c
+++ b/target/ppc/translate/fp-impl.inc.c
@@ -617,6 +617,28 @@ static void gen_mffs(DisasContext *ctx)
tcg_temp_free_i64(t0);
}
+/* mffsl */
+static void gen_mffsl(DisasContext *ctx)
+{
+ TCGv_i64 t0;
+
+ if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
+ return gen_mffs(ctx);
+ }
+
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ t0 = tcg_temp_new_i64();
+ gen_reset_fpstatus();
+ tcg_gen_extu_tl_i64(t0, cpu_fpscr);
+ /* Mask everything except mode, status, and enables. */
+ tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES);
+ set_fpr(rD(ctx->opcode), t0);
+ tcg_temp_free_i64(t0);
+}
+
/* mtfsb0 */
static void gen_mtfsb0(DisasContext *ctx)
{
diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c
index 621f6bf..88ebc25 100644
--- a/target/ppc/translate/fp-ops.inc.c
+++ b/target/ppc/translate/fp-ops.inc.c
@@ -104,7 +104,9 @@ GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
-GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE),
+GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT,
+ PPC2_ISA300),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index 663275b..0d71c10 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -142,38 +142,6 @@ GEN_VR_STVE(bx, 0x07, 0x04, 1);
GEN_VR_STVE(hx, 0x07, 0x05, 2);
GEN_VR_STVE(wx, 0x07, 0x06, 4);
-static void gen_lvsl(DisasContext *ctx)
-{
- TCGv_ptr rd;
- TCGv EA;
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- rd = gen_avr_ptr(rD(ctx->opcode));
- gen_helper_lvsl(rd, EA);
- tcg_temp_free(EA);
- tcg_temp_free_ptr(rd);
-}
-
-static void gen_lvsr(DisasContext *ctx)
-{
- TCGv_ptr rd;
- TCGv EA;
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- rd = gen_avr_ptr(rD(ctx->opcode));
- gen_helper_lvsr(rd, EA);
- tcg_temp_free(EA);
- tcg_temp_free_ptr(rd);
-}
-
static void gen_mfvscr(DisasContext *ctx)
{
TCGv_i32 t;
@@ -316,6 +284,16 @@ static void glue(gen_, name)(DisasContext *ctx) \
tcg_temp_free_ptr(rd); \
}
+#define GEN_VXFORM_TRANS(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ trans_##name(ctx); \
+}
+
#define GEN_VXFORM_ENV(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
@@ -515,6 +493,307 @@ static void gen_vmrgow(DisasContext *ctx)
tcg_temp_free_i64(avr);
}
+/*
+ * lvsl VRT,RA,RB - Load Vector for Shift Left
+ *
+ * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31].
+ * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
+ * Bytes sh:sh+15 of X are placed into vD.
+ */
+static void trans_lvsl(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ TCGv_i64 result = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv EA = tcg_temp_new();
+
+ /* Get sh(from description) by anding EA with 0xf. */
+ gen_addr_reg_index(ctx, EA);
+ tcg_gen_extu_tl_i64(sh, EA);
+ tcg_gen_andi_i64(sh, sh, 0xfULL);
+
+ /*
+ * Create bytes sh:sh+7 of X(from description) and place them in
+ * higher doubleword of vD.
+ */
+ tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
+ tcg_gen_addi_i64(result, sh, 0x0001020304050607ull);
+ set_avr64(VT, result, true);
+ /*
+ * Create bytes sh+8:sh+15 of X(from description) and place them in
+ * lower doubleword of vD.
+ */
+ tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL);
+ set_avr64(VT, result, false);
+
+ tcg_temp_free_i64(result);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free(EA);
+}
+
+/*
+ * lvsr VRT,RA,RB - Load Vector for Shift Right
+ *
+ * Let the EA be the sum (rA|0)+(rB). Let sh=EA[28–31].
+ * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
+ * Bytes (16-sh):(31-sh) of X are placed into vD.
+ */
+static void trans_lvsr(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ TCGv_i64 result = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv EA = tcg_temp_new();
+
+
+ /* Get sh(from description) by anding EA with 0xf. */
+ gen_addr_reg_index(ctx, EA);
+ tcg_gen_extu_tl_i64(sh, EA);
+ tcg_gen_andi_i64(sh, sh, 0xfULL);
+
+ /*
+ * Create bytes (16-sh):(23-sh) of X(from description) and place them in
+ * higher doubleword of vD.
+ */
+ tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
+ tcg_gen_subfi_i64(result, 0x1011121314151617ULL, sh);
+ set_avr64(VT, result, true);
+ /*
+ * Create bytes (24-sh):(32-sh) of X(from description) and place them in
+ * lower doubleword of vD.
+ */
+ tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh);
+ set_avr64(VT, result, false);
+
+ tcg_temp_free_i64(result);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free(EA);
+}
+
+/*
+ * vsl VRT,VRA,VRB - Vector Shift Left
+ *
+ * Shifting left 128 bit value of vA by value specified in bits 125-127 of vB.
+ * Lowest 3 bits in each byte element of register vB must be identical or
+ * result is undefined.
+ */
+static void trans_vsl(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 avrA = tcg_temp_new_i64();
+ TCGv_i64 avrB = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv_i64 shifted = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* Place bits 125-127 of vB in sh. */
+ get_avr64(avrB, VB, false);
+ tcg_gen_andi_i64(sh, avrB, 0x07ULL);
+
+ /*
+ * Save highest sh bits of lower doubleword element of vA in variable
+ * shifted and perform shift on lower doubleword.
+ */
+ get_avr64(avrA, VA, false);
+ tcg_gen_subfi_i64(tmp, 64, sh);
+ tcg_gen_shr_i64(shifted, avrA, tmp);
+ tcg_gen_andi_i64(shifted, shifted, 0x7fULL);
+ tcg_gen_shl_i64(avrA, avrA, sh);
+ set_avr64(VT, avrA, false);
+
+ /*
+ * Perform shift on higher doubleword element of vA and replace lowest
+ * sh bits with shifted.
+ */
+ get_avr64(avrA, VA, true);
+ tcg_gen_shl_i64(avrA, avrA, sh);
+ tcg_gen_or_i64(avrA, avrA, shifted);
+ set_avr64(VT, avrA, true);
+
+ tcg_temp_free_i64(avrA);
+ tcg_temp_free_i64(avrB);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free_i64(shifted);
+ tcg_temp_free_i64(tmp);
+}
+
+/*
+ * vsr VRT,VRA,VRB - Vector Shift Right
+ *
+ * Shifting right 128 bit value of vA by value specified in bits 125-127 of vB.
+ * Lowest 3 bits in each byte element of register vB must be identical or
+ * result is undefined.
+ */
+static void trans_vsr(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 avrA = tcg_temp_new_i64();
+ TCGv_i64 avrB = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv_i64 shifted = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* Place bits 125-127 of vB in sh. */
+ get_avr64(avrB, VB, false);
+ tcg_gen_andi_i64(sh, avrB, 0x07ULL);
+
+ /*
+ * Save lowest sh bits of higher doubleword element of vA in variable
+ * shifted and perform shift on higher doubleword.
+ */
+ get_avr64(avrA, VA, true);
+ tcg_gen_subfi_i64(tmp, 64, sh);
+ tcg_gen_shl_i64(shifted, avrA, tmp);
+ tcg_gen_andi_i64(shifted, shifted, 0xfe00000000000000ULL);
+ tcg_gen_shr_i64(avrA, avrA, sh);
+ set_avr64(VT, avrA, true);
+ /*
+ * Perform shift on lower doubleword element of vA and replace highest
+ * sh bits with shifted.
+ */
+ get_avr64(avrA, VA, false);
+ tcg_gen_shr_i64(avrA, avrA, sh);
+ tcg_gen_or_i64(avrA, avrA, shifted);
+ set_avr64(VT, avrA, false);
+
+ tcg_temp_free_i64(avrA);
+ tcg_temp_free_i64(avrB);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free_i64(shifted);
+ tcg_temp_free_i64(tmp);
+}
+
+/*
+ * vgbbd VRT,VRB - Vector Gather Bits by Bytes by Doubleword
+ *
+ * All ith bits (i in range 1 to 8) of each byte of doubleword element in source
+ * register are concatenated and placed into ith byte of appropriate doubleword
+ * element in destination register.
+ *
+ * Following solution is done for both doubleword elements of source register
+ * in parallel, in order to reduce the number of instructions needed(that's why
+ * arrays are used):
+ * First, both doubleword elements of source register vB are placed in
+ * appropriate element of array avr. Bits are gathered in 2x8 iterations(2 for
+ * loops). In first iteration bit 1 of byte 1, bit 2 of byte 2,... bit 8 of
+ * byte 8 are in their final spots so avr[i], i={0,1} can be and-ed with
+ * tcg_mask. For every following iteration, both avr[i] and tcg_mask variables
+ * have to be shifted right for 7 and 8 places, respectively, in order to get
+ * bit 1 of byte 2, bit 2 of byte 3.. bit 7 of byte 8 in their final spots so
+ * shifted avr values(saved in tmp) can be and-ed with new value of tcg_mask...
+ * After first 8 iteration(first loop), all the first bits are in their final
+ * places, all second bits but second bit from eight byte are in their places...
+ * only 1 eight bit from eight byte is in it's place). In second loop we do all
+ * operations symmetrically, in order to get other half of bits in their final
+ * spots. Results for first and second doubleword elements are saved in
+ * result[0] and result[1] respectively. In the end those results are saved in
+ * appropriate doubleword element of destination register vD.
+ */
+static void trans_vgbbd(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ uint64_t mask = 0x8040201008040201ULL;
+ int i, j;
+
+ TCGv_i64 result[2];
+ result[0] = tcg_temp_new_i64();
+ result[1] = tcg_temp_new_i64();
+ TCGv_i64 avr[2];
+ avr[0] = tcg_temp_new_i64();
+ avr[1] = tcg_temp_new_i64();
+ TCGv_i64 tcg_mask = tcg_temp_new_i64();
+
+ tcg_gen_movi_i64(tcg_mask, mask);
+ for (j = 0; j < 2; j++) {
+ get_avr64(avr[j], VB, j);
+ tcg_gen_and_i64(result[j], avr[j], tcg_mask);
+ }
+ for (i = 1; i < 8; i++) {
+ tcg_gen_movi_i64(tcg_mask, mask >> (i * 8));
+ for (j = 0; j < 2; j++) {
+ tcg_gen_shri_i64(tmp, avr[j], i * 7);
+ tcg_gen_and_i64(tmp, tmp, tcg_mask);
+ tcg_gen_or_i64(result[j], result[j], tmp);
+ }
+ }
+ for (i = 1; i < 8; i++) {
+ tcg_gen_movi_i64(tcg_mask, mask << (i * 8));
+ for (j = 0; j < 2; j++) {
+ tcg_gen_shli_i64(tmp, avr[j], i * 7);
+ tcg_gen_and_i64(tmp, tmp, tcg_mask);
+ tcg_gen_or_i64(result[j], result[j], tmp);
+ }
+ }
+ for (j = 0; j < 2; j++) {
+ set_avr64(VT, result[j], j);
+ }
+
+ tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(tcg_mask);
+ tcg_temp_free_i64(result[0]);
+ tcg_temp_free_i64(result[1]);
+ tcg_temp_free_i64(avr[0]);
+ tcg_temp_free_i64(avr[1]);
+}
+
+/*
+ * vclzw VRT,VRB - Vector Count Leading Zeros Word
+ *
+ * Counting the number of leading zero bits of each word element in source
+ * register and placing result in appropriate word element of destination
+ * register.
+ */
+static void trans_vclzw(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ int i;
+
+ /* Perform count for every word element using tcg_gen_clzi_i32. */
+ for (i = 0; i < 4; i++) {
+ tcg_gen_ld_i32(tmp, cpu_env,
+ offsetof(CPUPPCState, vsr[32 + VB].u64[0]) + i * 4);
+ tcg_gen_clzi_i32(tmp, tmp, 32);
+ tcg_gen_st_i32(tmp, cpu_env,
+ offsetof(CPUPPCState, vsr[32 + VT].u64[0]) + i * 4);
+ }
+
+ tcg_temp_free_i32(tmp);
+}
+
+/*
+ * vclzd VRT,VRB - Vector Count Leading Zeros Doubleword
+ *
+ * Counting the number of leading zero bits of each doubleword element in source
+ * register and placing result in appropriate doubleword element of destination
+ * register.
+ */
+static void trans_vclzd(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 avr = tcg_temp_new_i64();
+
+ /* high doubleword */
+ get_avr64(avr, VB, true);
+ tcg_gen_clzi_i64(avr, avr, 64);
+ set_avr64(VT, avr, true);
+
+ /* low doubleword */
+ get_avr64(avr, VB, false);
+ tcg_gen_clzi_i64(avr, avr, 64);
+ set_avr64(VT, avr, false);
+
+ tcg_temp_free_i64(avr);
+}
+
GEN_VXFORM(vmuloub, 4, 0);
GEN_VXFORM(vmulouh, 4, 1);
GEN_VXFORM(vmulouw, 4, 2);
@@ -627,11 +906,11 @@ GEN_VXFORM(vrld, 2, 3);
GEN_VXFORM(vrldmi, 2, 3);
GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \
vrldmi, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM(vsl, 2, 7);
+GEN_VXFORM_TRANS(vsl, 2, 7);
GEN_VXFORM(vrldnm, 2, 7);
GEN_VXFORM_DUAL(vsl, PPC_ALTIVEC, PPC_NONE, \
vrldnm, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM(vsr, 2, 11);
+GEN_VXFORM_TRANS(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
GEN_VXFORM_ENV(vpkuwum, 7, 1);
GEN_VXFORM_ENV(vpkudum, 7, 17);
@@ -662,6 +941,8 @@ GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
GEN_VXFORM_HETRO(vextubrx, 6, 28)
GEN_VXFORM_HETRO(vextuhrx, 6, 29)
GEN_VXFORM_HETRO(vextuwrx, 6, 30)
+GEN_VXFORM_TRANS(lvsl, 6, 31)
+GEN_VXFORM_TRANS(lvsr, 6, 32)
GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \
vextuwrx, PPC_NONE, PPC2_ISA300)
@@ -1028,8 +1309,8 @@ GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
GEN_VXFORM_NOA(vclzb, 1, 28)
GEN_VXFORM_NOA(vclzh, 1, 29)
-GEN_VXFORM_NOA(vclzw, 1, 30)
-GEN_VXFORM_NOA(vclzd, 1, 31)
+GEN_VXFORM_TRANS(vclzw, 1, 30)
+GEN_VXFORM_TRANS(vclzd, 1, 31)
GEN_VXFORM_NOA_2(vnegw, 1, 24, 6)
GEN_VXFORM_NOA_2(vnegd, 1, 24, 7)
GEN_VXFORM_NOA_2(vextsb2w, 1, 24, 16)
@@ -1057,7 +1338,7 @@ GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \
vpopcntd, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM(vbpermd, 6, 23);
GEN_VXFORM(vbpermq, 6, 21);
-GEN_VXFORM_NOA(vgbbd, 6, 20);
+GEN_VXFORM_TRANS(vgbbd, 6, 20);
GEN_VXFORM(vpmsumb, 4, 16)
GEN_VXFORM(vpmsumh, 4, 17)
GEN_VXFORM(vpmsumw, 4, 18)
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 66d9a73..4a21ed7 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -8196,6 +8196,18 @@ static void gen_spr_power8_pspb(CPUPPCState *env)
KVM_REG_PPC_PSPB, 0);
}
+static void gen_spr_power8_dpdes(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* Directed Privileged Door-bell Exception State, used for IPI */
+ spr_register_kvm_hv(env, SPR_DPDES, "DPDES",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_DPDES, 0x00000000);
+#endif
+}
+
static void gen_spr_power8_ic(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -8627,6 +8639,7 @@ static void init_proc_POWER8(CPUPPCState *env)
gen_spr_power8_pmu_user(env);
gen_spr_power8_tm(env);
gen_spr_power8_pspb(env);
+ gen_spr_power8_dpdes(env);
gen_spr_vtb(env);
gen_spr_power8_ic(env);
gen_spr_power8_book4(env);
@@ -8815,6 +8828,7 @@ static void init_proc_POWER9(CPUPPCState *env)
gen_spr_power8_pmu_user(env);
gen_spr_power8_tm(env);
gen_spr_power8_pspb(env);
+ gen_spr_power8_dpdes(env);
gen_spr_vtb(env);
gen_spr_power8_ic(env);
gen_spr_power8_book4(env);
@@ -9438,14 +9452,13 @@ static void fix_opcode_tables(opc_handler_t **ppc_opcodes)
static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- CPUPPCState *env = &cpu->env;
opcode_t *opc;
- fill_new_table(env->opcodes, PPC_CPU_OPCODES_LEN);
+ fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN);
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
if (((opc->handler.type & pcc->insns_flags) != 0) ||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
- if (register_insn(env->opcodes, opc) < 0) {
+ if (register_insn(cpu->opcodes, opc) < 0) {
error_setg(errp, "ERROR initializing PowerPC instruction "
"0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2,
opc->opc3);
@@ -9453,7 +9466,7 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
}
}
}
- fix_opcode_tables(env->opcodes);
+ fix_opcode_tables(cpu->opcodes);
fflush(stdout);
fflush(stderr);
}
@@ -10021,7 +10034,6 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(dev);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- CPUPPCState *env = &cpu->env;
Error *local_err = NULL;
opc_handler_t **table, **table_2;
int i, j, k;
@@ -10033,11 +10045,11 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp)
}
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
- if (env->opcodes[i] == &invalid_handler) {
+ if (cpu->opcodes[i] == &invalid_handler) {
continue;
}
- if (is_indirect_opcode(env->opcodes[i])) {
- table = ind_table(env->opcodes[i]);
+ if (is_indirect_opcode(cpu->opcodes[i])) {
+ table = ind_table(cpu->opcodes[i]);
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
if (table[j] == &invalid_handler) {
continue;
@@ -10055,7 +10067,7 @@ static void ppc_cpu_unrealize(DeviceState *dev, Error **errp)
~PPC_INDIRECT));
}
}
- g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] &
+ g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] &
~PPC_INDIRECT));
}
}
@@ -10469,6 +10481,28 @@ static bool ppc_cpu_is_big_endian(CPUState *cs)
return !msr_le;
}
+
+static void ppc_cpu_exec_enter(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->cpu_exec_enter(cpu->vhyp, cpu);
+ }
+}
+
+static void ppc_cpu_exec_exit(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->cpu_exec_exit(cpu->vhyp, cpu);
+ }
+}
#endif
static void ppc_cpu_instance_init(Object *obj)
@@ -10622,6 +10656,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->tcg_initialize = ppc_translate_init;
cc->tlb_fill = ppc_cpu_tlb_fill;
#endif
+#ifndef CONFIG_USER_ONLY
+ cc->cpu_exec_enter = ppc_cpu_exec_enter;
+ cc->cpu_exec_exit = ppc_cpu_exec_exit;
+#endif
+
cc->disas_set_info = ppc_disas_set_info;
dc->fw_name = "PowerPC,UNKNOWN";
diff --git a/vl.c b/vl.c
index edd5390..8e5af75 100644
--- a/vl.c
+++ b/vl.c
@@ -1557,6 +1557,20 @@ void qemu_system_reset(ShutdownCause reason)
cpu_synchronize_all_post_reset();
}
+/*
+ * Wake the VM after suspend.
+ */
+static void qemu_system_wakeup(void)
+{
+ MachineClass *mc;
+
+ mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL;
+
+ if (mc && mc->wakeup) {
+ mc->wakeup(current_machine);
+ }
+}
+
void qemu_system_guest_panicked(GuestPanicInformation *info)
{
qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed");
@@ -1765,7 +1779,7 @@ static bool main_loop_should_exit(void)
}
if (qemu_wakeup_requested()) {
pause_all_vcpus();
- qemu_system_reset(SHUTDOWN_CAUSE_NONE);
+ qemu_system_wakeup();
notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
wakeup_reason = QEMU_WAKEUP_REASON_NONE;
resume_all_vcpus();