aboutsummaryrefslogtreecommitdiffstats
path: root/include/hw/ppc
diff options
context:
space:
mode:
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
committerTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
commite02cda008591317b1625707ff8e115a4841aa889 (patch)
treeaee302e3cf8b59ec2d32ec481be3d1afddfc8968 /include/hw/ppc
parentcc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff)
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback design to work with QEMU and rust-vmm vhost-user backend without require any changes. Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'include/hw/ppc')
-rw-r--r--include/hw/ppc/fdt.h29
-rw-r--r--include/hw/ppc/mac_dbdma.h183
-rw-r--r--include/hw/ppc/openpic.h176
-rw-r--r--include/hw/ppc/openpic_kvm.h7
-rw-r--r--include/hw/ppc/pef.h17
-rw-r--r--include/hw/ppc/pnv.h332
-rw-r--r--include/hw/ppc/pnv_core.h73
-rw-r--r--include/hw/ppc/pnv_homer.h56
-rw-r--r--include/hw/ppc/pnv_lpc.h108
-rw-r--r--include/hw/ppc/pnv_occ.h63
-rw-r--r--include/hw/ppc/pnv_pnor.h31
-rw-r--r--include/hw/ppc/pnv_psi.h120
-rw-r--r--include/hw/ppc/pnv_xive.h98
-rw-r--r--include/hw/ppc/pnv_xscom.h148
-rw-r--r--include/hw/ppc/ppc.h115
-rw-r--r--include/hw/ppc/ppc4xx.h52
-rw-r--r--include/hw/ppc/ppc_e500.h6
-rw-r--r--include/hw/ppc/spapr.h991
-rw-r--r--include/hw/ppc/spapr_cpu_core.h58
-rw-r--r--include/hw/ppc/spapr_drc.h259
-rw-r--r--include/hw/ppc/spapr_irq.h117
-rw-r--r--include/hw/ppc/spapr_numa.h37
-rw-r--r--include/hw/ppc/spapr_nvdimm.h25
-rw-r--r--include/hw/ppc/spapr_ovec.h83
-rw-r--r--include/hw/ppc/spapr_rtas.h10
-rw-r--r--include/hw/ppc/spapr_tpm_proxy.h30
-rw-r--r--include/hw/ppc/spapr_vio.h141
-rw-r--r--include/hw/ppc/spapr_xive.h99
-rw-r--r--include/hw/ppc/vof.h60
-rw-r--r--include/hw/ppc/xics.h196
-rw-r--r--include/hw/ppc/xics_spapr.h43
-rw-r--r--include/hw/ppc/xive.h536
-rw-r--r--include/hw/ppc/xive_regs.h301
33 files changed, 4600 insertions, 0 deletions
diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h
new file mode 100644
index 000000000..a8cd85069
--- /dev/null
+++ b/include/hw/ppc/fdt.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU PowerPC helper routines for the device tree.
+ *
+ * Copyright (C) 2016 IBM Corp.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_FDT_H
+#define PPC_FDT_H
+
+#include "qemu/error-report.h"
+#include "target/ppc/cpu-qom.h"
+
+#define _FDT(exp) \
+ do { \
+ int ret = (exp); \
+ if (ret < 0) { \
+ error_report("error creating device tree: %s: %s", \
+ #exp, fdt_strerror(ret)); \
+ exit(1); \
+ } \
+ } while (0)
+
+size_t ppc_create_page_sizes_prop(PowerPCCPU *cpu, uint32_t *prop,
+ size_t maxsize);
+
+#endif /* PPC_FDT_H */
diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h
new file mode 100644
index 000000000..4a3f64451
--- /dev/null
+++ b/include/hw/ppc/mac_dbdma.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_MAC_DBDMA_H
+#define HW_MAC_DBDMA_H
+
+#include "exec/memory.h"
+#include "qemu/iov.h"
+#include "sysemu/dma.h"
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+typedef struct DBDMA_io DBDMA_io;
+
+typedef void (*DBDMA_flush)(DBDMA_io *io);
+typedef void (*DBDMA_rw)(DBDMA_io *io);
+typedef void (*DBDMA_end)(DBDMA_io *io);
+struct DBDMA_io {
+ void *opaque;
+ void *channel;
+ hwaddr addr;
+ int len;
+ int is_last;
+ int is_dma_out;
+ DBDMA_end dma_end;
+ /* DMA is in progress, don't start another one */
+ bool processing;
+ /* DMA request */
+ void *dma_mem;
+ dma_addr_t dma_len;
+ DMADirection dir;
+};
+
+/*
+ * DBDMA control/status registers. All little-endian.
+ */
+
+#define DBDMA_CONTROL 0x00
+#define DBDMA_STATUS 0x01
+#define DBDMA_CMDPTR_HI 0x02
+#define DBDMA_CMDPTR_LO 0x03
+#define DBDMA_INTR_SEL 0x04
+#define DBDMA_BRANCH_SEL 0x05
+#define DBDMA_WAIT_SEL 0x06
+#define DBDMA_XFER_MODE 0x07
+#define DBDMA_DATA2PTR_HI 0x08
+#define DBDMA_DATA2PTR_LO 0x09
+#define DBDMA_RES1 0x0A
+#define DBDMA_ADDRESS_HI 0x0B
+#define DBDMA_BRANCH_ADDR_HI 0x0C
+#define DBDMA_RES2 0x0D
+#define DBDMA_RES3 0x0E
+#define DBDMA_RES4 0x0F
+
+#define DBDMA_REGS 16
+#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t))
+
+#define DBDMA_CHANNEL_SHIFT 7
+#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT)
+
+#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT)
+
+/* Bits in control and status registers */
+
+#define RUN 0x8000
+#define PAUSE 0x4000
+#define FLUSH 0x2000
+#define WAKE 0x1000
+#define DEAD 0x0800
+#define ACTIVE 0x0400
+#define BT 0x0100
+#define DEVSTAT 0x00ff
+
+/*
+ * DBDMA command structure. These fields are all little-endian!
+ */
+
+typedef struct dbdma_cmd {
+ uint16_t req_count; /* requested byte transfer count */
+ uint16_t command; /* command word (has bit-fields) */
+ uint32_t phy_addr; /* physical data address */
+ uint32_t cmd_dep; /* command-dependent field */
+ uint16_t res_count; /* residual count after completion */
+ uint16_t xfer_status; /* transfer status */
+} dbdma_cmd;
+
+/* DBDMA command values in command field */
+
+#define COMMAND_MASK 0xf000
+#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */
+#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */
+#define INPUT_MORE 0x2000 /* transfer stream data to memory */
+#define INPUT_LAST 0x3000 /* ditto, expect end marker */
+#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */
+#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */
+#define DBDMA_NOP 0x6000 /* do nothing */
+#define DBDMA_STOP 0x7000 /* suspend processing */
+
+/* Key values in command field */
+
+#define KEY_MASK 0x0700
+#define KEY_STREAM0 0x0000 /* usual data stream */
+#define KEY_STREAM1 0x0100 /* control/status stream */
+#define KEY_STREAM2 0x0200 /* device-dependent stream */
+#define KEY_STREAM3 0x0300 /* device-dependent stream */
+#define KEY_STREAM4 0x0400 /* reserved */
+#define KEY_REGS 0x0500 /* device register space */
+#define KEY_SYSTEM 0x0600 /* system memory-mapped space */
+#define KEY_DEVICE 0x0700 /* device memory-mapped space */
+
+/* Interrupt control values in command field */
+
+#define INTR_MASK 0x0030
+#define INTR_NEVER 0x0000 /* don't interrupt */
+#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */
+#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */
+#define INTR_ALWAYS 0x0030 /* always interrupt */
+
+/* Branch control values in command field */
+
+#define BR_MASK 0x000c
+#define BR_NEVER 0x0000 /* don't branch */
+#define BR_IFSET 0x0004 /* branch if condition bit is 1 */
+#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */
+#define BR_ALWAYS 0x000c /* always branch */
+
+/* Wait control values in command field */
+
+#define WAIT_MASK 0x0003
+#define WAIT_NEVER 0x0000 /* don't wait */
+#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */
+#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */
+#define WAIT_ALWAYS 0x0003 /* always wait */
+
+typedef struct DBDMA_channel {
+ int channel;
+ uint32_t regs[DBDMA_REGS];
+ qemu_irq irq;
+ DBDMA_io io;
+ DBDMA_rw rw;
+ DBDMA_flush flush;
+ dbdma_cmd current;
+} DBDMA_channel;
+
+struct DBDMAState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mem;
+ DBDMA_channel channels[DBDMA_CHANNELS];
+ QEMUBH *bh;
+};
+typedef struct DBDMAState DBDMAState;
+
+/* Externally callable functions */
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+ DBDMA_rw rw, DBDMA_flush flush,
+ void *opaque);
+void DBDMA_kick(DBDMAState *dbdma);
+
+#define TYPE_MAC_DBDMA "mac-dbdma"
+OBJECT_DECLARE_SIMPLE_TYPE(DBDMAState, MAC_DBDMA)
+
+#endif
diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h
new file mode 100644
index 000000000..ebdaf8a49
--- /dev/null
+++ b/include/hw/ppc/openpic.h
@@ -0,0 +1,176 @@
+#ifndef OPENPIC_H
+#define OPENPIC_H
+
+#include "hw/sysbus.h"
+#include "hw/core/cpu.h"
+#include "qom/object.h"
+
+#define MAX_CPU 32
+#define MAX_MSI 8
+#define VID 0x03 /* MPIC version ID */
+
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
+enum {
+ OPENPIC_OUTPUT_INT = 0, /* IRQ */
+ OPENPIC_OUTPUT_CINT, /* critical IRQ */
+ OPENPIC_OUTPUT_MCK, /* Machine check event */
+ OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */
+ OPENPIC_OUTPUT_RESET, /* Core reset event */
+ OPENPIC_OUTPUT_NB,
+};
+
+typedef struct IrqLines { qemu_irq irq[OPENPIC_OUTPUT_NB]; } IrqLines;
+
+#define OPENPIC_MODEL_FSL_MPIC_20 1
+#define OPENPIC_MODEL_FSL_MPIC_42 2
+#define OPENPIC_MODEL_KEYLARGO 3
+
+#define OPENPIC_MAX_SRC 256
+#define OPENPIC_MAX_TMR 4
+#define OPENPIC_MAX_IPI 4
+#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \
+ OPENPIC_MAX_TMR)
+
+/* KeyLargo */
+#define KEYLARGO_MAX_CPU 4
+#define KEYLARGO_MAX_EXT 64
+#define KEYLARGO_MAX_IPI 4
+#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
+#define KEYLARGO_MAX_TMR 0
+#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
+/* Timers don't exist but this makes the code happy... */
+#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
+
+typedef struct FslMpicInfo {
+ int max_ext;
+} FslMpicInfo;
+
+typedef enum IRQType {
+ IRQ_TYPE_NORMAL = 0,
+ IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
+ IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
+} IRQType;
+
+/*
+ * Round up to the nearest 64 IRQs so that the queue length
+ * won't change when moving between 32 and 64 bit hosts.
+ */
+#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
+
+typedef struct IRQQueue {
+ unsigned long *queue;
+ int32_t queue_size; /* Only used for VMSTATE_BITMAP */
+ int next;
+ int priority;
+} IRQQueue;
+
+typedef struct IRQSource {
+ uint32_t ivpr; /* IRQ vector/priority register */
+ uint32_t idr; /* IRQ destination register */
+ uint32_t destmask; /* bitmap of CPU destinations */
+ int last_cpu;
+ int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
+ int pending; /* TRUE if IRQ is pending */
+ IRQType type;
+ bool level:1; /* level-triggered */
+ bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
+} IRQSource;
+
+#define IVPR_MASK_SHIFT 31
+#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
+#define IVPR_ACTIVITY_SHIFT 30
+#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
+#define IVPR_MODE_SHIFT 29
+#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
+#define IVPR_POLARITY_SHIFT 23
+#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
+#define IVPR_SENSE_SHIFT 22
+#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
+
+#define IVPR_PRIORITY_MASK (0xFU << 16)
+#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
+#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
+
+/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
+#define IDR_EP 0x80000000 /* external pin */
+#define IDR_CI 0x40000000 /* critical interrupt */
+
+typedef struct OpenPICTimer {
+ uint32_t tccr; /* Global timer current count register */
+ uint32_t tbcr; /* Global timer base count register */
+ int n_IRQ;
+ bool qemu_timer_active; /* Is the qemu_timer is running? */
+ struct QEMUTimer *qemu_timer;
+ struct OpenPICState *opp; /* Device timer is part of. */
+ /*
+ * The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
+ * current_count written or read, only defined if qemu_timer_active.
+ */
+ uint64_t origin_time;
+} OpenPICTimer;
+
+typedef struct OpenPICMSI {
+ uint32_t msir; /* Shared Message Signaled Interrupt Register */
+} OpenPICMSI;
+
+typedef struct IRQDest {
+ int32_t ctpr; /* CPU current task priority */
+ IRQQueue raised;
+ IRQQueue servicing;
+ qemu_irq *irqs;
+
+ /* Count of IRQ sources asserting on non-INT outputs */
+ uint32_t outputs_active[OPENPIC_OUTPUT_NB];
+} IRQDest;
+
+#define TYPE_OPENPIC "openpic"
+OBJECT_DECLARE_SIMPLE_TYPE(OpenPICState, OPENPIC)
+
+struct OpenPICState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion mem;
+
+ /* Behavior control */
+ FslMpicInfo *fsl;
+ uint32_t model;
+ uint32_t flags;
+ uint32_t nb_irqs;
+ uint32_t vid;
+ uint32_t vir; /* Vendor identification register */
+ uint32_t vector_mask;
+ uint32_t tfrr_reset;
+ uint32_t ivpr_reset;
+ uint32_t idr_reset;
+ uint32_t brr1;
+ uint32_t mpic_mode_mask;
+
+ /* Sub-regions */
+ MemoryRegion sub_io_mem[6];
+
+ /* Global registers */
+ uint32_t frr; /* Feature reporting register */
+ uint32_t gcr; /* Global configuration register */
+ uint32_t pir; /* Processor initialization register */
+ uint32_t spve; /* Spurious vector register */
+ uint32_t tfrr; /* Timer frequency reporting register */
+ /* Source registers */
+ IRQSource src[OPENPIC_MAX_IRQ];
+ /* Local registers per output pin */
+ IRQDest dst[MAX_CPU];
+ uint32_t nb_cpus;
+ /* Timer registers */
+ OpenPICTimer timers[OPENPIC_MAX_TMR];
+ uint32_t max_tmr;
+
+ /* Shared MSI registers */
+ OpenPICMSI msi[MAX_MSI];
+ uint32_t max_irq;
+ uint32_t irq_ipi0;
+ uint32_t irq_tim0;
+ uint32_t irq_msi;
+};
+
+#endif /* OPENPIC_H */
diff --git a/include/hw/ppc/openpic_kvm.h b/include/hw/ppc/openpic_kvm.h
new file mode 100644
index 000000000..9ef421525
--- /dev/null
+++ b/include/hw/ppc/openpic_kvm.h
@@ -0,0 +1,7 @@
+#ifndef OPENPIC_KVM_H
+#define OPENPIC_KVM_H
+
+#define TYPE_KVM_OPENPIC "kvm-openpic"
+int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
+
+#endif /* OPENPIC_KVM_H */
diff --git a/include/hw/ppc/pef.h b/include/hw/ppc/pef.h
new file mode 100644
index 000000000..707dbe524
--- /dev/null
+++ b/include/hw/ppc/pef.h
@@ -0,0 +1,17 @@
+/*
+ * PEF (Protected Execution Facility) for POWER support
+ *
+ * Copyright Red Hat.
+ *
+ * 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_PPC_PEF_H
+#define HW_PPC_PEF_H
+
+int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
+int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp);
+
+#endif /* HW_PPC_PEF_H */
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
new file mode 100644
index 000000000..aa08d79d2
--- /dev/null
+++ b/include/hw/ppc/pnv.h
@@ -0,0 +1,332 @@
+/*
+ * QEMU PowerPC PowerNV various definitions
+ *
+ * Copyright (c) 2014-2016 BenH, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_H
+#define PPC_PNV_H
+
+#include "hw/boards.h"
+#include "hw/sysbus.h"
+#include "hw/ipmi/ipmi.h"
+#include "hw/ppc/pnv_lpc.h"
+#include "hw/ppc/pnv_pnor.h"
+#include "hw/ppc/pnv_psi.h"
+#include "hw/ppc/pnv_occ.h"
+#include "hw/ppc/pnv_homer.h"
+#include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/pnv_core.h"
+#include "hw/pci-host/pnv_phb3.h"
+#include "hw/pci-host/pnv_phb4.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_CHIP "pnv-chip"
+OBJECT_DECLARE_TYPE(PnvChip, PnvChipClass,
+ PNV_CHIP)
+
+struct PnvChip {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ uint32_t chip_id;
+ uint64_t ram_start;
+ uint64_t ram_size;
+
+ uint32_t nr_cores;
+ uint32_t nr_threads;
+ uint64_t cores_mask;
+ PnvCore **cores;
+
+ uint32_t num_phbs;
+
+ MemoryRegion xscom_mmio;
+ MemoryRegion xscom;
+ AddressSpace xscom_as;
+
+ MemoryRegion *fw_mr;
+ gchar *dt_isa_nodename;
+};
+
+#define TYPE_PNV8_CHIP "pnv8-chip"
+typedef struct Pnv8Chip Pnv8Chip;
+DECLARE_INSTANCE_CHECKER(Pnv8Chip, PNV8_CHIP,
+ TYPE_PNV8_CHIP)
+
+struct Pnv8Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+
+ /*< public >*/
+ MemoryRegion icp_mmio;
+
+ PnvLpcController lpc;
+ Pnv8Psi psi;
+ PnvOCC occ;
+ PnvHomer homer;
+
+#define PNV8_CHIP_PHB3_MAX 4
+ PnvPHB3 phbs[PNV8_CHIP_PHB3_MAX];
+
+ XICSFabric *xics;
+};
+
+#define TYPE_PNV9_CHIP "pnv9-chip"
+typedef struct Pnv9Chip Pnv9Chip;
+DECLARE_INSTANCE_CHECKER(Pnv9Chip, PNV9_CHIP,
+ TYPE_PNV9_CHIP)
+
+struct Pnv9Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+
+ /*< public >*/
+ PnvXive xive;
+ Pnv9Psi psi;
+ PnvLpcController lpc;
+ PnvOCC occ;
+ PnvHomer homer;
+
+ uint32_t nr_quads;
+ PnvQuad *quads;
+
+#define PNV9_CHIP_MAX_PEC 3
+ PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC];
+};
+
+/*
+ * A SMT8 fused core is a pair of SMT4 cores.
+ */
+#define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
+#define PNV9_PIR2CHIP(pir) (((pir) >> 8) & 0x7f)
+
+#define TYPE_PNV10_CHIP "pnv10-chip"
+typedef struct Pnv10Chip Pnv10Chip;
+DECLARE_INSTANCE_CHECKER(Pnv10Chip, PNV10_CHIP,
+ TYPE_PNV10_CHIP)
+
+struct Pnv10Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+
+ /*< public >*/
+ Pnv9Psi psi;
+ PnvLpcController lpc;
+};
+
+struct PnvChipClass {
+ /*< private >*/
+ SysBusDeviceClass parent_class;
+
+ /*< public >*/
+ uint64_t chip_cfam_id;
+ uint64_t cores_mask;
+ uint32_t num_phbs;
+
+ DeviceRealize parent_realize;
+
+ uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
+ void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
+ void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu);
+ void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu);
+ void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, Monitor *mon);
+ ISABus *(*isa_create)(PnvChip *chip, Error **errp);
+ void (*dt_populate)(PnvChip *chip, void *fdt);
+ void (*pic_print_info)(PnvChip *chip, Monitor *mon);
+ uint64_t (*xscom_core_base)(PnvChip *chip, uint32_t core_id);
+ uint32_t (*xscom_pcba)(PnvChip *chip, uint64_t addr);
+};
+
+#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
+#define PNV_CHIP_TYPE_NAME(cpu_model) cpu_model PNV_CHIP_TYPE_SUFFIX
+
+#define TYPE_PNV_CHIP_POWER8E PNV_CHIP_TYPE_NAME("power8e_v2.1")
+DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8E,
+ TYPE_PNV_CHIP_POWER8E)
+
+#define TYPE_PNV_CHIP_POWER8 PNV_CHIP_TYPE_NAME("power8_v2.0")
+DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8,
+ TYPE_PNV_CHIP_POWER8)
+
+#define TYPE_PNV_CHIP_POWER8NVL PNV_CHIP_TYPE_NAME("power8nvl_v1.0")
+DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER8NVL,
+ TYPE_PNV_CHIP_POWER8NVL)
+
+#define TYPE_PNV_CHIP_POWER9 PNV_CHIP_TYPE_NAME("power9_v2.0")
+DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER9,
+ TYPE_PNV_CHIP_POWER9)
+
+#define TYPE_PNV_CHIP_POWER10 PNV_CHIP_TYPE_NAME("power10_v2.0")
+DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
+ TYPE_PNV_CHIP_POWER10)
+
+PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
+
+#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
+typedef struct PnvMachineClass PnvMachineClass;
+typedef struct PnvMachineState PnvMachineState;
+DECLARE_OBJ_CHECKERS(PnvMachineState, PnvMachineClass,
+ PNV_MACHINE, TYPE_PNV_MACHINE)
+
+
+struct PnvMachineClass {
+ /*< private >*/
+ MachineClass parent_class;
+
+ /*< public >*/
+ const char *compat;
+ int compat_size;
+
+ void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
+};
+
+struct PnvMachineState {
+ /*< private >*/
+ MachineState parent_obj;
+
+ uint32_t initrd_base;
+ long initrd_size;
+
+ uint32_t num_chips;
+ PnvChip **chips;
+
+ ISABus *isa_bus;
+ uint32_t cpld_irqstate;
+
+ IPMIBmc *bmc;
+ Notifier powerdown_notifier;
+
+ PnvPnor *pnor;
+
+ hwaddr fw_load_addr;
+};
+
+#define PNV_FDT_ADDR 0x01000000
+#define PNV_TIMEBASE_FREQ 512000000ULL
+
+/*
+ * BMC helpers
+ */
+void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt);
+void pnv_bmc_powerdown(IPMIBmc *bmc);
+IPMIBmc *pnv_bmc_create(PnvPnor *pnor);
+IPMIBmc *pnv_bmc_find(Error **errp);
+void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor);
+
+/*
+ * POWER8 MMIO base addresses
+ */
+#define PNV_XSCOM_SIZE 0x800000000ull
+#define PNV_XSCOM_BASE(chip) \
+ (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
+
+#define PNV_OCC_COMMON_AREA_SIZE 0x0000000000800000ull
+#define PNV_OCC_COMMON_AREA_BASE 0x7fff800000ull
+#define PNV_OCC_SENSOR_BASE(chip) (PNV_OCC_COMMON_AREA_BASE + \
+ PNV_OCC_SENSOR_DATA_BLOCK_BASE((chip)->chip_id))
+
+#define PNV_HOMER_SIZE 0x0000000000400000ull
+#define PNV_HOMER_BASE(chip) \
+ (0x7ffd800000ull + ((uint64_t)(chip)->chip_id) * PNV_HOMER_SIZE)
+
+
+/*
+ * XSCOM 0x20109CA defines the ICP BAR:
+ *
+ * 0:29 : bits 14 to 43 of address to define 1 MB region.
+ * 30 : 1 to enable ICP to receive loads/stores against its BAR region
+ * 31:63 : Constant 0
+ *
+ * Usually defined as :
+ *
+ * 0xffffe00200000000 -> 0x0003ffff80000000
+ * 0xffffe00600000000 -> 0x0003ffff80100000
+ * 0xffffe02200000000 -> 0x0003ffff80800000
+ * 0xffffe02600000000 -> 0x0003ffff80900000
+ */
+#define PNV_ICP_SIZE 0x0000000000100000ull
+#define PNV_ICP_BASE(chip) \
+ (0x0003ffff80000000ull + (uint64_t) (chip)->chip_id * PNV_ICP_SIZE)
+
+
+#define PNV_PSIHB_SIZE 0x0000000000100000ull
+#define PNV_PSIHB_BASE(chip) \
+ (0x0003fffe80000000ull + (uint64_t)(chip)->chip_id * PNV_PSIHB_SIZE)
+
+#define PNV_PSIHB_FSP_SIZE 0x0000000100000000ull
+#define PNV_PSIHB_FSP_BASE(chip) \
+ (0x0003ffe000000000ull + (uint64_t)(chip)->chip_id * \
+ PNV_PSIHB_FSP_SIZE)
+
+/*
+ * POWER9 MMIO base addresses
+ */
+#define PNV9_CHIP_BASE(chip, base) \
+ ((base) + ((uint64_t) (chip)->chip_id << 42))
+
+#define PNV9_XIVE_VC_SIZE 0x0000008000000000ull
+#define PNV9_XIVE_VC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006010000000000ull)
+
+#define PNV9_XIVE_PC_SIZE 0x0000001000000000ull
+#define PNV9_XIVE_PC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
+
+#define PNV9_LPCM_SIZE 0x0000000100000000ull
+#define PNV9_LPCM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
+
+#define PNV9_PSIHB_SIZE 0x0000000000100000ull
+#define PNV9_PSIHB_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
+
+#define PNV9_XIVE_IC_SIZE 0x0000000000080000ull
+#define PNV9_XIVE_IC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
+
+#define PNV9_XIVE_TM_SIZE 0x0000000000040000ull
+#define PNV9_XIVE_TM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
+
+#define PNV9_PSIHB_ESB_SIZE 0x0000000000010000ull
+#define PNV9_PSIHB_ESB_BASE(chip) PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
+
+#define PNV9_XSCOM_SIZE 0x0000000400000000ull
+#define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull)
+
+#define PNV9_OCC_COMMON_AREA_SIZE 0x0000000000800000ull
+#define PNV9_OCC_COMMON_AREA_BASE 0x203fff800000ull
+#define PNV9_OCC_SENSOR_BASE(chip) (PNV9_OCC_COMMON_AREA_BASE + \
+ PNV_OCC_SENSOR_DATA_BLOCK_BASE((chip)->chip_id))
+
+#define PNV9_HOMER_SIZE 0x0000000000400000ull
+#define PNV9_HOMER_BASE(chip) \
+ (0x203ffd800000ull + ((uint64_t)(chip)->chip_id) * PNV9_HOMER_SIZE)
+
+/*
+ * POWER10 MMIO base addresses - 16TB stride per chip
+ */
+#define PNV10_CHIP_BASE(chip, base) \
+ ((base) + ((uint64_t) (chip)->chip_id << 44))
+
+#define PNV10_XSCOM_SIZE 0x0000000400000000ull
+#define PNV10_XSCOM_BASE(chip) PNV10_CHIP_BASE(chip, 0x00603fc00000000ull)
+
+#define PNV10_LPCM_SIZE 0x0000000100000000ull
+#define PNV10_LPCM_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030000000000ull)
+
+#define PNV10_PSIHB_ESB_SIZE 0x0000000000100000ull
+#define PNV10_PSIHB_ESB_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030202000000ull)
+
+#define PNV10_PSIHB_SIZE 0x0000000000100000ull
+#define PNV10_PSIHB_BASE(chip) PNV10_CHIP_BASE(chip, 0x0006030203000000ull)
+
+#endif /* PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
new file mode 100644
index 000000000..c22eab2e1
--- /dev/null
+++ b/include/hw/ppc/pnv_core.h
@@ -0,0 +1,73 @@
+/*
+ * QEMU PowerPC PowerNV CPU Core model
+ *
+ * Copyright (c) 2016, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_CORE_H
+#define PPC_PNV_CORE_H
+
+#include "hw/cpu/core.h"
+#include "target/ppc/cpu.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_CORE "powernv-cpu-core"
+OBJECT_DECLARE_TYPE(PnvCore, PnvCoreClass,
+ PNV_CORE)
+
+typedef struct PnvChip PnvChip;
+
+struct PnvCore {
+ /*< private >*/
+ CPUCore parent_obj;
+
+ /*< public >*/
+ PowerPCCPU **threads;
+ uint32_t pir;
+ uint64_t hrmor;
+ PnvChip *chip;
+
+ MemoryRegion xscom_regs;
+};
+
+struct PnvCoreClass {
+ DeviceClass parent_class;
+
+ const MemoryRegionOps *xscom_ops;
+};
+
+#define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE
+#define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
+
+typedef struct PnvCPUState {
+ Object *intc;
+} PnvCPUState;
+
+static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
+{
+ return (PnvCPUState *)cpu->machine_data;
+}
+
+#define TYPE_PNV_QUAD "powernv-cpu-quad"
+OBJECT_DECLARE_SIMPLE_TYPE(PnvQuad, PNV_QUAD)
+
+struct PnvQuad {
+ DeviceState parent_obj;
+
+ uint32_t quad_id;
+ MemoryRegion xscom_regs;
+};
+#endif /* PPC_PNV_CORE_H */
diff --git a/include/hw/ppc/pnv_homer.h b/include/hw/ppc/pnv_homer.h
new file mode 100644
index 000000000..1889e3083
--- /dev/null
+++ b/include/hw/ppc/pnv_homer.h
@@ -0,0 +1,56 @@
+/*
+ * QEMU PowerPC PowerNV Emulation of a few HOMER related registers
+ *
+ * Copyright (c) 2019, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_HOMER_H
+#define PPC_PNV_HOMER_H
+
+#include "hw/ppc/pnv.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_HOMER "pnv-homer"
+OBJECT_DECLARE_TYPE(PnvHomer, PnvHomerClass,
+ PNV_HOMER)
+#define TYPE_PNV8_HOMER TYPE_PNV_HOMER "-POWER8"
+DECLARE_INSTANCE_CHECKER(PnvHomer, PNV8_HOMER,
+ TYPE_PNV8_HOMER)
+#define TYPE_PNV9_HOMER TYPE_PNV_HOMER "-POWER9"
+DECLARE_INSTANCE_CHECKER(PnvHomer, PNV9_HOMER,
+ TYPE_PNV9_HOMER)
+
+struct PnvHomer {
+ DeviceState parent;
+
+ struct PnvChip *chip;
+ MemoryRegion pba_regs;
+ MemoryRegion regs;
+};
+
+
+struct PnvHomerClass {
+ DeviceClass parent_class;
+
+ int pba_size;
+ const MemoryRegionOps *pba_ops;
+ int homer_size;
+ const MemoryRegionOps *homer_ops;
+
+ hwaddr core_max_base;
+};
+
+#endif /* PPC_PNV_HOMER_H */
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
new file mode 100644
index 000000000..e893e763d
--- /dev/null
+++ b/include/hw/ppc/pnv_lpc.h
@@ -0,0 +1,108 @@
+/*
+ * QEMU PowerPC PowerNV LPC controller
+ *
+ * Copyright (c) 2016, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_LPC_H
+#define PPC_PNV_LPC_H
+
+#include "hw/ppc/pnv_psi.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_LPC "pnv-lpc"
+typedef struct PnvLpcClass PnvLpcClass;
+typedef struct PnvLpcController PnvLpcController;
+DECLARE_OBJ_CHECKERS(PnvLpcController, PnvLpcClass,
+ PNV_LPC, TYPE_PNV_LPC)
+#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
+DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV8_LPC,
+ TYPE_PNV8_LPC)
+
+#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
+DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV9_LPC,
+ TYPE_PNV9_LPC)
+
+#define TYPE_PNV10_LPC TYPE_PNV_LPC "-POWER10"
+DECLARE_INSTANCE_CHECKER(PnvLpcController, PNV10_LPC,
+ TYPE_PNV10_LPC)
+
+struct PnvLpcController {
+ DeviceState parent;
+
+ uint64_t eccb_stat_reg;
+ uint32_t eccb_data_reg;
+
+ /* OPB bus */
+ MemoryRegion opb_mr;
+ AddressSpace opb_as;
+
+ /* ISA IO and Memory space */
+ MemoryRegion isa_io;
+ MemoryRegion isa_mem;
+ MemoryRegion isa_fw;
+
+ /* Windows from OPB to ISA (aliases) */
+ MemoryRegion opb_isa_io;
+ MemoryRegion opb_isa_mem;
+ MemoryRegion opb_isa_fw;
+
+ /* Registers */
+ MemoryRegion lpc_hc_regs;
+ MemoryRegion opb_master_regs;
+
+ /* OPB Master LS registers */
+ uint32_t opb_irq_route0;
+ uint32_t opb_irq_route1;
+ uint32_t opb_irq_stat;
+ uint32_t opb_irq_mask;
+ uint32_t opb_irq_pol;
+ uint32_t opb_irq_input;
+
+ /* LPC HC registers */
+ uint32_t lpc_hc_fw_seg_idsel;
+ uint32_t lpc_hc_fw_rd_acc_size;
+ uint32_t lpc_hc_irqser_ctrl;
+ uint32_t lpc_hc_irqmask;
+ uint32_t lpc_hc_irqstat;
+ uint32_t lpc_hc_error_addr;
+
+ /* XSCOM registers */
+ MemoryRegion xscom_regs;
+
+ /* PSI to generate interrupts */
+ PnvPsi *psi;
+};
+
+
+struct PnvLpcClass {
+ DeviceClass parent_class;
+
+ int psi_irq;
+
+ DeviceRealize parent_realize;
+};
+
+/*
+ * Old compilers error on typdef forward declarations. Keep them happy.
+ */
+struct PnvChip;
+
+ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
+int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset,
+ uint64_t lpcm_addr, uint64_t lpcm_size);
+
+#endif /* PPC_PNV_LPC_H */
diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
new file mode 100644
index 000000000..b78185aec
--- /dev/null
+++ b/include/hw/ppc/pnv_occ.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU PowerPC PowerNV Emulation of a few OCC related registers
+ *
+ * Copyright (c) 2015-2017, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_OCC_H
+#define PPC_PNV_OCC_H
+
+#include "hw/ppc/pnv_psi.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_OCC "pnv-occ"
+OBJECT_DECLARE_TYPE(PnvOCC, PnvOCCClass,
+ PNV_OCC)
+#define TYPE_PNV8_OCC TYPE_PNV_OCC "-POWER8"
+DECLARE_INSTANCE_CHECKER(PnvOCC, PNV8_OCC,
+ TYPE_PNV8_OCC)
+#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9"
+DECLARE_INSTANCE_CHECKER(PnvOCC, PNV9_OCC,
+ TYPE_PNV9_OCC)
+
+#define PNV_OCC_SENSOR_DATA_BLOCK_OFFSET 0x00580000
+#define PNV_OCC_SENSOR_DATA_BLOCK_SIZE 0x00025800
+
+struct PnvOCC {
+ DeviceState xd;
+
+ /* OCC Misc interrupt */
+ uint64_t occmisc;
+
+ PnvPsi *psi;
+
+ MemoryRegion xscom_regs;
+ MemoryRegion sram_regs;
+};
+
+
+struct PnvOCCClass {
+ DeviceClass parent_class;
+
+ int xscom_size;
+ const MemoryRegionOps *xscom_ops;
+ int psi_irq;
+};
+
+#define PNV_OCC_SENSOR_DATA_BLOCK_BASE(i) \
+ (PNV_OCC_SENSOR_DATA_BLOCK_OFFSET + (i) * PNV_OCC_SENSOR_DATA_BLOCK_SIZE)
+
+#endif /* PPC_PNV_OCC_H */
diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h
new file mode 100644
index 000000000..99f9a3adf
--- /dev/null
+++ b/include/hw/ppc/pnv_pnor.h
@@ -0,0 +1,31 @@
+/*
+ * QEMU PowerNV PNOR simple model
+ *
+ * Copyright (c) 2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#ifndef _PPC_PNV_PNOR_H
+#define _PPC_PNV_PNOR_H
+#include "qom/object.h"
+
+/*
+ * PNOR offset on the LPC FW address space
+ */
+#define PNOR_SPI_OFFSET 0x0c000000UL
+
+#define TYPE_PNV_PNOR "pnv-pnor"
+OBJECT_DECLARE_SIMPLE_TYPE(PnvPnor, PNV_PNOR)
+
+struct PnvPnor {
+ SysBusDevice parent_obj;
+
+ BlockBackend *blk;
+
+ uint8_t *storage;
+ int64_t size;
+ MemoryRegion mmio;
+};
+
+#endif /* _PPC_PNV_PNOR_H */
diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
new file mode 100644
index 000000000..eb841b34a
--- /dev/null
+++ b/include/hw/ppc/pnv_psi.h
@@ -0,0 +1,120 @@
+/*
+ * QEMU PowerPC PowerNV Processor Service Interface (PSI) model
+ *
+ * Copyright (c) 2015-2017, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_PSI_H
+#define PPC_PNV_PSI_H
+
+#include "hw/sysbus.h"
+#include "hw/ppc/xics.h"
+#include "hw/ppc/xive.h"
+#include "qom/object.h"
+
+#define TYPE_PNV_PSI "pnv-psi"
+OBJECT_DECLARE_TYPE(PnvPsi, PnvPsiClass,
+ PNV_PSI)
+
+#define PSIHB_XSCOM_MAX 0x20
+
+struct PnvPsi {
+ DeviceState parent;
+
+ MemoryRegion regs_mr;
+ uint64_t bar;
+
+ /* FSP region not supported */
+ /* MemoryRegion fsp_mr; */
+ uint64_t fsp_bar;
+
+ /* Interrupt generation */
+ qemu_irq *qirqs;
+
+ /* Registers */
+ uint64_t regs[PSIHB_XSCOM_MAX];
+
+ MemoryRegion xscom_regs;
+};
+
+#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
+OBJECT_DECLARE_SIMPLE_TYPE(Pnv8Psi, PNV8_PSI)
+
+struct Pnv8Psi {
+ PnvPsi parent;
+
+ ICSState ics;
+};
+
+#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
+OBJECT_DECLARE_SIMPLE_TYPE(Pnv9Psi, PNV9_PSI)
+
+struct Pnv9Psi {
+ PnvPsi parent;
+
+ XiveSource source;
+};
+
+#define TYPE_PNV10_PSI TYPE_PNV_PSI "-POWER10"
+
+
+struct PnvPsiClass {
+ SysBusDeviceClass parent_class;
+
+ uint32_t xscom_pcba;
+ uint32_t xscom_size;
+ uint64_t bar_mask;
+ const char *compat;
+ int compat_size;
+
+ void (*irq_set)(PnvPsi *psi, int, bool state);
+};
+
+/* The PSI and FSP interrupts are muxed on the same IRQ number */
+typedef enum PnvPsiIrq {
+ PSIHB_IRQ_PSI, /* internal use only */
+ PSIHB_IRQ_FSP, /* internal use only */
+ PSIHB_IRQ_OCC,
+ PSIHB_IRQ_FSI,
+ PSIHB_IRQ_LPC_I2C,
+ PSIHB_IRQ_LOCAL_ERR,
+ PSIHB_IRQ_EXTERNAL,
+} PnvPsiIrq;
+
+#define PSI_NUM_INTERRUPTS 6
+
+void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
+
+/* P9 PSI Interrupts */
+#define PSIHB9_IRQ_PSI 0
+#define PSIHB9_IRQ_OCC 1
+#define PSIHB9_IRQ_FSI 2
+#define PSIHB9_IRQ_LPCHC 3
+#define PSIHB9_IRQ_LOCAL_ERR 4
+#define PSIHB9_IRQ_GLOBAL_ERR 5
+#define PSIHB9_IRQ_TPM 6
+#define PSIHB9_IRQ_LPC_SIRQ0 7
+#define PSIHB9_IRQ_LPC_SIRQ1 8
+#define PSIHB9_IRQ_LPC_SIRQ2 9
+#define PSIHB9_IRQ_LPC_SIRQ3 10
+#define PSIHB9_IRQ_SBE_I2C 11
+#define PSIHB9_IRQ_DIO 12
+#define PSIHB9_IRQ_PSU 13
+#define PSIHB9_NUM_IRQS 14
+
+void pnv_psi_pic_print_info(Pnv9Psi *psi, Monitor *mon);
+
+#endif /* PPC_PNV_PSI_H */
diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h
new file mode 100644
index 000000000..7928e2796
--- /dev/null
+++ b/include/hw/ppc/pnv_xive.h
@@ -0,0 +1,98 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_PNV_XIVE_H
+#define PPC_PNV_XIVE_H
+
+#include "hw/ppc/xive.h"
+#include "qom/object.h"
+
+struct PnvChip;
+
+#define TYPE_PNV_XIVE "pnv-xive"
+OBJECT_DECLARE_TYPE(PnvXive, PnvXiveClass,
+ PNV_XIVE)
+
+#define XIVE_BLOCK_MAX 16
+
+#define XIVE_TABLE_BLK_MAX 16 /* Block Scope Table (0-15) */
+#define XIVE_TABLE_MIG_MAX 16 /* Migration Register Table (1-15) */
+#define XIVE_TABLE_VDT_MAX 16 /* VDT Domain Table (0-15) */
+#define XIVE_TABLE_EDT_MAX 64 /* EDT Domain Table (0-63) */
+
+struct PnvXive {
+ XiveRouter parent_obj;
+
+ /* Owning chip */
+ struct PnvChip *chip;
+
+ /* XSCOM addresses giving access to the controller registers */
+ MemoryRegion xscom_regs;
+
+ /* Main MMIO regions that can be configured by FW */
+ MemoryRegion ic_mmio;
+ MemoryRegion ic_reg_mmio;
+ MemoryRegion ic_notify_mmio;
+ MemoryRegion ic_lsi_mmio;
+ MemoryRegion tm_indirect_mmio;
+ MemoryRegion vc_mmio;
+ MemoryRegion pc_mmio;
+ MemoryRegion tm_mmio;
+
+ /*
+ * IPI and END address spaces modeling the EDT segmentation in the
+ * VC region
+ */
+ AddressSpace ipi_as;
+ MemoryRegion ipi_mmio;
+ MemoryRegion ipi_edt_mmio;
+
+ AddressSpace end_as;
+ MemoryRegion end_mmio;
+ MemoryRegion end_edt_mmio;
+
+ /* Shortcut values for the Main MMIO regions */
+ hwaddr ic_base;
+ uint32_t ic_shift;
+ hwaddr vc_base;
+ uint32_t vc_shift;
+ hwaddr pc_base;
+ uint32_t pc_shift;
+ hwaddr tm_base;
+ uint32_t tm_shift;
+
+ /* Our XIVE source objects for IPIs and ENDs */
+ XiveSource ipi_source;
+ XiveENDSource end_source;
+
+ /* Interrupt controller registers */
+ uint64_t regs[0x300];
+
+ /*
+ * Virtual Structure Descriptor tables : EAT, SBE, ENDT, NVTT, IRQ
+ * These are in a SRAM protected by ECC.
+ */
+ uint64_t vsds[5][XIVE_BLOCK_MAX];
+
+ /* Translation tables */
+ uint64_t blk[XIVE_TABLE_BLK_MAX];
+ uint64_t mig[XIVE_TABLE_MIG_MAX];
+ uint64_t vdt[XIVE_TABLE_VDT_MAX];
+ uint64_t edt[XIVE_TABLE_EDT_MAX];
+};
+
+struct PnvXiveClass {
+ XiveRouterClass parent_class;
+
+ DeviceRealize parent_realize;
+};
+
+void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon);
+
+#endif /* PPC_PNV_XIVE_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
new file mode 100644
index 000000000..2ff9f7a8d
--- /dev/null
+++ b/include/hw/ppc/pnv_xscom.h
@@ -0,0 +1,148 @@
+/*
+ * QEMU PowerPC PowerNV XSCOM bus definitions
+ *
+ * Copyright (c) 2016, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PPC_PNV_XSCOM_H
+#define PPC_PNV_XSCOM_H
+
+#include "qom/object.h"
+
+typedef struct PnvXScomInterface PnvXScomInterface;
+
+#define TYPE_PNV_XSCOM_INTERFACE "pnv-xscom-interface"
+#define PNV_XSCOM_INTERFACE(obj) \
+ INTERFACE_CHECK(PnvXScomInterface, (obj), TYPE_PNV_XSCOM_INTERFACE)
+typedef struct PnvXScomInterfaceClass PnvXScomInterfaceClass;
+DECLARE_CLASS_CHECKERS(PnvXScomInterfaceClass, PNV_XSCOM_INTERFACE,
+ TYPE_PNV_XSCOM_INTERFACE)
+
+struct PnvXScomInterfaceClass {
+ InterfaceClass parent;
+ int (*dt_xscom)(PnvXScomInterface *dev, void *fdt, int offset);
+};
+
+/*
+ * Layout of the XSCOM PCB addresses of EX core 1 (POWER 8)
+ *
+ * GPIO 0x1100xxxx
+ * SCOM 0x1101xxxx
+ * OHA 0x1102xxxx
+ * CLOCK CTL 0x1103xxxx
+ * FIR 0x1104xxxx
+ * THERM 0x1105xxxx
+ * <reserved> 0x1106xxxx
+ * ..
+ * 0x110Exxxx
+ * PCB SLAVE 0x110Fxxxx
+ */
+
+#define PNV_XSCOM_EX_CORE_BASE 0x10000000ull
+
+#define PNV_XSCOM_EX_BASE(core) \
+ (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
+#define PNV_XSCOM_EX_SIZE 0x100000
+
+#define PNV_XSCOM_LPC_BASE 0xb0020
+#define PNV_XSCOM_LPC_SIZE 0x4
+
+#define PNV_XSCOM_PSIHB_BASE 0x2010900
+#define PNV_XSCOM_PSIHB_SIZE 0x20
+
+#define PNV_XSCOM_OCC_BASE 0x0066000
+#define PNV_XSCOM_OCC_SIZE 0x6000
+
+#define PNV_XSCOM_PBA_BASE 0x2013f00
+#define PNV_XSCOM_PBA_SIZE 0x40
+
+#define PNV_XSCOM_PBCQ_NEST_BASE 0x2012000
+#define PNV_XSCOM_PBCQ_NEST_SIZE 0x46
+
+#define PNV_XSCOM_PBCQ_PCI_BASE 0x9012000
+#define PNV_XSCOM_PBCQ_PCI_SIZE 0x15
+
+#define PNV_XSCOM_PBCQ_SPCI_BASE 0x9013c00
+#define PNV_XSCOM_PBCQ_SPCI_SIZE 0x5
+
+/*
+ * Layout of the XSCOM PCB addresses (POWER 9)
+ */
+#define PNV9_XSCOM_EC_BASE(core) \
+ ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
+#define PNV9_XSCOM_EC_SIZE 0x100000
+
+#define PNV9_XSCOM_EQ_BASE(core) \
+ ((uint64_t)(((core) & 0x1C) + 0x40) << 22)
+#define PNV9_XSCOM_EQ_SIZE 0x100000
+
+#define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE
+#define PNV9_XSCOM_OCC_SIZE 0x8000
+
+#define PNV9_XSCOM_PBA_BASE 0x5012b00
+#define PNV9_XSCOM_PBA_SIZE 0x40
+
+#define PNV9_XSCOM_PSIHB_BASE 0x5012900
+#define PNV9_XSCOM_PSIHB_SIZE 0x100
+
+#define PNV9_XSCOM_XIVE_BASE 0x5013000
+#define PNV9_XSCOM_XIVE_SIZE 0x300
+
+#define PNV9_XSCOM_PEC_NEST_BASE 0x4010c00
+#define PNV9_XSCOM_PEC_NEST_SIZE 0x100
+
+#define PNV9_XSCOM_PEC_PCI_BASE 0xd010800
+#define PNV9_XSCOM_PEC_PCI_SIZE 0x200
+
+/* XSCOM PCI "pass-through" window to PHB SCOM */
+#define PNV9_XSCOM_PEC_PCI_STK0 0x100
+#define PNV9_XSCOM_PEC_PCI_STK1 0x140
+#define PNV9_XSCOM_PEC_PCI_STK2 0x180
+
+/*
+ * Layout of the XSCOM PCB addresses (POWER 10)
+ */
+#define PNV10_XSCOM_EQ_CHIPLET(core) (0x20 + ((core) >> 2))
+#define PNV10_XSCOM_EQ(chiplet) ((chiplet) << 24)
+#define PNV10_XSCOM_EC(proc) \
+ ((0x2 << 16) | ((1 << (3 - (proc))) << 12))
+
+#define PNV10_XSCOM_EQ_BASE(core) \
+ ((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core)))
+#define PNV10_XSCOM_EQ_SIZE 0x100000
+
+#define PNV10_XSCOM_EC_BASE(core) \
+ ((uint64_t) PNV10_XSCOM_EQ_BASE(core) | PNV10_XSCOM_EC(core & 0x3))
+#define PNV10_XSCOM_EC_SIZE 0x100000
+
+#define PNV10_XSCOM_PSIHB_BASE 0x3011D00
+#define PNV10_XSCOM_PSIHB_SIZE 0x100
+
+void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp);
+int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
+ uint64_t xscom_base, uint64_t xscom_size,
+ const char *compat, int compat_size);
+
+void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset,
+ MemoryRegion *mr);
+void pnv_xscom_region_init(MemoryRegion *mr,
+ Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size);
+
+#endif /* PPC_PNV_XSCOM_H */
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
new file mode 100644
index 000000000..93e614cff
--- /dev/null
+++ b/include/hw/ppc/ppc.h
@@ -0,0 +1,115 @@
+#ifndef HW_PPC_H
+#define HW_PPC_H
+
+#include "target/ppc/cpu-qom.h"
+
+void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir);
+int ppc_cpu_pir(PowerPCCPU *cpu);
+
+/* PowerPC hardware exceptions management helpers */
+typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
+typedef struct clk_setup_t clk_setup_t;
+struct clk_setup_t {
+ clk_setup_cb cb;
+ void *opaque;
+};
+static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
+{
+ if (clk->cb != NULL)
+ (*clk->cb)(clk->opaque, freq);
+}
+
+struct ppc_tb_t {
+ /* Time base management */
+ int64_t tb_offset; /* Compensation */
+ int64_t atb_offset; /* Compensation */
+ int64_t vtb_offset;
+ uint32_t tb_freq; /* TB frequency */
+ /* Decrementer management */
+ uint64_t decr_next; /* Tick for next decr interrupt */
+ uint32_t decr_freq; /* decrementer frequency */
+ QEMUTimer *decr_timer;
+ /* Hypervisor decrementer management */
+ uint64_t hdecr_next; /* Tick for next hdecr interrupt */
+ QEMUTimer *hdecr_timer;
+ int64_t purr_offset;
+ void *opaque;
+ uint32_t flags;
+};
+
+/* PPC Timers flags */
+#define PPC_TIMER_BOOKE (1 << 0) /* Enable Booke support */
+#define PPC_TIMER_E500 (1 << 1) /* Enable e500 support */
+#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
+ * the most significant bit
+ * changes from 0 to 1.
+ */
+#define PPC_DECR_ZERO_TRIGGERED (1 << 3) /* Decr interrupt triggered when
+ * the decrementer reaches zero.
+ */
+#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
+ * the most significant bit is 1.
+ */
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
+clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val);
+int ppc_dcr_init (CPUPPCState *env, int (*dcr_read_error)(int dcrn),
+ int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
+ dcr_read_cb drc_read, dcr_write_cb dcr_write);
+clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
+ unsigned int decr_excp);
+
+/* Embedded PowerPC reset */
+void ppc40x_core_reset(PowerPCCPU *cpu);
+void ppc40x_chip_reset(PowerPCCPU *cpu);
+void ppc40x_system_reset(PowerPCCPU *cpu);
+
+#if defined(CONFIG_USER_ONLY)
+static inline void ppc40x_irq_init(PowerPCCPU *cpu) {}
+static inline void ppc6xx_irq_init(PowerPCCPU *cpu) {}
+static inline void ppc970_irq_init(PowerPCCPU *cpu) {}
+static inline void ppcPOWER7_irq_init(PowerPCCPU *cpu) {}
+static inline void ppcPOWER9_irq_init(PowerPCCPU *cpu) {}
+static inline void ppce500_irq_init(PowerPCCPU *cpu) {}
+static inline void ppc_irq_reset(PowerPCCPU *cpu) {}
+#else
+void ppc40x_irq_init(PowerPCCPU *cpu);
+void ppce500_irq_init(PowerPCCPU *cpu);
+void ppc6xx_irq_init(PowerPCCPU *cpu);
+void ppc970_irq_init(PowerPCCPU *cpu);
+void ppcPOWER7_irq_init(PowerPCCPU *cpu);
+void ppcPOWER9_irq_init(PowerPCCPU *cpu);
+void ppc_irq_reset(PowerPCCPU *cpu);
+#endif
+
+/* PPC machines for OpenBIOS */
+enum {
+ ARCH_PREP = 0,
+ ARCH_MAC99,
+ ARCH_HEATHROW,
+ ARCH_MAC99_U3,
+};
+
+#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
+#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
+#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
+#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04)
+#define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07)
+#define FW_CFG_PPC_NVRAM_ADDR (FW_CFG_ARCH_LOCAL + 0x08)
+#define FW_CFG_PPC_BUSFREQ (FW_CFG_ARCH_LOCAL + 0x09)
+#define FW_CFG_PPC_NVRAM_FLAT (FW_CFG_ARCH_LOCAL + 0x0a)
+#define FW_CFG_PPC_VIACONFIG (FW_CFG_ARCH_LOCAL + 0x0b)
+
+#define PPC_SERIAL_MM_BAUDBASE 399193
+
+/* ppc_booke.c */
+void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
+#endif
diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
new file mode 100644
index 000000000..980f964b5
--- /dev/null
+++ b/include/hw/ppc/ppc4xx.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU PowerPC 4xx emulation shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef PPC4XX_H
+#define PPC4XX_H
+
+#include "hw/ppc/ppc.h"
+#include "exec/memory.h"
+
+/* PowerPC 4xx core initialization */
+PowerPCCPU *ppc4xx_init(const char *cpu_model,
+ clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+ uint32_t sysclk);
+
+void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
+ MemoryRegion ram_memories[],
+ hwaddr ram_bases[], hwaddr ram_sizes[],
+ const ram_addr_t sdram_bank_sizes[]);
+
+void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
+ MemoryRegion ram_memories[],
+ hwaddr *ram_bases,
+ hwaddr *ram_sizes,
+ int do_init);
+
+void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
+ qemu_irq irqs[4]);
+
+#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
+
+#endif /* PPC4XX_H */
diff --git a/include/hw/ppc/ppc_e500.h b/include/hw/ppc/ppc_e500.h
new file mode 100644
index 000000000..b66c0e3ee
--- /dev/null
+++ b/include/hw/ppc/ppc_e500.h
@@ -0,0 +1,6 @@
+#ifndef HW_PPC_E500_H
+#define HW_PPC_E500_H
+
+void ppce500_set_mpic_proxy(bool enabled);
+
+#endif
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
new file mode 100644
index 000000000..ee7504b97
--- /dev/null
+++ b/include/hw/ppc/spapr.h
@@ -0,0 +1,991 @@
+#ifndef HW_SPAPR_H
+#define HW_SPAPR_H
+
+#include "qemu/units.h"
+#include "sysemu/dma.h"
+#include "hw/boards.h"
+#include "hw/ppc/spapr_drc.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/ppc/spapr_ovec.h"
+#include "hw/ppc/spapr_irq.h"
+#include "qom/object.h"
+#include "hw/ppc/spapr_xive.h" /* For SpaprXive */
+#include "hw/ppc/xics.h" /* For ICSState */
+#include "hw/ppc/spapr_tpm_proxy.h"
+#include "hw/ppc/vof.h"
+
+struct SpaprVioBus;
+struct SpaprPhbState;
+struct SpaprNvram;
+
+typedef struct SpaprEventLogEntry SpaprEventLogEntry;
+typedef struct SpaprEventSource SpaprEventSource;
+typedef struct SpaprPendingHpt SpaprPendingHpt;
+
+#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
+#define SPAPR_ENTRY_POINT 0x100
+
+#define SPAPR_TIMEBASE_FREQ 512000000ULL
+
+#define TYPE_SPAPR_RTC "spapr-rtc"
+
+OBJECT_DECLARE_SIMPLE_TYPE(SpaprRtcState, SPAPR_RTC)
+
+struct SpaprRtcState {
+ /*< private >*/
+ DeviceState parent_obj;
+ int64_t ns_offset;
+};
+
+typedef struct SpaprDimmState SpaprDimmState;
+
+#define TYPE_SPAPR_MACHINE "spapr-machine"
+OBJECT_DECLARE_TYPE(SpaprMachineState, SpaprMachineClass, SPAPR_MACHINE)
+
+typedef enum {
+ SPAPR_RESIZE_HPT_DEFAULT = 0,
+ SPAPR_RESIZE_HPT_DISABLED,
+ SPAPR_RESIZE_HPT_ENABLED,
+ SPAPR_RESIZE_HPT_REQUIRED,
+} SpaprResizeHpt;
+
+/**
+ * Capabilities
+ */
+
+/* Hardware Transactional Memory */
+#define SPAPR_CAP_HTM 0x00
+/* Vector Scalar Extensions */
+#define SPAPR_CAP_VSX 0x01
+/* Decimal Floating Point */
+#define SPAPR_CAP_DFP 0x02
+/* Cache Flush on Privilege Change */
+#define SPAPR_CAP_CFPC 0x03
+/* Speculation Barrier Bounds Checking */
+#define SPAPR_CAP_SBBC 0x04
+/* Indirect Branch Serialisation */
+#define SPAPR_CAP_IBS 0x05
+/* HPT Maximum Page Size (encoded as a shift) */
+#define SPAPR_CAP_HPT_MAXPAGESIZE 0x06
+/* Nested KVM-HV */
+#define SPAPR_CAP_NESTED_KVM_HV 0x07
+/* Large Decrementer */
+#define SPAPR_CAP_LARGE_DECREMENTER 0x08
+/* Count Cache Flush Assist HW Instruction */
+#define SPAPR_CAP_CCF_ASSIST 0x09
+/* Implements PAPR FWNMI option */
+#define SPAPR_CAP_FWNMI 0x0A
+/* Support H_RPT_INVALIDATE */
+#define SPAPR_CAP_RPT_INVALIDATE 0x0B
+/* Num Caps */
+#define SPAPR_CAP_NUM (SPAPR_CAP_RPT_INVALIDATE + 1)
+
+/*
+ * Capability Values
+ */
+/* Bool Caps */
+#define SPAPR_CAP_OFF 0x00
+#define SPAPR_CAP_ON 0x01
+
+/* Custom Caps */
+
+/* Generic */
+#define SPAPR_CAP_BROKEN 0x00
+#define SPAPR_CAP_WORKAROUND 0x01
+#define SPAPR_CAP_FIXED 0x02
+/* SPAPR_CAP_IBS (cap-ibs) */
+#define SPAPR_CAP_FIXED_IBS 0x02
+#define SPAPR_CAP_FIXED_CCD 0x03
+#define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */
+
+#define FDT_MAX_SIZE 0x200000
+
+/* Max number of GPUs per system */
+#define NVGPU_MAX_NUM 6
+
+/* Max number of NUMA nodes */
+#define NUMA_NODES_MAX_NUM (MAX_NODES + NVGPU_MAX_NUM)
+
+/*
+ * NUMA FORM1 macros. FORM1_DIST_REF_POINTS was taken from
+ * MAX_DISTANCE_REF_POINTS in arch/powerpc/mm/numa.h from Linux
+ * kernel source. It represents the amount of associativity domains
+ * for non-CPU resources.
+ *
+ * FORM1_NUMA_ASSOC_SIZE is the base array size of an ibm,associativity
+ * array for any non-CPU resource.
+ */
+#define FORM1_DIST_REF_POINTS 4
+#define FORM1_NUMA_ASSOC_SIZE (FORM1_DIST_REF_POINTS + 1)
+
+/*
+ * FORM2 NUMA affinity has a single associativity domain, giving
+ * us a assoc size of 2.
+ */
+#define FORM2_DIST_REF_POINTS 1
+#define FORM2_NUMA_ASSOC_SIZE (FORM2_DIST_REF_POINTS + 1)
+
+typedef struct SpaprCapabilities SpaprCapabilities;
+struct SpaprCapabilities {
+ uint8_t caps[SPAPR_CAP_NUM];
+};
+
+/**
+ * SpaprMachineClass:
+ */
+struct SpaprMachineClass {
+ /*< private >*/
+ MachineClass parent_class;
+
+ /*< public >*/
+ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
+ bool dr_phb_enabled; /* enable dynamic-reconfig/hotplug of PHBs */
+ bool update_dt_enabled; /* enable KVMPPC_H_UPDATE_DT */
+ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
+ bool pre_2_10_has_unused_icps;
+ bool legacy_irq_allocation;
+ uint32_t nr_xirqs;
+ bool broken_host_serial_model; /* present real host info to the guest */
+ bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
+ bool linux_pci_probe;
+ bool smp_threads_vsmt; /* set VSMT to smp_threads by default */
+ hwaddr rma_limit; /* clamp the RMA to this size */
+ bool pre_5_1_assoc_refpoints;
+ bool pre_5_2_numa_associativity;
+ bool pre_6_2_numa_affinity;
+
+ bool (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
+ uint64_t *buid, hwaddr *pio,
+ hwaddr *mmio32, hwaddr *mmio64,
+ unsigned n_dma, uint32_t *liobns, hwaddr *nv2gpa,
+ hwaddr *nv2atsd, Error **errp);
+ SpaprResizeHpt resize_hpt_default;
+ SpaprCapabilities default_caps;
+ SpaprIrq *irq;
+};
+
+/**
+ * SpaprMachineState:
+ */
+struct SpaprMachineState {
+ /*< private >*/
+ MachineState parent_obj;
+
+ struct SpaprVioBus *vio_bus;
+ QLIST_HEAD(, SpaprPhbState) phbs;
+ struct SpaprNvram *nvram;
+ SpaprRtcState rtc;
+
+ SpaprResizeHpt resize_hpt;
+ void *htab;
+ uint32_t htab_shift;
+ uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROC_TBL */
+ SpaprPendingHpt *pending_hpt; /* in-progress resize */
+
+ hwaddr rma_size;
+ uint32_t fdt_size;
+ uint32_t fdt_initial_size;
+ void *fdt_blob;
+ long kernel_size;
+ bool kernel_le;
+ uint64_t kernel_addr;
+ uint32_t initrd_base;
+ long initrd_size;
+ Vof *vof;
+ uint64_t rtc_offset; /* Now used only during incoming migration */
+ struct PPCTimebase tb;
+ bool has_graphics;
+ uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */
+
+ Notifier epow_notifier;
+ QTAILQ_HEAD(, SpaprEventLogEntry) pending_events;
+ bool use_hotplug_event_source;
+ SpaprEventSource *event_sources;
+
+ /* ibm,client-architecture-support option negotiation */
+ bool cas_pre_isa3_guest;
+ SpaprOptionVector *ov5; /* QEMU-supported option vectors */
+ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */
+ uint32_t max_compat_pvr;
+
+ /* Migration state */
+ int htab_save_index;
+ bool htab_first_pass;
+ int htab_fd;
+
+ /* Pending DIMM unplug cache. It is populated when a LMB
+ * unplug starts. It can be regenerated if a migration
+ * occurs during the unplug process. */
+ QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs;
+
+ /* State related to FWNMI option */
+
+ /* System Reset and Machine Check Notification Routine addresses
+ * registered by "ibm,nmi-register" RTAS call.
+ */
+ target_ulong fwnmi_system_reset_addr;
+ target_ulong fwnmi_machine_check_addr;
+
+ /* Machine Check FWNMI synchronization, fwnmi_machine_check_interlock is
+ * set to -1 if a FWNMI machine check is not in progress, else is set to
+ * the CPU that was delivered the machine check, and is set back to -1
+ * when that CPU makes an "ibm,nmi-interlock" RTAS call. The cond is used
+ * to synchronize other CPUs.
+ */
+ int fwnmi_machine_check_interlock;
+ QemuCond fwnmi_machine_check_interlock_cond;
+
+ /* Set by -boot */
+ char *boot_device;
+
+ /*< public >*/
+ char *kvm_type;
+ char *host_model;
+ char *host_serial;
+
+ int32_t irq_map_nr;
+ unsigned long *irq_map;
+ SpaprIrq *irq;
+ qemu_irq *qirqs;
+ SpaprInterruptController *active_intc;
+ ICSState *ics;
+ SpaprXive *xive;
+
+ bool cmd_line_caps[SPAPR_CAP_NUM];
+ SpaprCapabilities def, eff, mig;
+
+ unsigned gpu_numa_id;
+ SpaprTpmProxy *tpm_proxy;
+
+ uint32_t FORM1_assoc_array[NUMA_NODES_MAX_NUM][FORM1_NUMA_ASSOC_SIZE];
+ uint32_t FORM2_assoc_array[NUMA_NODES_MAX_NUM][FORM2_NUMA_ASSOC_SIZE];
+
+ Error *fwnmi_migration_blocker;
+};
+
+#define H_SUCCESS 0
+#define H_BUSY 1 /* Hardware busy -- retry later */
+#define H_CLOSED 2 /* Resource closed */
+#define H_NOT_AVAILABLE 3
+#define H_CONSTRAINED 4 /* Resource request constrained to max allowed */
+#define H_PARTIAL 5
+#define H_IN_PROGRESS 14 /* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE 16
+#define H_PENDING 17 /* returned from H_POLL_PENDING */
+#define H_CONTINUE 18 /* Returned from H_Join on success */
+#define H_LONG_BUSY_START_RANGE 9900 /* Start of long busy range */
+#define H_LONG_BUSY_ORDER_1_MSEC 9900 /* Long busy, hint that 1msec \
+ is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_MSEC 9901 /* Long busy, hint that 10msec \
+ is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_MSEC 9902 /* Long busy, hint that 100msec \
+ is a good time to retry */
+#define H_LONG_BUSY_ORDER_1_SEC 9903 /* Long busy, hint that 1sec \
+ is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_SEC 9904 /* Long busy, hint that 10sec \
+ is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_SEC 9905 /* Long busy, hint that 100sec \
+ is a good time to retry */
+#define H_LONG_BUSY_END_RANGE 9905 /* End of long busy range */
+#define H_HARDWARE -1 /* Hardware error */
+#define H_FUNCTION -2 /* Function not supported */
+#define H_PRIVILEGE -3 /* Caller not privileged */
+#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */
+#define H_BAD_MODE -5 /* Illegal msr value */
+#define H_PTEG_FULL -6 /* PTEG is full */
+#define H_NOT_FOUND -7 /* PTE was not found" */
+#define H_RESERVED_DABR -8 /* DABR address is reserved by the hypervisor on this processor" */
+#define H_NO_MEM -9
+#define H_AUTHORITY -10
+#define H_PERMISSION -11
+#define H_DROPPED -12
+#define H_SOURCE_PARM -13
+#define H_DEST_PARM -14
+#define H_REMOTE_PARM -15
+#define H_RESOURCE -16
+#define H_ADAPTER_PARM -17
+#define H_RH_PARM -18
+#define H_RCQ_PARM -19
+#define H_SCQ_PARM -20
+#define H_EQ_PARM -21
+#define H_RT_PARM -22
+#define H_ST_PARM -23
+#define H_SIGT_PARM -24
+#define H_TOKEN_PARM -25
+#define H_MLENGTH_PARM -27
+#define H_MEM_PARM -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM -30
+#define H_PORT_PARM -31
+#define H_MCG_PARM -32
+#define H_VL_PARM -33
+#define H_TSIZE_PARM -34
+#define H_TRACE_PARM -35
+
+#define H_MASK_PARM -37
+#define H_MCG_FULL -38
+#define H_ALIAS_EXIST -39
+#define H_P_COUNTER -40
+#define H_TABLE_FULL -41
+#define H_ALT_TABLE -42
+#define H_MR_CONDITION -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE -45
+#define H_RESCINDEND -46
+#define H_P2 -55
+#define H_P3 -56
+#define H_P4 -57
+#define H_P5 -58
+#define H_P6 -59
+#define H_P7 -60
+#define H_P8 -61
+#define H_P9 -62
+#define H_OVERLAP -68
+#define H_UNSUPPORTED_FLAG -256
+#define H_MULTI_THREADS_ACTIVE -9005
+
+
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later. This prevents calls blocking in the
+ * firmware for long periods of time. Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying. If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_IS_LONG_BUSY(x) ((x >= H_LONG_BUSY_START_RANGE) \
+ && (x <= H_LONG_BUSY_END_RANGE))
+
+/* Flags */
+#define H_LARGE_PAGE (1ULL<<(63-16))
+#define H_EXACT (1ULL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE (1ULL<<(63-25)) /* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4 (1ULL<<(63-26)) /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
+#define H_PAGE_UNUSED ((1ULL<<(63-29)) | (1ULL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
+#define H_AVPN (1ULL<<(63-32)) /* An avpn is provided as a sanity test */
+#define H_ANDCOND (1ULL<<(63-33))
+#define H_ICACHE_INVALIDATE (1ULL<<(63-40)) /* icbi, etc. (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE (1ULL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE (1ULL<<(63-49))
+#define H_N (1ULL<<(63-61))
+#define H_PP1 (1ULL<<(63-62))
+#define H_PP2 (1ULL<<(63-63))
+
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_CIABR 1
+#define H_SET_MODE_RESOURCE_SET_DAWR0 2
+#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
+#define H_SET_MODE_RESOURCE_LE 4
+
+/* Flags for H_SET_MODE_RESOURCE_LE */
+#define H_SET_MODE_ENDIAN_BIG 0
+#define H_SET_MODE_ENDIAN_LITTLE 1
+
+/* VASI States */
+#define H_VASI_INVALID 0
+#define H_VASI_ENABLED 1
+#define H_VASI_ABORTED 2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED 4
+#define H_VASI_RESUMED 5
+#define H_VASI_COMPLETED 6
+
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
+#define H_DABRX_KERNEL (1ULL<<(63-62))
+#define H_DABRX_USER (1ULL<<(63-63))
+
+/* Values for KVM_PPC_GET_CPU_CHAR & H_GET_CPU_CHARACTERISTICS */
+#define H_CPU_CHAR_SPEC_BAR_ORI31 PPC_BIT(0)
+#define H_CPU_CHAR_BCCTRL_SERIALISED PPC_BIT(1)
+#define H_CPU_CHAR_L1D_FLUSH_ORI30 PPC_BIT(2)
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2 PPC_BIT(3)
+#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4)
+#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
+#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
+#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7)
+#define H_CPU_CHAR_BCCTR_FLUSH_ASSIST PPC_BIT(9)
+
+#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
+#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)
+#define H_CPU_BEHAV_FLUSH_COUNT_CACHE PPC_BIT(5)
+#define H_CPU_BEHAV_NO_L1D_FLUSH_ENTRY PPC_BIT(7)
+#define H_CPU_BEHAV_NO_L1D_FLUSH_UACCESS PPC_BIT(8)
+
+/* Each control block has to be on a 4K boundary */
+#define H_CB_ALIGNMENT 4096
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE 0x04
+#define H_ENTER 0x08
+#define H_READ 0x0c
+#define H_CLEAR_MOD 0x10
+#define H_CLEAR_REF 0x14
+#define H_PROTECT 0x18
+#define H_GET_TCE 0x1c
+#define H_PUT_TCE 0x20
+#define H_SET_SPRG0 0x24
+#define H_SET_DABR 0x28
+#define H_PAGE_INIT 0x2c
+#define H_SET_ASR 0x30
+#define H_ASR_ON 0x34
+#define H_ASR_OFF 0x38
+#define H_LOGICAL_CI_LOAD 0x3c
+#define H_LOGICAL_CI_STORE 0x40
+#define H_LOGICAL_CACHE_LOAD 0x44
+#define H_LOGICAL_CACHE_STORE 0x48
+#define H_LOGICAL_ICBI 0x4c
+#define H_LOGICAL_DCBF 0x50
+#define H_GET_TERM_CHAR 0x54
+#define H_PUT_TERM_CHAR 0x58
+#define H_REAL_TO_LOGICAL 0x5c
+#define H_HYPERVISOR_DATA 0x60
+#define H_EOI 0x64
+#define H_CPPR 0x68
+#define H_IPI 0x6c
+#define H_IPOLL 0x70
+#define H_XIRR 0x74
+#define H_PERFMON 0x7c
+#define H_MIGRATE_DMA 0x78
+#define H_REGISTER_VPA 0xDC
+#define H_CEDE 0xE0
+#define H_CONFER 0xE4
+#define H_PROD 0xE8
+#define H_GET_PPP 0xEC
+#define H_SET_PPP 0xF0
+#define H_PURR 0xF4
+#define H_PIC 0xF8
+#define H_REG_CRQ 0xFC
+#define H_FREE_CRQ 0x100
+#define H_VIO_SIGNAL 0x104
+#define H_SEND_CRQ 0x108
+#define H_COPY_RDMA 0x110
+#define H_REGISTER_LOGICAL_LAN 0x114
+#define H_FREE_LOGICAL_LAN 0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN 0x120
+#define H_BULK_REMOVE 0x124
+#define H_MULTICAST_CTRL 0x130
+#define H_SET_XDABR 0x134
+#define H_STUFF_TCE 0x138
+#define H_PUT_TCE_INDIRECT 0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+#define H_VTERM_PARTNER_INFO 0x150
+#define H_REGISTER_VTERM 0x154
+#define H_FREE_VTERM 0x158
+#define H_RESET_EVENTS 0x15C
+#define H_ALLOC_RESOURCE 0x160
+#define H_FREE_RESOURCE 0x164
+#define H_MODIFY_QP 0x168
+#define H_QUERY_QP 0x16C
+#define H_REREGISTER_PMR 0x170
+#define H_REGISTER_SMR 0x174
+#define H_QUERY_MR 0x178
+#define H_QUERY_MW 0x17C
+#define H_QUERY_HCA 0x180
+#define H_QUERY_PORT 0x184
+#define H_MODIFY_PORT 0x188
+#define H_DEFINE_AQP1 0x18C
+#define H_GET_TRACE_BUFFER 0x190
+#define H_DEFINE_AQP0 0x194
+#define H_RESIZE_MR 0x198
+#define H_ATTACH_MCQP 0x19C
+#define H_DETACH_MCQP 0x1A0
+#define H_CREATE_RPT 0x1A4
+#define H_REMOVE_RPT 0x1A8
+#define H_REGISTER_RPAGES 0x1AC
+#define H_DISABLE_AND_GETC 0x1B0
+#define H_ERROR_DATA 0x1B4
+#define H_GET_HCA_INFO 0x1B8
+#define H_GET_PERF_COUNT 0x1BC
+#define H_MANAGE_TRACE 0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+#define H_QUERY_INT_STATE 0x1E4
+#define H_POLL_PENDING 0x1D8
+#define H_ILLAN_ATTRIBUTES 0x244
+#define H_MODIFY_HEA_QP 0x250
+#define H_QUERY_HEA_QP 0x254
+#define H_QUERY_HEA 0x258
+#define H_QUERY_HEA_PORT 0x25C
+#define H_MODIFY_HEA_PORT 0x260
+#define H_REG_BCMC 0x264
+#define H_DEREG_BCMC 0x268
+#define H_REGISTER_HEA_RPAGES 0x26C
+#define H_DISABLE_AND_GET_HEA 0x270
+#define H_GET_HEA_INFO 0x274
+#define H_ALLOC_HEA_RESOURCE 0x278
+#define H_ADD_CONN 0x284
+#define H_DEL_CONN 0x288
+#define H_JOIN 0x298
+#define H_VASI_STATE 0x2A4
+#define H_ENABLE_CRQ 0x2B0
+#define H_GET_EM_PARMS 0x2B8
+#define H_SET_MPP 0x2D0
+#define H_GET_MPP 0x2D4
+#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
+#define H_XIRR_X 0x2FC
+#define H_RANDOM 0x300
+#define H_SET_MODE 0x31C
+#define H_RESIZE_HPT_PREPARE 0x36C
+#define H_RESIZE_HPT_COMMIT 0x370
+#define H_CLEAN_SLB 0x374
+#define H_INVALIDATE_PID 0x378
+#define H_REGISTER_PROC_TBL 0x37C
+#define H_SIGNAL_SYS_RESET 0x380
+
+#define H_INT_GET_SOURCE_INFO 0x3A8
+#define H_INT_SET_SOURCE_CONFIG 0x3AC
+#define H_INT_GET_SOURCE_CONFIG 0x3B0
+#define H_INT_GET_QUEUE_INFO 0x3B4
+#define H_INT_SET_QUEUE_CONFIG 0x3B8
+#define H_INT_GET_QUEUE_CONFIG 0x3BC
+#define H_INT_SET_OS_REPORTING_LINE 0x3C0
+#define H_INT_GET_OS_REPORTING_LINE 0x3C4
+#define H_INT_ESB 0x3C8
+#define H_INT_SYNC 0x3CC
+#define H_INT_RESET 0x3D0
+#define H_SCM_READ_METADATA 0x3E4
+#define H_SCM_WRITE_METADATA 0x3E8
+#define H_SCM_BIND_MEM 0x3EC
+#define H_SCM_UNBIND_MEM 0x3F0
+#define H_SCM_UNBIND_ALL 0x3FC
+#define H_SCM_HEALTH 0x400
+#define H_RPT_INVALIDATE 0x448
+
+#define MAX_HCALL_OPCODE H_RPT_INVALIDATE
+
+/* The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * We put those into the 0xf000-0xfffc range which is reserved by PAPR
+ * for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE 0xf000
+#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
+/* Client Architecture support */
+#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2)
+#define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3)
+/* 0x4 was used for KVMPPC_H_UPDATE_PHANDLE in SLOF */
+#define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5)
+#define KVMPPC_HCALL_MAX KVMPPC_H_VOF_CLIENT
+
+/*
+ * 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;
+
+#define hcall_dprintf(fmt, ...) \
+ do { \
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt, __func__, ## __VA_ARGS__); \
+ } while (0)
+
+typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
+ target_ulong opcode,
+ target_ulong *args);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
+ target_ulong *args);
+target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong shift);
+target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong flags, target_ulong shift);
+bool is_ram_address(SpaprMachineState *spapr, hwaddr addr);
+void push_sregs_to_kvm_pr(SpaprMachineState *spapr);
+
+/* 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
+#define RTAS_EEH_THAW_IO 2
+#define RTAS_EEH_THAW_DMA 3
+
+/* ibm,get-config-addr-info2 */
+#define RTAS_GET_PE_ADDR 0
+#define RTAS_GET_PE_MODE 1
+#define RTAS_PE_MODE_NONE 0
+#define RTAS_PE_MODE_NOT_SHARED 1
+#define RTAS_PE_MODE_SHARED 2
+
+/* ibm,read-slot-reset-state2 */
+#define RTAS_EEH_PE_STATE_NORMAL 0
+#define RTAS_EEH_PE_STATE_RESET 1
+#define RTAS_EEH_PE_STATE_STOPPED_IO_DMA 2
+#define RTAS_EEH_PE_STATE_STOPPED_DMA 4
+#define RTAS_EEH_PE_STATE_UNAVAIL 5
+#define RTAS_EEH_NOT_SUPPORT 0
+#define RTAS_EEH_SUPPORT 1
+#define RTAS_EEH_PE_UNAVAIL_INFO 1000
+#define RTAS_EEH_PE_RECOVER_INFO 0
+
+/* ibm,set-slot-reset */
+#define RTAS_SLOT_RESET_DEACTIVATE 0
+#define RTAS_SLOT_RESET_HOT 1
+#define RTAS_SLOT_RESET_FUNDAMENTAL 3
+
+/* ibm,slot-error-detail */
+#define RTAS_SLOT_TEMP_ERR_LOG 1
+#define RTAS_SLOT_PERM_ERR_LOG 2
+
+/* RTAS return codes */
+#define RTAS_OUT_SUCCESS 0
+#define RTAS_OUT_NO_ERRORS_FOUND 1
+#define RTAS_OUT_HW_ERROR -1
+#define RTAS_OUT_BUSY -2
+#define RTAS_OUT_PARAM_ERROR -3
+#define RTAS_OUT_NOT_SUPPORTED -3
+#define RTAS_OUT_NO_SUCH_INDICATOR -3
+#define RTAS_OUT_NOT_AUTHORIZED -9002
+#define RTAS_OUT_SYSPARM_PARAM_ERROR -9999
+
+/* DDW pagesize mask values from ibm,query-pe-dma-window */
+#define RTAS_DDW_PGSIZE_4K 0x01
+#define RTAS_DDW_PGSIZE_64K 0x02
+#define RTAS_DDW_PGSIZE_16M 0x04
+#define RTAS_DDW_PGSIZE_32M 0x08
+#define RTAS_DDW_PGSIZE_64M 0x10
+#define RTAS_DDW_PGSIZE_128M 0x20
+#define RTAS_DDW_PGSIZE_256M 0x40
+#define RTAS_DDW_PGSIZE_16G 0x80
+
+/* RTAS tokens */
+#define RTAS_TOKEN_BASE 0x2000
+
+#define RTAS_DISPLAY_CHARACTER (RTAS_TOKEN_BASE + 0x00)
+#define RTAS_GET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x01)
+#define RTAS_SET_TIME_OF_DAY (RTAS_TOKEN_BASE + 0x02)
+#define RTAS_POWER_OFF (RTAS_TOKEN_BASE + 0x03)
+#define RTAS_SYSTEM_REBOOT (RTAS_TOKEN_BASE + 0x04)
+#define RTAS_QUERY_CPU_STOPPED_STATE (RTAS_TOKEN_BASE + 0x05)
+#define RTAS_START_CPU (RTAS_TOKEN_BASE + 0x06)
+#define RTAS_STOP_SELF (RTAS_TOKEN_BASE + 0x07)
+#define RTAS_IBM_GET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x08)
+#define RTAS_IBM_SET_SYSTEM_PARAMETER (RTAS_TOKEN_BASE + 0x09)
+#define RTAS_IBM_SET_XIVE (RTAS_TOKEN_BASE + 0x0A)
+#define RTAS_IBM_GET_XIVE (RTAS_TOKEN_BASE + 0x0B)
+#define RTAS_IBM_INT_OFF (RTAS_TOKEN_BASE + 0x0C)
+#define RTAS_IBM_INT_ON (RTAS_TOKEN_BASE + 0x0D)
+#define RTAS_CHECK_EXCEPTION (RTAS_TOKEN_BASE + 0x0E)
+#define RTAS_EVENT_SCAN (RTAS_TOKEN_BASE + 0x0F)
+#define RTAS_IBM_SET_TCE_BYPASS (RTAS_TOKEN_BASE + 0x10)
+#define RTAS_QUIESCE (RTAS_TOKEN_BASE + 0x11)
+#define RTAS_NVRAM_FETCH (RTAS_TOKEN_BASE + 0x12)
+#define RTAS_NVRAM_STORE (RTAS_TOKEN_BASE + 0x13)
+#define RTAS_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x14)
+#define RTAS_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x15)
+#define RTAS_IBM_READ_PCI_CONFIG (RTAS_TOKEN_BASE + 0x16)
+#define RTAS_IBM_WRITE_PCI_CONFIG (RTAS_TOKEN_BASE + 0x17)
+#define RTAS_IBM_QUERY_INTERRUPT_SOURCE_NUMBER (RTAS_TOKEN_BASE + 0x18)
+#define RTAS_IBM_CHANGE_MSI (RTAS_TOKEN_BASE + 0x19)
+#define RTAS_SET_INDICATOR (RTAS_TOKEN_BASE + 0x1A)
+#define RTAS_SET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1B)
+#define RTAS_GET_POWER_LEVEL (RTAS_TOKEN_BASE + 0x1C)
+#define RTAS_GET_SENSOR_STATE (RTAS_TOKEN_BASE + 0x1D)
+#define RTAS_IBM_CONFIGURE_CONNECTOR (RTAS_TOKEN_BASE + 0x1E)
+#define RTAS_IBM_OS_TERM (RTAS_TOKEN_BASE + 0x1F)
+#define RTAS_IBM_SET_EEH_OPTION (RTAS_TOKEN_BASE + 0x20)
+#define RTAS_IBM_GET_CONFIG_ADDR_INFO2 (RTAS_TOKEN_BASE + 0x21)
+#define RTAS_IBM_READ_SLOT_RESET_STATE2 (RTAS_TOKEN_BASE + 0x22)
+#define RTAS_IBM_SET_SLOT_RESET (RTAS_TOKEN_BASE + 0x23)
+#define RTAS_IBM_CONFIGURE_PE (RTAS_TOKEN_BASE + 0x24)
+#define RTAS_IBM_SLOT_ERROR_DETAIL (RTAS_TOKEN_BASE + 0x25)
+#define RTAS_IBM_QUERY_PE_DMA_WINDOW (RTAS_TOKEN_BASE + 0x26)
+#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_IBM_NMI_REGISTER (RTAS_TOKEN_BASE + 0x2B)
+#define RTAS_IBM_NMI_INTERLOCK (RTAS_TOKEN_BASE + 0x2C)
+
+#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x2D)
+
+/* RTAS ibm,get-system-parameter token values */
+#define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20
+#define RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE 42
+#define RTAS_SYSPARM_UUID 48
+
+/* RTAS indicator/sensor types
+ *
+ * as defined by PAPR+ 2.7 7.3.5.4, Table 41
+ *
+ * NOTE: currently only DR-related sensors are implemented here
+ */
+#define RTAS_SENSOR_TYPE_ISOLATION_STATE 9001
+#define RTAS_SENSOR_TYPE_DR 9002
+#define RTAS_SENSOR_TYPE_ALLOCATION_STATE 9003
+#define RTAS_SENSOR_TYPE_ENTITY_SENSE RTAS_SENSOR_TYPE_ALLOCATION_STATE
+
+/* Possible values for the platform-processor-diagnostics-run-mode parameter
+ * of the RTAS ibm,get-system-parameter call.
+ */
+#define DIAGNOSTICS_RUN_MODE_DISABLED 0
+#define DIAGNOSTICS_RUN_MODE_STAGGERED 1
+#define DIAGNOSTICS_RUN_MODE_IMMEDIATE 2
+#define DIAGNOSTICS_RUN_MODE_PERIODIC 3
+
+static inline uint64_t ppc64_phys_to_real(uint64_t addr)
+{
+ return addr & ~0xF000000000000000ULL;
+}
+
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+ return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n));
+}
+
+static inline uint64_t rtas_ldq(target_ulong phys, int n)
+{
+ return (uint64_t)rtas_ld(phys, n) << 32 | rtas_ld(phys, n + 1);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+ stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
+}
+
+typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
+ uint32_t token,
+ uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets);
+void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(PowerPCCPU *cpu, SpaprMachineState *sm,
+ uint32_t token, uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets);
+void spapr_dt_rtas_tokens(void *fdt, int rtas);
+void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr);
+
+#define SPAPR_TCE_PAGE_SHIFT 12
+#define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT)
+#define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1)
+
+#define SPAPR_VIO_BASE_LIOBN 0x00000000
+#define SPAPR_VIO_LIOBN(reg) (0x00000000 | (reg))
+#define SPAPR_PCI_LIOBN(phb_index, window_num) \
+ (0x80000000 | ((phb_index) << 8) | (window_num))
+#define SPAPR_IS_PCI_LIOBN(liobn) (!!((liobn) & 0x80000000))
+#define SPAPR_PCI_DMA_WINDOW_NUM(liobn) ((liobn) & 0xff)
+
+#define RTAS_MIN_SIZE 20 /* hv_rtas_size in SLOF */
+#define RTAS_ERROR_LOG_MAX 2048
+
+/* Offset from rtas-base where error log is placed */
+#define RTAS_ERROR_LOG_OFFSET 0x30
+
+#define RTAS_EVENT_SCAN_RATE 1
+
+/* This helper should be used to encode interrupt specifiers when the related
+ * "interrupt-controller" node has its "#interrupt-cells" property set to 2 (ie,
+ * VIO devices, RTAS event sources and PHBs).
+ */
+static inline void spapr_dt_irq(uint32_t *intspec, int irq, bool is_lsi)
+{
+ intspec[0] = cpu_to_be32(irq);
+ intspec[1] = is_lsi ? cpu_to_be32(1) : 0;
+}
+
+
+#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table"
+OBJECT_DECLARE_SIMPLE_TYPE(SpaprTceTable, SPAPR_TCE_TABLE)
+
+#define TYPE_SPAPR_IOMMU_MEMORY_REGION "spapr-iommu-memory-region"
+DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, SPAPR_IOMMU_MEMORY_REGION,
+ TYPE_SPAPR_IOMMU_MEMORY_REGION)
+
+struct SpaprTceTable {
+ DeviceState parent;
+ uint32_t liobn;
+ uint32_t nb_table;
+ uint64_t bus_offset;
+ uint32_t page_shift;
+ uint64_t *table;
+ uint32_t mig_nb_table;
+ uint64_t *mig_table;
+ bool bypass;
+ bool need_vfio;
+ bool skipping_replay;
+ int fd;
+ MemoryRegion root;
+ IOMMUMemoryRegion iommu;
+ struct SpaprVioDevice *vdev; /* for @bypass migration compatibility only */
+ QLIST_ENTRY(SpaprTceTable) list;
+};
+
+SpaprTceTable *spapr_tce_find_by_liobn(target_ulong liobn);
+
+struct SpaprEventLogEntry {
+ uint32_t summary;
+ uint32_t extended_length;
+ void *extended_log;
+ QTAILQ_ENTRY(SpaprEventLogEntry) next;
+};
+
+void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space);
+void spapr_events_init(SpaprMachineState *sm);
+void spapr_dt_events(SpaprMachineState *sm, void *fdt);
+void close_htab_fd(SpaprMachineState *spapr);
+void spapr_setup_hpt(SpaprMachineState *spapr);
+void spapr_free_hpt(SpaprMachineState *spapr);
+void spapr_check_mmu_mode(bool guest_radix);
+SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
+void spapr_tce_table_enable(SpaprTceTable *tcet,
+ uint32_t page_shift, uint64_t bus_offset,
+ uint32_t nb_table);
+void spapr_tce_table_disable(SpaprTceTable *tcet);
+void spapr_tce_set_need_vfio(SpaprTceTable *tcet, bool need_vfio);
+
+MemoryRegion *spapr_tce_get_iommu(SpaprTceTable *tcet);
+int spapr_dma_dt(void *fdt, int node_off, const char *propname,
+ uint32_t liobn, uint64_t window, uint32_t size);
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+ SpaprTceTable *tcet);
+void spapr_pci_switch_vga(SpaprMachineState *spapr, bool big_endian);
+void spapr_hotplug_req_add_by_index(SpaprDrc *drc);
+void spapr_hotplug_req_remove_by_index(SpaprDrc *drc);
+void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,
+ uint32_t count);
+void spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type,
+ uint32_t count);
+void spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type,
+ uint32_t count, uint32_t index);
+void spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type,
+ uint32_t count, uint32_t index);
+int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
+int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp);
+void spapr_clear_pending_events(SpaprMachineState *spapr);
+void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr);
+void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev);
+int spapr_max_server_number(SpaprMachineState *spapr);
+void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1);
+void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered);
+
+/* DRC callbacks. */
+void spapr_core_release(DeviceState *dev);
+int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
+ void *fdt, int *fdt_start_offset, Error **errp);
+void spapr_lmb_release(DeviceState *dev);
+int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
+ void *fdt, int *fdt_start_offset, Error **errp);
+void spapr_phb_release(DeviceState *dev);
+int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
+ void *fdt, int *fdt_start_offset, Error **errp);
+
+void spapr_rtc_read(SpaprRtcState *rtc, struct tm *tm, uint32_t *ns);
+int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset);
+
+#define TYPE_SPAPR_RNG "spapr-rng"
+
+#define SPAPR_MEMORY_BLOCK_SIZE ((hwaddr)1 << 28) /* 256MB */
+
+/*
+ * This defines the maximum number of DIMM slots we can have for sPAPR
+ * guest. This is not defined by sPAPR but we are defining it to 32 slots
+ * based on default number of slots provided by PowerPC kernel.
+ */
+#define SPAPR_MAX_RAM_SLOTS 32
+
+/* 1GB alignment for hotplug memory region */
+#define SPAPR_DEVICE_MEM_ALIGN (1 * GiB)
+
+/*
+ * Number of 32 bit words in each LMB list entry in ibm,dynamic-memory
+ * property under ibm,dynamic-reconfiguration-memory node.
+ */
+#define SPAPR_DR_LMB_LIST_ENTRY_SIZE 6
+
+/*
+ * Defines for flag value in ibm,dynamic-memory property under
+ * ibm,dynamic-reconfiguration-memory node.
+ */
+#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008
+#define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
+#define SPAPR_LMB_FLAGS_RESERVED 0x00000080
+#define SPAPR_LMB_FLAGS_HOTREMOVABLE 0x00000100
+
+void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
+
+#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
+
+int spapr_get_vcpu_id(PowerPCCPU *cpu);
+bool spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp);
+PowerPCCPU *spapr_find_cpu(int vcpu_id);
+
+int spapr_caps_pre_load(void *opaque);
+int spapr_caps_pre_save(void *opaque);
+
+/*
+ * Handling of optional capabilities
+ */
+extern const VMStateDescription vmstate_spapr_cap_htm;
+extern const VMStateDescription vmstate_spapr_cap_vsx;
+extern const VMStateDescription vmstate_spapr_cap_dfp;
+extern const VMStateDescription vmstate_spapr_cap_cfpc;
+extern const VMStateDescription vmstate_spapr_cap_sbbc;
+extern const VMStateDescription vmstate_spapr_cap_ibs;
+extern const VMStateDescription vmstate_spapr_cap_hpt_maxpagesize;
+extern const VMStateDescription vmstate_spapr_cap_nested_kvm_hv;
+extern const VMStateDescription vmstate_spapr_cap_large_decr;
+extern const VMStateDescription vmstate_spapr_cap_ccf_assist;
+extern const VMStateDescription vmstate_spapr_cap_fwnmi;
+extern const VMStateDescription vmstate_spapr_cap_rpt_invalidate;
+
+static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap)
+{
+ return spapr->eff.caps[cap];
+}
+
+void spapr_caps_init(SpaprMachineState *spapr);
+void spapr_caps_apply(SpaprMachineState *spapr);
+void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu);
+void spapr_caps_add_properties(SpaprMachineClass *smc);
+int spapr_caps_post_migration(SpaprMachineState *spapr);
+
+bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize,
+ Error **errp);
+/*
+ * XIVE definitions
+ */
+#define SPAPR_OV5_XIVE_LEGACY 0x0
+#define SPAPR_OV5_XIVE_EXPLOIT 0x40
+#define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */
+
+void spapr_set_all_lpcrs(target_ulong value, target_ulong mask);
+hwaddr spapr_get_rtas_addr(void);
+bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr);
+
+void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp);
+void spapr_vof_quiesce(MachineState *ms);
+bool spapr_vof_setprop(MachineState *ms, const char *path, const char *propname,
+ void *val, int vallen);
+target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args);
+target_ulong spapr_vof_client_architecture_support(MachineState *ms,
+ CPUState *cs,
+ target_ulong ovec_addr);
+void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt);
+
+#endif /* HW_SPAPR_H */
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
new file mode 100644
index 000000000..dab3dfc76
--- /dev/null
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -0,0 +1,58 @@
+/*
+ * sPAPR CPU core device.
+ *
+ * Copyright (C) 2016 Bharata B Rao <bharata@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_CPU_CORE_H
+#define HW_SPAPR_CPU_CORE_H
+
+#include "hw/cpu/core.h"
+#include "hw/qdev-core.h"
+#include "target/ppc/cpu-qom.h"
+#include "target/ppc/cpu.h"
+#include "qom/object.h"
+
+#define TYPE_SPAPR_CPU_CORE "spapr-cpu-core"
+OBJECT_DECLARE_TYPE(SpaprCpuCore, SpaprCpuCoreClass,
+ SPAPR_CPU_CORE)
+
+#define SPAPR_CPU_CORE_TYPE_NAME(model) model "-" TYPE_SPAPR_CPU_CORE
+
+struct SpaprCpuCore {
+ /*< private >*/
+ CPUCore parent_obj;
+
+ /*< public >*/
+ PowerPCCPU **threads;
+ int node_id;
+ bool pre_3_0_migration; /* older machine don't know about SpaprCpuState */
+};
+
+struct SpaprCpuCoreClass {
+ DeviceClass parent_class;
+ const char *cpu_type;
+};
+
+const char *spapr_get_cpu_core_type(const char *cpu_type);
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4);
+
+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;
+
+static inline SpaprCpuState *spapr_cpu_state(PowerPCCPU *cpu)
+{
+ return (SpaprCpuState *)cpu->machine_data;
+}
+
+#endif
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
new file mode 100644
index 000000000..02a63b366
--- /dev/null
+++ b/include/hw/ppc/spapr_drc.h
@@ -0,0 +1,259 @@
+/*
+ * QEMU SPAPR Dynamic Reconfiguration Connector Implementation
+ *
+ * Copyright IBM Corp. 2014
+ *
+ * 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_DRC_H
+#define HW_SPAPR_DRC_H
+
+#include <libfdt.h>
+#include "qom/object.h"
+#include "sysemu/runstate.h"
+#include "hw/qdev-core.h"
+#include "qapi/error.h"
+
+#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector"
+#define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DR_CONNECTOR)
+#define SPAPR_DR_CONNECTOR_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, \
+ TYPE_SPAPR_DR_CONNECTOR)
+#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(SpaprDrc, (obj), \
+ TYPE_SPAPR_DR_CONNECTOR)
+
+#define TYPE_SPAPR_DRC_PHYSICAL "spapr-drc-physical"
+#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(SpaprDrcPhysical, (obj), \
+ TYPE_SPAPR_DRC_PHYSICAL)
+
+#define TYPE_SPAPR_DRC_LOGICAL "spapr-drc-logical"
+
+#define TYPE_SPAPR_DRC_CPU "spapr-drc-cpu"
+
+#define TYPE_SPAPR_DRC_PCI "spapr-drc-pci"
+
+#define TYPE_SPAPR_DRC_LMB "spapr-drc-lmb"
+
+#define TYPE_SPAPR_DRC_PHB "spapr-drc-phb"
+
+#define TYPE_SPAPR_DRC_PMEM "spapr-drc-pmem"
+
+/*
+ * Various hotplug types managed by SpaprDrc
+ *
+ * these are somewhat arbitrary, but to make things easier
+ * when generating DRC indexes later we've aligned the bit
+ * positions with the values used to assign DRC indexes on
+ * pSeries. we use those values as bit shifts to allow for
+ * the OR'ing of these values in various QEMU routines, but
+ * for values exposed to the guest (via DRC indexes for
+ * instance) we will use the shift amounts.
+ */
+typedef enum {
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU = 1,
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB = 2,
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO = 3,
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI = 4,
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB = 8,
+ SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM = 9,
+} SpaprDrcTypeShift;
+
+typedef enum {
+ SPAPR_DR_CONNECTOR_TYPE_ANY = ~0,
+ SPAPR_DR_CONNECTOR_TYPE_CPU = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU,
+ SPAPR_DR_CONNECTOR_TYPE_PHB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB,
+ SPAPR_DR_CONNECTOR_TYPE_VIO = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO,
+ SPAPR_DR_CONNECTOR_TYPE_PCI = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI,
+ SPAPR_DR_CONNECTOR_TYPE_LMB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB,
+ SPAPR_DR_CONNECTOR_TYPE_PMEM = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM,
+} SpaprDrcType;
+
+/*
+ * set via set-indicator RTAS calls
+ * as documented by PAPR+ 2.7 13.5.3.4, Table 177
+ *
+ * isolated: put device under firmware control
+ * unisolated: claim OS control of device (may or may not be in use)
+ */
+typedef enum {
+ SPAPR_DR_ISOLATION_STATE_ISOLATED = 0,
+ SPAPR_DR_ISOLATION_STATE_UNISOLATED = 1
+} SpaprDRIsolationState;
+
+/*
+ * set via set-indicator RTAS calls
+ * as documented by PAPR+ 2.7 13.5.3.4, Table 177
+ *
+ * unusable: mark device as unavailable to OS
+ * usable: mark device as available to OS
+ * exchange: (currently unused)
+ * recover: (currently unused)
+ */
+typedef enum {
+ SPAPR_DR_ALLOCATION_STATE_UNUSABLE = 0,
+ SPAPR_DR_ALLOCATION_STATE_USABLE = 1,
+ SPAPR_DR_ALLOCATION_STATE_EXCHANGE = 2,
+ SPAPR_DR_ALLOCATION_STATE_RECOVER = 3
+} SpaprDRAllocationState;
+
+/*
+ * DR-indicator (LED/visual indicator)
+ *
+ * set via set-indicator RTAS calls
+ * as documented by PAPR+ 2.7 13.5.3.4, Table 177,
+ * and PAPR+ 2.7 13.5.4.1, Table 180
+ *
+ * inactive: hotpluggable entity inactive and safely removable
+ * active: hotpluggable entity in use and not safely removable
+ * identify: (currently unused)
+ * action: (currently unused)
+ */
+typedef enum {
+ SPAPR_DR_INDICATOR_INACTIVE = 0,
+ SPAPR_DR_INDICATOR_ACTIVE = 1,
+ SPAPR_DR_INDICATOR_IDENTIFY = 2,
+ SPAPR_DR_INDICATOR_ACTION = 3,
+} SpaprDRIndicatorState;
+
+/*
+ * returned via get-sensor-state RTAS calls
+ * as documented by PAPR+ 2.7 13.5.3.3, Table 175:
+ *
+ * empty: connector slot empty (e.g. empty hotpluggable PCI slot)
+ * present: connector slot populated and device available to OS
+ * unusable: device not currently available to OS
+ * exchange: (currently unused)
+ * recover: (currently unused)
+ */
+typedef enum {
+ SPAPR_DR_ENTITY_SENSE_EMPTY = 0,
+ SPAPR_DR_ENTITY_SENSE_PRESENT = 1,
+ SPAPR_DR_ENTITY_SENSE_UNUSABLE = 2,
+ SPAPR_DR_ENTITY_SENSE_EXCHANGE = 3,
+ SPAPR_DR_ENTITY_SENSE_RECOVER = 4,
+} SpaprDREntitySense;
+
+typedef enum {
+ SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */
+ SPAPR_DR_CC_RESPONSE_NEXT_CHILD = 2,
+ SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY = 3,
+ SPAPR_DR_CC_RESPONSE_PREV_PARENT = 4,
+ SPAPR_DR_CC_RESPONSE_SUCCESS = 0,
+ SPAPR_DR_CC_RESPONSE_ERROR = -1,
+ SPAPR_DR_CC_RESPONSE_CONTINUE = -2,
+ SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE = -9003,
+} SpaprDRCCResponse;
+
+typedef enum {
+ /*
+ * Values come from Fig. 12 in LoPAPR section 13.4
+ *
+ * These are exposed in the migration stream, so don't change
+ * them.
+ */
+ SPAPR_DRC_STATE_INVALID = 0,
+ SPAPR_DRC_STATE_LOGICAL_UNUSABLE = 1,
+ SPAPR_DRC_STATE_LOGICAL_AVAILABLE = 2,
+ SPAPR_DRC_STATE_LOGICAL_UNISOLATE = 3,
+ SPAPR_DRC_STATE_LOGICAL_CONFIGURED = 4,
+ SPAPR_DRC_STATE_PHYSICAL_AVAILABLE = 5,
+ SPAPR_DRC_STATE_PHYSICAL_POWERON = 6,
+ SPAPR_DRC_STATE_PHYSICAL_UNISOLATE = 7,
+ SPAPR_DRC_STATE_PHYSICAL_CONFIGURED = 8,
+} SpaprDrcState;
+
+typedef struct SpaprDrc {
+ /*< private >*/
+ DeviceState parent;
+
+ uint32_t id;
+ Object *owner;
+
+ uint32_t state;
+
+ /* RTAS ibm,configure-connector state */
+ /* (only valid in UNISOLATE state) */
+ int ccs_offset;
+ int ccs_depth;
+
+ /* device pointer, via link property */
+ DeviceState *dev;
+ bool unplug_requested;
+ void *fdt;
+ int fdt_start_offset;
+} SpaprDrc;
+
+struct SpaprMachineState;
+
+typedef struct SpaprDrcClass {
+ /*< private >*/
+ DeviceClass parent;
+ SpaprDrcState empty_state;
+ SpaprDrcState ready_state;
+
+ /*< public >*/
+ SpaprDrcTypeShift typeshift;
+ const char *typename; /* used in device tree, PAPR 13.5.2.6 & C.6.1 */
+ const char *drc_name_prefix; /* used other places in device tree */
+
+ SpaprDREntitySense (*dr_entity_sense)(SpaprDrc *drc);
+ uint32_t (*isolate)(SpaprDrc *drc);
+ uint32_t (*unisolate)(SpaprDrc *drc);
+ void (*release)(DeviceState *dev);
+
+ int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr,
+ void *fdt, int *fdt_start_offset, Error **errp);
+} SpaprDrcClass;
+
+typedef struct SpaprDrcPhysical {
+ /*< private >*/
+ SpaprDrc parent;
+
+ /* DR-indicator */
+ uint32_t dr_indicator;
+} SpaprDrcPhysical;
+
+static inline bool spapr_drc_hotplugged(DeviceState *dev)
+{
+ return dev->hotplugged && !runstate_check(RUN_STATE_INMIGRATE);
+}
+
+/* Returns true if an unplug request completed */
+bool spapr_drc_reset(SpaprDrc *drc);
+
+uint32_t spapr_drc_index(SpaprDrc *drc);
+SpaprDrcType spapr_drc_type(SpaprDrc *drc);
+
+SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
+ uint32_t id);
+SpaprDrc *spapr_drc_by_index(uint32_t index);
+SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id);
+int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask);
+
+/*
+ * These functions respectively abort if called with a device already
+ * attached or no device attached. In the case of spapr_drc_attach(),
+ * this means that the attachability of the DRC *must* be checked
+ * beforehand (eg. check drc->dev at pre-plug).
+ */
+void spapr_drc_attach(SpaprDrc *drc, DeviceState *d);
+void spapr_drc_unplug_request(SpaprDrc *drc);
+
+/*
+ * Reset all DRCs, causing pending hot-plug/unplug requests to complete.
+ * Safely handles potential DRC removal (eg. PHBs or PCI bridges).
+ */
+void spapr_drc_reset_all(struct SpaprMachineState *spapr);
+
+static inline bool spapr_drc_unplug_requested(SpaprDrc *drc)
+{
+ return drc->unplug_requested;
+}
+
+#endif /* HW_SPAPR_DRC_H */
diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h
new file mode 100644
index 000000000..c22a72c9e
--- /dev/null
+++ b/include/hw/ppc/spapr_irq.h
@@ -0,0 +1,117 @@
+/*
+ * QEMU PowerPC sPAPR IRQ backend definitions
+ *
+ * Copyright (c) 2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef HW_SPAPR_IRQ_H
+#define HW_SPAPR_IRQ_H
+
+#include "target/ppc/cpu-qom.h"
+#include "qom/object.h"
+
+/*
+ * IRQ range offsets per device type
+ */
+#define SPAPR_IRQ_IPI 0x0
+
+#define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */
+#define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000)
+#define SPAPR_IRQ_HOTPLUG (SPAPR_XIRQ_BASE + 0x0001)
+#define SPAPR_IRQ_VIO (SPAPR_XIRQ_BASE + 0x0100) /* 256 VIO devices */
+#define SPAPR_IRQ_PCI_LSI (SPAPR_XIRQ_BASE + 0x0200) /* 32+ PHBs devices */
+
+/* Offset of the dynamic range covered by the bitmap allocator */
+#define SPAPR_IRQ_MSI (SPAPR_XIRQ_BASE + 0x0300)
+
+#define SPAPR_NR_XIRQS 0x1000
+
+struct SpaprMachineState;
+
+typedef struct SpaprInterruptController SpaprInterruptController;
+
+#define TYPE_SPAPR_INTC "spapr-interrupt-controller"
+#define SPAPR_INTC(obj) \
+ INTERFACE_CHECK(SpaprInterruptController, (obj), TYPE_SPAPR_INTC)
+typedef struct SpaprInterruptControllerClass SpaprInterruptControllerClass;
+DECLARE_CLASS_CHECKERS(SpaprInterruptControllerClass, SPAPR_INTC,
+ TYPE_SPAPR_INTC)
+
+struct SpaprInterruptControllerClass {
+ InterfaceClass parent;
+
+ int (*activate)(SpaprInterruptController *intc, uint32_t nr_servers,
+ Error **errp);
+ void (*deactivate)(SpaprInterruptController *intc);
+
+ /*
+ * These methods will typically be called on all intcs, active and
+ * inactive
+ */
+ int (*cpu_intc_create)(SpaprInterruptController *intc,
+ PowerPCCPU *cpu, Error **errp);
+ void (*cpu_intc_reset)(SpaprInterruptController *intc, PowerPCCPU *cpu);
+ void (*cpu_intc_destroy)(SpaprInterruptController *intc, PowerPCCPU *cpu);
+ int (*claim_irq)(SpaprInterruptController *intc, int irq, bool lsi,
+ Error **errp);
+ void (*free_irq)(SpaprInterruptController *intc, int irq);
+
+ /* These methods should only be called on the active intc */
+ void (*set_irq)(SpaprInterruptController *intc, int irq, int val);
+ void (*print_info)(SpaprInterruptController *intc, Monitor *mon);
+ void (*dt)(SpaprInterruptController *intc, uint32_t nr_servers,
+ void *fdt, uint32_t phandle);
+ int (*post_load)(SpaprInterruptController *intc, int version_id);
+};
+
+void spapr_irq_update_active_intc(struct SpaprMachineState *spapr);
+
+int spapr_irq_cpu_intc_create(struct SpaprMachineState *spapr,
+ PowerPCCPU *cpu, Error **errp);
+void spapr_irq_cpu_intc_reset(struct SpaprMachineState *spapr, PowerPCCPU *cpu);
+void spapr_irq_cpu_intc_destroy(struct SpaprMachineState *spapr, PowerPCCPU *cpu);
+void spapr_irq_print_info(struct SpaprMachineState *spapr, Monitor *mon);
+void spapr_irq_dt(struct SpaprMachineState *spapr, uint32_t nr_servers,
+ void *fdt, uint32_t phandle);
+
+uint32_t spapr_irq_nr_msis(struct SpaprMachineState *spapr);
+int spapr_irq_msi_alloc(struct SpaprMachineState *spapr, uint32_t num, bool align,
+ Error **errp);
+void spapr_irq_msi_free(struct SpaprMachineState *spapr, int irq, uint32_t num);
+
+typedef struct SpaprIrq {
+ bool xics;
+ bool xive;
+} SpaprIrq;
+
+extern SpaprIrq spapr_irq_xics;
+extern SpaprIrq spapr_irq_xics_legacy;
+extern SpaprIrq spapr_irq_xive;
+extern SpaprIrq spapr_irq_dual;
+
+void spapr_irq_init(struct SpaprMachineState *spapr, Error **errp);
+int spapr_irq_claim(struct SpaprMachineState *spapr, int irq, bool lsi, Error **errp);
+void spapr_irq_free(struct SpaprMachineState *spapr, int irq, int num);
+qemu_irq spapr_qirq(struct SpaprMachineState *spapr, int irq);
+int spapr_irq_post_load(struct SpaprMachineState *spapr, int version_id);
+void spapr_irq_reset(struct SpaprMachineState *spapr, Error **errp);
+int spapr_irq_get_phandle(struct SpaprMachineState *spapr, void *fdt, Error **errp);
+
+typedef int (*SpaprInterruptControllerInitKvm)(SpaprInterruptController *,
+ uint32_t, Error **);
+
+int spapr_irq_init_kvm(SpaprInterruptControllerInitKvm fn,
+ SpaprInterruptController *intc,
+ uint32_t nr_servers,
+ Error **errp);
+
+/*
+ * XICS legacy routines
+ */
+int spapr_irq_find(struct SpaprMachineState *spapr, int num, bool align, Error **errp);
+#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
+
+#endif
diff --git a/include/hw/ppc/spapr_numa.h b/include/hw/ppc/spapr_numa.h
new file mode 100644
index 000000000..7cb336740
--- /dev/null
+++ b/include/hw/ppc/spapr_numa.h
@@ -0,0 +1,37 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition NUMA associativity handling
+ *
+ * Copyright IBM Corp. 2020
+ *
+ * Authors:
+ * Daniel Henrique Barboza <danielhb413@gmail.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_NUMA_H
+#define HW_SPAPR_NUMA_H
+
+#include "hw/boards.h"
+#include "hw/ppc/spapr.h"
+
+/*
+ * Having both SpaprMachineState and MachineState as arguments
+ * feels odd, but it will spare a MACHINE() call inside the
+ * function. spapr_machine_init() is the only caller for it, and
+ * it has both pointers resolved already.
+ */
+void spapr_numa_associativity_init(SpaprMachineState *spapr,
+ MachineState *machine);
+void spapr_numa_associativity_check(SpaprMachineState *spapr);
+void spapr_numa_write_rtas_dt(SpaprMachineState *spapr, void *fdt, int rtas);
+void spapr_numa_write_associativity_dt(SpaprMachineState *spapr, void *fdt,
+ int offset, int nodeid);
+int spapr_numa_fixup_cpu_dt(SpaprMachineState *spapr, void *fdt,
+ int offset, PowerPCCPU *cpu);
+int spapr_numa_write_assoc_lookup_arrays(SpaprMachineState *spapr, void *fdt,
+ int offset);
+unsigned int spapr_numa_initial_nvgpu_numa_id(MachineState *machine);
+
+#endif /* HW_SPAPR_NUMA_H */
diff --git a/include/hw/ppc/spapr_nvdimm.h b/include/hw/ppc/spapr_nvdimm.h
new file mode 100644
index 000000000..764f999f5
--- /dev/null
+++ b/include/hw/ppc/spapr_nvdimm.h
@@ -0,0 +1,25 @@
+/*
+ * QEMU PowerPC PAPR SCM backend definitions
+ *
+ * Copyright (c) 2020, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef HW_SPAPR_NVDIMM_H
+#define HW_SPAPR_NVDIMM_H
+
+#include "hw/mem/nvdimm.h"
+
+typedef struct SpaprDrc SpaprDrc;
+typedef struct SpaprMachineState SpaprMachineState;
+
+int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
+ void *fdt, int *fdt_start_offset, Error **errp);
+void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt);
+bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
+ uint64_t size, Error **errp);
+void spapr_add_nvdimm(DeviceState *dev, uint64_t slot);
+
+#endif
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
new file mode 100644
index 000000000..c3e8b98e7
--- /dev/null
+++ b/include/hw/ppc/spapr_ovec.h
@@ -0,0 +1,83 @@
+/*
+ * QEMU SPAPR Option/Architecture Vector Definitions
+ *
+ * Each architecture option is organized/documented by the following
+ * in LoPAPR 1.1, Table 244:
+ *
+ * <vector number>: the bit-vector in which the option is located
+ * <vector byte>: the byte offset of the vector entry
+ * <vector bit>: the bit offset within the vector entry
+ *
+ * where each vector entry can be one or more bytes.
+ *
+ * Firmware expects a somewhat literal encoding of this bit-vector
+ * structure, where each entry is stored in little-endian so that the
+ * byte ordering reflects that of the documentation, but where each bit
+ * offset is from "left-to-right" in the traditional representation of
+ * a byte value where the MSB is the left-most bit. Thus, each
+ * individual byte encodes the option bits in reverse order of the
+ * documented bit.
+ *
+ * These definitions/helpers attempt to abstract away this internal
+ * representation so that we can define/set/test for individual option
+ * bits using only the documented values. This is done mainly by relying
+ * on a bitmap to approximate the documented "bit-vector" structure and
+ * handling conversations to-from the internal representation under the
+ * covers.
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * 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 SPAPR_OVEC_H
+#define SPAPR_OVEC_H
+
+#include "cpu.h"
+
+typedef struct SpaprOptionVector SpaprOptionVector;
+
+#define OV_BIT(byte, bit) ((byte - 1) * BITS_PER_BYTE + bit)
+
+/* option vector 1 */
+#define OV1_PPC_3_00 OV_BIT(3, 0) /* guest supports PowerPC 3.00? */
+
+/* option vector 5 */
+#define OV5_DRCONF_MEMORY OV_BIT(2, 2)
+#define OV5_FORM1_AFFINITY OV_BIT(5, 0)
+#define OV5_FORM2_AFFINITY OV_BIT(5, 2)
+#define OV5_HP_EVT OV_BIT(6, 5)
+#define OV5_HPT_RESIZE OV_BIT(6, 7)
+#define OV5_DRMEM_V2 OV_BIT(22, 0)
+#define OV5_XIVE_BOTH OV_BIT(23, 0)
+#define OV5_XIVE_EXPLOIT OV_BIT(23, 1) /* 1=exploitation 0=legacy */
+
+/* ISA 3.00 MMU features: */
+#define OV5_MMU_BOTH OV_BIT(24, 0) /* Radix and hash */
+#define OV5_MMU_RADIX_300 OV_BIT(24, 1) /* 1=Radix only, 0=Hash only */
+#define OV5_MMU_RADIX_GTSE OV_BIT(26, 1) /* Radix GTSE */
+
+/* interfaces */
+SpaprOptionVector *spapr_ovec_new(void);
+SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig);
+void spapr_ovec_intersect(SpaprOptionVector *ov,
+ SpaprOptionVector *ov1,
+ SpaprOptionVector *ov2);
+bool spapr_ovec_subset(SpaprOptionVector *ov1, SpaprOptionVector *ov2);
+void spapr_ovec_cleanup(SpaprOptionVector *ov);
+void spapr_ovec_set(SpaprOptionVector *ov, long bitnr);
+void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr);
+bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr);
+bool spapr_ovec_empty(SpaprOptionVector *ov);
+SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
+int spapr_dt_ovec(void *fdt, int fdt_offset,
+ SpaprOptionVector *ov, const char *name);
+
+/* migration */
+extern const VMStateDescription vmstate_spapr_ovec;
+
+#endif /* SPAPR_OVEC_H */
diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
new file mode 100644
index 000000000..383611f10
--- /dev/null
+++ b/include/hw/ppc/spapr_rtas.h
@@ -0,0 +1,10 @@
+#ifndef HW_SPAPR_RTAS_H
+#define HW_SPAPR_RTAS_H
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
+ uint32_t nret, uint64_t rets);
+#endif /* HW_SPAPR_RTAS_H */
diff --git a/include/hw/ppc/spapr_tpm_proxy.h b/include/hw/ppc/spapr_tpm_proxy.h
new file mode 100644
index 000000000..96d2a9697
--- /dev/null
+++ b/include/hw/ppc/spapr_tpm_proxy.h
@@ -0,0 +1,30 @@
+/*
+ * 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"
+OBJECT_DECLARE_SIMPLE_TYPE(SpaprTpmProxy, SPAPR_TPM_PROXY)
+
+struct SpaprTpmProxy {
+ /*< private >*/
+ DeviceState parent;
+
+ char *host_path;
+ int host_fd;
+};
+
+#endif /* HW_SPAPR_TPM_PROXY_H */
diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h
new file mode 100644
index 000000000..4bea87f39
--- /dev/null
+++ b/include/hw/ppc/spapr_vio.h
@@ -0,0 +1,141 @@
+#ifndef HW_SPAPR_VIO_H
+#define HW_SPAPR_VIO_H
+
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/ppc/spapr.h"
+#include "sysemu/dma.h"
+#include "hw/irq.h"
+#include "qom/object.h"
+
+#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
+OBJECT_DECLARE_TYPE(SpaprVioDevice, SpaprVioDeviceClass,
+ VIO_SPAPR_DEVICE)
+
+#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus"
+OBJECT_DECLARE_SIMPLE_TYPE(SpaprVioBus, SPAPR_VIO_BUS)
+
+#define TYPE_SPAPR_VIO_BRIDGE "spapr-vio-bridge"
+
+typedef struct SpaprVioCrq {
+ uint64_t qladdr;
+ uint32_t qsize;
+ uint32_t qnext;
+ int(*SendFunc)(struct SpaprVioDevice *vdev, uint8_t *crq);
+} SpaprVioCrq;
+
+
+struct SpaprVioDeviceClass {
+ DeviceClass parent_class;
+
+ const char *dt_name, *dt_type, *dt_compatible;
+ target_ulong signal_mask;
+ uint32_t rtce_window_size;
+ void (*realize)(SpaprVioDevice *dev, Error **errp);
+ void (*reset)(SpaprVioDevice *dev);
+ int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off);
+ const char *(*get_dt_compatible)(SpaprVioDevice *dev);
+};
+
+struct SpaprVioDevice {
+ DeviceState qdev;
+ uint32_t reg;
+ uint32_t irq;
+ uint64_t signal_state;
+ SpaprVioCrq crq;
+ AddressSpace as;
+ MemoryRegion mrroot;
+ MemoryRegion mrbypass;
+ SpaprTceTable *tcet;
+};
+
+#define DEFINE_SPAPR_PROPERTIES(type, field) \
+ DEFINE_PROP_UINT32("reg", type, field.reg, -1)
+
+struct SpaprVioBus {
+ BusState bus;
+ uint32_t next_reg;
+};
+
+SpaprVioBus *spapr_vio_bus_init(void);
+SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg);
+void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt);
+gchar *spapr_vio_stdout_path(SpaprVioBus *bus);
+
+static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+
+ qemu_irq_pulse(spapr_qirq(spapr, dev->irq));
+}
+
+static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr,
+ uint32_t size, DMADirection dir)
+{
+ return dma_memory_valid(&dev->as, taddr, size, dir);
+}
+
+static inline int spapr_vio_dma_read(SpaprVioDevice *dev, uint64_t taddr,
+ void *buf, uint32_t size)
+{
+ return (dma_memory_read(&dev->as, taddr, buf, size) != 0) ?
+ H_DEST_PARM : H_SUCCESS;
+}
+
+static inline int spapr_vio_dma_write(SpaprVioDevice *dev, uint64_t taddr,
+ const void *buf, uint32_t size)
+{
+ return (dma_memory_write(&dev->as, taddr, buf, size) != 0) ?
+ H_DEST_PARM : H_SUCCESS;
+}
+
+static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr,
+ uint8_t c, uint32_t size)
+{
+ return (dma_memory_set(&dev->as, taddr, c, size) != 0) ?
+ H_DEST_PARM : H_SUCCESS;
+}
+
+#define vio_stb(_dev, _addr, _val) (stb_dma(&(_dev)->as, (_addr), (_val)))
+#define vio_sth(_dev, _addr, _val) (stw_be_dma(&(_dev)->as, (_addr), (_val)))
+#define vio_stl(_dev, _addr, _val) (stl_be_dma(&(_dev)->as, (_addr), (_val)))
+#define vio_stq(_dev, _addr, _val) (stq_be_dma(&(_dev)->as, (_addr), (_val)))
+#define vio_ldq(_dev, _addr) (ldq_be_dma(&(_dev)->as, (_addr)))
+
+int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq);
+
+SpaprVioDevice *vty_lookup(SpaprMachineState *spapr, target_ulong reg);
+void vty_putchars(SpaprVioDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev);
+void spapr_vlan_create(SpaprVioBus *bus, NICInfo *nd);
+void spapr_vscsi_create(SpaprVioBus *bus);
+
+SpaprVioDevice *spapr_vty_get_default(SpaprVioBus *bus);
+
+extern const VMStateDescription vmstate_spapr_vio;
+
+#define VMSTATE_SPAPR_VIO(_f, _s) \
+ VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, SpaprVioDevice)
+
+void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass);
+
+#endif /* HW_SPAPR_VIO_H */
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
new file mode 100644
index 000000000..b282960ad
--- /dev/null
+++ b/include/hw/ppc/spapr_xive.h
@@ -0,0 +1,99 @@
+/*
+ * QEMU PowerPC sPAPR XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_SPAPR_XIVE_H
+#define PPC_SPAPR_XIVE_H
+
+#include "hw/ppc/spapr_irq.h"
+#include "hw/ppc/xive.h"
+
+#define TYPE_SPAPR_XIVE "spapr-xive"
+#define SPAPR_XIVE(obj) OBJECT_CHECK(SpaprXive, (obj), TYPE_SPAPR_XIVE)
+#define SPAPR_XIVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SpaprXiveClass, (klass), TYPE_SPAPR_XIVE)
+#define SPAPR_XIVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SpaprXiveClass, (obj), TYPE_SPAPR_XIVE)
+
+typedef struct SpaprXive {
+ XiveRouter parent;
+
+ /* Internal interrupt source for IPIs and virtual devices */
+ XiveSource source;
+ hwaddr vc_base;
+
+ /* END ESB MMIOs */
+ XiveENDSource end_source;
+ hwaddr end_base;
+
+ /* DT */
+ gchar *nodename;
+
+ /* Routing table */
+ XiveEAS *eat;
+ uint32_t nr_irqs;
+ XiveEND *endt;
+ uint32_t nr_ends;
+
+ /* TIMA mapping address */
+ hwaddr tm_base;
+ MemoryRegion tm_mmio;
+
+ /* KVM support */
+ int fd;
+ void *tm_mmap;
+ MemoryRegion tm_mmio_kvm;
+ VMChangeStateEntry *change;
+
+ uint8_t hv_prio;
+} SpaprXive;
+
+typedef struct SpaprXiveClass {
+ XiveRouterClass parent;
+
+ DeviceRealize parent_realize;
+} SpaprXiveClass;
+
+/*
+ * The sPAPR machine has a unique XIVE IC device. Assign a fixed value
+ * to the controller block id value. It can nevertheless be changed
+ * for testing purpose.
+ */
+#define SPAPR_XIVE_BLOCK_ID 0x0
+
+struct SpaprMachineState;
+void spapr_xive_hcall_init(struct SpaprMachineState *spapr);
+void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable);
+void spapr_xive_map_mmio(SpaprXive *xive);
+
+int spapr_xive_end_to_target(uint8_t end_blk, uint32_t end_idx,
+ uint32_t *out_server, uint8_t *out_prio);
+
+/*
+ * KVM XIVE device helpers
+ */
+int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
+ Error **errp);
+void kvmppc_xive_disconnect(SpaprInterruptController *intc);
+void kvmppc_xive_reset(SpaprXive *xive, Error **errp);
+int kvmppc_xive_set_source_config(SpaprXive *xive, uint32_t lisn, XiveEAS *eas,
+ Error **errp);
+void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp);
+uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,
+ uint64_t data, bool write);
+int kvmppc_xive_set_queue_config(SpaprXive *xive, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ Error **errp);
+int kvmppc_xive_get_queue_config(SpaprXive *xive, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ Error **errp);
+void kvmppc_xive_synchronize_state(SpaprXive *xive, Error **errp);
+int kvmppc_xive_pre_save(SpaprXive *xive);
+int kvmppc_xive_post_load(SpaprXive *xive, int version_id);
+
+#endif /* PPC_SPAPR_XIVE_H */
diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h
new file mode 100644
index 000000000..97fdef758
--- /dev/null
+++ b/include/hw/ppc/vof.h
@@ -0,0 +1,60 @@
+/*
+ * Virtual Open Firmware
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_VOF_H
+#define HW_VOF_H
+
+typedef struct Vof {
+ uint64_t top_addr; /* copied from rma_size */
+ GArray *claimed; /* array of SpaprOfClaimed */
+ uint64_t claimed_base;
+ GHashTable *of_instances; /* ihandle -> SpaprOfInstance */
+ uint32_t of_instance_last;
+ char *bootargs;
+ long fw_size;
+} Vof;
+
+int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
+ target_ulong args_real);
+uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size, uint64_t align);
+void vof_init(Vof *vof, uint64_t top_addr, Error **errp);
+void vof_cleanup(Vof *vof);
+void vof_build_dt(void *fdt, Vof *vof);
+uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename,
+ const char *prop, const char *path);
+
+#define TYPE_VOF_MACHINE_IF "vof-machine-if"
+
+typedef struct VofMachineIfClass VofMachineIfClass;
+DECLARE_CLASS_CHECKERS(VofMachineIfClass, VOF_MACHINE, TYPE_VOF_MACHINE_IF)
+
+struct VofMachineIfClass {
+ InterfaceClass parent;
+ target_ulong (*client_architecture_support)(MachineState *ms, CPUState *cs,
+ target_ulong vec);
+ void (*quiesce)(MachineState *ms);
+ bool (*setprop)(MachineState *ms, const char *path, const char *propname,
+ void *val, int vallen);
+};
+
+/*
+ * Initial stack size is from
+ * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#REF27292
+ *
+ * "Client programs shall be invoked with a valid stack pointer (r1) with
+ * at least 32K bytes of memory available for stack growth".
+ */
+#define VOF_STACK_SIZE 0x8000
+
+#define VOF_MEM_READ(pa, buf, size) \
+ address_space_read(&address_space_memory, \
+ (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size))
+#define VOF_MEM_WRITE(pa, buf, size) \
+ address_space_write(&address_space_memory, \
+ (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size))
+
+#define PROM_ERROR (~0U)
+
+#endif /* HW_VOF_H */
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
new file mode 100644
index 000000000..00b80b08c
--- /dev/null
+++ b/include/hw/ppc/xics.h
@@ -0,0 +1,196 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef XICS_H
+#define XICS_H
+
+#include "exec/memory.h"
+#include "hw/qdev-core.h"
+#include "qom/object.h"
+
+#define XICS_IPI 0x2
+#define XICS_BUID 0x1
+#define XICS_IRQ_BASE (XICS_BUID << 12)
+
+/*
+ * We currently only support one BUID which is our interrupt base
+ * (the kernel implementation supports more but we don't exploit
+ * that yet)
+ */
+typedef struct PnvICPState PnvICPState;
+typedef struct ICSStateClass ICSStateClass;
+typedef struct ICSState ICSState;
+typedef struct ICSIRQState ICSIRQState;
+typedef struct XICSFabric XICSFabric;
+
+#define TYPE_ICP "icp"
+OBJECT_DECLARE_TYPE(ICPState, ICPStateClass,
+ ICP)
+
+#define TYPE_PNV_ICP "pnv-icp"
+DECLARE_INSTANCE_CHECKER(PnvICPState, PNV_ICP,
+ TYPE_PNV_ICP)
+
+
+struct ICPStateClass {
+ DeviceClass parent_class;
+
+ DeviceRealize parent_realize;
+};
+
+struct ICPState {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+ CPUState *cs;
+ ICSState *xirr_owner;
+ uint32_t xirr;
+ uint8_t pending_priority;
+ uint8_t mfrr;
+ qemu_irq output;
+
+ XICSFabric *xics;
+};
+
+#define ICP_PROP_XICS "xics"
+#define ICP_PROP_CPU "cpu"
+
+struct PnvICPState {
+ ICPState parent_obj;
+
+ MemoryRegion mmio;
+ uint32_t links[3];
+};
+
+#define TYPE_ICS "ics"
+DECLARE_OBJ_CHECKERS(ICSState, ICSStateClass,
+ ICS, TYPE_ICS)
+
+
+struct ICSStateClass {
+ DeviceClass parent_class;
+
+ DeviceRealize parent_realize;
+ DeviceReset parent_reset;
+
+ void (*reject)(ICSState *s, uint32_t irq);
+ void (*resend)(ICSState *s);
+};
+
+struct ICSState {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+ uint32_t nr_irqs;
+ uint32_t offset;
+ ICSIRQState *irqs;
+ XICSFabric *xics;
+};
+
+#define ICS_PROP_XICS "xics"
+
+static inline bool ics_valid_irq(ICSState *ics, uint32_t nr)
+{
+ return (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs));
+}
+
+struct ICSIRQState {
+ uint32_t server;
+ uint8_t priority;
+ uint8_t saved_priority;
+#define XICS_STATUS_ASSERTED 0x1
+#define XICS_STATUS_SENT 0x2
+#define XICS_STATUS_REJECTED 0x4
+#define XICS_STATUS_MASKED_PENDING 0x8
+#define XICS_STATUS_PRESENTED 0x10
+#define XICS_STATUS_QUEUED 0x20
+ uint8_t status;
+/* (flags & XICS_FLAGS_IRQ_MASK) == 0 means the interrupt is not allocated */
+#define XICS_FLAGS_IRQ_LSI 0x1
+#define XICS_FLAGS_IRQ_MSI 0x2
+#define XICS_FLAGS_IRQ_MASK 0x3
+ uint8_t flags;
+};
+
+#define TYPE_XICS_FABRIC "xics-fabric"
+#define XICS_FABRIC(obj) \
+ INTERFACE_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC)
+typedef struct XICSFabricClass XICSFabricClass;
+DECLARE_CLASS_CHECKERS(XICSFabricClass, XICS_FABRIC,
+ TYPE_XICS_FABRIC)
+
+struct XICSFabricClass {
+ InterfaceClass parent;
+ ICSState *(*ics_get)(XICSFabric *xi, int irq);
+ void (*ics_resend)(XICSFabric *xi);
+ ICPState *(*icp_get)(XICSFabric *xi, int server);
+};
+
+ICPState *xics_icp_get(XICSFabric *xi, int server);
+
+/* Internal XICS interfaces */
+void icp_set_cppr(ICPState *icp, uint8_t cppr);
+void icp_set_mfrr(ICPState *icp, uint8_t mfrr);
+uint32_t icp_accept(ICPState *ss);
+uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr);
+void icp_eoi(ICPState *icp, uint32_t xirr);
+void icp_irq(ICSState *ics, int server, int nr, uint8_t priority);
+void icp_reset(ICPState *icp);
+
+void ics_write_xive(ICSState *ics, int nr, int server,
+ uint8_t priority, uint8_t saved_priority);
+void ics_set_irq(void *opaque, int srcno, int val);
+
+static inline bool ics_irq_free(ICSState *ics, uint32_t srcno)
+{
+ return !(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK);
+}
+
+void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
+void icp_pic_print_info(ICPState *icp, Monitor *mon);
+void ics_pic_print_info(ICSState *ics, Monitor *mon);
+
+void ics_resend(ICSState *ics);
+void icp_resend(ICPState *ss);
+
+Object *icp_create(Object *cpu, const char *type, XICSFabric *xi,
+ Error **errp);
+void icp_destroy(ICPState *icp);
+
+/* KVM */
+void icp_get_kvm_state(ICPState *icp);
+int icp_set_kvm_state(ICPState *icp, Error **errp);
+void icp_synchronize_state(ICPState *icp);
+void icp_kvm_realize(DeviceState *dev, Error **errp);
+
+void ics_get_kvm_state(ICSState *ics);
+int ics_set_kvm_state_one(ICSState *ics, int srcno, Error **errp);
+int ics_set_kvm_state(ICSState *ics, Error **errp);
+void ics_synchronize_state(ICSState *ics);
+void ics_kvm_set_irq(ICSState *ics, int srcno, int val);
+
+#endif /* XICS_H */
diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h
new file mode 100644
index 000000000..de752c0d2
--- /dev/null
+++ b/include/hw/ppc/xics_spapr.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010, 2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef XICS_SPAPR_H
+#define XICS_SPAPR_H
+
+#include "hw/ppc/spapr.h"
+#include "qom/object.h"
+
+#define TYPE_ICS_SPAPR "ics-spapr"
+/* This is reusing the ICSState typedef from TYPE_ICS */
+DECLARE_INSTANCE_CHECKER(ICSState, ICS_SPAPR,
+ TYPE_ICS_SPAPR)
+
+int xics_kvm_connect(SpaprInterruptController *intc, uint32_t nr_servers,
+ Error **errp);
+void xics_kvm_disconnect(SpaprInterruptController *intc);
+bool xics_kvm_has_broken_disconnect(void);
+
+#endif /* XICS_SPAPR_H */
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
new file mode 100644
index 000000000..b8ab0bf74
--- /dev/null
+++ b/include/hw/ppc/xive.h
@@ -0,0 +1,536 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ *
+ * The POWER9 processor comes with a new interrupt controller, called
+ * XIVE as "eXternal Interrupt Virtualization Engine".
+ *
+ * = Overall architecture
+ *
+ *
+ * XIVE Interrupt Controller
+ * +------------------------------------+ IPIs
+ * | +---------+ +---------+ +--------+ | +-------+
+ * | |VC | |CQ | |PC |----> | CORES |
+ * | | esb | | | | |----> | |
+ * | | eas | | Bridge | | tctx |----> | |
+ * | |SC end | | | | nvt | | | |
+ * +------+ | +---------+ +----+----+ +--------+ | +-+-+-+-+
+ * | RAM | +------------------|-----------------+ | | |
+ * | | | | | |
+ * | | | | | |
+ * | | +--------------------v------------------------v-v-v--+ other
+ * | <--+ Power Bus +--> chips
+ * | esb | +---------+-----------------------+------------------+
+ * | eas | | |
+ * | end | +--|------+ |
+ * | nvt | +----+----+ | +----+----+
+ * +------+ |SC | | |SC |
+ * | | | | |
+ * | PQ-bits | | | PQ-bits |
+ * | local |-+ | in VC |
+ * +---------+ +---------+
+ * PCIe NX,NPU,CAPI
+ *
+ * SC: Source Controller (aka. IVSE)
+ * VC: Virtualization Controller (aka. IVRE)
+ * PC: Presentation Controller (aka. IVPE)
+ * CQ: Common Queue (Bridge)
+ *
+ * PQ-bits: 2 bits source state machine (P:pending Q:queued)
+ * esb: Event State Buffer (Array of PQ bits in an IVSE)
+ * eas: Event Assignment Structure
+ * end: Event Notification Descriptor
+ * nvt: Notification Virtual Target
+ * tctx: Thread interrupt Context
+ *
+ *
+ * The XIVE IC is composed of three sub-engines :
+ *
+ * - Interrupt Virtualization Source Engine (IVSE), or Source
+ * Controller (SC). These are found in PCI PHBs, in the PSI host
+ * bridge controller, but also inside the main controller for the
+ * core IPIs and other sub-chips (NX, CAP, NPU) of the
+ * chip/processor. They are configured to feed the IVRE with events.
+ *
+ * - Interrupt Virtualization Routing Engine (IVRE) or Virtualization
+ * Controller (VC). Its job is to match an event source with an
+ * Event Notification Descriptor (END).
+ *
+ * - Interrupt Virtualization Presentation Engine (IVPE) or
+ * Presentation Controller (PC). It maintains the interrupt context
+ * state of each thread and handles the delivery of the external
+ * exception to the thread.
+ *
+ * In XIVE 1.0, the sub-engines used to be referred as:
+ *
+ * SC Source Controller
+ * VC Virtualization Controller
+ * PC Presentation Controller
+ * CQ Common Queue (PowerBUS Bridge)
+ *
+ *
+ * = XIVE internal tables
+ *
+ * Each of the sub-engines uses a set of tables to redirect exceptions
+ * from event sources to CPU threads.
+ *
+ * +-------+
+ * User or OS | EQ |
+ * or +------>|entries|
+ * Hypervisor | | .. |
+ * Memory | +-------+
+ * | ^
+ * | |
+ * +-------------------------------------------------+
+ * | |
+ * Hypervisor +------+ +---+--+ +---+--+ +------+
+ * Memory | ESB | | EAT | | ENDT | | NVTT |
+ * (skiboot) +----+-+ +----+-+ +----+-+ +------+
+ * ^ | ^ | ^ | ^
+ * | | | | | | |
+ * +-------------------------------------------------+
+ * | | | | | | |
+ * | | | | | | |
+ * +----|--|--------|--|--------|--|-+ +-|-----+ +------+
+ * | | | | | | | | | | tctx| |Thread|
+ * IPI or --> | + v + v + v |---| + .. |-----> |
+ * HW events --> | | | | | |
+ * IVSE | IVRE | | IVPE | +------+
+ * +---------------------------------+ +-------+
+ *
+ *
+ *
+ * The IVSE have a 2-bits state machine, P for pending and Q for queued,
+ * for each source that allows events to be triggered. They are stored in
+ * an Event State Buffer (ESB) array and can be controlled by MMIOs.
+ *
+ * If the event is let through, the IVRE looks up in the Event Assignment
+ * Structure (EAS) table for an Event Notification Descriptor (END)
+ * configured for the source. Each Event Notification Descriptor defines
+ * a notification path to a CPU and an in-memory Event Queue, in which
+ * will be enqueued an EQ data for the OS to pull.
+ *
+ * The IVPE determines if a Notification Virtual Target (NVT) can
+ * handle the event by scanning the thread contexts of the VCPUs
+ * dispatched on the processor HW threads. It maintains the state of
+ * the thread interrupt context (TCTX) of each thread in a NVT table.
+ *
+ * = Acronyms
+ *
+ * Description In XIVE 1.0, used to be referred as
+ *
+ * EAS Event Assignment Structure IVE Interrupt Virt. Entry
+ * EAT Event Assignment Table IVT Interrupt Virt. Table
+ * ENDT Event Notif. Descriptor Table EQDT Event Queue Desc. Table
+ * EQ Event Queue same
+ * ESB Event State Buffer SBE State Bit Entry
+ * NVT Notif. Virtual Target VPD Virtual Processor Desc.
+ * NVTT Notif. Virtual Target Table VPDT Virtual Processor Desc. Table
+ * TCTX Thread interrupt Context
+ *
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef PPC_XIVE_H
+#define PPC_XIVE_H
+
+#include "sysemu/kvm.h"
+#include "hw/sysbus.h"
+#include "hw/ppc/xive_regs.h"
+#include "qom/object.h"
+
+/*
+ * XIVE Notifier (Interface between Source and Router)
+ */
+
+typedef struct XiveNotifier XiveNotifier;
+
+#define TYPE_XIVE_NOTIFIER "xive-notifier"
+#define XIVE_NOTIFIER(obj) \
+ INTERFACE_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER)
+typedef struct XiveNotifierClass XiveNotifierClass;
+DECLARE_CLASS_CHECKERS(XiveNotifierClass, XIVE_NOTIFIER,
+ TYPE_XIVE_NOTIFIER)
+
+struct XiveNotifierClass {
+ InterfaceClass parent;
+ void (*notify)(XiveNotifier *xn, uint32_t lisn);
+};
+
+/*
+ * XIVE Interrupt Source
+ */
+
+#define TYPE_XIVE_SOURCE "xive-source"
+OBJECT_DECLARE_SIMPLE_TYPE(XiveSource, XIVE_SOURCE)
+
+/*
+ * XIVE Interrupt Source characteristics, which define how the ESB are
+ * controlled.
+ */
+#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */
+#define XIVE_SRC_STORE_EOI 0x2 /* Store EOI supported */
+
+struct XiveSource {
+ DeviceState parent;
+
+ /* IRQs */
+ uint32_t nr_irqs;
+ unsigned long *lsi_map;
+
+ /* PQ bits and LSI assertion bit */
+ uint8_t *status;
+
+ /* ESB memory region */
+ uint64_t esb_flags;
+ uint32_t esb_shift;
+ MemoryRegion esb_mmio;
+ MemoryRegion esb_mmio_emulated;
+
+ /* KVM support */
+ void *esb_mmap;
+ MemoryRegion esb_mmio_kvm;
+
+ XiveNotifier *xive;
+};
+
+/*
+ * ESB MMIO setting. Can be one page, for both source triggering and
+ * source management, or two different pages. See below for magic
+ * values.
+ */
+#define XIVE_ESB_4K 12 /* PSI HB only */
+#define XIVE_ESB_4K_2PAGE 13
+#define XIVE_ESB_64K 16
+#define XIVE_ESB_64K_2PAGE 17
+
+static inline bool xive_source_esb_has_2page(XiveSource *xsrc)
+{
+ return xsrc->esb_shift == XIVE_ESB_64K_2PAGE ||
+ xsrc->esb_shift == XIVE_ESB_4K_2PAGE;
+}
+
+static inline size_t xive_source_esb_len(XiveSource *xsrc)
+{
+ return (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
+}
+
+/* The trigger page is always the first/even page */
+static inline hwaddr xive_source_esb_page(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+ return (1ull << xsrc->esb_shift) * srcno;
+}
+
+/* In a two pages ESB MMIO setting, the odd page is for management */
+static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno)
+{
+ hwaddr addr = xive_source_esb_page(xsrc, srcno);
+
+ if (xive_source_esb_has_2page(xsrc)) {
+ addr += (1 << (xsrc->esb_shift - 1));
+ }
+
+ return addr;
+}
+
+/*
+ * Each interrupt source has a 2-bit state machine which can be
+ * controlled by MMIO. P indicates that an interrupt is pending (has
+ * been sent to a queue and is waiting for an EOI). Q indicates that
+ * the interrupt has been triggered while pending.
+ *
+ * This acts as a coalescing mechanism in order to guarantee that a
+ * given interrupt only occurs at most once in a queue.
+ *
+ * When doing an EOI, the Q bit will indicate if the interrupt
+ * needs to be re-triggered.
+ */
+#define XIVE_STATUS_ASSERTED 0x4 /* Extra bit for LSI */
+#define XIVE_ESB_VAL_P 0x2
+#define XIVE_ESB_VAL_Q 0x1
+
+#define XIVE_ESB_RESET 0x0
+#define XIVE_ESB_PENDING XIVE_ESB_VAL_P
+#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q)
+#define XIVE_ESB_OFF XIVE_ESB_VAL_Q
+
+bool xive_esb_trigger(uint8_t *pq);
+bool xive_esb_eoi(uint8_t *pq);
+uint8_t xive_esb_set(uint8_t *pq, uint8_t value);
+
+/*
+ * "magic" Event State Buffer (ESB) MMIO offsets.
+ *
+ * The following offsets into the ESB MMIO allow to read or manipulate
+ * the PQ bits. They must be used with an 8-byte load instruction.
+ * They all return the previous state of the interrupt (atomically).
+ *
+ * Additionally, some ESB pages support doing an EOI via a store and
+ * some ESBs support doing a trigger via a separate trigger page.
+ */
+#define XIVE_ESB_STORE_EOI 0x400 /* Store */
+#define XIVE_ESB_LOAD_EOI 0x000 /* Load */
+#define XIVE_ESB_GET 0x800 /* Load */
+#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */
+#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */
+#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */
+#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */
+
+uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno);
+uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);
+
+/*
+ * Source status helpers
+ */
+static inline void xive_source_set_status(XiveSource *xsrc, uint32_t srcno,
+ uint8_t status, bool enable)
+{
+ if (enable) {
+ xsrc->status[srcno] |= status;
+ } else {
+ xsrc->status[srcno] &= ~status;
+ }
+}
+
+static inline void xive_source_set_asserted(XiveSource *xsrc, uint32_t srcno,
+ bool enable)
+{
+ xive_source_set_status(xsrc, srcno, XIVE_STATUS_ASSERTED, enable);
+}
+
+static inline bool xive_source_is_asserted(XiveSource *xsrc, uint32_t srcno)
+{
+ return xsrc->status[srcno] & XIVE_STATUS_ASSERTED;
+}
+
+void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset,
+ Monitor *mon);
+
+static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+ return test_bit(srcno, xsrc->lsi_map);
+}
+
+static inline void xive_source_irq_set_lsi(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+ bitmap_set(xsrc->lsi_map, srcno, 1);
+}
+
+void xive_source_set_irq(void *opaque, int srcno, int val);
+
+/*
+ * XIVE Thread interrupt Management (TM) context
+ */
+
+#define TYPE_XIVE_TCTX "xive-tctx"
+OBJECT_DECLARE_SIMPLE_TYPE(XiveTCTX, XIVE_TCTX)
+
+/*
+ * XIVE Thread interrupt Management register rings :
+ *
+ * QW-0 User event-based exception state
+ * QW-1 O/S OS context for priority management, interrupt acks
+ * QW-2 Pool hypervisor pool context for virtual processors dispatched
+ * QW-3 Physical physical thread context and security context
+ */
+#define XIVE_TM_RING_COUNT 4
+#define XIVE_TM_RING_SIZE 0x10
+
+typedef struct XivePresenter XivePresenter;
+
+struct XiveTCTX {
+ DeviceState parent_obj;
+
+ CPUState *cs;
+ qemu_irq hv_output;
+ qemu_irq os_output;
+
+ uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
+
+ XivePresenter *xptr;
+};
+
+static inline uint32_t xive_tctx_word2(uint8_t *ring)
+{
+ return *((uint32_t *) &ring[TM_WORD2]);
+}
+
+/*
+ * XIVE Router
+ */
+typedef struct XiveFabric XiveFabric;
+
+struct XiveRouter {
+ SysBusDevice parent;
+
+ XiveFabric *xfb;
+};
+
+#define TYPE_XIVE_ROUTER "xive-router"
+OBJECT_DECLARE_TYPE(XiveRouter, XiveRouterClass,
+ XIVE_ROUTER)
+
+struct XiveRouterClass {
+ SysBusDeviceClass parent;
+
+ /* XIVE table accessors */
+ int (*get_eas)(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
+ XiveEAS *eas);
+ int (*get_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end);
+ int (*write_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
+ int (*get_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt);
+ int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt, uint8_t word_number);
+ uint8_t (*get_block_id)(XiveRouter *xrtr);
+};
+
+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,
+ XiveEND *end);
+int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
+int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt);
+int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt, uint8_t word_number);
+void xive_router_notify(XiveNotifier *xn, uint32_t lisn);
+
+/*
+ * XIVE Presenter
+ */
+
+typedef struct XiveTCTXMatch {
+ XiveTCTX *tctx;
+ uint8_t ring;
+} XiveTCTXMatch;
+
+#define TYPE_XIVE_PRESENTER "xive-presenter"
+#define XIVE_PRESENTER(obj) \
+ INTERFACE_CHECK(XivePresenter, (obj), TYPE_XIVE_PRESENTER)
+typedef struct XivePresenterClass XivePresenterClass;
+DECLARE_CLASS_CHECKERS(XivePresenterClass, XIVE_PRESENTER,
+ TYPE_XIVE_PRESENTER)
+
+struct XivePresenterClass {
+ InterfaceClass parent;
+ int (*match_nvt)(XivePresenter *xptr, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv, XiveTCTXMatch *match);
+ bool (*in_kernel)(const XivePresenter *xptr);
+};
+
+int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
+ uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint32_t logic_serv);
+bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv);
+
+/*
+ * XIVE Fabric (Interface between Interrupt Controller and Machine)
+ */
+
+#define TYPE_XIVE_FABRIC "xive-fabric"
+#define XIVE_FABRIC(obj) \
+ INTERFACE_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC)
+typedef struct XiveFabricClass XiveFabricClass;
+DECLARE_CLASS_CHECKERS(XiveFabricClass, XIVE_FABRIC,
+ TYPE_XIVE_FABRIC)
+
+struct XiveFabricClass {
+ InterfaceClass parent;
+ int (*match_nvt)(XiveFabric *xfb, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv, XiveTCTXMatch *match);
+};
+
+/*
+ * XIVE END ESBs
+ */
+
+#define TYPE_XIVE_END_SOURCE "xive-end-source"
+OBJECT_DECLARE_SIMPLE_TYPE(XiveENDSource, XIVE_END_SOURCE)
+
+struct XiveENDSource {
+ DeviceState parent;
+
+ uint32_t nr_ends;
+
+ /* ESB memory region */
+ uint32_t esb_shift;
+ MemoryRegion esb_mmio;
+
+ XiveRouter *xrtr;
+};
+
+/*
+ * For legacy compatibility, the exceptions define up to 256 different
+ * priorities. P9 implements only 9 levels : 8 active levels [0 - 7]
+ * and the least favored level 0xFF.
+ */
+#define XIVE_PRIORITY_MAX 7
+
+/*
+ * Convert a priority number to an Interrupt Pending Buffer (IPB)
+ * register, which indicates a pending interrupt at the priority
+ * corresponding to the bit number
+ */
+static inline uint8_t xive_priority_to_ipb(uint8_t priority)
+{
+ return priority > XIVE_PRIORITY_MAX ?
+ 0 : 1 << (XIVE_PRIORITY_MAX - priority);
+}
+
+/*
+ * XIVE Thread Interrupt Management Aera (TIMA)
+ *
+ * This region gives access to the registers of the thread interrupt
+ * management context. It is four page wide, each page providing a
+ * different view of the registers. The page with the lower offset is
+ * the most privileged and gives access to the entire context.
+ */
+#define XIVE_TM_HW_PAGE 0x0
+#define XIVE_TM_HV_PAGE 0x1
+#define XIVE_TM_OS_PAGE 0x2
+#define XIVE_TM_USER_PAGE 0x3
+
+void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
+ uint64_t value, unsigned size);
+uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
+ unsigned size);
+
+void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon);
+Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp);
+void xive_tctx_reset(XiveTCTX *tctx);
+void xive_tctx_destroy(XiveTCTX *tctx);
+void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb);
+
+/*
+ * KVM XIVE device helpers
+ */
+
+int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp);
+void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val);
+int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp);
+int kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp);
+int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp);
+int kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp);
+
+#endif /* PPC_XIVE_H */
diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
new file mode 100644
index 000000000..b7fde2354
--- /dev/null
+++ b/include/hw/ppc/xive_regs.h
@@ -0,0 +1,301 @@
+/*
+ * QEMU PowerPC XIVE internal structure definitions
+ *
+ *
+ * The XIVE structures are accessed by the HW and their format is
+ * architected to be big-endian. Some macros are provided to ease
+ * access to the different fields.
+ *
+ *
+ * Copyright (c) 2016-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_XIVE_REGS_H
+#define PPC_XIVE_REGS_H
+
+#include "qemu/bswap.h"
+#include "qemu/host-utils.h"
+
+/*
+ * Interrupt source number encoding on PowerBUS
+ */
+/*
+ * Trigger data definition
+ *
+ * The trigger definition is used for triggers both for HW source
+ * interrupts (PHB, PSI), as well as for rerouting interrupts between
+ * Interrupt Controller.
+ *
+ * HW source controllers set bit0 of word0 to ‘0’ as they provide EAS
+ * information (EAS block + EAS index) in the 8 byte data and not END
+ * information, which is use for rerouting interrupts.
+ *
+ * bit1 of word0 to ‘1’ signals that the state bit check has been
+ * performed.
+ */
+#define XIVE_TRIGGER_END PPC_BIT(0)
+#define XIVE_TRIGGER_PQ PPC_BIT(1)
+
+/*
+ * QEMU macros to manipulate the trigger payload in native endian
+ */
+#define XIVE_EAS_BLOCK(n) (((n) >> 28) & 0xf)
+#define XIVE_EAS_INDEX(n) ((n) & 0x0fffffff)
+#define XIVE_EAS(blk, idx) ((uint32_t)(blk) << 28 | (idx))
+
+#define TM_SHIFT 16
+
+/* TM register offsets */
+#define TM_QW0_USER 0x000 /* All rings */
+#define TM_QW1_OS 0x010 /* Ring 0..2 */
+#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
+#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
+
+/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
+#define TM_NSR 0x0 /* + + - + */
+#define TM_CPPR 0x1 /* - + - + */
+#define TM_IPB 0x2 /* - + + + */
+#define TM_LSMFB 0x3 /* - + + + */
+#define TM_ACK_CNT 0x4 /* - + - - */
+#define TM_INC 0x5 /* - + - + */
+#define TM_AGE 0x6 /* - + - + */
+#define TM_PIPR 0x7 /* - + - + */
+
+#define TM_WORD0 0x0
+#define TM_WORD1 0x4
+
+/*
+ * QW word 2 contains the valid bit at the top and other fields
+ * depending on the QW.
+ */
+#define TM_WORD2 0x8
+#define TM_QW0W2_VU PPC_BIT32(0)
+#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */
+#define TM_QW1W2_VO PPC_BIT32(0)
+#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31)
+#define TM_QW2W2_VP PPC_BIT32(0)
+#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31)
+#define TM_QW3W2_VT PPC_BIT32(0)
+#define TM_QW3W2_LP PPC_BIT32(6)
+#define TM_QW3W2_LE PPC_BIT32(7)
+#define TM_QW3W2_T PPC_BIT32(31)
+
+/*
+ * In addition to normal loads to "peek" and writes (only when invalid)
+ * using 4 and 8 bytes accesses, the above registers support these
+ * "special" byte operations:
+ *
+ * - Byte load from QW0[NSR] - User level NSR (EBB)
+ * - Byte store to QW0[NSR] - User level NSR (EBB)
+ * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
+ * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
+ * otherwise VT||0000000
+ * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
+ *
+ * Then we have all these "special" CI ops at these offset that trigger
+ * all sorts of side effects:
+ */
+#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
+#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
+#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */
+#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user
+ * context */
+#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
+#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS
+ * context to reg */
+#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate Pool
+ * context to reg*/
+#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
+#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd
+ * line */
+#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
+#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even
+ * line */
+#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
+/* XXX more... */
+
+/* NSR fields for the various QW ack types */
+#define TM_QW0_NSR_EB PPC_BIT8(0)
+#define TM_QW1_NSR_EO PPC_BIT8(0)
+#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1)
+#define TM_QW3_NSR_HE_NONE 0
+#define TM_QW3_NSR_HE_POOL 1
+#define TM_QW3_NSR_HE_PHYS 2
+#define TM_QW3_NSR_HE_LSI 3
+#define TM_QW3_NSR_I PPC_BIT8(2)
+#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7)
+
+/*
+ * EAS (Event Assignment Structure)
+ *
+ * One per interrupt source. Targets an interrupt to a given Event
+ * Notification Descriptor (END) and provides the corresponding
+ * logical interrupt number (END data)
+ */
+typedef struct XiveEAS {
+ /*
+ * Use a single 64-bit definition to make it easier to perform
+ * atomic updates
+ */
+ uint64_t w;
+#define EAS_VALID PPC_BIT(0)
+#define EAS_END_BLOCK PPC_BITMASK(4, 7) /* Destination END block# */
+#define EAS_END_INDEX PPC_BITMASK(8, 31) /* Destination END index */
+#define EAS_MASKED PPC_BIT(32) /* Masked */
+#define EAS_END_DATA PPC_BITMASK(33, 63) /* Data written to the END */
+} 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);
+}
+
+static inline uint64_t xive_set_field64(uint64_t mask, uint64_t word,
+ uint64_t value)
+{
+ uint64_t tmp =
+ (be64_to_cpu(word) & ~mask) | ((value << ctz64(mask)) & mask);
+ return cpu_to_be64(tmp);
+}
+
+static inline uint32_t xive_get_field32(uint32_t mask, uint32_t word)
+{
+ return (be32_to_cpu(word) & mask) >> ctz32(mask);
+}
+
+static inline uint32_t xive_set_field32(uint32_t mask, uint32_t word,
+ uint32_t value)
+{
+ uint32_t tmp =
+ (be32_to_cpu(word) & ~mask) | ((value << ctz32(mask)) & mask);
+ return cpu_to_be32(tmp);
+}
+
+/* Event Notification Descriptor (END) */
+typedef struct XiveEND {
+ uint32_t w0;
+#define END_W0_VALID PPC_BIT32(0) /* "v" bit */
+#define END_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */
+#define END_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */
+#define END_W0_BACKLOG PPC_BIT32(3) /* "b" bit */
+#define END_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */
+#define END_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */
+#define END_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */
+#define END_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */
+#define END_W0_QSIZE PPC_BITMASK32(12, 15)
+#define END_W0_SW0 PPC_BIT32(16)
+#define END_W0_FIRMWARE END_W0_SW0 /* Owned by FW */
+#define END_QSIZE_4K 0
+#define END_QSIZE_64K 4
+#define END_W0_HWDEP PPC_BITMASK32(24, 31)
+ uint32_t w1;
+#define END_W1_ESn PPC_BITMASK32(0, 1)
+#define END_W1_ESn_P PPC_BIT32(0)
+#define END_W1_ESn_Q PPC_BIT32(1)
+#define END_W1_ESe PPC_BITMASK32(2, 3)
+#define END_W1_ESe_P PPC_BIT32(2)
+#define END_W1_ESe_Q PPC_BIT32(3)
+#define END_W1_GENERATION PPC_BIT32(9)
+#define END_W1_PAGE_OFF PPC_BITMASK32(10, 31)
+ uint32_t w2;
+#define END_W2_MIGRATION_REG PPC_BITMASK32(0, 3)
+#define END_W2_OP_DESC_HI PPC_BITMASK32(4, 31)
+ uint32_t w3;
+#define END_W3_OP_DESC_LO PPC_BITMASK32(0, 31)
+ uint32_t w4;
+#define END_W4_ESC_END_BLOCK PPC_BITMASK32(4, 7)
+#define END_W4_ESC_END_INDEX PPC_BITMASK32(8, 31)
+ uint32_t w5;
+#define END_W5_ESC_END_DATA PPC_BITMASK32(1, 31)
+ uint32_t w6;
+#define END_W6_FORMAT_BIT PPC_BIT32(8)
+#define END_W6_NVT_BLOCK PPC_BITMASK32(9, 12)
+#define END_W6_NVT_INDEX PPC_BITMASK32(13, 31)
+ uint32_t w7;
+#define END_W7_F0_IGNORE PPC_BIT32(0)
+#define END_W7_F0_BLK_GROUPING PPC_BIT32(1)
+#define END_W7_F0_PRIORITY PPC_BITMASK32(8, 15)
+#define END_W7_F1_WAKEZ PPC_BIT32(0)
+#define END_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31)
+} XiveEND;
+
+#define xive_end_is_valid(end) (be32_to_cpu((end)->w0) & END_W0_VALID)
+#define xive_end_is_enqueue(end) (be32_to_cpu((end)->w0) & END_W0_ENQUEUE)
+#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)
+#define xive_end_is_firmware(end) \
+ (be32_to_cpu((end)->w0) & END_W0_FIRMWARE)
+
+static inline uint64_t xive_end_qaddr(XiveEND *end)
+{
+ return ((uint64_t) be32_to_cpu(end->w2) & 0x0fffffff) << 32 |
+ 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;
+#define NVT_W0_VALID PPC_BIT32(0)
+ uint32_t w1;
+#define NVT_W1_EQ_BLOCK PPC_BITMASK32(0, 3)
+#define NVT_W1_EQ_INDEX PPC_BITMASK32(4, 31)
+ uint32_t w2;
+ uint32_t w3;
+ uint32_t w4;
+#define NVT_W4_IPB PPC_BITMASK32(16, 23)
+ uint32_t w5;
+ uint32_t w6;
+ uint32_t w7;
+ uint32_t w8;
+#define NVT_W8_GRP_VALID PPC_BIT32(0)
+ uint32_t w9;
+ uint32_t wa;
+ uint32_t wb;
+ uint32_t wc;
+ uint32_t wd;
+ uint32_t we;
+ uint32_t wf;
+} XiveNVT;
+
+#define xive_nvt_is_valid(nvt) (be32_to_cpu((nvt)->w0) & NVT_W0_VALID)
+
+/*
+ * The VP number space in a block is defined by the END_W6_NVT_INDEX
+ * field of the XIVE END
+ */
+#define XIVE_NVT_SHIFT 19
+#define XIVE_NVT_COUNT (1 << XIVE_NVT_SHIFT)
+
+static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx)
+{
+ return (nvt_blk << XIVE_NVT_SHIFT) | nvt_idx;
+}
+
+static inline uint32_t xive_nvt_idx(uint32_t cam_line)
+{
+ return cam_line & ((1 << XIVE_NVT_SHIFT) - 1);
+}
+
+static inline uint32_t xive_nvt_blk(uint32_t cam_line)
+{
+ return (cam_line >> XIVE_NVT_SHIFT) & 0xf;
+}
+
+#endif /* PPC_XIVE_REGS_H */