aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS12
-rw-r--r--docs/papr-pef.txt30
-rw-r--r--docs/specs/ppc-spapr-hcalls.rst21
-rw-r--r--docs/system/ppc/pseries.rst75
-rw-r--r--hw/pci-host/pnv_phb3.c57
-rw-r--r--hw/pci-host/pnv_phb4.c486
-rw-r--r--hw/pci-host/pnv_phb4_pec.c347
-rw-r--r--hw/ppc/pnv.c55
-rw-r--r--hw/ppc/spapr.c10
-rw-r--r--include/hw/pci-host/pnv_phb3.h4
-rw-r--r--include/hw/pci-host/pnv_phb4.h14
-rw-r--r--include/hw/ppc/pnv.h8
-rw-r--r--linux-user/aarch64/target_structs.h59
-rw-r--r--linux-user/alpha/cpu_loop.c61
-rw-r--r--linux-user/arm/target_structs.h60
-rw-r--r--linux-user/cris/cpu_loop.c12
-rw-r--r--linux-user/cris/target_structs.h59
-rw-r--r--linux-user/generic/target_structs.h58
-rw-r--r--linux-user/hexagon/target_structs.h55
-rw-r--r--linux-user/hppa/cpu_loop.c26
-rw-r--r--linux-user/i386/cpu_loop.c78
-rw-r--r--linux-user/i386/target_structs.h59
-rw-r--r--linux-user/m68k/cpu_loop.c24
-rw-r--r--linux-user/m68k/target_structs.h59
-rw-r--r--linux-user/microblaze/cpu_loop.c71
-rw-r--r--linux-user/microblaze/target_structs.h59
-rw-r--r--linux-user/mips/cpu_loop.c166
-rw-r--r--linux-user/nios2/target_structs.h59
-rw-r--r--linux-user/openrisc/cpu_loop.c18
-rw-r--r--linux-user/openrisc/target_structs.h59
-rw-r--r--linux-user/ppc/cpu_loop.c136
-rw-r--r--linux-user/riscv/cpu_loop.c31
-rw-r--r--linux-user/riscv/target_structs.h47
-rw-r--r--linux-user/s390x/cpu_loop.c7
-rw-r--r--linux-user/sh4/cpu_loop.c6
-rw-r--r--linux-user/sh4/target_structs.h59
-rw-r--r--linux-user/sparc/cpu_loop.c14
-rw-r--r--linux-user/syscall.c19
-rw-r--r--linux-user/syscall_defs.h3
-rw-r--r--linux-user/x86_64/target_structs.h36
-rw-r--r--linux-user/xtensa/cpu_loop.c26
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin991920 -> 992384 bytes
m---------roms/SLOF0
-rw-r--r--target/mips/tcg/micromips_translate.c.inc10
-rw-r--r--target/mips/tcg/mips16e_translate.c.inc2
-rw-r--r--target/mips/tcg/nanomips_translate.c.inc4
-rw-r--r--target/mips/tcg/translate.c36
-rw-r--r--target/mips/tcg/translate.h1
-rw-r--r--target/ppc/arch_dump.c2
-rw-r--r--target/ppc/cpu.h25
-rw-r--r--target/ppc/cpu_init.c2
-rw-r--r--target/ppc/excp_helper.c185
53 files changed, 1054 insertions, 1760 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c98a61caee..6ccdec7f02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1245,7 +1245,7 @@ F: hw/openrisc/openrisc_sim.c
PowerPC Machines
----------------
-405
+405 (ref405ep and taihu)
L: qemu-ppc@nongnu.org
S: Orphan
F: hw/ppc/ppc405_boards.c
@@ -1281,6 +1281,7 @@ New World (mac99)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
L: qemu-ppc@nongnu.org
S: Odd Fixes
+F: docs/system/ppc/powermac.rst
F: hw/ppc/mac_newworld.c
F: hw/pci-host/uninorth.c
F: hw/pci-bridge/dec.[hc]
@@ -1299,6 +1300,7 @@ Old World (g3beige)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
L: qemu-ppc@nongnu.org
S: Odd Fixes
+F: docs/system/ppc/powermac.rst
F: hw/ppc/mac_oldworld.c
F: hw/pci-host/grackle.c
F: hw/misc/macio/
@@ -1312,6 +1314,7 @@ PReP
M: Hervé Poussineau <hpoussin@reactos.org>
L: qemu-ppc@nongnu.org
S: Maintained
+F: docs/system/ppc/prep.rst
F: hw/ppc/prep.c
F: hw/ppc/prep_systemio.c
F: hw/ppc/rs6000_mc.c
@@ -1324,7 +1327,7 @@ F: include/hw/isa/pc87312.h
F: include/hw/rtc/m48t59.h
F: tests/avocado/ppc_prep_40p.py
-sPAPR
+sPAPR (pseries)
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: David Gibson <david@gibson.dropbear.id.au>
@@ -1336,8 +1339,8 @@ F: include/hw/*/spapr*
F: hw/*/xics*
F: include/hw/*/xics*
F: pc-bios/slof.bin
-F: docs/specs/ppc-spapr-hcalls.txt
-F: docs/specs/ppc-spapr-hotplug.txt
+F: docs/system/ppc/pseries.rst
+F: docs/specs/ppc-spapr-*
F: tests/qtest/spapr*
F: tests/qtest/libqos/*spapr*
F: tests/qtest/rtas*
@@ -1348,6 +1351,7 @@ PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org
S: Maintained
+F: docs/system/ppc/powernv.rst
F: hw/ppc/pnv*
F: hw/intc/pnv*
F: hw/intc/xics_pnv.c
diff --git a/docs/papr-pef.txt b/docs/papr-pef.txt
deleted file mode 100644
index 72550e9bf8..0000000000
--- a/docs/papr-pef.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-POWER (PAPR) Protected Execution Facility (PEF)
-===============================================
-
-Protected Execution Facility (PEF), also known as Secure Guest support
-is a feature found on IBM POWER9 and POWER10 processors.
-
-If a suitable firmware including an Ultravisor is installed, it adds
-an extra memory protection mode to the CPU. The ultravisor manages a
-pool of secure memory which cannot be accessed by the hypervisor.
-
-When this feature is enabled in QEMU, a guest can use ultracalls to
-enter "secure mode". This transfers most of its memory to secure
-memory, where it cannot be eavesdropped by a compromised hypervisor.
-
-Launching
----------
-
-To launch a guest which will be permitted to enter PEF secure mode:
-
-# ${QEMU} \
- -object pef-guest,id=pef0 \
- -machine confidential-guest-support=pef0 \
- ...
-
-Live Migration
-----------------
-
-Live migration is not yet implemented for PEF guests. For
-consistency, we currently prevent migration if the PEF feature is
-enabled, whether or not the guest has actually entered secure mode.
diff --git a/docs/specs/ppc-spapr-hcalls.rst b/docs/specs/ppc-spapr-hcalls.rst
index 28daf9734a..6cdcef2026 100644
--- a/docs/specs/ppc-spapr-hcalls.rst
+++ b/docs/specs/ppc-spapr-hcalls.rst
@@ -1,13 +1,12 @@
+======================
sPAPR hypervisor calls
-----------------------
+======================
When used with the ``pseries`` machine type, ``qemu-system-ppc64`` implements
-a set of hypervisor calls (a.k.a. hcalls) defined in the `Linux on Power
-Architecture Reference document (LoPAR)
-<https://cdn.openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
-This document is a subset of the Power Architecture Platform Reference (PAPR+)
-specification (IBM internal only), which is what PowerVM, the IBM proprietary
-hypervisor, adheres to.
+a set of hypervisor calls (a.k.a. hcalls) defined in the Linux on Power
+Architecture Reference ([LoPAR]_) document. This document is a subset of the
+Power Architecture Platform Reference (PAPR+) specification (IBM internal only),
+which is what PowerVM, the IBM proprietary hypervisor, adheres to.
The subset in LoPAR is selected based on the requirements of Linux as a guest.
@@ -18,8 +17,8 @@ running in the guest and QEMU.
All those hypercalls start at hcall number 0xf000 which correspond
to an implementation specific range in PAPR.
-H_RTAS (0xf000)
-^^^^^^^^^^^^^^^
+``H_RTAS (0xf000)``
+===================
RTAS stands for Run-Time Abstraction Sercies and is a set of runtime services
generally provided by the firmware inside the guest to the operating system. It
@@ -44,8 +43,8 @@ Returns:
``H_PARAMETER``: Unknown token.
-H_LOGICAL_MEMOP (0xf001)
-^^^^^^^^^^^^^^^^^^^^^^^^
+``H_LOGICAL_MEMOP (0xf001)``
+============================
When the guest runs in "real mode" (in powerpc terminology this means with MMU
disabled, i.e. guest effective address equals to guest physical address), it
diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst
index 72e315eff6..1689324815 100644
--- a/docs/system/ppc/pseries.rst
+++ b/docs/system/ppc/pseries.rst
@@ -1,19 +1,18 @@
+===================================
pSeries family boards (``pseries``)
===================================
-The Power machine para-virtualized environment described by the `Linux on Power
-Architecture Reference document (LoPAR)
-<https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_
-is called pSeries. This environment is also known as sPAPR, System p guests, or
-simply Power Linux guests (although it is capable of running other operating
-systems, such as AIX).
+The Power machine para-virtualized environment described by the Linux on Power
+Architecture Reference ([LoPAR]_) document is called pSeries. This environment
+is also known as sPAPR, System p guests, or simply Power Linux guests (although
+it is capable of running other operating systems, such as AIX).
Even though pSeries is designed to behave as a guest environment, it is also
capable of acting as a hypervisor OS, providing, on that role, nested
virtualization capabilities.
Supported devices
------------------
+=================
* Multi processor support for many Power processors generations: POWER7,
POWER7+, POWER8, POWER8NVL, POWER9, and Power10. Support for POWER5+ exists,
@@ -26,12 +25,12 @@ Supported devices
* PCIe device pass through.
Missing devices
----------------
+===============
* SPICE support.
Firmware
---------
+========
`SLOF <https://github.com/aik/SLOF>`_ (Slimline Open Firmware) is an
implementation of the `IEEE 1275-1994, Standard for Boot (Initialization
@@ -42,14 +41,14 @@ QEMU includes a prebuilt image of SLOF which is updated when a more recent
version is required.
Build directions
-----------------
+================
.. code-block:: bash
./configure --target-list=ppc64-softmmu && make
Running instructions
---------------------
+====================
Someone can select the pSeries machine type by running QEMU with the following
options:
@@ -59,7 +58,7 @@ options:
qemu-system-ppc64 -M pseries <other QEMU arguments>
sPAPR devices
--------------
+=============
The sPAPR specification defines a set of para-virtualized devices, which are
also supported by the pSeries machine in QEMU and can be instantiated with the
@@ -102,11 +101,9 @@ device, or specify one with an ID
NVRAM device with ``-global spapr-nvram.drive=pfid``.
sPAPR specification
-^^^^^^^^^^^^^^^^^^^
+-------------------
-The main source of documentation on the sPAPR standard is the `Linux on Power
-Architecture Reference document (LoPAR)
-<https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
+The main source of documentation on the sPAPR standard is the [LoPAR]_ document.
However, documentation specific to QEMU's implementation of the specification
can also be found in QEMU documentation:
@@ -124,7 +121,7 @@ Other documentation available in QEMU docs directory:
(``/docs/specs/ppc-spapr-uv-hcalls.txt``).
Switching between the KVM-PR and KVM-HV kernel module
------------------------------------------------------
+=====================================================
Currently, there are two implementations of KVM on Power, ``kvm_hv.ko`` and
``kvm_pr.ko``.
@@ -139,7 +136,7 @@ possible to switch between the two modes with the ``kvm-type`` parameter:
instead.
KVM-PR
-^^^^^^
+------
KVM-PR uses the so-called **PR**\ oblem state of the PPC CPUs to run the guests,
i.e. the virtual machine is run in user mode and all privileged instructions
@@ -166,7 +163,7 @@ In order to run KVM-PR guests with POWER9 processors, someone will need to start
QEMU with ``kernel_irqchip=off`` command line option.
KVM-HV
-^^^^^^
+------
KVM-HV uses the hypervisor mode of more recent Power processors, that allow
access to the bare metal hardware directly. Although POWER7 had this capability,
@@ -188,7 +185,7 @@ CPUs generations, e.g. you can run a POWER7 guest on a POWER8 host by using
``-cpu POWER8,compat=power7`` as parameter to QEMU.
Modules support
----------------
+===============
As noticed in the sections above, each module can run in a different
environment. The following table shows with which environment each module can
@@ -230,9 +227,45 @@ nested. Combinations not shown in the table are not available.
.. [3] Introduced on Power10 machines.
+
+POWER (PAPR) Protected Execution Facility (PEF)
+-----------------------------------------------
+
+Protected Execution Facility (PEF), also known as Secure Guest support
+is a feature found on IBM POWER9 and POWER10 processors.
+
+If a suitable firmware including an Ultravisor is installed, it adds
+an extra memory protection mode to the CPU. The ultravisor manages a
+pool of secure memory which cannot be accessed by the hypervisor.
+
+When this feature is enabled in QEMU, a guest can use ultracalls to
+enter "secure mode". This transfers most of its memory to secure
+memory, where it cannot be eavesdropped by a compromised hypervisor.
+
+Launching
+^^^^^^^^^
+
+To launch a guest which will be permitted to enter PEF secure mode::
+
+ $ qemu-system-ppc64 \
+ -object pef-guest,id=pef0 \
+ -machine confidential-guest-support=pef0 \
+ ...
+
+Live Migration
+^^^^^^^^^^^^^^
+
+Live migration is not yet implemented for PEF guests. For
+consistency, QEMU currently prevents migration if the PEF feature is
+enabled, whether or not the guest has actually entered secure mode.
+
+
Maintainer contact information
-------------------------------
+==============================
Cédric Le Goater <clg@kaod.org>
Daniel Henrique Barboza <danielhb413@gmail.com>
+
+.. [LoPAR] `Linux on Power Architecture Reference document (LoPAR) revision
+ 2.9 <https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index c78084cce7..7fb35dc031 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -19,6 +19,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
+#include "sysemu/sysemu.h"
#define phb3_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb3[%d:%d]: " fmt "\n", \
@@ -981,10 +982,6 @@ static void pnv_phb3_instance_init(Object *obj)
/* Power Bus Common Queue */
object_initialize_child(obj, "pbcq", &phb->pbcq, TYPE_PNV_PBCQ);
- /* Root Port */
- object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB3_ROOT_PORT);
- qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false);
}
static void pnv_phb3_realize(DeviceState *dev, Error **errp)
@@ -994,6 +991,30 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
int i;
+ /* User created devices */
+ if (!phb->chip) {
+ Error *local_err = NULL;
+ BusState *s;
+
+ phb->chip = pnv_get_chip(pnv, phb->chip_id);
+ if (!phb->chip) {
+ error_setg(errp, "invalid chip id: %d", phb->chip_id);
+ return;
+ }
+
+ /*
+ * Reparent user created devices to the chip to build
+ * correctly the device tree.
+ */
+ pnv_chip_parent_fixup(phb->chip, OBJECT(phb), phb->phb_id);
+
+ s = qdev_get_parent_bus(DEVICE(phb->chip));
+ if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) {
error_setg(errp, "invalid PHB index: %d", phb->phb_id);
return;
@@ -1053,10 +1074,10 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
- /* Add a single Root port */
- qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id);
- qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id);
- qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal);
+ if (defaults_enabled()) {
+ pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb),
+ TYPE_PNV_PHB3_ROOT_PORT);
+ }
}
void pnv_phb3_update_regions(PnvPHB3 *phb)
@@ -1107,7 +1128,7 @@ static void pnv_phb3_class_init(ObjectClass *klass, void *data)
dc->realize = pnv_phb3_realize;
device_class_set_props(dc, pnv_phb3_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->user_creatable = false;
+ dc->user_creatable = true;
}
static const TypeInfo pnv_phb3_type_info = {
@@ -1142,8 +1163,24 @@ static const TypeInfo pnv_phb3_root_bus_info = {
static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+ PCIDevice *pci = PCI_DEVICE(dev);
+ PCIBus *bus = pci_get_bus(pci);
+ PnvPHB3 *phb = NULL;
Error *local_err = NULL;
+ phb = (PnvPHB3 *) object_dynamic_cast(OBJECT(bus->qbus.parent),
+ TYPE_PNV_PHB3);
+
+ if (!phb) {
+ error_setg(errp,
+"pnv_phb3_root_port devices must be connected to pnv-phb3 buses");
+ return;
+ }
+
+ /* Set unique chassis/slot values for the root port */
+ qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
+ qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
+
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1161,7 +1198,7 @@ static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data)
device_class_set_parent_realize(dc, pnv_phb3_root_port_realize,
&rpc->parent_realize);
- dc->user_creatable = false;
+ dc->user_creatable = true;
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = 0x03dc;
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 5ba26e250a..a7b638831e 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -22,12 +22,17 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
+#include "sysemu/sysemu.h"
#include "trace.h"
#define phb_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \
(phb)->chip_id, (phb)->phb_id, ## __VA_ARGS__)
+#define phb_pec_error(pec, fmt, ...) \
+ qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \
+ (pec)->chip_id, (pec)->index, ## __VA_ARGS__)
+
/*
* QEMU version of the GETFIELD/SETFIELD macros
*
@@ -151,7 +156,10 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off,
}
pdev = pci_find_device(pci->bus, 0, 0);
- assert(pdev);
+ if (!pdev) {
+ phb_error(phb, "rc_config_write device not found\n");
+ return;
+ }
pci_host_config_write_common(pdev, off, PHB_RC_CONFIG_SIZE,
bswap32(val), 4);
@@ -170,7 +178,10 @@ static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off,
}
pdev = pci_find_device(pci->bus, 0, 0);
- assert(pdev);
+ if (!pdev) {
+ phb_error(phb, "rc_config_read device not found\n");
+ return ~0ull;
+ }
val = pci_host_config_read_common(pdev, off, PHB_RC_CONFIG_SIZE, 4);
return bswap32(val);
@@ -847,6 +858,284 @@ const MemoryRegionOps pnv_phb4_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
+ uint32_t reg = addr >> 3;
+
+ /* TODO: add list of allowed registers and error out if not */
+ return stack->nest_regs[reg];
+}
+
+static void pnv_phb4_update_regions(PnvPhb4PecStack *stack)
+{
+ PnvPHB4 *phb = stack->phb;
+
+ /* Unmap first always */
+ if (memory_region_is_mapped(&phb->mr_regs)) {
+ memory_region_del_subregion(&stack->phbbar, &phb->mr_regs);
+ }
+ if (memory_region_is_mapped(&phb->xsrc.esb_mmio)) {
+ memory_region_del_subregion(&stack->intbar, &phb->xsrc.esb_mmio);
+ }
+
+ /* Map registers if enabled */
+ if (memory_region_is_mapped(&stack->phbbar)) {
+ memory_region_add_subregion(&stack->phbbar, 0, &phb->mr_regs);
+ }
+
+ /* Map ESB if enabled */
+ if (memory_region_is_mapped(&stack->intbar)) {
+ memory_region_add_subregion(&stack->intbar, 0, &phb->xsrc.esb_mmio);
+ }
+
+ /* Check/update m32 */
+ pnv_phb4_check_all_mbt(phb);
+}
+
+static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack)
+{
+ PnvPhb4PecState *pec = stack->pec;
+ MemoryRegion *sysmem = get_system_memory();
+ uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN];
+ uint64_t bar, mask, size;
+ char name[64];
+
+ /*
+ * NOTE: This will really not work well if those are remapped
+ * after the PHB has created its sub regions. We could do better
+ * if we had a way to resize regions but we don't really care
+ * that much in practice as the stuff below really only happens
+ * once early during boot
+ */
+
+ /* Handle unmaps */
+ if (memory_region_is_mapped(&stack->mmbar0) &&
+ !(bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
+ memory_region_del_subregion(sysmem, &stack->mmbar0);
+ }
+ if (memory_region_is_mapped(&stack->mmbar1) &&
+ !(bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
+ memory_region_del_subregion(sysmem, &stack->mmbar1);
+ }
+ if (memory_region_is_mapped(&stack->phbbar) &&
+ !(bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
+ memory_region_del_subregion(sysmem, &stack->phbbar);
+ }
+ if (memory_region_is_mapped(&stack->intbar) &&
+ !(bar_en & PEC_NEST_STK_BAR_EN_INT)) {
+ memory_region_del_subregion(sysmem, &stack->intbar);
+ }
+
+ /* Update PHB */
+ pnv_phb4_update_regions(stack);
+
+ /* Handle maps */
+ if (!memory_region_is_mapped(&stack->mmbar0) &&
+ (bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
+ bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0] >> 8;
+ mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0_MASK];
+ size = ((~mask) >> 8) + 1;
+ snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio0",
+ pec->chip_id, pec->index, stack->stack_no);
+ memory_region_init(&stack->mmbar0, OBJECT(stack), name, size);
+ memory_region_add_subregion(sysmem, bar, &stack->mmbar0);
+ stack->mmio0_base = bar;
+ stack->mmio0_size = size;
+ }
+ if (!memory_region_is_mapped(&stack->mmbar1) &&
+ (bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
+ bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1] >> 8;
+ mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1_MASK];
+ size = ((~mask) >> 8) + 1;
+ snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio1",
+ pec->chip_id, pec->index, stack->stack_no);
+ memory_region_init(&stack->mmbar1, OBJECT(stack), name, size);
+ memory_region_add_subregion(sysmem, bar, &stack->mmbar1);
+ stack->mmio1_base = bar;
+ stack->mmio1_size = size;
+ }
+ if (!memory_region_is_mapped(&stack->phbbar) &&
+ (bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
+ bar = stack->nest_regs[PEC_NEST_STK_PHB_REGS_BAR] >> 8;
+ size = PNV_PHB4_NUM_REGS << 3;
+ snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-phb",
+ pec->chip_id, pec->index, stack->stack_no);
+ memory_region_init(&stack->phbbar, OBJECT(stack), name, size);
+ memory_region_add_subregion(sysmem, bar, &stack->phbbar);
+ }
+ if (!memory_region_is_mapped(&stack->intbar) &&
+ (bar_en & PEC_NEST_STK_BAR_EN_INT)) {
+ bar = stack->nest_regs[PEC_NEST_STK_INT_BAR] >> 8;
+ size = PNV_PHB4_MAX_INTs << 16;
+ snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-int",
+ stack->pec->chip_id, stack->pec->index, stack->stack_no);
+ memory_region_init(&stack->intbar, OBJECT(stack), name, size);
+ memory_region_add_subregion(sysmem, bar, &stack->intbar);
+ }
+
+ /* Update PHB */
+ pnv_phb4_update_regions(stack);
+}
+
+static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
+ PnvPhb4PecState *pec = stack->pec;
+ uint32_t reg = addr >> 3;
+
+ switch (reg) {
+ case PEC_NEST_STK_PCI_NEST_FIR:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_CLR:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_SET:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_MSK:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_MSKC:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_MSKS:
+ stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] |= val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_ACT0:
+ case PEC_NEST_STK_PCI_NEST_FIR_ACT1:
+ stack->nest_regs[reg] = val;
+ break;
+ case PEC_NEST_STK_PCI_NEST_FIR_WOF:
+ stack->nest_regs[reg] = 0;
+ break;
+ case PEC_NEST_STK_ERR_REPORT_0:
+ case PEC_NEST_STK_ERR_REPORT_1:
+ case PEC_NEST_STK_PBCQ_GNRL_STATUS:
+ /* Flag error ? */
+ break;
+ case PEC_NEST_STK_PBCQ_MODE:
+ stack->nest_regs[reg] = val & 0xff00000000000000ull;
+ break;
+ case PEC_NEST_STK_MMIO_BAR0:
+ case PEC_NEST_STK_MMIO_BAR0_MASK:
+ case PEC_NEST_STK_MMIO_BAR1:
+ case PEC_NEST_STK_MMIO_BAR1_MASK:
+ if (stack->nest_regs[PEC_NEST_STK_BAR_EN] &
+ (PEC_NEST_STK_BAR_EN_MMIO0 |
+ PEC_NEST_STK_BAR_EN_MMIO1)) {
+ phb_pec_error(pec, "Changing enabled BAR unsupported\n");
+ }
+ stack->nest_regs[reg] = val & 0xffffffffff000000ull;
+ break;
+ case PEC_NEST_STK_PHB_REGS_BAR:
+ if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) {
+ phb_pec_error(pec, "Changing enabled BAR unsupported\n");
+ }
+ stack->nest_regs[reg] = val & 0xffffffffffc00000ull;
+ break;
+ case PEC_NEST_STK_INT_BAR:
+ if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) {
+ phb_pec_error(pec, "Changing enabled BAR unsupported\n");
+ }
+ stack->nest_regs[reg] = val & 0xfffffff000000000ull;
+ break;
+ case PEC_NEST_STK_BAR_EN:
+ stack->nest_regs[reg] = val & 0xf000000000000000ull;
+ pnv_pec_stk_update_map(stack);
+ break;
+ case PEC_NEST_STK_DATA_FRZ_TYPE:
+ case PEC_NEST_STK_PBCQ_TUN_BAR:
+ /* Not used for now */
+ stack->nest_regs[reg] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx
+ "=%"PRIx64"\n", addr, val);
+ }
+}
+
+static const MemoryRegionOps pnv_pec_stk_nest_xscom_ops = {
+ .read = pnv_pec_stk_nest_xscom_read,
+ .write = pnv_pec_stk_nest_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
+ uint32_t reg = addr >> 3;
+
+ /* TODO: add list of allowed registers and error out if not */
+ return stack->pci_regs[reg];
+}
+
+static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
+ uint32_t reg = addr >> 3;
+
+ switch (reg) {
+ case PEC_PCI_STK_PCI_FIR:
+ stack->pci_regs[reg] = val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_CLR:
+ stack->pci_regs[PEC_PCI_STK_PCI_FIR] &= val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_SET:
+ stack->pci_regs[PEC_PCI_STK_PCI_FIR] |= val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_MSK:
+ stack->pci_regs[reg] = val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_MSKC:
+ stack->pci_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_MSKS:
+ stack->pci_regs[PEC_PCI_STK_PCI_FIR_MSK] |= val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_ACT0:
+ case PEC_PCI_STK_PCI_FIR_ACT1:
+ stack->pci_regs[reg] = val;
+ break;
+ case PEC_PCI_STK_PCI_FIR_WOF:
+ stack->pci_regs[reg] = 0;
+ break;
+ case PEC_PCI_STK_ETU_RESET:
+ stack->pci_regs[reg] = val & 0x8000000000000000ull;
+ /* TODO: Implement reset */
+ break;
+ case PEC_PCI_STK_PBAIB_ERR_REPORT:
+ break;
+ case PEC_PCI_STK_PBAIB_TX_CMD_CRED:
+ case PEC_PCI_STK_PBAIB_TX_DAT_CRED:
+ stack->pci_regs[reg] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx
+ "=%"PRIx64"\n", addr, val);
+ }
+}
+
+static const MemoryRegionOps pnv_pec_stk_pci_xscom_ops = {
+ .read = pnv_pec_stk_pci_xscom_read,
+ .write = pnv_pec_stk_pci_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
static int pnv_phb4_map_irq(PCIDevice *pci_dev, int irq_num)
{
/* Check that out properly ... */
@@ -1063,6 +1352,23 @@ static const TypeInfo pnv_phb4_iommu_memory_region_info = {
};
/*
+ * Return the index/phb-id of a PHB4 that belongs to a
+ * pec->stacks[stack_index] stack.
+ */
+int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index)
+{
+ PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ int index = pec->index;
+ int offset = 0;
+
+ while (index--) {
+ offset += pecc->num_stacks[index];
+ }
+
+ return offset + stack_index;
+}
+
+/*
* MSI/MSIX memory region implementation.
* The handler handles both MSI and MSIX.
*/
@@ -1151,6 +1457,52 @@ static AddressSpace *pnv_phb4_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &ds->dma_as;
}
+static void pnv_phb4_xscom_realize(PnvPHB4 *phb)
+{
+ PnvPhb4PecStack *stack = phb->stack;
+ PnvPhb4PecState *pec = stack->pec;
+ PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ uint32_t pec_nest_base;
+ uint32_t pec_pci_base;
+ char name[64];
+
+ assert(pec);
+
+ /* Initialize the XSCOM regions for the stack registers */
+ snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest-stack-%d",
+ pec->chip_id, pec->index, stack->stack_no);
+ pnv_xscom_region_init(&stack->nest_regs_mr, OBJECT(stack),
+ &pnv_pec_stk_nest_xscom_ops, stack, name,
+ PHB4_PEC_NEST_STK_REGS_COUNT);
+
+ snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d",
+ pec->chip_id, pec->index, stack->stack_no);
+ pnv_xscom_region_init(&stack->pci_regs_mr, OBJECT(stack),
+ &pnv_pec_stk_pci_xscom_ops, stack, name,
+ PHB4_PEC_PCI_STK_REGS_COUNT);
+
+ /* PHB pass-through */
+ snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d-phb",
+ pec->chip_id, pec->index, stack->stack_no);
+ pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(phb),
+ &pnv_phb4_xscom_ops, phb, name, 0x40);
+
+ pec_nest_base = pecc->xscom_nest_base(pec);
+ pec_pci_base = pecc->xscom_pci_base(pec);
+
+ /* Populate the XSCOM address space. */
+ pnv_xscom_add_subregion(pec->chip,
+ pec_nest_base + 0x40 * (stack->stack_no + 1),
+ &stack->nest_regs_mr);
+ pnv_xscom_add_subregion(pec->chip,
+ pec_pci_base + 0x40 * (stack->stack_no + 1),
+ &stack->pci_regs_mr);
+ pnv_xscom_add_subregion(pec->chip,
+ pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 +
+ 0x40 * stack->stack_no,
+ &stack->phb_regs_mr);
+}
+
static void pnv_phb4_instance_init(Object *obj)
{
PnvPHB4 *phb = PNV_PHB4(obj);
@@ -1159,12 +1511,35 @@ static void pnv_phb4_instance_init(Object *obj)
/* XIVE interrupt source object */
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
+}
- /* Root Port */
- object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB4_ROOT_PORT);
+static PnvPhb4PecStack *pnv_phb4_get_stack(PnvChip *chip, PnvPHB4 *phb,
+ Error **errp)
+{
+ Pnv9Chip *chip9 = PNV9_CHIP(chip);
+ int chip_id = phb->chip_id;
+ int index = phb->phb_id;
+ int i, j;
+
+ for (i = 0; i < chip->num_pecs; i++) {
+ /*
+ * For each PEC, check the amount of stacks it supports
+ * and see if the given phb4 index matches a stack.
+ */
+ PnvPhb4PecState *pec = &chip9->pecs[i];
- qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false);
+ for (j = 0; j < pec->num_stacks; j++) {
+ if (index == pnv_phb4_pec_get_phb_id(pec, j)) {
+ return &pec->stacks[j];
+ }
+ }
+ }
+
+ error_setg(errp,
+ "pnv-phb4 chip-id %d index %d didn't match any existing PEC",
+ chip_id, index);
+
+ return NULL;
}
static void pnv_phb4_realize(DeviceState *dev, Error **errp)
@@ -1172,10 +1547,51 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
PnvPHB4 *phb = PNV_PHB4(dev);
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
XiveSource *xsrc = &phb->xsrc;
+ Error *local_err = NULL;
int nr_irqs;
char name[32];
- assert(phb->stack);
+ /* User created PHB */
+ if (!phb->stack) {
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvChip *chip = pnv_get_chip(pnv, phb->chip_id);
+ PnvPhb4PecClass *pecc;
+ BusState *s;
+
+ if (!chip) {
+ error_setg(errp, "invalid chip id: %d", phb->chip_id);
+ return;
+ }
+
+ phb->stack = pnv_phb4_get_stack(chip, phb, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* All other phb properties but 'version' are already set */
+ pecc = PNV_PHB4_PEC_GET_CLASS(phb->stack->pec);
+ object_property_set_int(OBJECT(phb), "version", pecc->version,
+ &error_fatal);
+
+ /*
+ * Assign stack->phb since pnv_phb4_update_regions() uses it
+ * to access the phb.
+ */
+ phb->stack->phb = phb;
+
+ /*
+ * Reparent user created devices to the chip to build
+ * correctly the device tree.
+ */
+ pnv_chip_parent_fixup(chip, OBJECT(phb), phb->phb_id);
+
+ s = qdev_get_parent_bus(DEVICE(chip));
+ if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
/* Set the "big_phb" flag */
phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3;
@@ -1208,10 +1624,11 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
- /* Add a single Root port */
- qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id);
- qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id);
- qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal);
+ /* Add a single Root port if running with defaults */
+ if (defaults_enabled()) {
+ pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb),
+ TYPE_PNV_PHB4_ROOT_PORT);
+ }
/* Setup XIVE Source */
if (phb->big_phb) {
@@ -1228,6 +1645,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pnv_phb4_update_xsrc(phb);
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
+
+ pnv_phb4_xscom_realize(phb);
}
static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge,
@@ -1277,7 +1696,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data)
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->user_creatable = false;
+ dc->user_creatable = true;
xfc->notify = pnv_phb4_xive_notify;
}
@@ -1338,8 +1757,23 @@ static void pnv_phb4_root_port_reset(DeviceState *dev)
static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp)
{
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+ PCIDevice *pci = PCI_DEVICE(dev);
+ PCIBus *bus = pci_get_bus(pci);
+ PnvPHB4 *phb = NULL;
Error *local_err = NULL;
+ phb = (PnvPHB4 *) object_dynamic_cast(OBJECT(bus->qbus.parent),
+ TYPE_PNV_PHB4);
+
+ if (!phb) {
+ error_setg(errp, "%s must be connected to pnv-phb4 buses", dev->id);
+ return;
+ }
+
+ /* Set unique chassis/slot values for the root port */
+ qdev_prop_set_uint8(&pci->qdev, "chassis", phb->chip_id);
+ qdev_prop_set_uint16(&pci->qdev, "slot", phb->phb_id);
+
rpc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1354,7 +1788,7 @@ static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data)
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
dc->desc = "IBM PHB4 PCIE Root Port";
- dc->user_creatable = false;
+ dc->user_creatable = true;
device_class_set_parent_realize(dc, pnv_phb4_root_port_realize,
&rpc->parent_realize);
@@ -1388,32 +1822,6 @@ static void pnv_phb4_register_types(void)
type_init(pnv_phb4_register_types);
-void pnv_phb4_update_regions(PnvPhb4PecStack *stack)
-{
- PnvPHB4 *phb = &stack->phb;
-
- /* Unmap first always */
- if (memory_region_is_mapped(&phb->mr_regs)) {
- memory_region_del_subregion(&stack->phbbar, &phb->mr_regs);
- }
- if (memory_region_is_mapped(&phb->xsrc.esb_mmio)) {
- memory_region_del_subregion(&stack->intbar, &phb->xsrc.esb_mmio);
- }
-
- /* Map registers if enabled */
- if (memory_region_is_mapped(&stack->phbbar)) {
- memory_region_add_subregion(&stack->phbbar, 0, &phb->mr_regs);
- }
-
- /* Map ESB if enabled */
- if (memory_region_is_mapped(&stack->intbar)) {
- memory_region_add_subregion(&stack->intbar, 0, &phb->xsrc.esb_mmio);
- }
-
- /* Check/update m32 */
- pnv_phb4_check_all_mbt(phb);
-}
-
void pnv_phb4_pic_print_info(PnvPHB4 *phb, Monitor *mon)
{
uint32_t offset = phb->regs[PHB_INT_NOTIFY_INDEX >> 3];
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index f3e4fa0c82..7fe7f1f007 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -19,6 +19,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/ppc/pnv.h"
#include "hw/qdev-properties.h"
+#include "sysemu/sysemu.h"
#include <libfdt.h>
@@ -111,258 +112,6 @@ static const MemoryRegionOps pnv_pec_pci_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
- uint32_t reg = addr >> 3;
-
- /* TODO: add list of allowed registers and error out if not */
- return stack->nest_regs[reg];
-}
-
-static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack)
-{
- PnvPhb4PecState *pec = stack->pec;
- MemoryRegion *sysmem = get_system_memory();
- uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN];
- uint64_t bar, mask, size;
- char name[64];
-
- /*
- * NOTE: This will really not work well if those are remapped
- * after the PHB has created its sub regions. We could do better
- * if we had a way to resize regions but we don't really care
- * that much in practice as the stuff below really only happens
- * once early during boot
- */
-
- /* Handle unmaps */
- if (memory_region_is_mapped(&stack->mmbar0) &&
- !(bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
- memory_region_del_subregion(sysmem, &stack->mmbar0);
- }
- if (memory_region_is_mapped(&stack->mmbar1) &&
- !(bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
- memory_region_del_subregion(sysmem, &stack->mmbar1);
- }
- if (memory_region_is_mapped(&stack->phbbar) &&
- !(bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
- memory_region_del_subregion(sysmem, &stack->phbbar);
- }
- if (memory_region_is_mapped(&stack->intbar) &&
- !(bar_en & PEC_NEST_STK_BAR_EN_INT)) {
- memory_region_del_subregion(sysmem, &stack->intbar);
- }
-
- /* Update PHB */
- pnv_phb4_update_regions(stack);
-
- /* Handle maps */
- if (!memory_region_is_mapped(&stack->mmbar0) &&
- (bar_en & PEC_NEST_STK_BAR_EN_MMIO0)) {
- bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0] >> 8;
- mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR0_MASK];
- size = ((~mask) >> 8) + 1;
- snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio0",
- pec->chip_id, pec->index, stack->stack_no);
- memory_region_init(&stack->mmbar0, OBJECT(stack), name, size);
- memory_region_add_subregion(sysmem, bar, &stack->mmbar0);
- stack->mmio0_base = bar;
- stack->mmio0_size = size;
- }
- if (!memory_region_is_mapped(&stack->mmbar1) &&
- (bar_en & PEC_NEST_STK_BAR_EN_MMIO1)) {
- bar = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1] >> 8;
- mask = stack->nest_regs[PEC_NEST_STK_MMIO_BAR1_MASK];
- size = ((~mask) >> 8) + 1;
- snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-mmio1",
- pec->chip_id, pec->index, stack->stack_no);
- memory_region_init(&stack->mmbar1, OBJECT(stack), name, size);
- memory_region_add_subregion(sysmem, bar, &stack->mmbar1);
- stack->mmio1_base = bar;
- stack->mmio1_size = size;
- }
- if (!memory_region_is_mapped(&stack->phbbar) &&
- (bar_en & PEC_NEST_STK_BAR_EN_PHB)) {
- bar = stack->nest_regs[PEC_NEST_STK_PHB_REGS_BAR] >> 8;
- size = PNV_PHB4_NUM_REGS << 3;
- snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-phb",
- pec->chip_id, pec->index, stack->stack_no);
- memory_region_init(&stack->phbbar, OBJECT(stack), name, size);
- memory_region_add_subregion(sysmem, bar, &stack->phbbar);
- }
- if (!memory_region_is_mapped(&stack->intbar) &&
- (bar_en & PEC_NEST_STK_BAR_EN_INT)) {
- bar = stack->nest_regs[PEC_NEST_STK_INT_BAR] >> 8;
- size = PNV_PHB4_MAX_INTs << 16;
- snprintf(name, sizeof(name), "pec-%d.%d-stack-%d-int",
- stack->pec->chip_id, stack->pec->index, stack->stack_no);
- memory_region_init(&stack->intbar, OBJECT(stack), name, size);
- memory_region_add_subregion(sysmem, bar, &stack->intbar);
- }
-
- /* Update PHB */
- pnv_phb4_update_regions(stack);
-}
-
-static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
- PnvPhb4PecState *pec = stack->pec;
- uint32_t reg = addr >> 3;
-
- switch (reg) {
- case PEC_NEST_STK_PCI_NEST_FIR:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] = val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_CLR:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] &= val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_SET:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR] |= val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_MSK:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] = val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_MSKC:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] &= val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_MSKS:
- stack->nest_regs[PEC_NEST_STK_PCI_NEST_FIR_MSK] |= val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_ACT0:
- case PEC_NEST_STK_PCI_NEST_FIR_ACT1:
- stack->nest_regs[reg] = val;
- break;
- case PEC_NEST_STK_PCI_NEST_FIR_WOF:
- stack->nest_regs[reg] = 0;
- break;
- case PEC_NEST_STK_ERR_REPORT_0:
- case PEC_NEST_STK_ERR_REPORT_1:
- case PEC_NEST_STK_PBCQ_GNRL_STATUS:
- /* Flag error ? */
- break;
- case PEC_NEST_STK_PBCQ_MODE:
- stack->nest_regs[reg] = val & 0xff00000000000000ull;
- break;
- case PEC_NEST_STK_MMIO_BAR0:
- case PEC_NEST_STK_MMIO_BAR0_MASK:
- case PEC_NEST_STK_MMIO_BAR1:
- case PEC_NEST_STK_MMIO_BAR1_MASK:
- if (stack->nest_regs[PEC_NEST_STK_BAR_EN] &
- (PEC_NEST_STK_BAR_EN_MMIO0 |
- PEC_NEST_STK_BAR_EN_MMIO1)) {
- phb_pec_error(pec, "Changing enabled BAR unsupported\n");
- }
- stack->nest_regs[reg] = val & 0xffffffffff000000ull;
- break;
- case PEC_NEST_STK_PHB_REGS_BAR:
- if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) {
- phb_pec_error(pec, "Changing enabled BAR unsupported\n");
- }
- stack->nest_regs[reg] = val & 0xffffffffffc00000ull;
- break;
- case PEC_NEST_STK_INT_BAR:
- if (stack->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) {
- phb_pec_error(pec, "Changing enabled BAR unsupported\n");
- }
- stack->nest_regs[reg] = val & 0xfffffff000000000ull;
- break;
- case PEC_NEST_STK_BAR_EN:
- stack->nest_regs[reg] = val & 0xf000000000000000ull;
- pnv_pec_stk_update_map(stack);
- break;
- case PEC_NEST_STK_DATA_FRZ_TYPE:
- case PEC_NEST_STK_PBCQ_TUN_BAR:
- /* Not used for now */
- stack->nest_regs[reg] = val;
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "phb4_pec: nest_xscom_write 0x%"HWADDR_PRIx
- "=%"PRIx64"\n", addr, val);
- }
-}
-
-static const MemoryRegionOps pnv_pec_stk_nest_xscom_ops = {
- .read = pnv_pec_stk_nest_xscom_read,
- .write = pnv_pec_stk_nest_xscom_write,
- .valid.min_access_size = 8,
- .valid.max_access_size = 8,
- .impl.min_access_size = 8,
- .impl.max_access_size = 8,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static uint64_t pnv_pec_stk_pci_xscom_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
- uint32_t reg = addr >> 3;
-
- /* TODO: add list of allowed registers and error out if not */
- return stack->pci_regs[reg];
-}
-
-static void pnv_pec_stk_pci_xscom_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(opaque);
- uint32_t reg = addr >> 3;
-
- switch (reg) {
- case PEC_PCI_STK_PCI_FIR:
- stack->nest_regs[reg] = val;
- break;
- case PEC_PCI_STK_PCI_FIR_CLR:
- stack->nest_regs[PEC_PCI_STK_PCI_FIR] &= val;
- break;
- case PEC_PCI_STK_PCI_FIR_SET:
- stack->nest_regs[PEC_PCI_STK_PCI_FIR] |= val;
- break;
- case PEC_PCI_STK_PCI_FIR_MSK:
- stack->nest_regs[reg] = val;
- break;
- case PEC_PCI_STK_PCI_FIR_MSKC:
- stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] &= val;
- break;
- case PEC_PCI_STK_PCI_FIR_MSKS:
- stack->nest_regs[PEC_PCI_STK_PCI_FIR_MSK] |= val;
- break;
- case PEC_PCI_STK_PCI_FIR_ACT0:
- case PEC_PCI_STK_PCI_FIR_ACT1:
- stack->nest_regs[reg] = val;
- break;
- case PEC_PCI_STK_PCI_FIR_WOF:
- stack->nest_regs[reg] = 0;
- break;
- case PEC_PCI_STK_ETU_RESET:
- stack->nest_regs[reg] = val & 0x8000000000000000ull;
- /* TODO: Implement reset */
- break;
- case PEC_PCI_STK_PBAIB_ERR_REPORT:
- break;
- case PEC_PCI_STK_PBAIB_TX_CMD_CRED:
- case PEC_PCI_STK_PBAIB_TX_DAT_CRED:
- stack->nest_regs[reg] = val;
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "phb4_pec_stk: pci_xscom_write 0x%"HWADDR_PRIx
- "=%"PRIx64"\n", addr, val);
- }
-}
-
-static const MemoryRegionOps pnv_pec_stk_pci_xscom_ops = {
- .read = pnv_pec_stk_pci_xscom_read,
- .write = pnv_pec_stk_pci_xscom_write,
- .valid.min_access_size = 8,
- .valid.max_access_size = 8,
- .impl.min_access_size = 8,
- .impl.max_access_size = 8,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
static void pnv_pec_instance_init(Object *obj)
{
PnvPhb4PecState *pec = PNV_PHB4_PEC(obj);
@@ -374,19 +123,6 @@ static void pnv_pec_instance_init(Object *obj)
}
}
-static int pnv_pec_phb_offset(PnvPhb4PecState *pec)
-{
- PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
- int index = pec->index;
- int offset = 0;
-
- while (index--) {
- offset += pecc->num_stacks[index];
- }
-
- return offset;
-}
-
static void pnv_pec_realize(DeviceState *dev, Error **errp)
{
PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
@@ -405,10 +141,8 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp)
for (i = 0; i < pec->num_stacks; i++) {
PnvPhb4PecStack *stack = &pec->stacks[i];
Object *stk_obj = OBJECT(stack);
- int phb_id = pnv_pec_phb_offset(pec) + i;
object_property_set_int(stk_obj, "stack-no", i, &error_abort);
- object_property_set_int(stk_obj, "phb-id", phb_id, &error_abort);
object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort);
if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) {
return;
@@ -462,8 +196,7 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
pecc->compat_size)));
for (i = 0; i < pec->num_stacks; i++) {
- PnvPhb4PecStack *stack = &pec->stacks[i];
- PnvPHB4 *phb = &stack->phb;
+ int phb_id = pnv_phb4_pec_get_phb_id(pec, i);
int stk_offset;
name = g_strdup_printf("stack@%x", i);
@@ -473,7 +206,7 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
_FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat,
pecc->stk_compat_size)));
_FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i)));
- _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb->phb_id)));
+ _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb_id)));
}
return 0;
@@ -543,69 +276,38 @@ static const TypeInfo pnv_pec_type_info = {
}
};
-static void pnv_pec_stk_instance_init(Object *obj)
+static void pnv_pec_stk_default_phb_realize(PnvPhb4PecStack *stack,
+ Error **errp)
{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj);
-
- object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4);
- object_property_add_alias(obj, "phb-id", OBJECT(&stack->phb), "index");
-}
-
-static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
-{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev);
PnvPhb4PecState *pec = stack->pec;
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
- PnvChip *chip = pec->chip;
- uint32_t pec_nest_base;
- uint32_t pec_pci_base;
- char name[64];
-
- assert(pec);
-
- /* Initialize the XSCOM regions for the stack registers */
- snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest-stack-%d",
- pec->chip_id, pec->index, stack->stack_no);
- pnv_xscom_region_init(&stack->nest_regs_mr, OBJECT(stack),
- &pnv_pec_stk_nest_xscom_ops, stack, name,
- PHB4_PEC_NEST_STK_REGS_COUNT);
-
- snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d",
- pec->chip_id, pec->index, stack->stack_no);
- pnv_xscom_region_init(&stack->pci_regs_mr, OBJECT(stack),
- &pnv_pec_stk_pci_xscom_ops, stack, name,
- PHB4_PEC_PCI_STK_REGS_COUNT);
+ int phb_id = pnv_phb4_pec_get_phb_id(pec, stack->stack_no);
- /* PHB pass-through */
- snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-stack-%d-phb",
- pec->chip_id, pec->index, stack->stack_no);
- pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(&stack->phb),
- &pnv_phb4_xscom_ops, &stack->phb, name, 0x40);
+ stack->phb = PNV_PHB4(qdev_new(TYPE_PNV_PHB4));
- object_property_set_int(OBJECT(&stack->phb), "chip-id", pec->chip_id,
+ object_property_set_int(OBJECT(stack->phb), "chip-id", pec->chip_id,
&error_fatal);
- object_property_set_int(OBJECT(&stack->phb), "version", pecc->version,
+ object_property_set_int(OBJECT(stack->phb), "index", phb_id,
&error_fatal);
- object_property_set_link(OBJECT(&stack->phb), "stack", OBJECT(stack),
+ object_property_set_int(OBJECT(stack->phb), "version", pecc->version,
+ &error_fatal);
+ object_property_set_link(OBJECT(stack->phb), "stack", OBJECT(stack),
&error_abort);
- if (!sysbus_realize(SYS_BUS_DEVICE(&stack->phb), errp)) {
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(stack->phb), errp)) {
+ return;
+ }
+}
+
+static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
+{
+ PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev);
+
+ if (!defaults_enabled()) {
return;
}
- pec_nest_base = pecc->xscom_nest_base(pec);
- pec_pci_base = pecc->xscom_pci_base(pec);
-
- /* Populate the XSCOM address space. */
- pnv_xscom_add_subregion(chip,
- pec_nest_base + 0x40 * (stack->stack_no + 1),
- &stack->nest_regs_mr);
- pnv_xscom_add_subregion(chip,
- pec_pci_base + 0x40 * (stack->stack_no + 1),
- &stack->pci_regs_mr);
- pnv_xscom_add_subregion(chip,
- pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 +
- 0x40 * stack->stack_no,
- &stack->phb_regs_mr);
+ pnv_pec_stk_default_phb_realize(stack, errp);
}
static Property pnv_pec_stk_properties[] = {
@@ -630,7 +332,6 @@ static const TypeInfo pnv_pec_stk_type_info = {
.name = TYPE_PNV_PHB4_PEC_STACK,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvPhb4PecStack),
- .instance_init = pnv_pec_stk_instance_init,
.class_init = pnv_pec_stk_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 9de8b83530..837146a2fb 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1099,7 +1099,6 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
static void pnv_chip_power8_instance_init(Object *obj)
{
- PnvChip *chip = PNV_CHIP(obj);
Pnv8Chip *chip8 = PNV8_CHIP(obj);
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
int i;
@@ -1117,14 +1116,14 @@ static void pnv_chip_power8_instance_init(Object *obj)
object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER);
- for (i = 0; i < pcc->num_phbs; i++) {
+ if (defaults_enabled()) {
+ chip8->num_phbs = pcc->num_phbs;
+ }
+
+ for (i = 0; i < chip8->num_phbs; i++) {
object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3);
}
- /*
- * Number of PHBs is the chip default
- */
- chip->num_phbs = pcc->num_phbs;
}
static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
@@ -1156,6 +1155,14 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
}
}
+/* Attach a root port device */
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name)
+{
+ PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name);
+
+ pci_realize_and_unref(root, pci->bus, &error_fatal);
+}
+
static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
@@ -1239,7 +1246,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
&chip8->homer.regs);
/* PHB3 controllers */
- for (i = 0; i < chip->num_phbs; i++) {
+ for (i = 0; i < chip8->num_phbs; i++) {
PnvPHB3 *phb = &chip8->phbs[i];
object_property_set_int(OBJECT(phb), "index", i, &error_fatal);
@@ -1806,6 +1813,36 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
return NULL;
}
+void pnv_chip_parent_fixup(PnvChip *chip, Object *obj, int index)
+{
+ Object *parent = OBJECT(chip);
+ g_autofree char *default_id =
+ g_strdup_printf("%s[%d]", object_get_typename(obj), index);
+
+ if (obj->parent == parent) {
+ return;
+ }
+
+ object_ref(obj);
+ object_unparent(obj);
+ object_property_add_child(
+ parent, DEVICE(obj)->id ? DEVICE(obj)->id : default_id, obj);
+ object_unref(obj);
+}
+
+PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id)
+{
+ int i;
+
+ for (i = 0; i < pnv->num_chips; i++) {
+ PnvChip *chip = pnv->chips[i];
+ if (chip->chip_id == chip_id) {
+ return chip;
+ }
+ }
+ return NULL;
+}
+
static int pnv_ics_resend_child(Object *child, void *opaque)
{
PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
@@ -1903,6 +1940,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB3);
}
static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
@@ -1921,6 +1960,8 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB4);
}
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 8373429325..72f5dce751 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -723,10 +723,12 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
*
* Only CPUs for which we create core types in spapr_cpu_core.c
* are possible, and all of those have VMX */
- if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
- } else {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
+ if (env->insns_flags & PPC_ALTIVEC) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
+ } else {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
+ }
}
/* Advertise DFP (Decimal Floating Point) if available
diff --git a/include/hw/pci-host/pnv_phb3.h b/include/hw/pci-host/pnv_phb3.h
index e9c13e6bd8..af6ec83cf6 100644
--- a/include/hw/pci-host/pnv_phb3.h
+++ b/include/hw/pci-host/pnv_phb3.h
@@ -105,7 +105,7 @@ struct PnvPBCQState {
/*
* PHB3 PCIe Root port
*/
-#define TYPE_PNV_PHB3_ROOT_BUS "pnv-phb3-root-bus"
+#define TYPE_PNV_PHB3_ROOT_BUS "pnv-phb3-root"
#define TYPE_PNV_PHB3_ROOT_PORT "pnv-phb3-root-port"
@@ -155,8 +155,6 @@ struct PnvPHB3 {
PnvPBCQState pbcq;
- PnvPHB3RootPort root;
-
QLIST_HEAD(, PnvPhb3DMASpace) dma_spaces;
PnvChip *chip;
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 4a19338db3..4b7ce8a723 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -15,6 +15,7 @@
#include "hw/ppc/xive.h"
#include "qom/object.h"
+typedef struct PnvPhb4PecState PnvPhb4PecState;
typedef struct PnvPhb4PecStack PnvPhb4PecStack;
typedef struct PnvPHB4 PnvPHB4;
typedef struct PnvChip PnvChip;
@@ -46,7 +47,7 @@ typedef struct PnvPhb4DMASpace {
/*
* PHB4 PCIe Root port
*/
-#define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root-bus"
+#define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root"
#define TYPE_PNV_PHB4_ROOT_PORT "pnv-phb4-root-port"
typedef struct PnvPHB4RootPort {
@@ -78,8 +79,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
struct PnvPHB4 {
PCIExpressHost parent_obj;
- PnvPHB4RootPort root;
-
uint32_t chip_id;
uint32_t phb_id;
@@ -132,7 +131,7 @@ struct PnvPHB4 {
};
void pnv_phb4_pic_print_info(PnvPHB4 *phb, Monitor *mon);
-void pnv_phb4_update_regions(PnvPhb4PecStack *stack);
+int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
extern const MemoryRegionOps pnv_phb4_xscom_ops;
/*
@@ -177,8 +176,11 @@ struct PnvPhb4PecStack {
/* The owner PEC */
PnvPhb4PecState *pec;
- /* The actual PHB */
- PnvPHB4 phb;
+ /*
+ * PHB4 pointer. pnv_phb4_update_regions() needs to access
+ * the PHB4 via a PnvPhb4PecStack pointer.
+ */
+ PnvPHB4 *phb;
};
struct PnvPhb4PecState {
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index c781525277..0e9e16544f 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -52,7 +52,6 @@ struct PnvChip {
uint64_t cores_mask;
PnvCore **cores;
- uint32_t num_phbs;
uint32_t num_pecs;
MemoryRegion xscom_mmio;
@@ -82,6 +81,7 @@ struct Pnv8Chip {
#define PNV8_CHIP_PHB3_MAX 4
PnvPHB3 phbs[PNV8_CHIP_PHB3_MAX];
+ uint32_t num_phbs;
XICSFabric *xics;
};
@@ -136,8 +136,8 @@ struct PnvChipClass {
/*< public >*/
uint64_t chip_cfam_id;
uint64_t cores_mask;
- uint32_t num_phbs;
uint32_t num_pecs;
+ uint32_t num_phbs;
DeviceRealize parent_realize;
@@ -177,6 +177,8 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
TYPE_PNV_CHIP_POWER10)
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name);
+void pnv_chip_parent_fixup(PnvChip *chip, Object *obj, int index);
#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
typedef struct PnvMachineClass PnvMachineClass;
@@ -217,6 +219,8 @@ struct PnvMachineState {
hwaddr fw_load_addr;
};
+PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
+
#define PNV_FDT_ADDR 0x01000000
#define PNV_TIMEBASE_FREQ 512000000ULL
diff --git a/linux-user/aarch64/target_structs.h b/linux-user/aarch64/target_structs.h
index 7c748344ca..3a06f373c3 100644
--- a/linux-user/aarch64/target_structs.h
+++ b/linux-user/aarch64/target_structs.h
@@ -1,58 +1 @@
-/*
- * ARM AArch64 specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 AARCH64_TARGET_STRUCTS_H
-#define AARCH64_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c
index 37c33f0ccd..de6e0c901c 100644
--- a/linux-user/alpha/cpu_loop.c
+++ b/linux-user/alpha/cpu_loop.c
@@ -27,8 +27,7 @@
void cpu_loop(CPUAlphaState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr;
- target_siginfo_t info;
+ int trapnr, si_code;
abi_long sysret;
while (1) {
@@ -56,18 +55,10 @@ void cpu_loop(CPUAlphaState *env)
break;
case EXCP_OPCDEC:
do_sigill:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case EXCP_ARITH:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTINV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_FLTINV, env->pc);
break;
case EXCP_FEN:
/* No-op. Linux simply re-enables the FPU. */
@@ -76,20 +67,10 @@ void cpu_loop(CPUAlphaState *env)
switch (env->error_code) {
case 0x80:
/* BPT */
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
+ goto do_sigtrap_brkpt;
case 0x81:
/* BUGCHK */
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
+ goto do_sigtrap_unk;
case 0x83:
/* CALLSYS */
trapnr = env->ir[IR_V0];
@@ -130,47 +111,43 @@ void cpu_loop(CPUAlphaState *env)
abort();
case 0xAA:
/* GENTRAP */
- info.si_signo = TARGET_SIGFPE;
switch (env->ir[IR_A0]) {
case TARGET_GEN_INTOVF:
- info.si_code = TARGET_FPE_INTOVF;
+ si_code = TARGET_FPE_INTOVF;
break;
case TARGET_GEN_INTDIV:
- info.si_code = TARGET_FPE_INTDIV;
+ si_code = TARGET_FPE_INTDIV;
break;
case TARGET_GEN_FLTOVF:
- info.si_code = TARGET_FPE_FLTOVF;
+ si_code = TARGET_FPE_FLTOVF;
break;
case TARGET_GEN_FLTUND:
- info.si_code = TARGET_FPE_FLTUND;
+ si_code = TARGET_FPE_FLTUND;
break;
case TARGET_GEN_FLTINV:
- info.si_code = TARGET_FPE_FLTINV;
+ si_code = TARGET_FPE_FLTINV;
break;
case TARGET_GEN_FLTINE:
- info.si_code = TARGET_FPE_FLTRES;
+ si_code = TARGET_FPE_FLTRES;
break;
case TARGET_GEN_ROPRAND:
- info.si_code = 0;
+ si_code = TARGET_FPE_FLTUNK;
break;
default:
- info.si_signo = TARGET_SIGTRAP;
- info.si_code = 0;
- break;
+ goto do_sigtrap_unk;
}
- info.si_errno = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
break;
default:
goto do_sigill;
}
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ do_sigtrap_brkpt:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+ break;
+ do_sigtrap_unk:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_UNK, env->pc);
break;
case EXCP_INTERRUPT:
/* Just indicate that signals should be handled asap. */
diff --git a/linux-user/arm/target_structs.h b/linux-user/arm/target_structs.h
index 339b070bf1..3a06f373c3 100644
--- a/linux-user/arm/target_structs.h
+++ b/linux-user/arm/target_structs.h
@@ -1,59 +1 @@
-/*
- * ARM specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 ARM_TARGET_STRUCTS_H
-#define ARM_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
- abi_ulong __unused1;
- abi_ulong shm_dtime; /* time of last shmdt() */
- abi_ulong __unused2;
- abi_ulong shm_ctime; /* time of last change by shmctl() */
- abi_ulong __unused3;
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-struct target_oabi_flock64 {
- abi_short l_type;
- abi_short l_whence;
- abi_llong l_start;
- abi_llong l_len;
- abi_int l_pid;
-} QEMU_PACKED;
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
index 5213aebf55..0f46b3c1a8 100644
--- a/linux-user/cris/cpu_loop.c
+++ b/linux-user/cris/cpu_loop.c
@@ -28,8 +28,7 @@ void cpu_loop(CPUCRISState *env)
{
CPUState *cs = env_cpu(env);
int trapnr, ret;
- target_siginfo_t info;
-
+
while (1) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
@@ -38,8 +37,8 @@ void cpu_loop(CPUCRISState *env)
switch (trapnr) {
case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
+ /* just indicate that signals should be handled asap */
+ break;
case EXCP_BREAK:
ret = do_syscall(env,
env->regs[9],
@@ -57,10 +56,7 @@ void cpu_loop(CPUCRISState *env)
}
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/cris/target_structs.h b/linux-user/cris/target_structs.h
index f949d2331e..3a06f373c3 100644
--- a/linux-user/cris/target_structs.h
+++ b/linux-user/cris/target_structs.h
@@ -1,58 +1 @@
-/*
- * CRIS specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 CRIS_TARGET_STRUCTS_H
-#define CRIS_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/generic/target_structs.h b/linux-user/generic/target_structs.h
new file mode 100644
index 0000000000..09ff858b6e
--- /dev/null
+++ b/linux-user/generic/target_structs.h
@@ -0,0 +1,58 @@
+/*
+ * Generic structures for linux-user
+ *
+ * Copyright (c) 2013 Fabrice Bellard
+ *
+ * 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 GENERIC_TARGET_STRUCTS_H
+#define GENERIC_TARGET_STRUCTS_H
+
+struct target_ipc_perm {
+ abi_int __key; /* Key. */
+ abi_uint uid; /* Owner's user ID. */
+ abi_uint gid; /* Owner's group ID. */
+ abi_uint cuid; /* Creator's user ID. */
+ abi_uint cgid; /* Creator's group ID. */
+ abi_ushort mode; /* Read/write permission. */
+ abi_ushort __pad1;
+ abi_ushort __seq; /* Sequence number. */
+ abi_ushort __pad2;
+ abi_ulong __unused1;
+ abi_ulong __unused2;
+};
+
+struct target_shmid_ds {
+ struct target_ipc_perm shm_perm; /* operation permission struct */
+ abi_long shm_segsz; /* size of segment in bytes */
+ abi_ulong shm_atime; /* time of last shmat() */
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused1;
+#endif
+ abi_ulong shm_dtime; /* time of last shmdt() */
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused2;
+#endif
+ abi_ulong shm_ctime; /* time of last change by shmctl() */
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused3;
+#endif
+ abi_int shm_cpid; /* pid of creator */
+ abi_int shm_lpid; /* pid of last shmop */
+ abi_ulong shm_nattch; /* number of current attaches */
+ abi_ulong __unused4;
+ abi_ulong __unused5;
+};
+
+#endif
diff --git a/linux-user/hexagon/target_structs.h b/linux-user/hexagon/target_structs.h
index c217d9442a..3a06f373c3 100644
--- a/linux-user/hexagon/target_structs.h
+++ b/linux-user/hexagon/target_structs.h
@@ -1,54 +1 @@
-/*
- * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Hexagon specific structures for linux-user
- */
-#ifndef HEXAGON_TARGET_STRUCTS_H
-#define HEXAGON_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
- abi_ulong __unused1;
- abi_ulong shm_dtime; /* time of last shmdt() */
- abi_ulong __unused2;
- abi_ulong shm_ctime; /* time of last change by shmctl() */
- abi_ulong __unused3;
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index a47a63176b..a576d1a249 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -110,7 +110,6 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
void cpu_loop(CPUHPPAState *env)
{
CPUState *cs = env_cpu(env);
- target_siginfo_t info;
abi_ulong ret;
int trapnr;
@@ -145,28 +144,25 @@ void cpu_loop(CPUHPPAState *env)
env->iaoq_b = env->gr[31] + 4;
break;
case EXCP_ILL:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->iaoq_f);
+ break;
case EXCP_PRIV_OPR:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f);
+ break;
case EXCP_PRIV_REG:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->iaoq_f;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f);
break;
case EXCP_OVERFLOW:
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->iaoq_f);
+ break;
case EXCP_COND:
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
+ break;
case EXCP_ASSIST:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->iaoq_f;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 9aaae93e2f..29dfd7cd0c 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -84,17 +84,6 @@ static void set_idt(int n, unsigned int dpl)
}
#endif
-static void gen_signal(CPUX86State *env, int sig, int code, abi_ptr addr)
-{
- target_siginfo_t info = {
- .si_signo = sig,
- .si_code = code,
- ._sifields._sigfault._addr = addr
- };
-
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
#ifdef TARGET_X86_64
static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len)
{
@@ -107,7 +96,7 @@ static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len)
}
env->error_code = PG_ERROR_W_MASK | PG_ERROR_U_MASK;
- gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, addr);
+ force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, addr);
return false;
}
@@ -193,11 +182,21 @@ static void emulate_vsyscall(CPUX86State *env)
return;
sigsegv:
- /* Like force_sig(SIGSEGV). */
- gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0);
+ force_sig(TARGET_SIGSEGV);
}
#endif
+static bool maybe_handle_vm86_trap(CPUX86State *env, int trapnr)
+{
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ return true;
+ }
+#endif
+ return false;
+}
+
void cpu_loop(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
@@ -255,65 +254,54 @@ void cpu_loop(CPUX86State *env)
#endif
case EXCP0B_NOSEG:
case EXCP0C_STACK:
- gen_signal(env, TARGET_SIGBUS, TARGET_SI_KERNEL, 0);
+ force_sig(TARGET_SIGBUS);
break;
case EXCP0D_GPF:
/* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_fault(env);
+ if (maybe_handle_vm86_trap(env, trapnr)) {
break;
}
-#endif
- gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0);
+ force_sig(TARGET_SIGSEGV);
break;
case EXCP0E_PAGE:
- gen_signal(env, TARGET_SIGSEGV,
- (env->error_code & 1 ?
- TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR),
- env->cr[2]);
+ force_sig_fault(TARGET_SIGSEGV,
+ (env->error_code & PG_ERROR_P_MASK ?
+ TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR),
+ env->cr[2]);
break;
case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
+ if (maybe_handle_vm86_trap(env, trapnr)) {
break;
}
-#endif
- gen_signal(env, TARGET_SIGFPE, TARGET_FPE_INTDIV, env->eip);
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->eip);
break;
case EXCP01_DB:
- case EXCP03_INT3:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
+ if (maybe_handle_vm86_trap(env, trapnr)) {
break;
}
-#endif
- if (trapnr == EXCP01_DB) {
- gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->eip);
- } else {
- gen_signal(env, TARGET_SIGTRAP, TARGET_SI_KERNEL, 0);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->eip);
+ break;
+ case EXCP03_INT3:
+ if (maybe_handle_vm86_trap(env, trapnr)) {
+ break;
}
+ force_sig(TARGET_SIGTRAP);
break;
case EXCP04_INTO:
case EXCP05_BOUND:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
+ if (maybe_handle_vm86_trap(env, trapnr)) {
break;
}
-#endif
- gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0);
+ force_sig(TARGET_SIGSEGV);
break;
case EXCP06_ILLOP:
- gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPN, env->eip);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->eip);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
- gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, 0);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->eip);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/i386/target_structs.h b/linux-user/i386/target_structs.h
index e22847fd20..3a06f373c3 100644
--- a/linux-user/i386/target_structs.h
+++ b/linux-user/i386/target_structs.h
@@ -1,58 +1 @@
-/*
- * i386 specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 I386_TARGET_STRUCTS_H
-#define I386_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index 3181594414..928a18e3cf 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -29,7 +29,6 @@ void cpu_loop(CPUM68KState *env)
CPUState *cs = env_cpu(env);
int trapnr;
unsigned int n;
- target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
@@ -46,25 +45,13 @@ void cpu_loop(CPUM68KState *env)
case EXCP_ILLEGAL:
case EXCP_LINEA:
case EXCP_LINEF:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
break;
case EXCP_CHK:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTOVF;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
break;
case EXCP_DIV0:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
case EXCP_TRAP0:
{
@@ -91,10 +78,7 @@ void cpu_loop(CPUM68KState *env)
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/m68k/target_structs.h b/linux-user/m68k/target_structs.h
index e373d481e1..3a06f373c3 100644
--- a/linux-user/m68k/target_structs.h
+++ b/linux-user/m68k/target_structs.h
@@ -1,58 +1 @@
-/*
- * m68k specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 M68K_TARGET_STRUCTS_H
-#define M68K_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c
index ff1fb26c8b..1a2556be2c 100644
--- a/linux-user/microblaze/cpu_loop.c
+++ b/linux-user/microblaze/cpu_loop.c
@@ -27,9 +27,8 @@
void cpu_loop(CPUMBState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr, ret;
- target_siginfo_t info;
-
+ int trapnr, ret, si_code;
+
while (1) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
@@ -38,8 +37,8 @@ void cpu_loop(CPUMBState *env)
switch (trapnr) {
case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
+ /* just indicate that signals should be handled asap */
+ break;
case EXCP_SYSCALL:
/* Return address is 4 bytes after the call. */
env->regs[14] += 4;
@@ -67,6 +66,7 @@ void cpu_loop(CPUMBState *env)
*/
env->regs[14] = env->pc;
break;
+
case EXCP_HW_EXCP:
env->regs[17] = env->pc + 4;
if (env->iflags & D_FLAG) {
@@ -74,42 +74,41 @@ void cpu_loop(CPUMBState *env)
env->pc -= 4;
/* FIXME: if branch was immed, replay the imm as well. */
}
-
env->iflags &= ~(IMM_FLAG | D_FLAG);
-
switch (env->esr & 31) {
- case ESR_EC_DIVZERO:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTDIV;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case ESR_EC_FPU:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- if (env->fsr & FSR_IO) {
- info.si_code = TARGET_FPE_FLTINV;
- }
- if (env->fsr & FSR_DZ) {
- info.si_code = TARGET_FPE_FLTDIV;
- }
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- default:
- fprintf(stderr, "Unhandled hw-exception: 0x%x\n",
- env->esr & ESR_EC_MASK);
- cpu_dump_state(cs, stderr, 0);
- exit(EXIT_FAILURE);
- break;
+ case ESR_EC_DIVZERO:
+ si_code = TARGET_FPE_INTDIV;
+ break;
+ case ESR_EC_FPU:
+ /*
+ * Note that the kernel passes along fsr as si_code
+ * if there's no recognized bit set. Possibly this
+ * implies that si_code is 0, but follow the structure.
+ */
+ si_code = env->fsr;
+ if (si_code & FSR_IO) {
+ si_code = TARGET_FPE_FLTINV;
+ } else if (si_code & FSR_OF) {
+ si_code = TARGET_FPE_FLTOVF;
+ } else if (si_code & FSR_UF) {
+ si_code = TARGET_FPE_FLTUND;
+ } else if (si_code & FSR_DZ) {
+ si_code = TARGET_FPE_FLTDIV;
+ } else if (si_code & FSR_DO) {
+ si_code = TARGET_FPE_FLTRES;
+ }
+ break;
+ default:
+ fprintf(stderr, "Unhandled hw-exception: 0x%x\n",
+ env->esr & ESR_EC_MASK);
+ cpu_dump_state(cs, stderr, 0);
+ exit(EXIT_FAILURE);
}
+ force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
break;
+
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/microblaze/target_structs.h b/linux-user/microblaze/target_structs.h
index d08f6a53a8..3a06f373c3 100644
--- a/linux-user/microblaze/target_structs.h
+++ b/linux-user/microblaze/target_structs.h
@@ -1,58 +1 @@
-/*
- * MicroBlaze specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 MICROBLAZE_TARGET_STRUCTS_H
-#define MICROBLAZE_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
index 32f9fc1c1c..9bb12a07ba 100644
--- a/linux-user/mips/cpu_loop.c
+++ b/linux-user/mips/cpu_loop.c
@@ -40,36 +40,32 @@ enum {
BRK_DIVZERO = 7
};
-static int do_break(CPUMIPSState *env, target_siginfo_t *info,
- unsigned int code)
+static void do_tr_or_bp(CPUMIPSState *env, unsigned int code, bool trap)
{
- int ret = -1;
+ target_ulong pc = env->active_tc.PC;
switch (code) {
case BRK_OVERFLOW:
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, pc);
+ break;
case BRK_DIVZERO:
- info->si_signo = TARGET_SIGFPE;
- info->si_errno = 0;
- info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
- queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
- ret = 0;
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, pc);
break;
default:
- info->si_signo = TARGET_SIGTRAP;
- info->si_errno = 0;
- queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
- ret = 0;
+ if (trap) {
+ force_sig(TARGET_SIGTRAP);
+ } else {
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, pc);
+ }
break;
}
-
- return ret;
}
void cpu_loop(CPUMIPSState *env)
{
CPUState *cs = env_cpu(env);
- target_siginfo_t info;
- int trapnr;
+ int trapnr, si_code;
+ unsigned int code;
abi_long ret;
# ifdef TARGET_ABI_MIPSO32
unsigned int syscall_num;
@@ -160,149 +156,53 @@ done_syscall:
break;
case EXCP_CpU:
case EXCP_RI:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ case EXCP_DSPDIS:
+ force_sig(TARGET_SIGILL);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_DSPDIS:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT,
+ env->active_tc.PC);
break;
case EXCP_FPE:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTUNK;
+ si_code = TARGET_FPE_FLTUNK;
if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {
- info.si_code = TARGET_FPE_FLTINV;
+ si_code = TARGET_FPE_FLTINV;
} else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_DIV0) {
- info.si_code = TARGET_FPE_FLTDIV;
+ si_code = TARGET_FPE_FLTDIV;
} else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_OVERFLOW) {
- info.si_code = TARGET_FPE_FLTOVF;
+ si_code = TARGET_FPE_FLTOVF;
} else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_UNDERFLOW) {
- info.si_code = TARGET_FPE_FLTUND;
+ si_code = TARGET_FPE_FLTUND;
} else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INEXACT) {
- info.si_code = TARGET_FPE_FLTRES;
+ si_code = TARGET_FPE_FLTRES;
}
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, si_code, env->active_tc.PC);
break;
+
/* The code below was inspired by the MIPS Linux kernel trap
* handling code in arch/mips/kernel/traps.c.
*/
case EXCP_BREAK:
- {
- abi_ulong trap_instr;
- unsigned int code;
-
- if (env->hflags & MIPS_HFLAG_M16) {
- if (env->insn_flags & ASE_MICROMIPS) {
- /* microMIPS mode */
- ret = get_user_u16(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
-
- if ((trap_instr >> 10) == 0x11) {
- /* 16-bit instruction */
- code = trap_instr & 0xf;
- } else {
- /* 32-bit instruction */
- abi_ulong instr_lo;
-
- ret = get_user_u16(instr_lo,
- env->active_tc.PC + 2);
- if (ret != 0) {
- goto error;
- }
- trap_instr = (trap_instr << 16) | instr_lo;
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- /* Unfortunately, microMIPS also suffers from
- the old assembler bug... */
- if (code >= (1 << 10)) {
- code >>= 10;
- }
- }
- } else {
- /* MIPS16e mode */
- ret = get_user_u16(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
- code = (trap_instr >> 6) & 0x3f;
- }
- } else {
- ret = get_user_u32(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
-
- /* As described in the original Linux kernel code, the
- * below checks on 'code' are to work around an old
- * assembly bug.
- */
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- if (code >= (1 << 10)) {
- code >>= 10;
- }
- }
-
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
+ /*
+ * As described in the original Linux kernel code, the below
+ * checks on 'code' are to work around an old assembly bug.
+ */
+ code = env->error_code;
+ if (code >= (1 << 10)) {
+ code >>= 10;
}
+ do_tr_or_bp(env, code, false);
break;
case EXCP_TRAP:
- {
- abi_ulong trap_instr;
- unsigned int code = 0;
-
- if (env->hflags & MIPS_HFLAG_M16) {
- /* microMIPS mode */
- abi_ulong instr[2];
-
- ret = get_user_u16(instr[0], env->active_tc.PC) ||
- get_user_u16(instr[1], env->active_tc.PC + 2);
-
- trap_instr = (instr[0] << 16) | instr[1];
- } else {
- ret = get_user_u32(trap_instr, env->active_tc.PC);
- }
-
- if (ret != 0) {
- goto error;
- }
-
- /* The immediate versions don't provide a code. */
- if (!(trap_instr & 0xFC000000)) {
- if (env->hflags & MIPS_HFLAG_M16) {
- /* microMIPS mode */
- code = ((trap_instr >> 12) & ((1 << 4) - 1));
- } else {
- code = ((trap_instr >> 6) & ((1 << 10) - 1));
- }
- }
-
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
- }
+ do_tr_or_bp(env, env->error_code, true);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
default:
-error:
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
diff --git a/linux-user/nios2/target_structs.h b/linux-user/nios2/target_structs.h
index daa2886f98..3a06f373c3 100644
--- a/linux-user/nios2/target_structs.h
+++ b/linux-user/nios2/target_structs.h
@@ -1,58 +1 @@
-/*
- * Nios2 specific structures for linux-user
- *
- * Copyright (c) 2016 Marek Vasut <marex@denx.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/>.
- */
-#ifndef NIOS2_TARGET_STRUCTS_H
-#define NIOS2_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c
index 592901a68b..7683bea064 100644
--- a/linux-user/openrisc/cpu_loop.c
+++ b/linux-user/openrisc/cpu_loop.c
@@ -29,7 +29,6 @@ void cpu_loop(CPUOpenRISCState *env)
CPUState *cs = env_cpu(env);
int trapnr;
abi_long ret;
- target_siginfo_t info;
for (;;) {
cpu_exec_start(cs);
@@ -55,27 +54,16 @@ void cpu_loop(CPUOpenRISCState *env)
}
break;
case EXCP_ALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, env->eear);
break;
case EXCP_ILLEGAL:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case EXCP_INTERRUPT:
/* We processed the pending cpu work above. */
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/openrisc/target_structs.h b/linux-user/openrisc/target_structs.h
index e98e2bc799..3a06f373c3 100644
--- a/linux-user/openrisc/target_structs.h
+++ b/linux-user/openrisc/target_structs.h
@@ -1,58 +1 @@
-/*
- * OpenRISC specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 OPENRISC_TARGET_STRUCTS_H
-#define OPENRISC_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 30c82f2354..46e6ffd6d3 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -76,8 +76,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
void cpu_loop(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
- target_siginfo_t info;
- int trapnr;
+ int trapnr, si_signo, si_code;
target_ulong ret;
for(;;) {
@@ -102,61 +101,10 @@ void cpu_loop(CPUPPCState *env)
"Aborting\n");
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- /* XXX: check this. Seems bugged */
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- case 0x42000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x04000000:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLADR;
- break;
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
- env->error_code);
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = env->spr[SPR_DAR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- /* XXX: check this */
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x10000000:
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
- env->error_code);
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ /* FIXME: handle maperr in ppc_cpu_record_sigsegv. */
+ force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
+ env->spr[SPR_DAR]);
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
cpu_abort(cs, "External interrupt while in user mode. "
@@ -167,24 +115,23 @@ void cpu_loop(CPUPPCState *env)
/* XXX: check this */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
+ si_signo = TARGET_SIGFPE;
switch (env->error_code & 0xF) {
case POWERPC_EXCP_FP_OX:
- info.si_code = TARGET_FPE_FLTOVF;
+ si_code = TARGET_FPE_FLTOVF;
break;
case POWERPC_EXCP_FP_UX:
- info.si_code = TARGET_FPE_FLTUND;
+ si_code = TARGET_FPE_FLTUND;
break;
case POWERPC_EXCP_FP_ZX:
case POWERPC_EXCP_FP_VXZDZ:
- info.si_code = TARGET_FPE_FLTDIV;
+ si_code = TARGET_FPE_FLTDIV;
break;
case POWERPC_EXCP_FP_XX:
- info.si_code = TARGET_FPE_FLTRES;
+ si_code = TARGET_FPE_FLTRES;
break;
case POWERPC_EXCP_FP_VXSOFT:
- info.si_code = TARGET_FPE_FLTINV;
+ si_code = TARGET_FPE_FLTINV;
break;
case POWERPC_EXCP_FP_VXSNAN:
case POWERPC_EXCP_FP_VXISI:
@@ -193,51 +140,50 @@ void cpu_loop(CPUPPCState *env)
case POWERPC_EXCP_FP_VXVC:
case POWERPC_EXCP_FP_VXSQRT:
case POWERPC_EXCP_FP_VXCVI:
- info.si_code = TARGET_FPE_FLTSUB;
+ si_code = TARGET_FPE_FLTSUB;
break;
default:
EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
env->error_code);
+ si_code = 0;
break;
}
break;
case POWERPC_EXCP_INVAL:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
+ si_signo = TARGET_SIGILL;
switch (env->error_code & 0xF) {
case POWERPC_EXCP_INVAL_INVAL:
- info.si_code = TARGET_ILL_ILLOPC;
+ si_code = TARGET_ILL_ILLOPC;
break;
case POWERPC_EXCP_INVAL_LSWX:
- info.si_code = TARGET_ILL_ILLOPN;
+ si_code = TARGET_ILL_ILLOPN;
break;
case POWERPC_EXCP_INVAL_SPR:
- info.si_code = TARGET_ILL_PRVREG;
+ si_code = TARGET_ILL_PRVREG;
break;
case POWERPC_EXCP_INVAL_FP:
- info.si_code = TARGET_ILL_COPROC;
+ si_code = TARGET_ILL_COPROC;
break;
default:
EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF);
- info.si_code = TARGET_ILL_ILLADR;
+ si_code = TARGET_ILL_ILLADR;
break;
}
break;
case POWERPC_EXCP_PRIV:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
+ si_signo = TARGET_SIGILL;
switch (env->error_code & 0xF) {
case POWERPC_EXCP_PRIV_OPC:
- info.si_code = TARGET_ILL_PRVOPC;
+ si_code = TARGET_ILL_PRVOPC;
break;
case POWERPC_EXCP_PRIV_REG:
- info.si_code = TARGET_ILL_PRVREG;
+ si_code = TARGET_ILL_PRVREG;
break;
default:
EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
env->error_code & 0xF);
- info.si_code = TARGET_ILL_PRVOPC;
+ si_code = TARGET_ILL_PRVOPC;
break;
}
break;
@@ -250,28 +196,19 @@ void cpu_loop(CPUPPCState *env)
env->error_code);
break;
}
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(si_signo, si_code, env->nip);
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
+ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->nip);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
case POWERPC_EXCP_SYSCALL_VECTORED:
cpu_abort(cs, "Syscall exception while in user mode. "
"Aborting\n");
break;
- case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case POWERPC_EXCP_DECR: /* Decrementer exception */
cpu_abort(cs, "Decrementer interrupt while in user mode. "
"Aborting\n");
@@ -292,13 +229,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "Instruction TLB exception while in user mode. "
"Aborting\n");
break;
- case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
break;
@@ -355,13 +285,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "Hypervisor instruction segment exception "
"while in user mode. Aborting\n");
break;
- case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
cpu_abort(cs, "Programmable interval timer interrupt "
"while in user mode. Aborting\n");
@@ -444,10 +367,7 @@ void cpu_loop(CPUPPCState *env)
env->gpr[3] = ret;
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->nip);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 0cd8985cb8..26d446f323 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -30,8 +30,7 @@
void cpu_loop(CPURISCVState *env)
{
CPUState *cs = env_cpu(env);
- int trapnr, signum, sigcode;
- target_ulong sigaddr;
+ int trapnr;
target_ulong ret;
for (;;) {
@@ -40,10 +39,6 @@ void cpu_loop(CPURISCVState *env)
cpu_exec_end(cs);
process_queued_cpu_work(cs);
- signum = 0;
- sigcode = 0;
- sigaddr = 0;
-
switch (trapnr) {
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
@@ -79,39 +74,23 @@ void cpu_loop(CPURISCVState *env)
}
break;
case RISCV_EXCP_ILLEGAL_INST:
- signum = TARGET_SIGILL;
- sigcode = TARGET_ILL_ILLOPC;
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case RISCV_EXCP_BREAKPOINT:
- signum = TARGET_SIGTRAP;
- sigcode = TARGET_TRAP_BRKPT;
- sigaddr = env->pc;
+ case EXCP_DEBUG:
+ gdbstep:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case RISCV_EXCP_SEMIHOST:
env->gpr[xA0] = do_common_semihosting(cs);
env->pc += 4;
break;
- case EXCP_DEBUG:
- gdbstep:
- signum = TARGET_SIGTRAP;
- sigcode = TARGET_TRAP_BRKPT;
- break;
default:
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
trapnr);
exit(EXIT_FAILURE);
}
- if (signum) {
- target_siginfo_t info = {
- .si_signo = signum,
- .si_errno = 0,
- .si_code = sigcode,
- ._sifields._sigfault._addr = sigaddr
- };
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
-
process_pending_signals(env);
}
}
diff --git a/linux-user/riscv/target_structs.h b/linux-user/riscv/target_structs.h
index ea3e5ed17e..3a06f373c3 100644
--- a/linux-user/riscv/target_structs.h
+++ b/linux-user/riscv/target_structs.h
@@ -1,46 +1 @@
-/*
- * RISC-V specific structures for linux-user
- *
- * This is a copy of ../aarch64/target_structs.h atm.
- *
- */
-#ifndef RISCV_TARGET_STRUCTS_H
-#define RISCV_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index ad0c3cd263..7901dfe6f5 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -58,7 +58,6 @@ void cpu_loop(CPUS390XState *env)
{
CPUState *cs = env_cpu(env);
int trapnr, n, sig;
- target_siginfo_t info;
target_ulong addr;
abi_long ret;
@@ -158,11 +157,7 @@ void cpu_loop(CPUS390XState *env)
*/
env->psw.addr += env->int_pgm_ilen;
do_signal:
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = n;
- info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(sig, n, addr);
break;
case EXCP_ATOMIC:
diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c
index 3290f6445c..1bd313cb19 100644
--- a/linux-user/sh4/cpu_loop.c
+++ b/linux-user/sh4/cpu_loop.c
@@ -28,7 +28,6 @@ void cpu_loop(CPUSH4State *env)
{
CPUState *cs = env_cpu(env);
int trapnr, ret;
- target_siginfo_t info;
while (1) {
bool arch_interrupt = true;
@@ -60,10 +59,7 @@ void cpu_loop(CPUSH4State *env)
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/sh4/target_structs.h b/linux-user/sh4/target_structs.h
index 00ac39478b..3a06f373c3 100644
--- a/linux-user/sh4/target_structs.h
+++ b/linux-user/sh4/target_structs.h
@@ -1,58 +1 @@
-/*
- * SH4 specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 SH4_TARGET_STRUCTS_H
-#define SH4_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
+#include "../generic/target_structs.h"
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index 8765ab6020..baf3d9ae01 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -155,7 +155,6 @@ void cpu_loop (CPUSPARCState *env)
CPUState *cs = env_cpu(env);
int trapnr;
abi_long ret;
- target_siginfo_t info;
while (1) {
cpu_exec_start(cs);
@@ -241,19 +240,10 @@ void cpu_loop (CPUSPARCState *env)
/* just indicate that signals should be handled asap */
break;
case TT_ILL_INSN:
- {
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ce9d64896c..5950222a77 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6444,11 +6444,15 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
int deathsig;
ret = get_errno(prctl(PR_GET_PDEATHSIG, &deathsig,
arg3, arg4, arg5));
- if (!is_error(ret) && arg2 && put_user_s32(deathsig, arg2)) {
+ if (!is_error(ret) &&
+ put_user_s32(host_to_target_signal(deathsig), arg2)) {
return -TARGET_EFAULT;
}
return ret;
}
+ case PR_SET_PDEATHSIG:
+ return get_errno(prctl(PR_SET_PDEATHSIG, target_to_host_signal(arg2),
+ arg3, arg4, arg5));
case PR_GET_NAME:
{
void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
@@ -6500,10 +6504,15 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
case PR_SET_UNALIGN:
return do_prctl_set_unalign(env, arg2);
+ case PR_CAP_AMBIENT:
+ case PR_CAPBSET_READ:
+ case PR_CAPBSET_DROP:
case PR_GET_DUMPABLE:
case PR_SET_DUMPABLE:
case PR_GET_KEEPCAPS:
case PR_SET_KEEPCAPS:
+ case PR_GET_SECUREBITS:
+ case PR_SET_SECUREBITS:
case PR_GET_TIMING:
case PR_SET_TIMING:
case PR_GET_TIMERSLACK:
@@ -6927,6 +6936,14 @@ typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
+struct target_oabi_flock64 {
+ abi_short l_type;
+ abi_short l_whence;
+ abi_llong l_start;
+ abi_llong l_len;
+ abi_int l_pid;
+} QEMU_PACKED;
+
static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
abi_ulong target_flock_addr)
{
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index cca561f622..f23f0a2178 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -688,7 +688,7 @@ typedef struct target_siginfo {
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
#define TARGET_FPE_FLTUNK (14) /* undiagnosed fp exception */
-#define TARGET_NSIGFPE 15
+#define TARGET_FPE_CONDTRAP (15) /* trap on condition */
/*
* SIGSEGV si_codes
@@ -715,6 +715,7 @@ typedef struct target_siginfo {
#define TARGET_TRAP_TRACE (2) /* process trace trap */
#define TARGET_TRAP_BRANCH (3) /* process taken branch trap */
#define TARGET_TRAP_HWBKPT (4) /* hardware breakpoint/watchpoint */
+#define TARGET_TRAP_UNK (5) /* undiagnosed trap */
struct target_rlimit {
abi_ulong rlim_cur;
diff --git a/linux-user/x86_64/target_structs.h b/linux-user/x86_64/target_structs.h
index ce367b253b..f1181383c4 100644
--- a/linux-user/x86_64/target_structs.h
+++ b/linux-user/x86_64/target_structs.h
@@ -19,41 +19,7 @@
#ifndef X86_64_TARGET_STRUCTS_H
#define X86_64_TARGET_STRUCTS_H
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
+#include "../generic/target_structs.h"
/* The x86 definition differs from the generic one in that the
* two padding fields exist whether the ABI is 32 bits or 64 bits.
diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c
index 6bc6d6dee6..d51ce05392 100644
--- a/linux-user/xtensa/cpu_loop.c
+++ b/linux-user/xtensa/cpu_loop.c
@@ -126,7 +126,6 @@ static void xtensa_underflow12(CPUXtensaState *env)
void cpu_loop(CPUXtensaState *env)
{
CPUState *cs = env_cpu(env);
- target_siginfo_t info;
abi_ulong ret;
int trapnr;
@@ -163,14 +162,12 @@ void cpu_loop(CPUXtensaState *env)
case EXC_USER:
switch (env->sregs[EXCCAUSE]) {
case ILLEGAL_INSTRUCTION_CAUSE:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
+ env->sregs[EPC1]);
+ break;
case PRIVILEGED_CAUSE:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code =
- env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
- TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
- info._sifields._sigfault._addr = env->sregs[EPC1];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC,
+ env->sregs[EPC1]);
break;
case SYSCALL_CAUSE:
@@ -219,11 +216,8 @@ void cpu_loop(CPUXtensaState *env)
break;
case INTEGER_DIVIDE_BY_ZERO_CAUSE:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->sregs[EPC1];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV,
+ env->sregs[EPC1]);
break;
default:
@@ -232,10 +226,8 @@ void cpu_loop(CPUXtensaState *env)
}
break;
case EXCP_DEBUG:
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT,
+ env->sregs[EPC1]);
break;
case EXC_DEBUG:
default:
diff --git a/pc-bios/README b/pc-bios/README
index c51ae58824..ba6c15e769 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,7 +14,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20211112.
+ built from git tag qemu-slof-20220110.
- VOF (Virtual Open Firmware) is a minimalistic firmware to work with
-machine pseries,x-vof=on. When enabled, the firmware acts as a slim shim and
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 046ca63709..cbbe23e910 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/roms/SLOF b/roms/SLOF
-Subproject a6906b024c6cca5a86496f51eb4bfee3a0c3614
+Subproject 5b4c5acdcd552a4e1796aeca6bb700f6cbb0282
diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc
index 0760941431..fc6ede75b8 100644
--- a/target/mips/tcg/micromips_translate.c.inc
+++ b/target/mips/tcg/micromips_translate.c.inc
@@ -822,7 +822,7 @@ static void gen_pool16c_insn(DisasContext *ctx)
gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode));
break;
case BREAK16:
- generate_exception_end(ctx, EXCP_BREAK);
+ generate_exception_break(ctx, extract32(ctx->opcode, 0, 4));
break;
case SDBBP16:
if (is_uhi(extract32(ctx->opcode, 0, 4))) {
@@ -937,7 +937,7 @@ static void gen_pool16c_r6_insn(DisasContext *ctx)
break;
case R6_BREAK16:
/* BREAK16 */
- generate_exception(ctx, EXCP_BREAK);
+ generate_exception_break(ctx, extract32(ctx->opcode, 6, 4));
break;
case R6_SDBBP16:
/* SDBBP16 */
@@ -1047,7 +1047,7 @@ static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
case TNE:
mips32_op = OPC_TNE;
do_trap:
- gen_trap(ctx, mips32_op, rs, rt, -1);
+ gen_trap(ctx, mips32_op, rs, rt, -1, extract32(ctx->opcode, 12, 4));
break;
#ifndef CONFIG_USER_ONLY
case MFC0:
@@ -1812,7 +1812,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
gen_pool32axf(env, ctx, rt, rs);
break;
case BREAK32:
- generate_exception_end(ctx, EXCP_BREAK);
+ generate_exception_break(ctx, extract32(ctx->opcode, 6, 20));
break;
case SIGRIE:
check_insn(ctx, ISA_MIPS_R6);
@@ -2439,7 +2439,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS_R6);
mips32_op = OPC_TEQI;
do_trapi:
- gen_trap(ctx, mips32_op, rs, -1, imm);
+ gen_trap(ctx, mips32_op, rs, -1, imm, 0);
break;
case BNEZC:
diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc
index 84d816603a..f57e0a5f2a 100644
--- a/target/mips/tcg/mips16e_translate.c.inc
+++ b/target/mips/tcg/mips16e_translate.c.inc
@@ -969,7 +969,7 @@ static int decode_ase_mips16e(CPUMIPSState *env, DisasContext *ctx)
gen_slt(ctx, OPC_SLTU, 24, rx, ry);
break;
case RR_BREAK:
- generate_exception_end(ctx, EXCP_BREAK);
+ generate_exception_break(ctx, extract32(ctx->opcode, 5, 6));
break;
case RR_SLLV:
gen_shift(ctx, OPC_SLLV, ry, rx, ry);
diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc
index 2c022a49f2..916cece4d2 100644
--- a/target/mips/tcg/nanomips_translate.c.inc
+++ b/target/mips/tcg/nanomips_translate.c.inc
@@ -1268,11 +1268,11 @@ static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx)
switch (extract32(ctx->opcode, 10, 1)) {
case NM_TEQ:
check_nms(ctx);
- gen_trap(ctx, OPC_TEQ, rs, rt, -1);
+ gen_trap(ctx, OPC_TEQ, rs, rt, -1, rd);
break;
case NM_TNE:
check_nms(ctx);
- gen_trap(ctx, OPC_TNE, rs, rt, -1);
+ gen_trap(ctx, OPC_TNE, rs, rt, -1, rd);
break;
}
break;
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 1c2264417c..b82a7ec6ad 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -1367,6 +1367,16 @@ void generate_exception_end(DisasContext *ctx, int excp)
generate_exception_err(ctx, excp, 0);
}
+void generate_exception_break(DisasContext *ctx, int code)
+{
+#ifdef CONFIG_USER_ONLY
+ /* Pass the break code along to cpu_loop. */
+ tcg_gen_st_i32(tcg_constant_i32(code), cpu_env,
+ offsetof(CPUMIPSState, error_code));
+#endif
+ generate_exception_end(ctx, EXCP_BREAK);
+}
+
void gen_reserved_instruction(DisasContext *ctx)
{
generate_exception_end(ctx, EXCP_RI);
@@ -4723,7 +4733,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
/* Traps */
static void gen_trap(DisasContext *ctx, uint32_t opc,
- int rs, int rt, int16_t imm)
+ int rs, int rt, int16_t imm, int code)
{
int cond;
TCGv t0 = tcg_temp_new();
@@ -4768,6 +4778,11 @@ static void gen_trap(DisasContext *ctx, uint32_t opc,
case OPC_TGEU: /* rs >= rs unsigned */
case OPC_TGEIU: /* r0 >= 0 unsigned */
/* Always trap */
+#ifdef CONFIG_USER_ONLY
+ /* Pass the break code along to cpu_loop. */
+ tcg_gen_st_i32(tcg_constant_i32(code), cpu_env,
+ offsetof(CPUMIPSState, error_code));
+#endif
generate_exception_end(ctx, EXCP_TRAP);
break;
case OPC_TLT: /* rs < rs */
@@ -4808,6 +4823,18 @@ static void gen_trap(DisasContext *ctx, uint32_t opc,
tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1);
break;
}
+#ifdef CONFIG_USER_ONLY
+ /* Pass the break code along to cpu_loop. */
+ tcg_gen_st_i32(tcg_constant_i32(code), cpu_env,
+ offsetof(CPUMIPSState, error_code));
+#endif
+ /* Like save_cpu_state, only don't update saved values. */
+ if (ctx->base.pc_next != ctx->saved_pc) {
+ gen_save_pc(ctx->base.pc_next);
+ }
+ if (ctx->hflags != ctx->saved_hflags) {
+ tcg_gen_movi_i32(hflags, ctx->hflags);
+ }
generate_exception(ctx, EXCP_TRAP);
gen_set_label(l1);
}
@@ -14145,7 +14172,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
case OPC_TEQ:
case OPC_TNE:
check_insn(ctx, ISA_MIPS2);
- gen_trap(ctx, op1, rs, rt, -1);
+ gen_trap(ctx, op1, rs, rt, -1, extract32(ctx->opcode, 6, 10));
break;
case OPC_PMON:
/* Pmon entry point, also R4010 selsl */
@@ -14160,7 +14187,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
generate_exception_end(ctx, EXCP_SYSCALL);
break;
case OPC_BREAK:
- generate_exception_end(ctx, EXCP_BREAK);
+ generate_exception_break(ctx, extract32(ctx->opcode, 6, 20));
break;
case OPC_SYNC:
check_insn(ctx, ISA_MIPS2);
@@ -15279,11 +15306,10 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
case OPC_TLTI:
case OPC_TLTIU:
case OPC_TEQI:
-
case OPC_TNEI:
check_insn(ctx, ISA_MIPS2);
check_insn_opc_removed(ctx, ISA_MIPS_R6);
- gen_trap(ctx, op1, rs, -1, imm);
+ gen_trap(ctx, op1, rs, -1, imm, 0);
break;
case OPC_SIGRIE:
check_insn(ctx, ISA_MIPS_R6);
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 6111493651..ae01515efe 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -129,6 +129,7 @@ enum {
void generate_exception(DisasContext *ctx, int excp);
void generate_exception_err(DisasContext *ctx, int excp, int err);
void generate_exception_end(DisasContext *ctx, int excp);
+void generate_exception_break(DisasContext *ctx, int code);
void gen_reserved_instruction(DisasContext *ctx);
void check_insn(DisasContext *ctx, uint64_t flags);
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index bb392f6d88..993740897d 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -237,7 +237,7 @@ int cpu_get_dump_info(ArchDumpInfo *info,
info->d_machine = PPC_ELF_MACHINE;
info->d_class = ELFCLASS;
- if (ppc_interrupts_little_endian(cpu)) {
+ if (ppc_interrupts_little_endian(cpu, cpu->env.has_hv_mode)) {
info->d_endian = ELFDATA2LSB;
} else {
info->d_endian = ELFDATA2MSB;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index f20d4ffa6d..f99cd0ea92 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2728,20 +2728,29 @@ static inline bool ppc_has_spr(PowerPCCPU *cpu, int spr)
return cpu->env.spr_cb[spr].name != NULL;
}
-static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu)
+#if !defined(CONFIG_USER_ONLY)
+static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu, bool hv)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+ bool ile;
+
+ if (hv && env->has_hv_mode) {
+ if (is_isa300(pcc)) {
+ ile = !!(env->spr[SPR_HID0] & HID0_POWER9_HILE);
+ } else {
+ ile = !!(env->spr[SPR_HID0] & HID0_HILE);
+ }
- /*
- * Only models that have an LPCR and know about LPCR_ILE can do little
- * endian.
- */
- if (pcc->lpcr_mask & LPCR_ILE) {
- return !!(cpu->env.spr[SPR_LPCR] & LPCR_ILE);
+ } else if (pcc->lpcr_mask & LPCR_ILE) {
+ ile = !!(env->spr[SPR_LPCR] & LPCR_ILE);
+ } else {
+ ile = !!(msr_ile);
}
- return false;
+ return ile;
}
+#endif
void dump_mmu(CPUPPCState *env);
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index cc93bff3fa..e30e86fe9d 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6953,10 +6953,12 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
PPC_FLOAT_STFIWX |
+ PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B |
+ PPC_POPCNTB |
PPC_SEGMENT_64B | PPC_SLBI;
pcc->insns_flags2 = PPC2_FP_CVT_S64;
pcc->msr_mask = (1ull << MSR_SF) |
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index a779dc936a..bc646c67a0 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -30,8 +30,6 @@
#include "exec/cpu_ldst.h"
#endif
-/* #define DEBUG_SOFTWARE_TLB */
-
/*****************************************************************************/
/* Exception processing */
#if !defined(CONFIG_USER_ONLY)
@@ -135,6 +133,39 @@ static void dump_hcall(CPUPPCState *env)
env->nip);
}
+static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
+{
+ const char *es;
+ target_ulong *miss, *cmp;
+ int en;
+
+ if (!qemu_loglevel_mask(CPU_LOG_MMU)) {
+ return;
+ }
+
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB) {
+ es = "DL";
+ } else {
+ es = "DS";
+ }
+ en = 'D';
+ miss = &env->spr[SPR_DMISS];
+ cmp = &env->spr[SPR_DCMP];
+ }
+ qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+ TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+ TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+ env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+ env->error_code);
+}
+
+
static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
target_ulong *msr)
{
@@ -365,7 +396,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu,
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
*/
-static void powerpc_excp(PowerPCCPU *cpu, int excp)
+static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
@@ -669,23 +700,6 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
break;
- case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Embedded floating point data exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- break;
- case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Embedded floating point round exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- break;
- case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
- /* XXX: TODO */
- cpu_abort(cs,
- "Performance counter exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
break;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
@@ -750,19 +764,6 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
trace_ppc_excp_print("PIT");
break;
- case POWERPC_EXCP_IO: /* IO error exception */
- /* XXX: TODO */
- cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
- break;
- case POWERPC_EXCP_RUNM: /* Run mode exception */
- /* XXX: TODO */
- cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
- break;
- case POWERPC_EXCP_EMUL: /* Emulation trap exception */
- /* XXX: TODO */
- cpu_abort(cs, "602 emulation trap exception "
- "is not implemented yet !\n");
- break;
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
@@ -777,34 +778,8 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
}
/* fall through */
case POWERPC_EXCP_7x5:
-#if defined(DEBUG_SOFTWARE_TLB)
- if (qemu_log_enabled()) {
- const char *es;
- target_ulong *miss, *cmp;
- int en;
-
- if (excp == POWERPC_EXCP_IFTLB) {
- es = "I";
- en = 'I';
- miss = &env->spr[SPR_IMISS];
- cmp = &env->spr[SPR_ICMP];
- } else {
- if (excp == POWERPC_EXCP_DLTLB) {
- es = "DL";
- } else {
- es = "DS";
- }
- en = 'D';
- miss = &env->spr[SPR_DMISS];
- cmp = &env->spr[SPR_DCMP];
- }
- qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
- TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
- TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
- env->spr[SPR_HASH1], env->spr[SPR_HASH2],
- env->error_code);
- }
-#endif
+ ppc_excp_debug_sw_tlb(env, excp);
+
msr |= env->crf[0] << 28;
msr |= env->error_code; /* key, D/I, S/L bits */
/* Set way using a LRU mechanism */
@@ -815,56 +790,25 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
break;
}
break;
+ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
+ case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
+ case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
+ case POWERPC_EXCP_IO: /* IO error exception */
+ case POWERPC_EXCP_RUNM: /* Run mode exception */
+ case POWERPC_EXCP_EMUL: /* Emulation trap exception */
case POWERPC_EXCP_FPA: /* Floating-point assist exception */
- /* XXX: TODO */
- cpu_abort(cs, "Floating point assist exception "
- "is not implemented yet !\n");
- break;
case POWERPC_EXCP_DABR: /* Data address breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "DABR exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "IABR exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_SMI: /* System management interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "SMI exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_THERM: /* Thermal interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Thermal management exception "
- "is not implemented yet !\n");
- break;
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
- /* XXX: TODO */
- cpu_abort(cs,
- "Performance counter exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_VPUA: /* Vector assist exception */
- /* XXX: TODO */
- cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_SOFTP: /* Soft patch exception */
- /* XXX: TODO */
- cpu_abort(cs,
- "970 soft-patch exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_MAINT: /* Maintenance exception */
- /* XXX: TODO */
- cpu_abort(cs,
- "970 maintenance exception is not implemented yet !\n");
- break;
case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "Maskable external exception "
- "is not implemented yet !\n");
- break;
case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "Non maskable external exception "
- "is not implemented yet !\n");
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
break;
default:
excp_invalid:
@@ -888,36 +832,9 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
*/
-#ifdef TARGET_PPC64
- if (excp_model == POWERPC_EXCP_POWER7) {
- if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
- } else if (excp_model == POWERPC_EXCP_POWER8) {
- if (new_msr & MSR_HVB) {
- if (env->spr[SPR_HID0] & HID0_HILE) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
- } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
- } else if (excp_model == POWERPC_EXCP_POWER9 ||
- excp_model == POWERPC_EXCP_POWER10) {
- if (new_msr & MSR_HVB) {
- if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
- } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
- } else if (msr_ile) {
+ if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
new_msr |= (target_ulong)1 << MSR_LE;
}
-#else
- if (msr_ile) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
-#endif
#if defined(TARGET_PPC64)
if (excp_model == POWERPC_EXCP_BOOKE) {
@@ -950,6 +867,16 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
powerpc_set_excp_state(cpu, vector, new_msr);
}
+static void powerpc_excp(PowerPCCPU *cpu, int excp)
+{
+ CPUPPCState *env = &cpu->env;
+
+ switch (env->excp_model) {
+ default:
+ powerpc_excp_legacy(cpu, excp);
+ }
+}
+
void ppc_cpu_do_interrupt(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -1126,7 +1053,7 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
*/
msr = (1ULL << MSR_ME);
msr |= env->msr & (1ULL << MSR_SF);
- if (ppc_interrupts_little_endian(cpu)) {
+ if (ppc_interrupts_little_endian(cpu, false)) {
msr |= (1ULL << MSR_LE);
}