aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--blockdev.c15
-rw-r--r--configs/targets/hppa-linux-user.mak1
-rw-r--r--docs/system/i386/xen.rst107
-rw-r--r--hw/block/xen-block.c118
-rw-r--r--hw/char/trace-events8
-rw-r--r--hw/char/xen_console.c572
-rw-r--r--hw/hppa/machine.c152
-rw-r--r--hw/i386/kvm/meson.build1
-rw-r--r--hw/i386/kvm/trace-events2
-rw-r--r--hw/i386/kvm/xen-stubs.c8
-rw-r--r--hw/i386/kvm/xen_evtchn.c151
-rw-r--r--hw/i386/kvm/xen_gnttab.c7
-rw-r--r--hw/i386/kvm/xen_primary_console.c193
-rw-r--r--hw/i386/kvm/xen_primary_console.h23
-rw-r--r--hw/i386/kvm/xen_xenstore.c23
-rw-r--r--hw/i386/pc.c11
-rw-r--r--hw/i386/pc_piix.c2
-rw-r--r--hw/i386/pc_q35.c2
-rw-r--r--hw/i386/xen/xen_platform.c77
-rw-r--r--hw/net/meson.build2
-rw-r--r--hw/net/trace-events11
-rw-r--r--hw/net/xen_nic.c484
-rw-r--r--hw/pci-host/astro.c11
-rw-r--r--hw/xen/xen-backend.c27
-rw-r--r--hw/xen/xen-bus.c23
-rw-r--r--hw/xen/xen-legacy-backend.c1
-rw-r--r--hw/xen/xen_devconfig.c28
-rw-r--r--hw/xenpv/xen_machine_pv.c10
-rw-r--r--include/hw/elf_ops.h17
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/hw/xen/interface/arch-arm.h37
-rw-r--r--include/hw/xen/interface/arch-x86/cpuid.h31
-rw-r--r--include/hw/xen/interface/arch-x86/xen-x86_32.h19
-rw-r--r--include/hw/xen/interface/arch-x86/xen-x86_64.h19
-rw-r--r--include/hw/xen/interface/arch-x86/xen.h26
-rw-r--r--include/hw/xen/interface/event_channel.h19
-rw-r--r--include/hw/xen/interface/features.h19
-rw-r--r--include/hw/xen/interface/grant_table.h19
-rw-r--r--include/hw/xen/interface/hvm/hvm_op.h19
-rw-r--r--include/hw/xen/interface/hvm/params.h19
-rw-r--r--include/hw/xen/interface/io/blkif.h27
-rw-r--r--include/hw/xen/interface/io/console.h19
-rw-r--r--include/hw/xen/interface/io/fbif.h19
-rw-r--r--include/hw/xen/interface/io/kbdif.h19
-rw-r--r--include/hw/xen/interface/io/netif.h25
-rw-r--r--include/hw/xen/interface/io/protocols.h19
-rw-r--r--include/hw/xen/interface/io/ring.h49
-rw-r--r--include/hw/xen/interface/io/usbif.h19
-rw-r--r--include/hw/xen/interface/io/xenbus.h19
-rw-r--r--include/hw/xen/interface/io/xs_wire.h36
-rw-r--r--include/hw/xen/interface/memory.h30
-rw-r--r--include/hw/xen/interface/physdev.h23
-rw-r--r--include/hw/xen/interface/sched.h19
-rw-r--r--include/hw/xen/interface/trace.h19
-rw-r--r--include/hw/xen/interface/vcpu.h19
-rw-r--r--include/hw/xen/interface/version.h19
-rw-r--r--include/hw/xen/interface/xen-compat.h19
-rw-r--r--include/hw/xen/interface/xen.h19
-rw-r--r--include/hw/xen/xen-backend.h1
-rw-r--r--include/hw/xen/xen-bus.h5
-rw-r--r--include/hw/xen/xen-legacy-backend.h1
-rw-r--r--linux-user/hppa/cpu_loop.c4
-rw-r--r--linux-user/hppa/signal.c6
-rw-r--r--linux-user/hppa/target_elf.h2
-rw-r--r--qemu-options.hx12
-rw-r--r--target/hppa/cpu-param.h22
-rw-r--r--target/hppa/cpu-qom.h1
-rw-r--r--target/hppa/cpu.c70
-rw-r--r--target/hppa/cpu.h180
-rw-r--r--target/hppa/gdbstub.c32
-rw-r--r--target/hppa/helper.c101
-rw-r--r--target/hppa/helper.h55
-rw-r--r--target/hppa/insns.decode197
-rw-r--r--target/hppa/int_helper.c77
-rw-r--r--target/hppa/machine.c194
-rw-r--r--target/hppa/mem_helper.c434
-rw-r--r--target/hppa/op_helper.c310
-rw-r--r--target/hppa/sys_helper.c14
-rw-r--r--target/hppa/trace-events1
-rw-r--r--target/hppa/translate.c2139
-rw-r--r--target/i386/kvm/kvm.c4
-rw-r--r--target/i386/kvm/xen-emu.c43
83 files changed, 4217 insertions, 2426 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 59b92ee..fd6b362 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -490,7 +490,7 @@ S: Supported
F: include/sysemu/kvm_xen.h
F: target/i386/kvm/xen*
F: hw/i386/kvm/xen*
-F: tests/avocado/xen_guest.py
+F: tests/avocado/kvm_xen_guest.py
Guest CPU Cores (other accelerators)
------------------------------------
diff --git a/blockdev.c b/blockdev.c
index 1517dc6..e9b7e38 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -255,13 +255,13 @@ void drive_check_orphaned(void)
* Ignore default drives, because we create certain default
* drives unconditionally, then leave them unclaimed. Not the
* users fault.
- * Ignore IF_VIRTIO, because it gets desugared into -device,
- * so we can leave failing to -device.
+ * Ignore IF_VIRTIO or IF_XEN, because it gets desugared into
+ * -device, so we can leave failing to -device.
* Ignore IF_NONE, because leaving unclaimed IF_NONE remains
* available for device_add is a feature.
*/
if (dinfo->is_default || dinfo->type == IF_VIRTIO
- || dinfo->type == IF_NONE) {
+ || dinfo->type == IF_XEN || dinfo->type == IF_NONE) {
continue;
}
if (!blk_get_attached_dev(blk)) {
@@ -977,6 +977,15 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
qemu_opt_set(devopts, "driver", "virtio-blk", &error_abort);
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
&error_abort);
+ } else if (type == IF_XEN) {
+ QemuOpts *devopts;
+ devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
+ &error_abort);
+ qemu_opt_set(devopts, "driver",
+ (media == MEDIA_CDROM) ? "xen-cdrom" : "xen-disk",
+ &error_abort);
+ qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
+ &error_abort);
}
filename = qemu_opt_get(legacy_opts, "file");
diff --git a/configs/targets/hppa-linux-user.mak b/configs/targets/hppa-linux-user.mak
index 361ea39..8e0a804 100644
--- a/configs/targets/hppa-linux-user.mak
+++ b/configs/targets/hppa-linux-user.mak
@@ -1,4 +1,5 @@
TARGET_ARCH=hppa
+TARGET_ABI32=y
TARGET_SYSTBL_ABI=common,32
TARGET_SYSTBL=syscall.tbl
TARGET_BIG_ENDIAN=y
diff --git a/docs/system/i386/xen.rst b/docs/system/i386/xen.rst
index f06765e..8189876 100644
--- a/docs/system/i386/xen.rst
+++ b/docs/system/i386/xen.rst
@@ -15,46 +15,24 @@ Setup
-----
Xen mode is enabled by setting the ``xen-version`` property of the KVM
-accelerator, for example for Xen 4.10:
+accelerator, for example for Xen 4.17:
.. parsed-literal::
- |qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split
+ |qemu_system| --accel kvm,xen-version=0x40011,kernel-irqchip=split
Additionally, virtual APIC support can be advertised to the guest through the
``xen-vapic`` CPU flag:
.. parsed-literal::
- |qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split --cpu host,+xen_vapic
+ |qemu_system| --accel kvm,xen-version=0x40011,kernel-irqchip=split --cpu host,+xen-vapic
When Xen support is enabled, QEMU changes hypervisor identification (CPUID
0x40000000..0x4000000A) to Xen. The KVM identification and features are not
advertised to a Xen guest. If Hyper-V is also enabled, the Xen identification
moves to leaves 0x40000100..0x4000010A.
-The Xen platform device is enabled automatically for a Xen guest. This allows
-a guest to unplug all emulated devices, in order to use Xen PV block and network
-drivers instead. Under Xen, the boot disk is typically available both via IDE
-emulation, and as a PV block device. Guest bootloaders typically use IDE to load
-the guest kernel, which then unplugs the IDE and continues with the Xen PV block
-device.
-
-This configuration can be achieved as follows
-
-.. parsed-literal::
-
- |qemu_system| -M pc --accel kvm,xen-version=0x4000a,kernel-irqchip=split \\
- -drive file=${GUEST_IMAGE},if=none,id=disk,file.locking=off -device xen-disk,drive=disk,vdev=xvda \\
- -drive file=${GUEST_IMAGE},index=2,media=disk,file.locking=off,if=ide
-
-It is necessary to use the pc machine type, as the q35 machine uses AHCI instead
-of legacy IDE, and AHCI disks are not unplugged through the Xen PV unplug
-mechanism.
-
-VirtIO devices can also be used; Linux guests may need to be dissuaded from
-umplugging them by adding 'xen_emul_unplug=never' on their command line.
-
Properties
----------
@@ -63,7 +41,10 @@ The following properties exist on the KVM accelerator object:
``xen-version``
This property contains the Xen version in ``XENVER_version`` form, with the
major version in the top 16 bits and the minor version in the low 16 bits.
- Setting this property enables the Xen guest support.
+ Setting this property enables the Xen guest support. If Xen version 4.5 or
+ greater is specified, the HVM leaf in Xen CPUID is populated. Xen version
+ 4.6 enables the vCPU ID in CPUID, and version 4.17 advertises vCPU upcall
+ vector support to the guest.
``xen-evtchn-max-pirq``
Xen PIRQs represent an emulated physical interrupt, either GSI or MSI, which
@@ -83,8 +64,78 @@ The following properties exist on the KVM accelerator object:
through simultaneous grants. For guests with large numbers of PV devices and
high throughput, it may be desirable to increase this value.
-OS requirements
----------------
+Xen paravirtual devices
+-----------------------
+
+The Xen PCI platform device is enabled automatically for a Xen guest. This
+allows a guest to unplug all emulated devices, in order to use paravirtual
+block and network drivers instead.
+
+Those paravirtual Xen block, network (and console) devices can be created
+through the command line, and/or hot-plugged.
+
+To provide a Xen console device, define a character device and then a device
+of type ``xen-console`` to connect to it. For the Xen console equivalent of
+the handy ``-serial mon:stdio`` option, for example:
+
+.. parsed-literal::
+ -chardev stdio,mux=on,id=char0,signal=off -mon char0 \\
+ -device xen-console,chardev=char0
+
+The Xen network device is ``xen-net-device``, which becomes the default NIC
+model for emulated Xen guests, meaning that just the default NIC provided
+by QEMU should automatically work and present a Xen network device to the
+guest.
+
+Disks can be configured with '``-drive file=${GUEST_IMAGE},if=xen``' and will
+appear to the guest as ``xvda`` onwards.
+
+Under Xen, the boot disk is typically available both via IDE emulation, and
+as a PV block device. Guest bootloaders typically use IDE to load the guest
+kernel, which then unplugs the IDE and continues with the Xen PV block device.
+
+This configuration can be achieved as follows:
+
+.. parsed-literal::
+
+ |qemu_system| --accel kvm,xen-version=0x40011,kernel-irqchip=split \\
+ -drive file=${GUEST_IMAGE},if=xen \\
+ -drive file=${GUEST_IMAGE},file.locking=off,if=ide
+
+VirtIO devices can also be used; Linux guests may need to be dissuaded from
+umplugging them by adding '``xen_emul_unplug=never``' on their command line.
+
+Booting Xen PV guests
+---------------------
+
+Booting PV guest kernels is possible by using the Xen PV shim (a version of Xen
+itself, designed to run inside a Xen HVM guest and provide memory management
+services for one guest alone).
+
+The Xen binary is provided as the ``-kernel`` and the guest kernel itself (or
+PV Grub image) as the ``-initrd`` image, which actually just means the first
+multiboot "module". For example:
+
+.. parsed-literal::
+
+ |qemu_system| --accel kvm,xen-version=0x40011,kernel-irqchip=split \\
+ -chardev stdio,id=char0 -device xen-console,chardev=char0 \\
+ -display none -m 1G -kernel xen -initrd bzImage \\
+ -append "pv-shim console=xen,pv -- console=hvc0 root=/dev/xvda1" \\
+ -drive file=${GUEST_IMAGE},if=xen
+
+The Xen image must be built with the ``CONFIG_XEN_GUEST`` and ``CONFIG_PV_SHIM``
+options, and as of Xen 4.17, Xen's PV shim mode does not support using a serial
+port; it must have a Xen console or it will panic.
+
+The example above provides the guest kernel command line after a separator
+(" ``--`` ") on the Xen command line, and does not provide the guest kernel
+with an actual initramfs, which would need to listed as a second multiboot
+module. For more complicated alternatives, see the command line
+documentation for the ``-initrd`` option.
+
+Host OS requirements
+--------------------
The minimal Xen support in the KVM accelerator requires the host to be running
Linux v5.12 or newer. Later versions add optimisations: Linux v5.17 added
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index bfa5396..6d64ede 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -27,13 +27,119 @@
#include "sysemu/block-backend.h"
#include "sysemu/iothread.h"
#include "dataplane/xen-block.h"
+#include "hw/xen/interface/io/xs_wire.h"
#include "trace.h"
+#define XVDA_MAJOR 202
+#define XVDQ_MAJOR (1 << 20)
+#define XVDBGQCV_MAJOR ((1 << 21) - 1)
+#define HDA_MAJOR 3
+#define HDC_MAJOR 22
+#define SDA_MAJOR 8
+
+
+static int vdev_to_diskno(unsigned int vdev_nr)
+{
+ switch (vdev_nr >> 8) {
+ case XVDA_MAJOR:
+ case SDA_MAJOR:
+ return (vdev_nr >> 4) & 0x15;
+
+ case HDA_MAJOR:
+ return (vdev_nr >> 6) & 1;
+
+ case HDC_MAJOR:
+ return ((vdev_nr >> 6) & 1) + 2;
+
+ case XVDQ_MAJOR ... XVDBGQCV_MAJOR:
+ return (vdev_nr >> 8) & 0xfffff;
+
+ default:
+ return -1;
+ }
+}
+
+#define MAX_AUTO_VDEV 4096
+
+/*
+ * Find a free device name in the xvda → xvdfan range and set it in
+ * blockdev->props.vdev. Our definition of "free" is that there must
+ * be no other disk or partition with the same disk number.
+ *
+ * You are technically permitted to have all of hda, hda1, sda, sda1,
+ * xvda and xvda1 as *separate* PV block devices with separate backing
+ * stores. That doesn't make it a good idea. This code will skip xvda
+ * if *any* of those "conflicting" devices already exists.
+ *
+ * The limit of xvdfan (disk 4095) is fairly arbitrary just to avoid a
+ * stupidly sized bitmap, but Linux as of v6.6 doesn't support anything
+ * higher than that anyway.
+ */
+static bool xen_block_find_free_vdev(XenBlockDevice *blockdev, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(blockdev)));
+ unsigned long used_devs[BITS_TO_LONGS(MAX_AUTO_VDEV)];
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+ char fe_path[XENSTORE_ABS_PATH_MAX + 1];
+ char **existing_frontends;
+ unsigned int nr_existing = 0;
+ unsigned int vdev_nr;
+ int i, disk = 0;
+
+ snprintf(fe_path, sizeof(fe_path), "/local/domain/%u/device/vbd",
+ blockdev->xendev.frontend_id);
+
+ existing_frontends = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, fe_path,
+ &nr_existing);
+ if (!existing_frontends && errno != ENOENT) {
+ error_setg_errno(errp, errno, "cannot read %s", fe_path);
+ return false;
+ }
+
+ memset(used_devs, 0, sizeof(used_devs));
+ for (i = 0; i < nr_existing; i++) {
+ if (qemu_strtoui(existing_frontends[i], NULL, 10, &vdev_nr)) {
+ free(existing_frontends[i]);
+ continue;
+ }
+
+ free(existing_frontends[i]);
+
+ disk = vdev_to_diskno(vdev_nr);
+ if (disk < 0 || disk >= MAX_AUTO_VDEV) {
+ continue;
+ }
+
+ set_bit(disk, used_devs);
+ }
+ free(existing_frontends);
+
+ disk = find_first_zero_bit(used_devs, MAX_AUTO_VDEV);
+ if (disk == MAX_AUTO_VDEV) {
+ error_setg(errp, "cannot find device vdev for block device");
+ return false;
+ }
+
+ vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
+ vdev->partition = 0;
+ vdev->disk = disk;
+ if (disk < (1 << 4)) {
+ vdev->number = (XVDA_MAJOR << 8) | (disk << 4);
+ } else {
+ vdev->number = (XVDQ_MAJOR << 8) | (disk << 8);
+ }
+ return true;
+}
+
static char *xen_block_get_name(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
XenBlockVdev *vdev = &blockdev->props.vdev;
+ if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID &&
+ !xen_block_find_free_vdev(blockdev, errp)) {
+ return NULL;
+ }
return g_strdup_printf("%lu", vdev->number);
}
@@ -482,10 +588,10 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
case XEN_BLOCK_VDEV_TYPE_DP:
case XEN_BLOCK_VDEV_TYPE_XVD:
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
- vdev->number = (202 << 8) | (vdev->disk << 4) |
+ vdev->number = (XVDA_MAJOR << 8) | (vdev->disk << 4) |
vdev->partition;
} else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
- vdev->number = (1 << 28) | (vdev->disk << 8) |
+ vdev->number = (XVDQ_MAJOR << 8) | (vdev->disk << 8) |
vdev->partition;
} else {
goto invalid;
@@ -495,10 +601,11 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
case XEN_BLOCK_VDEV_TYPE_HD:
if ((vdev->disk == 0 || vdev->disk == 1) &&
vdev->partition < (1 << 6)) {
- vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
+ vdev->number = (HDA_MAJOR << 8) | (vdev->disk << 6) |
+ vdev->partition;
} else if ((vdev->disk == 2 || vdev->disk == 3) &&
vdev->partition < (1 << 6)) {
- vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
+ vdev->number = (HDC_MAJOR << 8) | ((vdev->disk - 2) << 6) |
vdev->partition;
} else {
goto invalid;
@@ -507,7 +614,8 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
case XEN_BLOCK_VDEV_TYPE_SD:
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
- vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
+ vdev->number = (SDA_MAJOR << 8) | (vdev->disk << 4) |
+ vdev->partition;
} else {
goto invalid;
}
diff --git a/hw/char/trace-events b/hw/char/trace-events
index babf4d3..7a398c8 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -105,3 +105,11 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
# sh_serial.c
sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
+
+# xen_console.c
+xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
+xen_console_disconnect(unsigned int idx) "idx %u"
+xen_console_unrealize(unsigned int idx) "idx %u"
+xen_console_realize(unsigned int idx, const char *chrdev) "idx %u chrdev %s"
+xen_console_device_create(unsigned int idx) "idx %u"
+xen_console_device_destroy(unsigned int idx) "idx %u"
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 810dae3..5cbee2f 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -20,15 +20,22 @@
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include <sys/select.h>
#include <termios.h>
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "chardev/char-fe.h"
-#include "hw/xen/xen-legacy-backend.h"
-
+#include "hw/xen/xen-backend.h"
+#include "hw/xen/xen-bus-helper.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/xen/interface/io/console.h"
+#include "hw/xen/interface/io/xs_wire.h"
+#include "hw/xen/interface/grant_table.h"
+#include "hw/i386/kvm/xen_primary_console.h"
+#include "trace.h"
struct buffer {
uint8_t *data;
@@ -39,16 +46,22 @@ struct buffer {
};
struct XenConsole {
- struct XenLegacyDevice xendev; /* must be first */
+ struct XenDevice xendev; /* must be first */
+ XenEventChannel *event_channel;
+ int dev;
struct buffer buffer;
- char console[XEN_BUFSIZE];
- int ring_ref;
+ char *fe_path;
+ unsigned int ring_ref;
void *sring;
CharBackend chr;
int backlog;
};
+typedef struct XenConsole XenConsole;
+
+#define TYPE_XEN_CONSOLE_DEVICE "xen-console"
+OBJECT_DECLARE_SIMPLE_TYPE(XenConsole, XEN_CONSOLE_DEVICE)
-static void buffer_append(struct XenConsole *con)
+static bool buffer_append(XenConsole *con)
{
struct buffer *buffer = &con->buffer;
XENCONS_RING_IDX cons, prod, size;
@@ -60,7 +73,7 @@ static void buffer_append(struct XenConsole *con)
size = prod - cons;
if ((size == 0) || (size > sizeof(intf->out)))
- return;
+ return false;
if ((buffer->capacity - buffer->size) < size) {
buffer->capacity += (size + 1024);
@@ -73,7 +86,7 @@ static void buffer_append(struct XenConsole *con)
xen_mb();
intf->out_cons = cons;
- xen_pv_send_notify(&con->xendev);
+ xen_device_notify_event_channel(XEN_DEVICE(con), con->event_channel, NULL);
if (buffer->max_capacity &&
buffer->size > buffer->max_capacity) {
@@ -89,6 +102,7 @@ static void buffer_append(struct XenConsole *con)
if (buffer->consumed > buffer->max_capacity - over)
buffer->consumed = buffer->max_capacity - over;
}
+ return true;
}
static void buffer_advance(struct buffer *buffer, size_t len)
@@ -100,7 +114,7 @@ static void buffer_advance(struct buffer *buffer, size_t len)
}
}
-static int ring_free_bytes(struct XenConsole *con)
+static int ring_free_bytes(XenConsole *con)
{
struct xencons_interface *intf = con->sring;
XENCONS_RING_IDX cons, prod, space;
@@ -118,13 +132,13 @@ static int ring_free_bytes(struct XenConsole *con)
static int xencons_can_receive(void *opaque)
{
- struct XenConsole *con = opaque;
+ XenConsole *con = opaque;
return ring_free_bytes(con);
}
static void xencons_receive(void *opaque, const uint8_t *buf, int len)
{
- struct XenConsole *con = opaque;
+ XenConsole *con = opaque;
struct xencons_interface *intf = con->sring;
XENCONS_RING_IDX prod;
int i, max;
@@ -141,10 +155,10 @@ static void xencons_receive(void *opaque, const uint8_t *buf, int len)
}
xen_wmb();
intf->in_prod = prod;
- xen_pv_send_notify(&con->xendev);
+ xen_device_notify_event_channel(XEN_DEVICE(con), con->event_channel, NULL);
}
-static void xencons_send(struct XenConsole *con)
+static bool xencons_send(XenConsole *con)
{
ssize_t len, size;
@@ -159,174 +173,472 @@ static void xencons_send(struct XenConsole *con)
if (len < 1) {
if (!con->backlog) {
con->backlog = 1;
- xen_pv_printf(&con->xendev, 1,
- "backlog piling up, nobody listening?\n");
}
} else {
buffer_advance(&con->buffer, len);
if (con->backlog && len == size) {
con->backlog = 0;
- xen_pv_printf(&con->xendev, 1, "backlog is gone\n");
}
}
+ return len > 0;
}
/* -------------------------------------------------------------------- */
-static int store_con_info(struct XenConsole *con)
+static bool con_event(void *_xendev)
{
- Chardev *cs = qemu_chr_fe_get_driver(&con->chr);
- char *pts = NULL;
- char *dom_path;
- g_autoptr(GString) path = NULL;
+ XenConsole *con = XEN_CONSOLE_DEVICE(_xendev);
+ bool done_something;
- /* Only continue if we're talking to a pty. */
- if (!CHARDEV_IS_PTY(cs)) {
- return 0;
+ if (xen_device_backend_get_state(&con->xendev) != XenbusStateConnected) {
+ return false;
}
- pts = cs->filename + 4;
- dom_path = qemu_xen_xs_get_domain_path(xenstore, xen_domid);
- if (!dom_path) {
- return 0;
+ done_something = buffer_append(con);
+
+ if (con->buffer.size - con->buffer.consumed) {
+ done_something |= xencons_send(con);
}
+ return done_something;
+}
- path = g_string_new(dom_path);
- free(dom_path);
+/* -------------------------------------------------------------------- */
- if (con->xendev.dev) {
- g_string_append_printf(path, "/device/console/%d", con->xendev.dev);
- } else {
- g_string_append(path, "/console");
+static bool xen_console_connect(XenDevice *xendev, Error **errp)
+{
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+ unsigned int port, limit;
+
+ if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
+ &con->ring_ref) != 1) {
+ error_setg(errp, "failed to read ring-ref");
+ return false;
+ }
+
+ if (xen_device_frontend_scanf(xendev, "port", "%u", &port) != 1) {
+ error_setg(errp, "failed to read remote port");
+ return false;
+ }
+
+ if (xen_device_frontend_scanf(xendev, "limit", "%u", &limit) == 1) {
+ con->buffer.max_capacity = limit;
+ }
+
+ con->event_channel = xen_device_bind_event_channel(xendev, port,
+ con_event,
+ con,
+ errp);
+ if (!con->event_channel) {
+ return false;
}
- g_string_append(path, "/tty");
- if (xenstore_write_str(con->console, path->str, pts)) {
- fprintf(stderr, "xenstore_write_str for '%s' fail", path->str);
- return -1;
+ switch (con->dev) {
+ case 0:
+ /*
+ * The primary console is special. For real Xen the ring-ref is
+ * actually a GFN which needs to be mapped as foreignmem.
+ */
+ if (xen_mode != XEN_EMULATE) {
+ xen_pfn_t mfn = (xen_pfn_t)con->ring_ref;
+ con->sring = qemu_xen_foreignmem_map(xendev->frontend_id, NULL,
+ PROT_READ | PROT_WRITE,
+ 1, &mfn, NULL);
+ if (!con->sring) {
+ error_setg(errp, "failed to map console page");
+ return false;
+ }
+ break;
+ }
+
+ /*
+ * For Xen emulation, we still follow the convention of ring-ref
+ * holding the GFN, but we map the fixed GNTTAB_RESERVED_CONSOLE
+ * grant ref because there is no implementation of foreignmem
+ * operations for emulated mode. The emulation code which handles
+ * the guest-side page and event channel also needs to be informed
+ * of the backend event channel port, in order to reconnect to it
+ * after a soft reset.
+ */
+ xen_primary_console_set_be_port(
+ xen_event_channel_get_local_port(con->event_channel));
+ con->ring_ref = GNTTAB_RESERVED_CONSOLE;
+ /* fallthrough */
+ default:
+ con->sring = xen_device_map_grant_refs(xendev,
+ &con->ring_ref, 1,
+ PROT_READ | PROT_WRITE,
+ errp);
+ if (!con->sring) {
+ error_prepend(errp, "failed to map console grant ref: ");
+ return false;
+ }
+ break;
}
- return 0;
+
+ trace_xen_console_connect(con->dev, con->ring_ref, port,
+ con->buffer.max_capacity);
+
+ qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
+ xencons_receive, NULL, NULL, con, NULL,
+ true);
+ return true;
}
-static int con_init(struct XenLegacyDevice *xendev)
+static void xen_console_disconnect(XenDevice *xendev, Error **errp)
{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
- char *type, *dom, label[32];
- int ret = 0;
- const char *output;
-
- /* setup */
- dom = qemu_xen_xs_get_domain_path(xenstore, con->xendev.dom);
- if (!xendev->dev) {
- snprintf(con->console, sizeof(con->console), "%s/console", dom);
- } else {
- snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev);
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+
+ trace_xen_console_disconnect(con->dev);
+
+ qemu_chr_fe_set_handlers(&con->chr, NULL, NULL, NULL, NULL,
+ con, NULL, true);
+
+ if (con->event_channel) {
+ xen_device_unbind_event_channel(xendev, con->event_channel,
+ errp);
+ con->event_channel = NULL;
+
+ if (xen_mode == XEN_EMULATE && !con->dev) {
+ xen_primary_console_set_be_port(0);
+ }
}
- free(dom);
- type = xenstore_read_str(con->console, "type");
- if (!type || strcmp(type, "ioemu") != 0) {
- xen_pv_printf(xendev, 1, "not for me (type=%s)\n", type);
- ret = -1;
- goto out;
+ if (con->sring) {
+ if (!con->dev && xen_mode != XEN_EMULATE) {
+ qemu_xen_foreignmem_unmap(con->sring, 1);
+ } else {
+ xen_device_unmap_grant_refs(xendev, con->sring,
+ &con->ring_ref, 1, errp);
+ }
+ con->sring = NULL;
}
+}
+
+static void xen_console_frontend_changed(XenDevice *xendev,
+ enum xenbus_state frontend_state,
+ Error **errp)
+{
+ ERRP_GUARD();
+ enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
+
+ switch (frontend_state) {
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ if (backend_state == XenbusStateConnected) {
+ break;
+ }
- output = xenstore_read_str(con->console, "output");
+ xen_console_disconnect(xendev, errp);
+ if (*errp) {
+ break;
+ }
- /* no Xen override, use qemu output device */
- if (output == NULL) {
- if (con->xendev.dev) {
- qemu_chr_fe_init(&con->chr, serial_hd(con->xendev.dev),
- &error_abort);
+ if (!xen_console_connect(xendev, errp)) {
+ xen_device_backend_set_state(xendev, XenbusStateClosing);
+ break;
}
- } else {
- snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
- qemu_chr_fe_init(&con->chr,
- /*
- * FIXME: sure we want to support implicit
- * muxed monitors here?
- */
- qemu_chr_new_mux_mon(label, output, NULL),
- &error_abort);
+
+ xen_device_backend_set_state(xendev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xen_device_backend_set_state(xendev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ case XenbusStateUnknown:
+ xen_console_disconnect(xendev, errp);
+ if (*errp) {
+ break;
+ }
+
+ xen_device_backend_set_state(xendev, XenbusStateClosed);
+ break;
+
+ default:
+ break;
}
+}
- store_con_info(con);
+static char *xen_console_get_name(XenDevice *xendev, Error **errp)
+{
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+
+ if (con->dev == -1) {
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ char fe_path[XENSTORE_ABS_PATH_MAX + 1];
+ int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
+ char *value;
+
+ /* Theoretically we could go up to INT_MAX here but that's overkill */
+ while (idx < 100) {
+ if (!idx) {
+ snprintf(fe_path, sizeof(fe_path),
+ "/local/domain/%u/console", xendev->frontend_id);
+ } else {
+ snprintf(fe_path, sizeof(fe_path),
+ "/local/domain/%u/device/console/%u",
+ xendev->frontend_id, idx);
+ }
+ value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
+ if (!value) {
+ if (errno == ENOENT) {
+ con->dev = idx;
+ goto found;
+ }
+ error_setg(errp, "cannot read %s: %s", fe_path,
+ strerror(errno));
+ return NULL;
+ }
+ free(value);
+ idx++;
+ }
+ error_setg(errp, "cannot find device index for console device");
+ return NULL;
+ }
+ found:
+ return g_strdup_printf("%u", con->dev);
+}
-out:
- g_free(type);
- return ret;
+static void xen_console_unrealize(XenDevice *xendev)
+{
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+
+ trace_xen_console_unrealize(con->dev);
+
+ /* Disconnect from the frontend in case this has not already happened */
+ xen_console_disconnect(xendev, NULL);
+
+ qemu_chr_fe_deinit(&con->chr, false);
}
-static int con_initialise(struct XenLegacyDevice *xendev)
+static void xen_console_realize(XenDevice *xendev, Error **errp)
{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
- int limit;
-
- if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
- return -1;
- if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
- return -1;
- if (xenstore_read_int(con->console, "limit", &limit) == 0)
- con->buffer.max_capacity = limit;
+ ERRP_GUARD();
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+ Chardev *cs = qemu_chr_fe_get_driver(&con->chr);
+ unsigned int u;
- if (!xendev->dev) {
- xen_pfn_t mfn = con->ring_ref;
- con->sring = qemu_xen_foreignmem_map(con->xendev.dom, NULL,
- PROT_READ | PROT_WRITE,
- 1, &mfn, NULL);
+ if (!cs) {
+ error_setg(errp, "no backing character device");
+ return;
+ }
+
+ if (con->dev == -1) {
+ error_setg(errp, "no device index provided");
+ return;
+ }
+
+ /*
+ * The Xen primary console is special. The ring-ref is actually a GFN to
+ * be mapped directly as foreignmem (not a grant ref), and the guest port
+ * was allocated *for* the guest by the toolstack. The guest gets these
+ * through HVMOP_get_param and can use the console long before it's got
+ * XenStore up and running. We cannot create those for a true Xen guest,
+ * but we can for Xen emulation.
+ */
+ if (!con->dev) {
+ if (xen_mode == XEN_EMULATE) {
+ xen_primary_console_create();
+ } else if (xen_device_frontend_scanf(xendev, "ring-ref", "%u", &u)
+ != 1 ||
+ xen_device_frontend_scanf(xendev, "port", "%u", &u) != 1) {
+ error_setg(errp, "cannot create primary Xen console");
+ return;
+ }
+ }
+
+ trace_xen_console_realize(con->dev, object_get_typename(OBJECT(cs)));
+
+ if (CHARDEV_IS_PTY(cs)) {
+ /* Strip the leading 'pty:' */
+ xen_device_frontend_printf(xendev, "tty", "%s", cs->filename + 4);
+ }
+
+ /* No normal PV driver initialization for the primary console under Xen */
+ if (!con->dev && xen_mode != XEN_EMULATE) {
+ xen_console_connect(xendev, errp);
+ }
+}
+
+static char *console_frontend_path(struct qemu_xs_handle *xenstore,
+ unsigned int dom_id, unsigned int dev)
+{
+ if (!dev) {
+ return g_strdup_printf("/local/domain/%u/console", dom_id);
} else {
- con->sring = xen_be_map_grant_ref(xendev, con->ring_ref,
- PROT_READ | PROT_WRITE);
+ return g_strdup_printf("/local/domain/%u/device/console/%u", dom_id,
+ dev);
}
- if (!con->sring)
- return -1;
+}
- xen_be_bind_evtchn(&con->xendev);
- qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
- xencons_receive, NULL, NULL, con, NULL, true);
-
- xen_pv_printf(xendev, 1,
- "ring mfn %d, remote port %d, local port %d, limit %zd\n",
- con->ring_ref,
- con->xendev.remote_port,
- con->xendev.local_port,
- con->buffer.max_capacity);
- return 0;
+static char *xen_console_get_frontend_path(XenDevice *xendev, Error **errp)
+{
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ char *ret = console_frontend_path(xenbus->xsh, xendev->frontend_id,
+ con->dev);
+
+ if (!ret) {
+ error_setg(errp, "failed to create frontend path");
+ }
+ return ret;
}
-static void con_disconnect(struct XenLegacyDevice *xendev)
+
+static Property xen_console_properties[] = {
+ DEFINE_PROP_CHR("chardev", XenConsole, chr),
+ DEFINE_PROP_INT32("idx", XenConsole, dev, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xen_console_class_init(ObjectClass *class, void *data)
{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+ XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
+
+ xendev_class->backend = "console";
+ xendev_class->device = "console";
+ xendev_class->get_name = xen_console_get_name;
+ xendev_class->realize = xen_console_realize;
+ xendev_class->frontend_changed = xen_console_frontend_changed;
+ xendev_class->unrealize = xen_console_unrealize;
+ xendev_class->get_frontend_path = xen_console_get_frontend_path;
+
+ device_class_set_props(dev_class, xen_console_properties);
+}
- qemu_chr_fe_deinit(&con->chr, false);
- xen_pv_unbind_evtchn(&con->xendev);
+static const TypeInfo xen_console_type_info = {
+ .name = TYPE_XEN_CONSOLE_DEVICE,
+ .parent = TYPE_XEN_DEVICE,
+ .instance_size = sizeof(XenConsole),
+ .class_init = xen_console_class_init,
+};
- if (con->sring) {
- if (!xendev->dev) {
- qemu_xen_foreignmem_unmap(con->sring, 1);
- } else {
- xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref);
+static void xen_console_register_types(void)
+{
+ type_register_static(&xen_console_type_info);
+}
+
+type_init(xen_console_register_types)
+
+/* Called to instantiate a XenConsole when the backend is detected. */
+static void xen_console_device_create(XenBackendInstance *backend,
+ QDict *opts, Error **errp)
+{
+ ERRP_GUARD();
+ XenBus *xenbus = xen_backend_get_bus(backend);
+ const char *name = xen_backend_get_name(backend);
+ unsigned long number;
+ char *fe = NULL, *type = NULL, *output = NULL;
+ char label[32];
+ XenDevice *xendev = NULL;
+ XenConsole *con;
+ Chardev *cd = NULL;
+ struct qemu_xs_handle *xsh = xenbus->xsh;
+
+ if (qemu_strtoul(name, NULL, 10, &number) || number > INT_MAX) {
+ error_setg(errp, "failed to parse name '%s'", name);
+ goto fail;
+ }
+
+ trace_xen_console_device_create(number);
+
+ fe = console_frontend_path(xsh, xen_domid, number);
+ if (fe == NULL) {
+ error_setg(errp, "failed to generate frontend path");
+ goto fail;
+ }
+
+ if (xs_node_scanf(xsh, XBT_NULL, fe, "type", errp, "%ms", &type) != 1) {
+ error_prepend(errp, "failed to read console device type: ");
+ goto fail;
+ }
+
+ if (strcmp(type, "ioemu")) {
+ error_setg(errp, "declining to handle console type '%s'",
+ type);
+ goto fail;
+ }
+
+ xendev = XEN_DEVICE(qdev_new(TYPE_XEN_CONSOLE_DEVICE));
+ con = XEN_CONSOLE_DEVICE(xendev);
+
+ con->dev = number;
+
+ snprintf(label, sizeof(label), "xencons%ld", number);
+
+ if (xs_node_scanf(xsh, XBT_NULL, fe, "output", NULL, "%ms", &output) == 1) {
+ /*
+ * FIXME: sure we want to support implicit
+ * muxed monitors here?
+ */
+ cd = qemu_chr_new_mux_mon(label, output, NULL);
+ if (!cd) {
+ error_setg(errp, "console: No valid chardev found at '%s': ",
+ output);
+ goto fail;
}
- con->sring = NULL;
+ } else if (number) {
+ cd = serial_hd(number);
+ if (!cd) {
+ error_prepend(errp, "console: No serial device #%ld found: ",
+ number);
+ goto fail;
+ }
+ } else {
+ /* No 'output' node on primary console: use null. */
+ cd = qemu_chr_new(label, "null", NULL);
+ if (!cd) {
+ error_setg(errp, "console: failed to create null device");
+ goto fail;
+ }
+ }
+
+ if (!qemu_chr_fe_init(&con->chr, cd, errp)) {
+ error_prepend(errp, "console: failed to initialize backing chardev: ");
+ goto fail;
+ }
+
+ if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) {
+ xen_backend_set_device(backend, xendev);
+ goto done;
+ }
+
+ error_prepend(errp, "realization of console device %lu failed: ",
+ number);
+
+ fail:
+ if (xendev) {
+ object_unparent(OBJECT(xendev));
}
+ done:
+ g_free(fe);
+ free(type);
+ free(output);
}
-static void con_event(struct XenLegacyDevice *xendev)
+static void xen_console_device_destroy(XenBackendInstance *backend,
+ Error **errp)
{
- struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ ERRP_GUARD();
+ XenDevice *xendev = xen_backend_get_device(backend);
+ XenConsole *con = XEN_CONSOLE_DEVICE(xendev);
- buffer_append(con);
- if (con->buffer.size - con->buffer.consumed)
- xencons_send(con);
-}
+ trace_xen_console_device_destroy(con->dev);
-/* -------------------------------------------------------------------- */
+ object_unparent(OBJECT(xendev));
+}
-struct XenDevOps xen_console_ops = {
- .size = sizeof(struct XenConsole),
- .flags = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV,
- .init = con_init,
- .initialise = con_initialise,
- .event = con_event,
- .disconnect = con_disconnect,
+static const XenBackendInfo xen_console_backend_info = {
+ .type = "console",
+ .create = xen_console_device_create,
+ .destroy = xen_console_device_destroy,
};
+
+static void xen_console_register_backend(void)
+{
+ xen_backend_register(&xen_console_backend_info);
+}
+
+xen_backend_init(xen_console_register_backend);
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 67d4d1b..a3222d3 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -87,7 +87,7 @@ static const MemoryRegionOps hppa_pci_ignore_ops = {
},
};
-static ISABus *hppa_isa_bus(void)
+static ISABus *hppa_isa_bus(hwaddr addr)
{
ISABus *isa_bus;
qemu_irq *isa_irqs;
@@ -96,8 +96,7 @@ static ISABus *hppa_isa_bus(void)
isa_region = g_new(MemoryRegion, 1);
memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops,
NULL, "isa-io", 0x800);
- memory_region_add_subregion(get_system_memory(), IDE_HPA,
- isa_region);
+ memory_region_add_subregion(get_system_memory(), addr, isa_region);
isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region,
&error_abort);
@@ -163,13 +162,24 @@ static const MemoryRegionOps hppa_io_helper_ops = {
},
};
+typedef uint64_t TranslateFn(void *opaque, uint64_t addr);
-static uint64_t cpu_hppa_to_phys(void *opaque, uint64_t addr)
+static uint64_t linux_kernel_virt_to_phys(void *opaque, uint64_t addr)
{
addr &= (0x10000000 - 1);
return addr;
}
+static uint64_t translate_pa10(void *dummy, uint64_t addr)
+{
+ return (uint32_t)addr;
+}
+
+static uint64_t translate_pa20(void *dummy, uint64_t addr)
+{
+ return hppa_abs_to_phys_pa2_w0(addr);
+}
+
static HPPACPU *cpu[HPPA_MAX_CPUS];
static uint64_t firmware_entry;
@@ -179,15 +189,17 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device,
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
-static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus)
+static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
+ hwaddr addr)
{
FWCfgState *fw_cfg;
uint64_t val;
const char qemu_version[] = QEMU_VERSION;
MachineClass *mc = MACHINE_GET_CLASS(ms);
+ int btlb_entries = HPPA_BTLB_ENTRIES(&cpu[0]->env);
int len;
- fw_cfg = fw_cfg_init_mem(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4);
+ fw_cfg = fw_cfg_init_mem(addr, addr + 4);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, HPPA_MAX_CPUS);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
@@ -196,11 +208,11 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus)
fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version",
g_memdup(&val, sizeof(val)), sizeof(val));
- val = cpu_to_le64(HPPA_TLB_ENTRIES - HPPA_BTLB_ENTRIES);
+ val = cpu_to_le64(HPPA_TLB_ENTRIES - btlb_entries);
fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries",
g_memdup(&val, sizeof(val)), sizeof(val));
- val = cpu_to_le64(HPPA_BTLB_ENTRIES);
+ val = cpu_to_le64(btlb_entries);
fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries",
g_memdup(&val, sizeof(val)), sizeof(val));
@@ -257,32 +269,45 @@ static DinoState *dino_init(MemoryRegion *addr_space)
/*
* Step 1: Create CPUs and Memory
*/
-static void machine_HP_common_init_cpus(MachineState *machine)
+static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
{
MemoryRegion *addr_space = get_system_memory();
- MemoryRegion *cpu_region;
- long i;
unsigned int smp_cpus = machine->smp.cpus;
- char *name;
+ TranslateFn *translate;
+ MemoryRegion *cpu_region;
/* Create CPUs. */
- for (i = 0; i < smp_cpus; i++) {
- name = g_strdup_printf("cpu%ld-io-eir", i);
+ for (unsigned int i = 0; i < smp_cpus; i++) {
cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type));
+ }
+
+ /*
+ * For now, treat address layout as if PSW_W is clear.
+ * TODO: create a proper hppa64 board model and load elf64 firmware.
+ */
+ if (hppa_is_pa20(&cpu[0]->env)) {
+ translate = translate_pa20;
+ } else {
+ translate = translate_pa10;
+ }
+
+ for (unsigned int i = 0; i < smp_cpus; i++) {
+ g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i);
cpu_region = g_new(MemoryRegion, 1);
memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops,
cpu[i], name, 4);
- memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000,
+ memory_region_add_subregion(addr_space,
+ translate(NULL, CPU_HPA + i * 0x1000),
cpu_region);
- g_free(name);
}
/* RTC and DebugOutputPort on CPU #0 */
cpu_region = g_new(MemoryRegion, 1);
memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops,
cpu[0], "cpu0-io-rtc", 2 * sizeof(uint64_t));
- memory_region_add_subregion(addr_space, CPU_HPA + 16, cpu_region);
+ memory_region_add_subregion(addr_space, translate(NULL, CPU_HPA + 16),
+ cpu_region);
/* Main memory region. */
if (machine->ram_size > 3 * GiB) {
@@ -290,12 +315,15 @@ static void machine_HP_common_init_cpus(MachineState *machine)
exit(EXIT_FAILURE);
}
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
+
+ return translate;
}
/*
* Last creation step: Add SCSI discs, NICs, graphics & load firmware
*/
-static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
+static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
+ TranslateFn *translate)
{
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
@@ -323,13 +351,13 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
dev = qdev_new("artist");
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, LASI_GFX_HPA);
- sysbus_mmio_map(s, 1, ARTIST_FB_ADDR);
+ sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
+ sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
}
/* Network setup. */
if (enable_lasi_lan()) {
- lasi_82596_init(addr_space, LASI_LAN_HPA,
+ lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA),
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA));
}
@@ -373,7 +401,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier);
/* fw_cfg configuration interface */
- create_fw_cfg(machine, pci_bus);
+ create_fw_cfg(machine, pci_bus, translate(NULL, FW_CFG_IO_BASE));
/* Load firmware. Given that this is not "real" firmware,
but one explicitly written for the emulation, we might as
@@ -385,15 +413,10 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
exit(1);
}
- size = load_elf(firmware_filename, NULL, NULL, NULL,
+ size = load_elf(firmware_filename, NULL, translate, NULL,
&firmware_entry, &firmware_low, &firmware_high, NULL,
true, EM_PARISC, 0, 0);
- /* Unfortunately, load_elf sign-extends reading elf32. */
- firmware_entry = (target_ureg)firmware_entry;
- firmware_low = (target_ureg)firmware_low;
- firmware_high = (target_ureg)firmware_high;
-
if (size < 0) {
error_report("could not load firmware '%s'", firmware_filename);
exit(1);
@@ -401,7 +424,8 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64
"-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n",
firmware_low, firmware_high, firmware_entry);
- if (firmware_low < FIRMWARE_START || firmware_high >= FIRMWARE_END) {
+ if (firmware_low < translate(NULL, FIRMWARE_START) ||
+ firmware_high >= translate(NULL, FIRMWARE_END)) {
error_report("Firmware overlaps with memory or IO space");
exit(1);
}
@@ -410,18 +434,16 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus)
rom_region = g_new(MemoryRegion, 1);
memory_region_init_ram(rom_region, NULL, "firmware",
(FIRMWARE_END - FIRMWARE_START), &error_fatal);
- memory_region_add_subregion(addr_space, FIRMWARE_START, rom_region);
+ memory_region_add_subregion(addr_space,
+ translate(NULL, FIRMWARE_START), rom_region);
/* Load kernel */
if (kernel_filename) {
- size = load_elf(kernel_filename, NULL, &cpu_hppa_to_phys,
+ size = load_elf(kernel_filename, NULL, linux_kernel_virt_to_phys,
NULL, &kernel_entry, &kernel_low, &kernel_high, NULL,
true, EM_PARISC, 0, 0);
- /* Unfortunately, load_elf sign-extends reading elf32. */
- kernel_entry = (target_ureg) cpu_hppa_to_phys(NULL, kernel_entry);
- kernel_low = (target_ureg)kernel_low;
- kernel_high = (target_ureg)kernel_high;
+ kernel_entry = linux_kernel_virt_to_phys(NULL, kernel_entry);
if (size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
@@ -499,41 +521,48 @@ static void machine_HP_B160L_init(MachineState *machine)
{
DeviceState *dev, *dino_dev;
MemoryRegion *addr_space = get_system_memory();
+ TranslateFn *translate;
ISABus *isa_bus;
PCIBus *pci_bus;
/* Create CPUs and RAM. */
- machine_HP_common_init_cpus(machine);
+ translate = machine_HP_common_init_cpus(machine);
+
+ if (hppa_is_pa20(&cpu[0]->env)) {
+ error_report("The HP B160L workstation requires a 32-bit "
+ "CPU. Use '-machine C3700' instead.");
+ exit(1);
+ }
/* Init Lasi chip */
lasi_dev = DEVICE(lasi_init());
- memory_region_add_subregion(addr_space, LASI_HPA,
+ memory_region_add_subregion(addr_space, translate(NULL, LASI_HPA),
sysbus_mmio_get_region(
SYS_BUS_DEVICE(lasi_dev), 0));
/* Init Dino (PCI host bus chip). */
dino_dev = DEVICE(dino_init(addr_space));
- memory_region_add_subregion(addr_space, DINO_HPA,
+ memory_region_add_subregion(addr_space, translate(NULL, DINO_HPA),
sysbus_mmio_get_region(
SYS_BUS_DEVICE(dino_dev), 0));
pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci"));
assert(pci_bus);
/* Create ISA bus, needed for PS/2 kbd/mouse port emulation */
- isa_bus = hppa_isa_bus();
+ isa_bus = hppa_isa_bus(translate(NULL, IDE_HPA));
assert(isa_bus);
/* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */
- serial_mm_init(addr_space, LASI_UART_HPA + 0x800, 0,
+ serial_mm_init(addr_space, translate(NULL, LASI_UART_HPA + 0x800), 0,
qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16,
serial_hd(0), DEVICE_BIG_ENDIAN);
- serial_mm_init(addr_space, DINO_UART_HPA + 0x800, 0,
+ serial_mm_init(addr_space, translate(NULL, DINO_UART_HPA + 0x800), 0,
qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16,
serial_hd(1), DEVICE_BIG_ENDIAN);
/* Parallel port */
- parallel_mm_init(addr_space, LASI_LPT_HPA + 0x800, 0,
+ parallel_mm_init(addr_space, translate(NULL, LASI_LPT_HPA + 0x800), 0,
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA),
parallel_hds[0]);
@@ -542,15 +571,17 @@ static void machine_HP_B160L_init(MachineState *machine)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA));
- memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA,
+ memory_region_add_subregion(addr_space,
+ translate(NULL, LASI_PS2KBD_HPA),
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
0));
- memory_region_add_subregion(addr_space, LASI_PS2KBD_HPA + 0x100,
+ memory_region_add_subregion(addr_space,
+ translate(NULL, LASI_PS2KBD_HPA + 0x100),
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
1));
/* Add SCSI discs, NICs, graphics & load firmware */
- machine_HP_common_init_tail(machine, pci_bus);
+ machine_HP_common_init_tail(machine, pci_bus, translate);
}
static AstroState *astro_init(void)
@@ -572,21 +603,28 @@ static void machine_HP_C3700_init(MachineState *machine)
AstroState *astro;
DeviceState *astro_dev;
MemoryRegion *addr_space = get_system_memory();
+ TranslateFn *translate;
/* Create CPUs and RAM. */
- machine_HP_common_init_cpus(machine);
+ translate = machine_HP_common_init_cpus(machine);
+
+ if (!hppa_is_pa20(&cpu[0]->env)) {
+ error_report("The HP C3000 workstation requires a 64-bit CPU. "
+ "Use '-machine B160L' instead.");
+ exit(1);
+ }
/* Init Astro and the Elroys (PCI host bus chips). */
astro = astro_init();
astro_dev = DEVICE(astro);
- memory_region_add_subregion(addr_space, ASTRO_HPA,
+ memory_region_add_subregion(addr_space, translate(NULL, ASTRO_HPA),
sysbus_mmio_get_region(
SYS_BUS_DEVICE(astro_dev), 0));
pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci"));
assert(pci_bus);
/* Add SCSI discs, NICs, graphics & load firmware */
- machine_HP_common_init_tail(machine, pci_bus);
+ machine_HP_common_init_tail(machine, pci_bus, translate);
}
static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
@@ -608,10 +646,6 @@ static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
cs->exception_index = -1;
cs->halted = 0;
-
- /* clear any existing TLB and BTLB entries */
- memset(cpu[i]->env.tlb, 0, sizeof(cpu[i]->env.tlb));
- cpu[i]->env.tlb_last = HPPA_BTLB_ENTRIES;
}
/* already initialized by machine_hppa_init()? */
@@ -637,6 +671,11 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
}
}
+static const char *HP_B160L_machine_valid_cpu_types[] = {
+ TYPE_HPPA_CPU,
+ NULL
+};
+
static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -644,6 +683,7 @@ static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
mc->desc = "HP B160L workstation";
mc->default_cpu_type = TYPE_HPPA_CPU;
+ mc->valid_cpu_types = HP_B160L_machine_valid_cpu_types;
mc->init = machine_HP_B160L_init;
mc->reset = hppa_machine_reset;
mc->block_default_type = IF_SCSI;
@@ -668,13 +708,19 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = {
},
};
+static const char *HP_C3700_machine_valid_cpu_types[] = {
+ TYPE_HPPA64_CPU,
+ NULL
+};
+
static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
mc->desc = "HP C3700 workstation";
- mc->default_cpu_type = TYPE_HPPA_CPU;
+ mc->default_cpu_type = TYPE_HPPA64_CPU;
+ mc->valid_cpu_types = HP_C3700_machine_valid_cpu_types;
mc->init = machine_HP_C3700_init;
mc->reset = hppa_machine_reset;
mc->block_default_type = IF_SCSI;
diff --git a/hw/i386/kvm/meson.build b/hw/i386/kvm/meson.build
index ab143d6..a4a2e23 100644
--- a/hw/i386/kvm/meson.build
+++ b/hw/i386/kvm/meson.build
@@ -9,6 +9,7 @@ i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files(
'xen_evtchn.c',
'xen_gnttab.c',
'xen_xenstore.c',
+ 'xen_primary_console.c',
'xenstore_impl.c',
))
diff --git a/hw/i386/kvm/trace-events b/hw/i386/kvm/trace-events
index e4c82de..67bf7f1 100644
--- a/hw/i386/kvm/trace-events
+++ b/hw/i386/kvm/trace-events
@@ -18,3 +18,5 @@ xenstore_watch(const char *path, const char *token) "path %s token %s"
xenstore_unwatch(const char *path, const char *token) "path %s token %s"
xenstore_reset_watches(void) ""
xenstore_watch_event(const char *path, const char *token) "path %s token %s"
+xen_primary_console_create(void) ""
+xen_primary_console_reset(int port) "port %u"
diff --git a/hw/i386/kvm/xen-stubs.c b/hw/i386/kvm/xen-stubs.c
index ae406e0..d03131e 100644
--- a/hw/i386/kvm/xen-stubs.c
+++ b/hw/i386/kvm/xen-stubs.c
@@ -15,6 +15,7 @@
#include "qapi/qapi-commands-misc-target.h"
#include "xen_evtchn.h"
+#include "xen_primary_console.h"
void xen_evtchn_snoop_msi(PCIDevice *dev, bool is_msix, unsigned int vector,
uint64_t addr, uint32_t data, bool is_masked)
@@ -30,6 +31,13 @@ bool xen_evtchn_deliver_pirq_msi(uint64_t address, uint32_t data)
return false;
}
+void xen_primary_console_create(void)
+{
+}
+
+void xen_primary_console_set_be_port(uint16_t port)
+{
+}
#ifdef TARGET_I386
EvtchnInfoList *qmp_xen_event_list(Error **errp)
{
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c
index b2b4be9..02b8cbf 100644
--- a/hw/i386/kvm/xen_evtchn.c
+++ b/hw/i386/kvm/xen_evtchn.c
@@ -58,7 +58,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(XenEvtchnState, XEN_EVTCHN)
typedef struct XenEvtchnPort {
uint32_t vcpu; /* Xen/ACPI vcpu_id */
uint16_t type; /* EVTCHNSTAT_xxxx */
- uint16_t type_val; /* pirq# / virq# / remote port according to type */
+ union {
+ uint16_t val; /* raw value for serialization etc. */
+ uint16_t pirq;
+ uint16_t virq;
+ struct {
+ uint16_t port:15;
+ uint16_t to_qemu:1; /* Only two targets; qemu or loopback */
+ } interdomain;
+ } u;
} XenEvtchnPort;
/* 32-bit compatibility definitions, also used natively in 32-bit build */
@@ -106,14 +114,6 @@ struct xenevtchn_handle {
};
/*
- * For unbound/interdomain ports there are only two possible remote
- * domains; self and QEMU. Use a single high bit in type_val for that,
- * and the low bits for the remote port number (or 0 for unbound).
- */
-#define PORT_INFO_TYPEVAL_REMOTE_QEMU 0x8000
-#define PORT_INFO_TYPEVAL_REMOTE_PORT_MASK 0x7FFF
-
-/*
* These 'emuirq' values are used by Xen in the LM stream... and yes, I am
* insane enough to think about guest-transparent live migration from actual
* Xen to QEMU, and ensuring that we can convert/consume the stream.
@@ -210,16 +210,16 @@ static int xen_evtchn_post_load(void *opaque, int version_id)
XenEvtchnPort *p = &s->port_table[i];
if (p->type == EVTCHNSTAT_pirq) {
- assert(p->type_val);
- assert(p->type_val < s->nr_pirqs);
+ assert(p->u.pirq);
+ assert(p->u.pirq < s->nr_pirqs);
/*
* Set the gsi to IRQ_UNBOUND; it may be changed to an actual
* GSI# below, or to IRQ_MSI_EMU when the MSI table snooping
* catches up with it.
*/
- s->pirq[p->type_val].gsi = IRQ_UNBOUND;
- s->pirq[p->type_val].port = i;
+ s->pirq[p->u.pirq].gsi = IRQ_UNBOUND;
+ s->pirq[p->u.pirq].port = i;
}
}
/* Rebuild s->pirq[].gsi mapping */
@@ -243,7 +243,7 @@ static const VMStateDescription xen_evtchn_port_vmstate = {
.fields = (VMStateField[]) {
VMSTATE_UINT32(vcpu, XenEvtchnPort),
VMSTATE_UINT16(type, XenEvtchnPort),
- VMSTATE_UINT16(type_val, XenEvtchnPort),
+ VMSTATE_UINT16(u.val, XenEvtchnPort),
VMSTATE_END_OF_LIST()
}
};
@@ -605,14 +605,13 @@ static void unbind_backend_ports(XenEvtchnState *s)
for (i = 1; i < s->nr_ports; i++) {
p = &s->port_table[i];
- if (p->type == EVTCHNSTAT_interdomain &&
- (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU)) {
- evtchn_port_t be_port = p->type_val & PORT_INFO_TYPEVAL_REMOTE_PORT_MASK;
+ if (p->type == EVTCHNSTAT_interdomain && p->u.interdomain.to_qemu) {
+ evtchn_port_t be_port = p->u.interdomain.port;
if (s->be_handles[be_port]) {
/* This part will be overwritten on the load anyway. */
p->type = EVTCHNSTAT_unbound;
- p->type_val = PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ p->u.interdomain.port = 0;
/* Leave the backend port open and unbound too. */
if (kvm_xen_has_cap(EVTCHN_SEND)) {
@@ -650,30 +649,22 @@ int xen_evtchn_status_op(struct evtchn_status *status)
switch (p->type) {
case EVTCHNSTAT_unbound:
- if (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU) {
- status->u.unbound.dom = DOMID_QEMU;
- } else {
- status->u.unbound.dom = xen_domid;
- }
+ status->u.unbound.dom = p->u.interdomain.to_qemu ? DOMID_QEMU
+ : xen_domid;
break;
case EVTCHNSTAT_interdomain:
- if (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU) {
- status->u.interdomain.dom = DOMID_QEMU;
- } else {
- status->u.interdomain.dom = xen_domid;
- }
-
- status->u.interdomain.port = p->type_val &
- PORT_INFO_TYPEVAL_REMOTE_PORT_MASK;
+ status->u.interdomain.dom = p->u.interdomain.to_qemu ? DOMID_QEMU
+ : xen_domid;
+ status->u.interdomain.port = p->u.interdomain.port;
break;
case EVTCHNSTAT_pirq:
- status->u.pirq = p->type_val;
+ status->u.pirq = p->u.pirq;
break;
case EVTCHNSTAT_virq:
- status->u.virq = p->type_val;
+ status->u.virq = p->u.virq;
break;
}
@@ -989,7 +980,7 @@ static int clear_port_pending(XenEvtchnState *s, evtchn_port_t port)
static void free_port(XenEvtchnState *s, evtchn_port_t port)
{
s->port_table[port].type = EVTCHNSTAT_closed;
- s->port_table[port].type_val = 0;
+ s->port_table[port].u.val = 0;
s->port_table[port].vcpu = 0;
if (s->nr_ports == port + 1) {
@@ -1012,7 +1003,7 @@ static int allocate_port(XenEvtchnState *s, uint32_t vcpu, uint16_t type,
if (s->port_table[p].type == EVTCHNSTAT_closed) {
s->port_table[p].vcpu = vcpu;
s->port_table[p].type = type;
- s->port_table[p].type_val = val;
+ s->port_table[p].u.val = val;
*port = p;
@@ -1053,15 +1044,15 @@ static int close_port(XenEvtchnState *s, evtchn_port_t port,
return -ENOENT;
case EVTCHNSTAT_pirq:
- s->pirq[p->type_val].port = 0;
- if (s->pirq[p->type_val].is_translated) {
+ s->pirq[p->u.pirq].port = 0;
+ if (s->pirq[p->u.pirq].is_translated) {
*flush_kvm_routes = true;
}
break;
case EVTCHNSTAT_virq:
- kvm_xen_set_vcpu_virq(virq_is_global(p->type_val) ? 0 : p->vcpu,
- p->type_val, 0);
+ kvm_xen_set_vcpu_virq(virq_is_global(p->u.virq) ? 0 : p->vcpu,
+ p->u.virq, 0);
break;
case EVTCHNSTAT_ipi:
@@ -1071,8 +1062,8 @@ static int close_port(XenEvtchnState *s, evtchn_port_t port,
break;
case EVTCHNSTAT_interdomain:
- if (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU) {
- uint16_t be_port = p->type_val & ~PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ if (p->u.interdomain.to_qemu) {
+ uint16_t be_port = p->u.interdomain.port;
struct xenevtchn_handle *xc = s->be_handles[be_port];
if (xc) {
if (kvm_xen_has_cap(EVTCHN_SEND)) {
@@ -1082,14 +1073,15 @@ static int close_port(XenEvtchnState *s, evtchn_port_t port,
}
} else {
/* Loopback interdomain */
- XenEvtchnPort *rp = &s->port_table[p->type_val];
- if (!valid_port(p->type_val) || rp->type_val != port ||
+ XenEvtchnPort *rp = &s->port_table[p->u.interdomain.port];
+ if (!valid_port(p->u.interdomain.port) ||
+ rp->u.interdomain.port != port ||
rp->type != EVTCHNSTAT_interdomain) {
error_report("Inconsistent state for interdomain unbind");
} else {
/* Set the other end back to unbound */
rp->type = EVTCHNSTAT_unbound;
- rp->type_val = 0;
+ rp->u.interdomain.port = 0;
}
}
break;
@@ -1214,7 +1206,7 @@ int xen_evtchn_bind_vcpu_op(struct evtchn_bind_vcpu *vcpu)
if (p->type == EVTCHNSTAT_interdomain ||
p->type == EVTCHNSTAT_unbound ||
p->type == EVTCHNSTAT_pirq ||
- (p->type == EVTCHNSTAT_virq && virq_is_global(p->type_val))) {
+ (p->type == EVTCHNSTAT_virq && virq_is_global(p->u.virq))) {
/*
* unmask_port() with do_unmask==false will just raise the event
* on the new vCPU if the port was already pending.
@@ -1359,19 +1351,15 @@ int xen_evtchn_bind_ipi_op(struct evtchn_bind_ipi *ipi)
int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain)
{
XenEvtchnState *s = xen_evtchn_singleton;
- uint16_t type_val;
int ret;
if (!s) {
return -ENOTSUP;
}
- if (interdomain->remote_dom == DOMID_QEMU) {
- type_val = PORT_INFO_TYPEVAL_REMOTE_QEMU;
- } else if (interdomain->remote_dom == DOMID_SELF ||
- interdomain->remote_dom == xen_domid) {
- type_val = 0;
- } else {
+ if (interdomain->remote_dom != DOMID_QEMU &&
+ interdomain->remote_dom != DOMID_SELF &&
+ interdomain->remote_dom != xen_domid) {
return -ESRCH;
}
@@ -1382,8 +1370,8 @@ int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain)
qemu_mutex_lock(&s->port_lock);
/* The newly allocated port starts out as unbound */
- ret = allocate_port(s, 0, EVTCHNSTAT_unbound, type_val,
- &interdomain->local_port);
+ ret = allocate_port(s, 0, EVTCHNSTAT_unbound, 0, &interdomain->local_port);
+
if (ret) {
goto out;
}
@@ -1408,7 +1396,8 @@ int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain)
assign_kernel_eventfd(lp->type, xc->guest_port, xc->fd);
}
lp->type = EVTCHNSTAT_interdomain;
- lp->type_val = PORT_INFO_TYPEVAL_REMOTE_QEMU | interdomain->remote_port;
+ lp->u.interdomain.to_qemu = 1;
+ lp->u.interdomain.port = interdomain->remote_port;
ret = 0;
} else {
/* Loopback */
@@ -1416,19 +1405,18 @@ int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain)
XenEvtchnPort *lp = &s->port_table[interdomain->local_port];
/*
- * The 'remote' port for loopback must be an unbound port allocated for
- * communication with the local domain (as indicated by rp->type_val
- * being zero, not PORT_INFO_TYPEVAL_REMOTE_QEMU), and must *not* be
- * the port that was just allocated for the local end.
+ * The 'remote' port for loopback must be an unbound port allocated
+ * for communication with the local domain, and must *not* be the
+ * port that was just allocated for the local end.
*/
if (interdomain->local_port != interdomain->remote_port &&
- rp->type == EVTCHNSTAT_unbound && rp->type_val == 0) {
+ rp->type == EVTCHNSTAT_unbound && !rp->u.interdomain.to_qemu) {
rp->type = EVTCHNSTAT_interdomain;
- rp->type_val = interdomain->local_port;
+ rp->u.interdomain.port = interdomain->local_port;
lp->type = EVTCHNSTAT_interdomain;
- lp->type_val = interdomain->remote_port;
+ lp->u.interdomain.port = interdomain->remote_port;
} else {
ret = -EINVAL;
}
@@ -1447,7 +1435,6 @@ int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain)
int xen_evtchn_alloc_unbound_op(struct evtchn_alloc_unbound *alloc)
{
XenEvtchnState *s = xen_evtchn_singleton;
- uint16_t type_val;
int ret;
if (!s) {
@@ -1458,18 +1445,20 @@ int xen_evtchn_alloc_unbound_op(struct evtchn_alloc_unbound *alloc)
return -ESRCH;
}
- if (alloc->remote_dom == DOMID_QEMU) {
- type_val = PORT_INFO_TYPEVAL_REMOTE_QEMU;
- } else if (alloc->remote_dom == DOMID_SELF ||
- alloc->remote_dom == xen_domid) {
- type_val = 0;
- } else {
+ if (alloc->remote_dom != DOMID_QEMU &&
+ alloc->remote_dom != DOMID_SELF &&
+ alloc->remote_dom != xen_domid) {
return -EPERM;
}
qemu_mutex_lock(&s->port_lock);
- ret = allocate_port(s, 0, EVTCHNSTAT_unbound, type_val, &alloc->port);
+ ret = allocate_port(s, 0, EVTCHNSTAT_unbound, 0, &alloc->port);
+
+ if (!ret && alloc->remote_dom == DOMID_QEMU) {
+ XenEvtchnPort *p = &s->port_table[alloc->port];
+ p->u.interdomain.to_qemu = 1;
+ }
qemu_mutex_unlock(&s->port_lock);
@@ -1496,12 +1485,12 @@ int xen_evtchn_send_op(struct evtchn_send *send)
switch (p->type) {
case EVTCHNSTAT_interdomain:
- if (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU) {
+ if (p->u.interdomain.to_qemu) {
/*
* This is an event from the guest to qemu itself, which is
* serving as the driver domain.
*/
- uint16_t be_port = p->type_val & ~PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ uint16_t be_port = p->u.interdomain.port;
struct xenevtchn_handle *xc = s->be_handles[be_port];
if (xc) {
eventfd_write(xc->fd, 1);
@@ -1511,7 +1500,7 @@ int xen_evtchn_send_op(struct evtchn_send *send)
}
} else {
/* Loopback interdomain ports; just a complex IPI */
- set_port_pending(s, p->type_val);
+ set_port_pending(s, p->u.interdomain.port);
}
break;
@@ -1553,8 +1542,7 @@ int xen_evtchn_set_port(uint16_t port)
/* QEMU has no business sending to anything but these */
if (p->type == EVTCHNSTAT_virq ||
- (p->type == EVTCHNSTAT_interdomain &&
- (p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU))) {
+ (p->type == EVTCHNSTAT_interdomain && p->u.interdomain.to_qemu)) {
set_port_pending(s, port);
ret = 0;
}
@@ -2064,7 +2052,7 @@ int xen_be_evtchn_bind_interdomain(struct xenevtchn_handle *xc, uint32_t domid,
switch (gp->type) {
case EVTCHNSTAT_interdomain:
/* Allow rebinding after migration, preserve port # if possible */
- be_port = gp->type_val & ~PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ be_port = gp->u.interdomain.port;
assert(be_port != 0);
if (!s->be_handles[be_port]) {
s->be_handles[be_port] = xc;
@@ -2085,7 +2073,8 @@ int xen_be_evtchn_bind_interdomain(struct xenevtchn_handle *xc, uint32_t domid,
}
gp->type = EVTCHNSTAT_interdomain;
- gp->type_val = be_port | PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ gp->u.interdomain.to_qemu = 1;
+ gp->u.interdomain.port = be_port;
xc->guest_port = guest_port;
if (kvm_xen_has_cap(EVTCHN_SEND)) {
assign_kernel_eventfd(gp->type, guest_port, xc->fd);
@@ -2130,7 +2119,7 @@ int xen_be_evtchn_unbind(struct xenevtchn_handle *xc, evtchn_port_t port)
/* This should never *not* be true */
if (gp->type == EVTCHNSTAT_interdomain) {
gp->type = EVTCHNSTAT_unbound;
- gp->type_val = PORT_INFO_TYPEVAL_REMOTE_QEMU;
+ gp->u.interdomain.port = 0;
}
if (kvm_xen_has_cap(EVTCHN_SEND)) {
@@ -2284,11 +2273,11 @@ EvtchnInfoList *qmp_xen_event_list(Error **errp)
info->type = p->type;
if (p->type == EVTCHNSTAT_interdomain) {
- info->remote_domain = g_strdup((p->type_val & PORT_INFO_TYPEVAL_REMOTE_QEMU) ?
+ info->remote_domain = g_strdup(p->u.interdomain.to_qemu ?
"qemu" : "loopback");
- info->target = p->type_val & PORT_INFO_TYPEVAL_REMOTE_PORT_MASK;
+ info->target = p->u.interdomain.port;
} else {
- info->target = p->type_val;
+ info->target = p->u.val; /* pirq# or virq# */
}
info->vcpu = p->vcpu;
info->pending = test_bit(i, pending);
diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c
index 839ec92..0a24f53 100644
--- a/hw/i386/kvm/xen_gnttab.c
+++ b/hw/i386/kvm/xen_gnttab.c
@@ -25,6 +25,7 @@
#include "hw/xen/xen_backend_ops.h"
#include "xen_overlay.h"
#include "xen_gnttab.h"
+#include "xen_primary_console.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_xen.h"
@@ -537,9 +538,13 @@ int xen_gnttab_reset(void)
s->nr_frames = 0;
memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames);
-
s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags = GTF_permit_access;
s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame = XEN_SPECIAL_PFN(XENSTORE);
+ if (xen_primary_console_get_pfn()) {
+ s->entries.v1[GNTTAB_RESERVED_CONSOLE].flags = GTF_permit_access;
+ s->entries.v1[GNTTAB_RESERVED_CONSOLE].frame = XEN_SPECIAL_PFN(CONSOLE);
+ }
+
return 0;
}
diff --git a/hw/i386/kvm/xen_primary_console.c b/hw/i386/kvm/xen_primary_console.c
new file mode 100644
index 0000000..abe79f5
--- /dev/null
+++ b/hw/i386/kvm/xen_primary_console.c
@@ -0,0 +1,193 @@
+/*
+ * QEMU Xen emulation: Primary console support
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Authors: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/error.h"
+
+#include "hw/sysbus.h"
+#include "hw/xen/xen.h"
+#include "hw/xen/xen_backend_ops.h"
+#include "xen_evtchn.h"
+#include "xen_overlay.h"
+#include "xen_primary_console.h"
+
+#include "sysemu/kvm.h"
+#include "sysemu/kvm_xen.h"
+
+#include "trace.h"
+
+#include "hw/xen/interface/event_channel.h"
+#include "hw/xen/interface/grant_table.h"
+
+#define TYPE_XEN_PRIMARY_CONSOLE "xen-primary-console"
+OBJECT_DECLARE_SIMPLE_TYPE(XenPrimaryConsoleState, XEN_PRIMARY_CONSOLE)
+
+struct XenPrimaryConsoleState {
+ /*< private >*/
+ SysBusDevice busdev;
+ /*< public >*/
+
+ MemoryRegion console_page;
+ void *cp;
+
+ evtchn_port_t guest_port;
+ evtchn_port_t be_port;
+
+ struct xengntdev_handle *gt;
+ void *granted_xs;
+};
+
+struct XenPrimaryConsoleState *xen_primary_console_singleton;
+
+static void xen_primary_console_realize(DeviceState *dev, Error **errp)
+{
+ XenPrimaryConsoleState *s = XEN_PRIMARY_CONSOLE(dev);
+
+ if (xen_mode != XEN_EMULATE) {
+ error_setg(errp, "Xen primary console support is for Xen emulation");
+ return;
+ }
+
+ memory_region_init_ram(&s->console_page, OBJECT(dev), "xen:console_page",
+ XEN_PAGE_SIZE, &error_abort);
+ memory_region_set_enabled(&s->console_page, true);
+ s->cp = memory_region_get_ram_ptr(&s->console_page);
+ memset(s->cp, 0, XEN_PAGE_SIZE);
+
+ /* We can't map it this early as KVM isn't ready */
+ xen_primary_console_singleton = s;
+}
+
+static void xen_primary_console_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = xen_primary_console_realize;
+}
+
+static const TypeInfo xen_primary_console_info = {
+ .name = TYPE_XEN_PRIMARY_CONSOLE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XenPrimaryConsoleState),
+ .class_init = xen_primary_console_class_init,
+};
+
+
+void xen_primary_console_create(void)
+{
+ DeviceState *dev = sysbus_create_simple(TYPE_XEN_PRIMARY_CONSOLE, -1, NULL);
+
+ trace_xen_primary_console_create();
+
+ xen_primary_console_singleton = XEN_PRIMARY_CONSOLE(dev);
+
+ /*
+ * Defer the init (xen_primary_console_reset()) until KVM is set up and the
+ * overlay page can be mapped.
+ */
+}
+
+static void xen_primary_console_register_types(void)
+{
+ type_register_static(&xen_primary_console_info);
+}
+
+type_init(xen_primary_console_register_types)
+
+uint16_t xen_primary_console_get_port(void)
+{
+ XenPrimaryConsoleState *s = xen_primary_console_singleton;
+ if (!s) {
+ return 0;
+ }
+ return s->guest_port;
+}
+
+void xen_primary_console_set_be_port(uint16_t port)
+{
+ XenPrimaryConsoleState *s = xen_primary_console_singleton;
+ if (s) {
+ s->be_port = port;
+ }
+}
+
+uint64_t xen_primary_console_get_pfn(void)
+{
+ XenPrimaryConsoleState *s = xen_primary_console_singleton;
+ if (!s) {
+ return 0;
+ }
+ return XEN_SPECIAL_PFN(CONSOLE);
+}
+
+void *xen_primary_console_get_map(void)
+{
+ XenPrimaryConsoleState *s = xen_primary_console_singleton;
+ if (!s) {
+ return 0;
+ }
+ return s->cp;
+}
+
+static void alloc_guest_port(XenPrimaryConsoleState *s)
+{
+ struct evtchn_alloc_unbound alloc = {
+ .dom = DOMID_SELF,
+ .remote_dom = DOMID_QEMU,
+ };
+
+ if (!xen_evtchn_alloc_unbound_op(&alloc)) {
+ s->guest_port = alloc.port;
+ }
+}
+
+static void rebind_guest_port(XenPrimaryConsoleState *s)
+{
+ struct evtchn_bind_interdomain inter = {
+ .remote_dom = DOMID_QEMU,
+ .remote_port = s->be_port,
+ };
+
+ if (!xen_evtchn_bind_interdomain_op(&inter)) {
+ s->guest_port = inter.local_port;
+ }
+
+ s->be_port = 0;
+}
+
+int xen_primary_console_reset(void)
+{
+ XenPrimaryConsoleState *s = xen_primary_console_singleton;
+ if (!s) {
+ return 0;
+ }
+
+ if (!memory_region_is_mapped(&s->console_page)) {
+ uint64_t gpa = XEN_SPECIAL_PFN(CONSOLE) << TARGET_PAGE_BITS;
+ xen_overlay_do_map_page(&s->console_page, gpa);
+ }
+
+ if (s->be_port) {
+ rebind_guest_port(s);
+ } else {
+ alloc_guest_port(s);
+ }
+
+ trace_xen_primary_console_reset(s->guest_port);
+
+ s->gt = qemu_xen_gnttab_open();
+ uint32_t xs_gntref = GNTTAB_RESERVED_CONSOLE;
+ s->granted_xs = qemu_xen_gnttab_map_refs(s->gt, 1, xen_domid, &xs_gntref,
+ PROT_READ | PROT_WRITE);
+
+ return 0;
+}
diff --git a/hw/i386/kvm/xen_primary_console.h b/hw/i386/kvm/xen_primary_console.h
new file mode 100644
index 0000000..7e2989e
--- /dev/null
+++ b/hw/i386/kvm/xen_primary_console.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU Xen emulation: Primary console support
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Authors: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_XEN_PRIMARY_CONSOLE_H
+#define QEMU_XEN_PRIMARY_CONSOLE_H
+
+void xen_primary_console_create(void);
+int xen_primary_console_reset(void);
+
+uint16_t xen_primary_console_get_port(void);
+void xen_primary_console_set_be_port(uint16_t port);
+uint64_t xen_primary_console_get_pfn(void);
+void *xen_primary_console_get_map(void);
+
+#endif /* QEMU_XEN_PRIMARY_CONSOLE_H */
diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c
index 8e716a7..6e65196 100644
--- a/hw/i386/kvm/xen_xenstore.c
+++ b/hw/i386/kvm/xen_xenstore.c
@@ -25,6 +25,7 @@
#include "hw/xen/xen_backend_ops.h"
#include "xen_overlay.h"
#include "xen_evtchn.h"
+#include "xen_primary_console.h"
#include "xen_xenstore.h"
#include "sysemu/kvm.h"
@@ -331,7 +332,7 @@ static void xs_error(XenXenstoreState *s, unsigned int id,
const char *errstr = NULL;
for (unsigned int i = 0; i < ARRAY_SIZE(xsd_errors); i++) {
- struct xsd_errors *xsd_error = &xsd_errors[i];
+ const struct xsd_errors *xsd_error = &xsd_errors[i];
if (xsd_error->errnum == errnum) {
errstr = xsd_error->errstring;
@@ -1434,6 +1435,8 @@ static void alloc_guest_port(XenXenstoreState *s)
int xen_xenstore_reset(void)
{
XenXenstoreState *s = xen_xenstore_singleton;
+ int console_port;
+ GList *perms;
int err;
if (!s) {
@@ -1461,6 +1464,24 @@ int xen_xenstore_reset(void)
}
s->be_port = err;
+ /* Create frontend store nodes */
+ perms = g_list_append(NULL, xs_perm_as_string(XS_PERM_NONE, DOMID_QEMU));
+ perms = g_list_append(perms, xs_perm_as_string(XS_PERM_READ, xen_domid));
+
+ relpath_printf(s, perms, "store/port", "%u", s->guest_port);
+ relpath_printf(s, perms, "store/ring-ref", "%lu",
+ XEN_SPECIAL_PFN(XENSTORE));
+
+ console_port = xen_primary_console_get_port();
+ if (console_port) {
+ relpath_printf(s, perms, "console/ring-ref", "%lu",
+ XEN_SPECIAL_PFN(CONSOLE));
+ relpath_printf(s, perms, "console/port", "%u", console_port);
+ relpath_printf(s, perms, "console/state", "%u", XenbusStateInitialised);
+ }
+
+ g_list_free_full(perms, g_free);
+
/*
* We don't actually access the guest's page through the grant, because
* this isn't real Xen, and we can just use the page we gave it in the
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 1aef21a..188bc9d 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1261,7 +1261,7 @@ void pc_basic_device_init(struct PCMachineState *pcms,
if (pcms->bus) {
pci_create_simple(pcms->bus, -1, "xen-platform");
}
- xen_bus_init();
+ pcms->xenbus = xen_bus_init();
xen_be_init();
}
#endif
@@ -1289,7 +1289,8 @@ void pc_basic_device_init(struct PCMachineState *pcms,
pcms->vmport != ON_OFF_AUTO_ON);
}
-void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
+void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus,
+ BusState *xen_bus)
{
MachineClass *mc = MACHINE_CLASS(pcmc);
int i;
@@ -1299,7 +1300,11 @@ void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
NICInfo *nd = &nd_table[i];
const char *model = nd->model ? nd->model : mc->default_nic;
- if (g_str_equal(model, "ne2k_isa")) {
+ if (xen_bus && (!nd->model || g_str_equal(model, "xen-net-device"))) {
+ DeviceState *dev = qdev_new("xen-net-device");
+ qdev_set_nic_properties(dev, nd);
+ qdev_realize_and_unref(dev, xen_bus, &error_fatal);
+ } else if (g_str_equal(model, "ne2k_isa")) {
pc_init_ne2k_isa(isa_bus, nd);
} else {
pci_nic_init_nofail(nd, pci_bus, model, NULL);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 26e161b..eace854 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -342,7 +342,7 @@ static void pc_init1(MachineState *machine,
pc_basic_device_init(pcms, isa_bus, x86ms->gsi, rtc_state, true,
0x4);
- pc_nic_init(pcmc, isa_bus, pci_bus);
+ pc_nic_init(pcmc, isa_bus, pci_bus, pcms->xenbus);
if (pcmc->pci_enabled) {
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 597943f..4f3e541 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -340,7 +340,7 @@ static void pc_q35_init(MachineState *machine)
/* the rest devices to which pci devfn is automatically assigned */
pc_vga_init(isa_bus, host_bus);
- pc_nic_init(pcmc, isa_bus, host_bus);
+ pc_nic_init(pcmc, isa_bus, host_bus, pcms->xenbus);
if (machine->nvdimms_state->is_enabled) {
nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 17457ff..ef7d3fc 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -140,9 +140,14 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
/* Remove the peer of the NIC device. Normally, this would be a tap device. */
static void del_nic_peer(NICState *nic, void *opaque)
{
- NetClientState *nc;
+ NetClientState *nc = qemu_get_queue(nic);
+ ObjectClass *klass = module_object_class_by_name(nc->model);
+
+ /* Only delete peers of PCI NICs that we're about to delete */
+ if (!klass || !object_class_dynamic_cast(klass, TYPE_PCI_DEVICE)) {
+ return;
+ }
- nc = qemu_get_queue(nic);
if (nc->peer)
qemu_del_net_client(nc->peer);
}
@@ -164,39 +169,60 @@ static void pci_unplug_nics(PCIBus *bus)
*
* [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc
*/
-static void pci_xen_ide_unplug(PCIDevice *d, bool aux)
+struct ide_unplug_state {
+ bool aux;
+ int nr_unplugged;
+};
+
+static int ide_dev_unplug(DeviceState *dev, void *_st)
{
- DeviceState *dev = DEVICE(d);
- PCIIDEState *pci_ide;
- int i;
+ struct ide_unplug_state *st = _st;
IDEDevice *idedev;
IDEBus *idebus;
BlockBackend *blk;
+ int unit;
- pci_ide = PCI_IDE(dev);
+ idedev = IDE_DEVICE(object_dynamic_cast(OBJECT(dev), "ide-hd"));
+ if (!idedev) {
+ return 0;
+ }
- for (i = aux ? 1 : 0; i < 4; i++) {
- idebus = &pci_ide->bus[i / 2];
- blk = idebus->ifs[i % 2].blk;
+ idebus = IDE_BUS(qdev_get_parent_bus(dev));
- if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) {
- if (!(i % 2)) {
- idedev = idebus->master;
- } else {
- idedev = idebus->slave;
- }
+ unit = (idedev == idebus->slave);
+ assert(unit || idedev == idebus->master);
- blk_drain(blk);
- blk_flush(blk);
+ if (st->aux && !unit && !strcmp(BUS(idebus)->name, "ide.0")) {
+ return 0;
+ }
- blk_detach_dev(blk, DEVICE(idedev));
- idebus->ifs[i % 2].blk = NULL;
- idedev->conf.blk = NULL;
- monitor_remove_blk(blk);
- blk_unref(blk);
- }
+ blk = idebus->ifs[unit].blk;
+ if (blk) {
+ blk_drain(blk);
+ blk_flush(blk);
+
+ blk_detach_dev(blk, DEVICE(idedev));
+ idebus->ifs[unit].blk = NULL;
+ idedev->conf.blk = NULL;
+ monitor_remove_blk(blk);
+ blk_unref(blk);
+ }
+
+ object_unparent(OBJECT(dev));
+ st->nr_unplugged++;
+
+ return 0;
+}
+
+static void pci_xen_ide_unplug(PCIDevice *d, bool aux)
+{
+ struct ide_unplug_state st = { aux, 0 };
+ DeviceState *dev = DEVICE(d);
+
+ qdev_walk_children(dev, NULL, NULL, ide_dev_unplug, NULL, &st);
+ if (st.nr_unplugged) {
+ pci_device_reset(d);
}
- pci_device_reset(d);
}
static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
@@ -211,6 +237,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
case PCI_CLASS_STORAGE_IDE:
+ case PCI_CLASS_STORAGE_SATA:
pci_xen_ide_unplug(d, aux);
break;
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 2632634..f64651c 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -1,5 +1,5 @@
system_ss.add(when: 'CONFIG_DP8393X', if_true: files('dp8393x.c'))
-system_ss.add(when: 'CONFIG_XEN', if_true: files('xen_nic.c'))
+system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_nic.c'))
system_ss.add(when: 'CONFIG_NE2000_COMMON', if_true: files('ne2000.c'))
# PCI network cards
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 3abfd65..3097742 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -482,3 +482,14 @@ dp8393x_receive_oversize(int size) "oversize packet, pkt_size is %d"
dp8393x_receive_not_netcard(void) "packet not for netcard"
dp8393x_receive_packet(int crba) "Receive packet at 0x%"PRIx32
dp8393x_receive_write_status(int crba) "Write status at 0x%"PRIx32
+
+# xen_nic.c
+xen_netdev_realize(int dev, const char *info, const char *peer) "vif%u info '%s' peer '%s'"
+xen_netdev_unrealize(int dev) "vif%u"
+xen_netdev_create(int dev) "vif%u"
+xen_netdev_destroy(int dev) "vif%u"
+xen_netdev_disconnect(int dev) "vif%u"
+xen_netdev_connect(int dev, unsigned int tx, unsigned int rx, int port) "vif%u tx %u rx %u port %u"
+xen_netdev_frontend_changed(const char *dev, int state) "vif%s state %d"
+xen_netdev_tx(int dev, int ref, int off, int len, unsigned int flags, const char *c, const char *d, const char *m, const char *e) "vif%u ref %u off %u len %u flags 0x%x%s%s%s%s"
+xen_netdev_rx(int dev, int idx, int status, int flags) "vif%u idx %d status %d flags 0x%x"
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 9bbf659..af4ba3f 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -20,6 +20,13 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/qemu-print.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/error.h"
+
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
@@ -27,18 +34,26 @@
#include "net/net.h"
#include "net/checksum.h"
#include "net/util.h"
-#include "hw/xen/xen-legacy-backend.h"
+
+#include "hw/xen/xen-backend.h"
+#include "hw/xen/xen-bus-helper.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/xen/interface/io/netif.h"
+#include "hw/xen/interface/io/xs_wire.h"
+
+#include "trace.h"
/* ------------------------------------------------------------- */
struct XenNetDev {
- struct XenLegacyDevice xendev; /* must be first */
- char *mac;
+ struct XenDevice xendev; /* must be first */
+ XenEventChannel *event_channel;
+ int dev;
int tx_work;
- int tx_ring_ref;
- int rx_ring_ref;
+ unsigned int tx_ring_ref;
+ unsigned int rx_ring_ref;
struct netif_tx_sring *txs;
struct netif_rx_sring *rxs;
netif_tx_back_ring_t tx_ring;
@@ -47,6 +62,11 @@ struct XenNetDev {
NICState *nic;
};
+typedef struct XenNetDev XenNetDev;
+
+#define TYPE_XEN_NET_DEVICE "xen-net-device"
+OBJECT_DECLARE_SIMPLE_TYPE(XenNetDev, XEN_NET_DEVICE)
+
/* ------------------------------------------------------------- */
static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
@@ -68,7 +88,8 @@ static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, i
netdev->tx_ring.rsp_prod_pvt = ++i;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
if (notify) {
- xen_pv_send_notify(&netdev->xendev);
+ xen_device_notify_event_channel(XEN_DEVICE(netdev),
+ netdev->event_channel, NULL);
}
if (i == netdev->tx_ring.req_cons) {
@@ -104,13 +125,16 @@ static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING
#endif
}
-static void net_tx_packets(struct XenNetDev *netdev)
+static bool net_tx_packets(struct XenNetDev *netdev)
{
+ bool done_something = false;
netif_tx_request_t txreq;
RING_IDX rc, rp;
void *page;
void *tmpbuf = NULL;
+ assert(qemu_mutex_iothread_locked());
+
for (;;) {
rc = netdev->tx_ring.req_cons;
rp = netdev->tx_ring.sring->req_prod;
@@ -122,49 +146,52 @@ static void net_tx_packets(struct XenNetDev *netdev)
}
memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
netdev->tx_ring.req_cons = ++rc;
+ done_something = true;
#if 1
/* should not happen in theory, we don't announce the *
* feature-{sg,gso,whatelse} flags in xenstore (yet?) */
if (txreq.flags & NETTXF_extra_info) {
- xen_pv_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+ qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: extra info flag\n",
+ netdev->dev);
net_tx_error(netdev, &txreq, rc);
continue;
}
if (txreq.flags & NETTXF_more_data) {
- xen_pv_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+ qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: more data flag\n",
+ netdev->dev);
net_tx_error(netdev, &txreq, rc);
continue;
}
#endif
if (txreq.size < 14) {
- xen_pv_printf(&netdev->xendev, 0, "bad packet size: %d\n",
- txreq.size);
+ qemu_log_mask(LOG_GUEST_ERROR, "vif%u: bad packet size: %d\n",
+ netdev->dev, txreq.size);
net_tx_error(netdev, &txreq, rc);
continue;
}
if ((txreq.offset + txreq.size) > XEN_PAGE_SIZE) {
- xen_pv_printf(&netdev->xendev, 0, "error: page crossing\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "vif%u: error: page crossing\n",
+ netdev->dev);
net_tx_error(netdev, &txreq, rc);
continue;
}
- xen_pv_printf(&netdev->xendev, 3,
- "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
- txreq.gref, txreq.offset, txreq.size, txreq.flags,
- (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "",
- (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
- (txreq.flags & NETTXF_more_data) ? " more_data" : "",
- (txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
+ trace_xen_netdev_tx(netdev->dev, txreq.gref, txreq.offset,
+ txreq.size, txreq.flags,
+ (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "",
+ (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+ (txreq.flags & NETTXF_more_data) ? " more_data" : "",
+ (txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
- page = xen_be_map_grant_ref(&netdev->xendev, txreq.gref,
- PROT_READ);
+ page = xen_device_map_grant_refs(&netdev->xendev, &txreq.gref, 1,
+ PROT_READ, NULL);
if (page == NULL) {
- xen_pv_printf(&netdev->xendev, 0,
- "error: tx gref dereference failed (%d)\n",
- txreq.gref);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "vif%u: tx gref dereference failed (%d)\n",
+ netdev->dev, txreq.gref);
net_tx_error(netdev, &txreq, rc);
continue;
}
@@ -181,7 +208,8 @@ static void net_tx_packets(struct XenNetDev *netdev)
qemu_send_packet(qemu_get_queue(netdev->nic),
page + txreq.offset, txreq.size);
}
- xen_be_unmap_grant_ref(&netdev->xendev, page, txreq.gref);
+ xen_device_unmap_grant_refs(&netdev->xendev, page, &txreq.gref, 1,
+ NULL);
net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
}
if (!netdev->tx_work) {
@@ -190,6 +218,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
netdev->tx_work = 0;
}
g_free(tmpbuf);
+ return done_something;
}
/* ------------------------------------------------------------- */
@@ -212,14 +241,13 @@ static void net_rx_response(struct XenNetDev *netdev,
resp->status = (int16_t)st;
}
- xen_pv_printf(&netdev->xendev, 3,
- "rx response: idx %d, status %d, flags 0x%x\n",
- i, resp->status, resp->flags);
+ trace_xen_netdev_rx(netdev->dev, i, resp->status, resp->flags);
netdev->rx_ring.rsp_prod_pvt = ++i;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
if (notify) {
- xen_pv_send_notify(&netdev->xendev);
+ xen_device_notify_event_channel(XEN_DEVICE(netdev),
+ netdev->event_channel, NULL);
}
}
@@ -232,7 +260,9 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
RING_IDX rc, rp;
void *page;
- if (netdev->xendev.be_state != XenbusStateConnected) {
+ assert(qemu_mutex_iothread_locked());
+
+ if (xen_device_backend_get_state(&netdev->xendev) != XenbusStateConnected) {
return -1;
}
@@ -244,24 +274,26 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
return 0;
}
if (size > XEN_PAGE_SIZE - NET_IP_ALIGN) {
- xen_pv_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
- (unsigned long)size, XEN_PAGE_SIZE - NET_IP_ALIGN);
+ qemu_log_mask(LOG_GUEST_ERROR, "vif%u: packet too big (%lu > %ld)",
+ netdev->dev, (unsigned long)size,
+ XEN_PAGE_SIZE - NET_IP_ALIGN);
return -1;
}
memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
netdev->rx_ring.req_cons = ++rc;
- page = xen_be_map_grant_ref(&netdev->xendev, rxreq.gref, PROT_WRITE);
+ page = xen_device_map_grant_refs(&netdev->xendev, &rxreq.gref, 1,
+ PROT_WRITE, NULL);
if (page == NULL) {
- xen_pv_printf(&netdev->xendev, 0,
- "error: rx gref dereference failed (%d)\n",
- rxreq.gref);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "vif%u: rx gref dereference failed (%d)\n",
+ netdev->dev, rxreq.gref);
net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
return -1;
}
memcpy(page + NET_IP_ALIGN, buf, size);
- xen_be_unmap_grant_ref(&netdev->xendev, page, rxreq.gref);
+ xen_device_unmap_grant_refs(&netdev->xendev, page, &rxreq.gref, 1, NULL);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
return size;
@@ -275,139 +307,361 @@ static NetClientInfo net_xen_info = {
.receive = net_rx_packet,
};
-static int net_init(struct XenLegacyDevice *xendev)
+static void xen_netdev_realize(XenDevice *xendev, Error **errp)
{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ ERRP_GUARD();
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+ NetClientState *nc;
- /* read xenstore entries */
- if (netdev->mac == NULL) {
- netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
- }
-
- /* do we have all we need? */
- if (netdev->mac == NULL) {
- return -1;
- }
+ qemu_macaddr_default_if_unset(&netdev->conf.macaddr);
- if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
- return -1;
- }
+ xen_device_frontend_printf(xendev, "mac", "%02x:%02x:%02x:%02x:%02x:%02x",
+ netdev->conf.macaddr.a[0],
+ netdev->conf.macaddr.a[1],
+ netdev->conf.macaddr.a[2],
+ netdev->conf.macaddr.a[3],
+ netdev->conf.macaddr.a[4],
+ netdev->conf.macaddr.a[5]);
netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
- "xen", NULL, netdev);
+ object_get_typename(OBJECT(xendev)),
+ DEVICE(xendev)->id, netdev);
- qemu_set_info_str(qemu_get_queue(netdev->nic),
- "nic: xenbus vif macaddr=%s", netdev->mac);
+ nc = qemu_get_queue(netdev->nic);
+ qemu_format_nic_info_str(nc, netdev->conf.macaddr.a);
/* fill info */
- xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
- xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
+ xen_device_backend_printf(xendev, "feature-rx-copy", "%u", 1);
+ xen_device_backend_printf(xendev, "feature-rx-flip", "%u", 0);
- return 0;
+ trace_xen_netdev_realize(netdev->dev, nc->info_str, nc->peer ?
+ nc->peer->name : "(none)");
}
-static int net_connect(struct XenLegacyDevice *xendev)
+static bool net_event(void *_xendev)
{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
- int rx_copy;
+ XenNetDev *netdev = XEN_NET_DEVICE(_xendev);
+ bool done_something;
- if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
- &netdev->tx_ring_ref) == -1) {
- return -1;
+ done_something = net_tx_packets(netdev);
+ qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
+ return done_something;
+}
+
+static bool xen_netdev_connect(XenDevice *xendev, Error **errp)
+{
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+ unsigned int port, rx_copy;
+
+ assert(qemu_mutex_iothread_locked());
+
+ if (xen_device_frontend_scanf(xendev, "tx-ring-ref", "%u",
+ &netdev->tx_ring_ref) != 1) {
+ error_setg(errp, "failed to read tx-ring-ref");
+ return false;
}
- if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
- &netdev->rx_ring_ref) == -1) {
- return 1;
+
+ if (xen_device_frontend_scanf(xendev, "rx-ring-ref", "%u",
+ &netdev->rx_ring_ref) != 1) {
+ error_setg(errp, "failed to read rx-ring-ref");
+ return false;
}
- if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
- &netdev->xendev.remote_port) == -1) {
- return -1;
+
+ if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
+ &port) != 1) {
+ error_setg(errp, "failed to read event-channel");
+ return false;
}
- if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
+ if (xen_device_frontend_scanf(xendev, "request-rx-copy", "%u",
+ &rx_copy) != 1) {
rx_copy = 0;
}
if (rx_copy == 0) {
- xen_pv_printf(&netdev->xendev, 0,
- "frontend doesn't support rx-copy.\n");
- return -1;
+ error_setg(errp, "frontend doesn't support rx-copy");
+ return false;
}
- netdev->txs = xen_be_map_grant_ref(&netdev->xendev,
- netdev->tx_ring_ref,
- PROT_READ | PROT_WRITE);
+ netdev->txs = xen_device_map_grant_refs(xendev,
+ &netdev->tx_ring_ref, 1,
+ PROT_READ | PROT_WRITE,
+ errp);
if (!netdev->txs) {
- return -1;
+ error_prepend(errp, "failed to map tx grant ref: ");
+ return false;
}
- netdev->rxs = xen_be_map_grant_ref(&netdev->xendev,
- netdev->rx_ring_ref,
- PROT_READ | PROT_WRITE);
+
+ netdev->rxs = xen_device_map_grant_refs(xendev,
+ &netdev->rx_ring_ref, 1,
+ PROT_READ | PROT_WRITE,
+ errp);
if (!netdev->rxs) {
- xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs,
- netdev->tx_ring_ref);
- netdev->txs = NULL;
- return -1;
+ error_prepend(errp, "failed to map rx grant ref: ");
+ return false;
}
+
BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE);
BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE);
- xen_be_bind_evtchn(&netdev->xendev);
+ netdev->event_channel = xen_device_bind_event_channel(xendev, port,
+ net_event,
+ netdev,
+ errp);
+ if (!netdev->event_channel) {
+ return false;
+ }
- xen_pv_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
- "remote port %d, local port %d\n",
- netdev->tx_ring_ref, netdev->rx_ring_ref,
- netdev->xendev.remote_port, netdev->xendev.local_port);
+ trace_xen_netdev_connect(netdev->dev, netdev->tx_ring_ref,
+ netdev->rx_ring_ref, port);
net_tx_packets(netdev);
- return 0;
+ return true;
}
-static void net_disconnect(struct XenLegacyDevice *xendev)
+static void xen_netdev_disconnect(XenDevice *xendev, Error **errp)
{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+
+ trace_xen_netdev_disconnect(netdev->dev);
+
+ assert(qemu_mutex_iothread_locked());
- xen_pv_unbind_evtchn(&netdev->xendev);
+ netdev->tx_ring.sring = NULL;
+ netdev->rx_ring.sring = NULL;
+ if (netdev->event_channel) {
+ xen_device_unbind_event_channel(xendev, netdev->event_channel,
+ errp);
+ netdev->event_channel = NULL;
+ }
if (netdev->txs) {
- xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs,
- netdev->tx_ring_ref);
+ xen_device_unmap_grant_refs(xendev, netdev->txs,
+ &netdev->tx_ring_ref, 1, errp);
netdev->txs = NULL;
}
if (netdev->rxs) {
- xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs,
- netdev->rx_ring_ref);
+ xen_device_unmap_grant_refs(xendev, netdev->rxs,
+ &netdev->rx_ring_ref, 1, errp);
netdev->rxs = NULL;
}
}
-static void net_event(struct XenLegacyDevice *xendev)
+/* -------------------------------------------------------------------- */
+
+
+static void xen_netdev_frontend_changed(XenDevice *xendev,
+ enum xenbus_state frontend_state,
+ Error **errp)
{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
- net_tx_packets(netdev);
- qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
+ ERRP_GUARD();
+ enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
+
+ trace_xen_netdev_frontend_changed(xendev->name, frontend_state);
+
+ switch (frontend_state) {
+ case XenbusStateConnected:
+ if (backend_state == XenbusStateConnected) {
+ break;
+ }
+
+ xen_netdev_disconnect(xendev, errp);
+ if (*errp) {
+ break;
+ }
+
+ if (!xen_netdev_connect(xendev, errp)) {
+ xen_netdev_disconnect(xendev, NULL);
+ xen_device_backend_set_state(xendev, XenbusStateClosing);
+ break;
+ }
+
+ xen_device_backend_set_state(xendev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xen_device_backend_set_state(xendev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ case XenbusStateUnknown:
+ xen_netdev_disconnect(xendev, errp);
+ if (*errp) {
+ break;
+ }
+
+ xen_device_backend_set_state(xendev, XenbusStateClosed);
+ break;
+
+ case XenbusStateInitialised:
+ /*
+ * Linux netback does nothing on the frontend going (back) to
+ * XenbusStateInitialised, so do the same here.
+ */
+ default:
+ break;
+ }
}
-static int net_free(struct XenLegacyDevice *xendev)
+static char *xen_netdev_get_name(XenDevice *xendev, Error **errp)
{
- struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+
+ if (netdev->dev == -1) {
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ char fe_path[XENSTORE_ABS_PATH_MAX + 1];
+ int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
+ char *value;
+
+ /* Theoretically we could go up to INT_MAX here but that's overkill */
+ while (idx < 100) {
+ snprintf(fe_path, sizeof(fe_path),
+ "/local/domain/%u/device/vif/%u",
+ xendev->frontend_id, idx);
+ value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
+ if (!value) {
+ if (errno == ENOENT) {
+ netdev->dev = idx;
+ goto found;
+ }
+ error_setg(errp, "cannot read %s: %s", fe_path,
+ strerror(errno));
+ return NULL;
+ }
+ free(value);
+ idx++;
+ }
+ error_setg(errp, "cannot find device index for netdev device");
+ return NULL;
+ }
+ found:
+ return g_strdup_printf("%u", netdev->dev);
+}
+
+static void xen_netdev_unrealize(XenDevice *xendev)
+{
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+
+ trace_xen_netdev_unrealize(netdev->dev);
+
+ /* Disconnect from the frontend in case this has not already happened */
+ xen_netdev_disconnect(xendev, NULL);
if (netdev->nic) {
qemu_del_nic(netdev->nic);
- netdev->nic = NULL;
}
- g_free(netdev->mac);
- netdev->mac = NULL;
- return 0;
}
/* ------------------------------------------------------------- */
-struct XenDevOps xen_netdev_ops = {
- .size = sizeof(struct XenNetDev),
- .flags = DEVOPS_FLAG_NEED_GNTDEV,
- .init = net_init,
- .initialise = net_connect,
- .event = net_event,
- .disconnect = net_disconnect,
- .free = net_free,
+static Property xen_netdev_properties[] = {
+ DEFINE_NIC_PROPERTIES(XenNetDev, conf),
+ DEFINE_PROP_INT32("idx", XenNetDev, dev, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xen_netdev_class_init(ObjectClass *class, void *data)
+{
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+ XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
+
+ xendev_class->backend = "qnic";
+ xendev_class->device = "vif";
+ xendev_class->get_name = xen_netdev_get_name;
+ xendev_class->realize = xen_netdev_realize;
+ xendev_class->frontend_changed = xen_netdev_frontend_changed;
+ xendev_class->unrealize = xen_netdev_unrealize;
+ set_bit(DEVICE_CATEGORY_NETWORK, dev_class->categories);
+ dev_class->user_creatable = true;
+
+ device_class_set_props(dev_class, xen_netdev_properties);
+}
+
+static const TypeInfo xen_net_type_info = {
+ .name = TYPE_XEN_NET_DEVICE,
+ .parent = TYPE_XEN_DEVICE,
+ .instance_size = sizeof(XenNetDev),
+ .class_init = xen_netdev_class_init,
+};
+
+static void xen_net_register_types(void)
+{
+ type_register_static(&xen_net_type_info);
+}
+
+type_init(xen_net_register_types)
+
+/* Called to instantiate a XenNetDev when the backend is detected. */
+static void xen_net_device_create(XenBackendInstance *backend,
+ QDict *opts, Error **errp)
+{
+ ERRP_GUARD();
+ XenBus *xenbus = xen_backend_get_bus(backend);
+ const char *name = xen_backend_get_name(backend);
+ XenDevice *xendev = NULL;
+ unsigned long number;
+ const char *macstr;
+ XenNetDev *net;
+ MACAddr mac;
+
+ if (qemu_strtoul(name, NULL, 10, &number) || number >= INT_MAX) {
+ error_setg(errp, "failed to parse name '%s'", name);
+ goto fail;
+ }
+
+ trace_xen_netdev_create(number);
+
+ macstr = qdict_get_try_str(opts, "mac");
+ if (macstr == NULL) {
+ error_setg(errp, "no MAC address found");
+ goto fail;
+ }
+
+ if (net_parse_macaddr(mac.a, macstr) < 0) {
+ error_setg(errp, "failed to parse MAC address");
+ goto fail;
+ }
+
+ xendev = XEN_DEVICE(qdev_new(TYPE_XEN_NET_DEVICE));
+ net = XEN_NET_DEVICE(xendev);
+
+ net->dev = number;
+ memcpy(&net->conf.macaddr, &mac, sizeof(mac));
+
+ if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) {
+ xen_backend_set_device(backend, xendev);
+ return;
+ }
+
+ error_prepend(errp, "realization of net device %lu failed: ",
+ number);
+
+ fail:
+ if (xendev) {
+ object_unparent(OBJECT(xendev));
+ }
+}
+
+static void xen_net_device_destroy(XenBackendInstance *backend,
+ Error **errp)
+{
+ ERRP_GUARD();
+ XenDevice *xendev = xen_backend_get_device(backend);
+ XenNetDev *netdev = XEN_NET_DEVICE(xendev);
+
+ trace_xen_netdev_destroy(netdev->dev);
+
+ object_unparent(OBJECT(xendev));
+}
+
+static const XenBackendInfo xen_net_backend_info = {
+ .type = "qnic",
+ .create = xen_net_device_create,
+ .destroy = xen_net_device_destroy,
};
+
+static void xen_net_register_backend(void)
+{
+ xen_backend_register(&xen_net_backend_info);
+}
+
+xen_backend_init(xen_net_register_backend);
diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index 84e0ca1..bd22658 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -19,6 +19,8 @@
#define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region"
+#define F_EXTEND(addr) ((addr) | MAKE_64BIT_MASK(32, 32))
+
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/units.h"
@@ -386,7 +388,7 @@ static void elroy_set_irq(void *opaque, int irq, int level)
uint32_t ena = bit & ~old_ilr;
s->ilr = old_ilr | bit;
if (ena != 0) {
- stl_be_phys(&address_space_memory, cpu_hpa, val & 63);
+ stl_be_phys(&address_space_memory, F_EXTEND(cpu_hpa), val & 63);
}
} else {
s->ilr = old_ilr & ~bit;
@@ -825,15 +827,16 @@ static void astro_realize(DeviceState *obj, Error **errp)
/* map elroys mmio */
map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC;
- map_addr = (uint32_t) (LMMIO_DIST_BASE_ADDR + rope * map_size);
+ map_addr = F_EXTEND(LMMIO_DIST_BASE_ADDR + rope * map_size);
memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy),
"pci-mmio-alias",
- &elroy->pci_mmio, map_addr, map_size);
+ &elroy->pci_mmio, (uint32_t) map_addr, map_size);
memory_region_add_subregion(get_system_memory(), map_addr,
&elroy->pci_mmio_alias);
+ /* map elroys io */
map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
- map_addr = (uint32_t) (IOS_DIST_BASE_ADDR + rope * map_size);
+ map_addr = F_EXTEND(IOS_DIST_BASE_ADDR + rope * map_size);
memory_region_add_subregion(get_system_memory(), map_addr,
&elroy->pci_io);
diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c
index 5b0fb76..b9bf70a 100644
--- a/hw/xen/xen-backend.c
+++ b/hw/xen/xen-backend.c
@@ -101,6 +101,24 @@ static XenBackendInstance *xen_backend_list_find(XenDevice *xendev)
return NULL;
}
+bool xen_backend_exists(const char *type, const char *name)
+{
+ const XenBackendImpl *impl = xen_backend_table_lookup(type);
+ XenBackendInstance *backend;
+
+ if (!impl) {
+ return false;
+ }
+
+ QLIST_FOREACH(backend, &backend_list, entry) {
+ if (backend->impl == impl && !strcmp(backend->name, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void xen_backend_list_remove(XenBackendInstance *backend)
{
QLIST_REMOVE(backend, entry);
@@ -122,11 +140,6 @@ void xen_backend_device_create(XenBus *xenbus, const char *type,
backend->name = g_strdup(name);
impl->create(backend, opts, errp);
- if (*errp) {
- g_free(backend->name);
- g_free(backend);
- return;
- }
backend->impl = impl;
xen_backend_list_add(backend);
@@ -165,7 +178,9 @@ bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp)
}
impl = backend->impl;
- impl->destroy(backend, errp);
+ if (backend->xendev) {
+ impl->destroy(backend, errp);
+ }
xen_backend_list_remove(backend);
g_free(backend->name);
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index ece8ec4..4973e7d 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -209,7 +209,8 @@ static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
NULL, "%u", &online) != 1)
online = 0;
- if (online && state == XenbusStateInitialising) {
+ if (online && state == XenbusStateInitialising &&
+ !xen_backend_exists(type, backend[i])) {
Error *local_err = NULL;
xen_bus_backend_create(xenbus, type, backend[i], backend_path,
@@ -711,8 +712,17 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
{
ERRP_GUARD();
XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
- xendev->frontend_path = xen_device_get_frontend_path(xendev);
+ if (xendev_class->get_frontend_path) {
+ xendev->frontend_path = xendev_class->get_frontend_path(xendev, errp);
+ if (!xendev->frontend_path) {
+ error_prepend(errp, "failed to create frontend: ");
+ return;
+ }
+ } else {
+ xendev->frontend_path = xen_device_get_frontend_path(xendev);
+ }
/*
* The frontend area may have already been created by a legacy
@@ -912,6 +922,11 @@ void xen_device_notify_event_channel(XenDevice *xendev,
}
}
+unsigned int xen_event_channel_get_local_port(XenEventChannel *channel)
+{
+ return channel->local_port;
+}
+
void xen_device_unbind_event_channel(XenDevice *xendev,
XenEventChannel *channel,
Error **errp)
@@ -1118,11 +1133,13 @@ static void xen_register_types(void)
type_init(xen_register_types)
-void xen_bus_init(void)
+BusState *xen_bus_init(void)
{
DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE);
BusState *bus = qbus_new(TYPE_XEN_BUS, dev, NULL);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
qbus_set_bus_hotplug_handler(bus);
+
+ return bus;
}
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 4ded3ce..124dd5f 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -623,7 +623,6 @@ void xen_be_init(void)
xen_set_dynamic_sysbus();
- xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
#ifdef CONFIG_VIRTFS
xen_be_register("9pfs", &xen_9pfs_ops);
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index 9b7304e..3f77c67 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -46,34 +46,6 @@ static int xen_config_dev_all(char *fe, char *be)
/* ------------------------------------------------------------- */
-int xen_config_dev_blk(DriveInfo *disk)
-{
- char fe[256], be[256], device_name[32];
- int vdev = 202 * 256 + 16 * disk->unit;
- int cdrom = disk->media_cd;
- const char *devtype = cdrom ? "cdrom" : "disk";
- const char *mode = cdrom ? "r" : "w";
- const char *filename = qemu_opt_get(disk->opts, "file");
-
- snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
- xen_pv_printf(NULL, 1, "config disk %d [%s]: %s\n",
- disk->unit, device_name, filename);
- xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
-
- /* frontend */
- xenstore_write_int(fe, "virtual-device", vdev);
- xenstore_write_str(fe, "device-type", devtype);
-
- /* backend */
- xenstore_write_str(be, "dev", device_name);
- xenstore_write_str(be, "type", "file");
- xenstore_write_str(be, "params", filename);
- xenstore_write_str(be, "mode", mode);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
int xen_config_dev_nic(NICInfo *nic)
{
char fe[256], be[256];
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index 17cda5e..9f9f137 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -32,7 +32,6 @@
static void xen_init_pv(MachineState *machine)
{
- DriveInfo *dinfo;
int i;
setup_xen_backend_ops();
@@ -55,7 +54,6 @@ static void xen_init_pv(MachineState *machine)
}
xen_be_register("vfb", &xen_framebuffer_ops);
- xen_be_register("qnic", &xen_netdev_ops);
/* configure framebuffer */
if (vga_interface_type == VGA_XENFB) {
@@ -64,14 +62,6 @@ static void xen_init_pv(MachineState *machine)
vga_interface_created = true;
}
- /* configure disks */
- for (i = 0; i < 16; i++) {
- dinfo = drive_get(IF_XEN, 0, i);
- if (!dinfo)
- continue;
- xen_config_dev_blk(dinfo);
- }
-
/* configure nics */
for (i = 0; i < nb_nics; i++) {
if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index dffb0e7..0a5c258 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -385,10 +385,11 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
}
if (pflags) {
- *pflags = (elf_word)ehdr.e_flags;
+ *pflags = ehdr.e_flags;
+ }
+ if (pentry) {
+ *pentry = ehdr.e_entry;
}
- if (pentry)
- *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
@@ -610,10 +611,12 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
}
}
- if (lowaddr)
- *lowaddr = (uint64_t)(elf_sword)low;
- if (highaddr)
- *highaddr = (uint64_t)(elf_sword)high;
+ if (lowaddr) {
+ *lowaddr = low;
+ }
+ if (highaddr) {
+ *highaddr = high;
+ }
ret = total_size;
fail:
if (mapped_file) {
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 29a9724..a10ceea 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -33,6 +33,7 @@ typedef struct PCMachineState {
/* Pointers to devices and objects: */
PCIBus *bus;
+ BusState *xenbus;
I2CBus *smbus;
PFlashCFI01 *flash[2];
ISADevice *pcspk;
@@ -184,7 +185,8 @@ void pc_basic_device_init(struct PCMachineState *pcms,
void pc_cmos_init(PCMachineState *pcms,
BusState *ide0, BusState *ide1,
ISADevice *s);
-void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus);
+void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus,
+ BusState *xen_bus);
void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs);
diff --git a/include/hw/xen/interface/arch-arm.h b/include/hw/xen/interface/arch-arm.h
index 94b3151..1528ced 100644
--- a/include/hw/xen/interface/arch-arm.h
+++ b/include/hw/xen/interface/arch-arm.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* arch-arm.h
*
* Guest OS interface to ARM Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright 2011 (C) Citrix Systems
*/
@@ -361,6 +344,7 @@ typedef uint64_t xen_callback_t;
#define PSR_DBG_MASK (1<<9) /* arm64: Debug Exception mask */
#define PSR_IT_MASK (0x0600fc00) /* Thumb If-Then Mask */
#define PSR_JAZELLE (1<<24) /* Jazelle Mode */
+#define PSR_Z (1<<30) /* Zero condition flag */
/* 32 bit modes */
#define PSR_MODE_USR 0x10
@@ -383,7 +367,15 @@ typedef uint64_t xen_callback_t;
#define PSR_MODE_EL1t 0x04
#define PSR_MODE_EL0t 0x00
-#define PSR_GUEST32_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC)
+/*
+ * We set PSR_Z to be able to boot Linux kernel versions with an invalid
+ * encoding of the first 8 NOP instructions. See commit a92882a4d270 in
+ * Linux.
+ *
+ * Note that PSR_Z is also set by U-Boot and QEMU -kernel when loading
+ * zImage kernels on aarch32.
+ */
+#define PSR_GUEST32_INIT (PSR_Z|PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC)
#define PSR_GUEST64_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h)
#define SCTLR_GUEST_INIT xen_mk_ullong(0x00c50078)
@@ -398,6 +390,10 @@ typedef uint64_t xen_callback_t;
/* Physical Address Space */
+/* Virtio MMIO mappings */
+#define GUEST_VIRTIO_MMIO_BASE xen_mk_ullong(0x02000000)
+#define GUEST_VIRTIO_MMIO_SIZE xen_mk_ullong(0x00100000)
+
/*
* vGIC mappings: Only one set of mapping is used by the guest.
* Therefore they can overlap.
@@ -484,6 +480,9 @@ typedef uint64_t xen_callback_t;
#define GUEST_VPL011_SPI 32
+#define GUEST_VIRTIO_MMIO_SPI_FIRST 33
+#define GUEST_VIRTIO_MMIO_SPI_LAST 43
+
/* PSCI functions */
#define PSCI_cpu_suspend 0
#define PSCI_cpu_off 1
diff --git a/include/hw/xen/interface/arch-x86/cpuid.h b/include/hw/xen/interface/arch-x86/cpuid.h
index ce46305..7ecd16a 100644
--- a/include/hw/xen/interface/arch-x86/cpuid.h
+++ b/include/hw/xen/interface/arch-x86/cpuid.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* arch-x86/cpuid.h
*
* CPUID interface to Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2007 Citrix Systems, Inc.
*
* Authors:
@@ -102,6 +85,18 @@
#define XEN_HVM_CPUID_IOMMU_MAPPINGS (1u << 2)
#define XEN_HVM_CPUID_VCPU_ID_PRESENT (1u << 3) /* vcpu id is present in EBX */
#define XEN_HVM_CPUID_DOMID_PRESENT (1u << 4) /* domid is present in ECX */
+/*
+ * With interrupt format set to 0 (non-remappable) bits 55:49 from the
+ * IO-APIC RTE and bits 11:5 from the MSI address can be used to store
+ * high bits for the Destination ID. This expands the Destination ID
+ * field from 8 to 15 bits, allowing to target APIC IDs up 32768.
+ */
+#define XEN_HVM_CPUID_EXT_DEST_ID (1u << 5)
+/*
+ * Per-vCPU event channel upcalls work correctly with physical IRQs
+ * bound to event channels.
+ */
+#define XEN_HVM_CPUID_UPCALL_VECTOR (1u << 6)
/*
* Leaf 6 (0x40000x05)
diff --git a/include/hw/xen/interface/arch-x86/xen-x86_32.h b/include/hw/xen/interface/arch-x86/xen-x86_32.h
index 19d7388..139438e 100644
--- a/include/hw/xen/interface/arch-x86/xen-x86_32.h
+++ b/include/hw/xen/interface/arch-x86/xen-x86_32.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* xen-x86_32.h
*
* Guest OS interface to x86 32-bit Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2004-2007, K A Fraser
*/
diff --git a/include/hw/xen/interface/arch-x86/xen-x86_64.h b/include/hw/xen/interface/arch-x86/xen-x86_64.h
index 40aed14..5d9035e 100644
--- a/include/hw/xen/interface/arch-x86/xen-x86_64.h
+++ b/include/hw/xen/interface/arch-x86/xen-x86_64.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* xen-x86_64.h
*
* Guest OS interface to x86 64-bit Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2004-2006, K A Fraser
*/
diff --git a/include/hw/xen/interface/arch-x86/xen.h b/include/hw/xen/interface/arch-x86/xen.h
index 7acd94c..c0f4551 100644
--- a/include/hw/xen/interface/arch-x86/xen.h
+++ b/include/hw/xen/interface/arch-x86/xen.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* arch-x86/xen.h
*
* Guest OS interface to x86 Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2004-2006, K A Fraser
*/
@@ -320,12 +303,9 @@ struct xen_arch_domainconfig {
uint32_t misc_flags;
};
-/* Location of online VCPU bitmap. */
-#define XEN_ACPI_CPU_MAP 0xaf00
-#define XEN_ACPI_CPU_MAP_LEN ((HVM_MAX_VCPUS + 7) / 8)
+/* Max XEN_X86_* constant. Used for ABI checking. */
+#define XEN_X86_MISC_FLAGS_MAX XEN_X86_MSR_RELAXED
-/* GPE0 bit set during CPU hotplug */
-#define XEN_ACPI_GPE0_CPUHP_BIT 2
#endif
/*
diff --git a/include/hw/xen/interface/event_channel.h b/include/hw/xen/interface/event_channel.h
index 73c9f38..0d91a1c 100644
--- a/include/hw/xen/interface/event_channel.h
+++ b/include/hw/xen/interface/event_channel.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* event_channel.h
*
* Event channels between domains.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2003-2004, K A Fraser.
*/
diff --git a/include/hw/xen/interface/features.h b/include/hw/xen/interface/features.h
index 9ee2f76..d2a9175 100644
--- a/include/hw/xen/interface/features.h
+++ b/include/hw/xen/interface/features.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* features.h
*
* Feature flags, reported by XENVER_get_features.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2006, Keir Fraser <keir@xensource.com>
*/
diff --git a/include/hw/xen/interface/grant_table.h b/include/hw/xen/interface/grant_table.h
index 7934d7b..1dfa17a 100644
--- a/include/hw/xen/interface/grant_table.h
+++ b/include/hw/xen/interface/grant_table.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* grant_table.h
*
* Interface for granting foreign access to page frames, and receiving
* page-ownership transfers.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2004, K A Fraser
*/
diff --git a/include/hw/xen/interface/hvm/hvm_op.h b/include/hw/xen/interface/hvm/hvm_op.h
index 870ec52..e22adf0 100644
--- a/include/hw/xen/interface/hvm/hvm_op.h
+++ b/include/hw/xen/interface/hvm/hvm_op.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2007, Keir Fraser
*/
diff --git a/include/hw/xen/interface/hvm/params.h b/include/hw/xen/interface/hvm/params.h
index c9d6e70..a22b4ed 100644
--- a/include/hw/xen/interface/hvm/params.h
+++ b/include/hw/xen/interface/hvm/params.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2007, Keir Fraser
*/
diff --git a/include/hw/xen/interface/io/blkif.h b/include/hw/xen/interface/io/blkif.h
index 4cdba79..22f1eef 100644
--- a/include/hw/xen/interface/io/blkif.h
+++ b/include/hw/xen/interface/io/blkif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* blkif.h
*
* Unified block-device I/O interface for Xen guest OSes.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2003-2004, Keir Fraser
* Copyright (c) 2012, Spectra Logic Corporation
*/
@@ -363,6 +346,14 @@
* that the frontend requires that the logical block size is 512 as it
* is hardcoded (which is the case in some frontend implementations).
*
+ * trusted
+ * Values: 0/1 (boolean)
+ * Default value: 1
+ *
+ * A value of "0" indicates that the frontend should not trust the
+ * backend, and should deploy whatever measures available to protect from
+ * a malicious backend on the other end.
+ *
*------------------------- Virtual Device Properties -------------------------
*
* device-type
diff --git a/include/hw/xen/interface/io/console.h b/include/hw/xen/interface/io/console.h
index 4811f47..4509b4b 100644
--- a/include/hw/xen/interface/io/console.h
+++ b/include/hw/xen/interface/io/console.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* console.h
*
* Console I/O interface for Xen guest OSes.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2005, Keir Fraser
*/
diff --git a/include/hw/xen/interface/io/fbif.h b/include/hw/xen/interface/io/fbif.h
index cc25aab..93c7319 100644
--- a/include/hw/xen/interface/io/fbif.h
+++ b/include/hw/xen/interface/io/fbif.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
/*
* fbif.h -- Xen virtual frame buffer device
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
* Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
*/
diff --git a/include/hw/xen/interface/io/kbdif.h b/include/hw/xen/interface/io/kbdif.h
index a6b01c5..4bde6b3 100644
--- a/include/hw/xen/interface/io/kbdif.h
+++ b/include/hw/xen/interface/io/kbdif.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
/*
* kbdif.h -- Xen virtual keyboard/mouse
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
* Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
*/
diff --git a/include/hw/xen/interface/io/netif.h b/include/hw/xen/interface/io/netif.h
index 00dd258..c13b850 100644
--- a/include/hw/xen/interface/io/netif.h
+++ b/include/hw/xen/interface/io/netif.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* netif.h
*
* Unified network-device I/O interface for Xen guest OSes.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2003-2004, Keir Fraser
*/
@@ -161,6 +144,12 @@
*/
/*
+ * The setting of "trusted" node to "0" in the frontend path signals that the
+ * frontend should not trust the backend, and should deploy whatever measures
+ * available to protect from a malicious backend on the other end.
+ */
+
+/*
* Control ring
* ============
*
diff --git a/include/hw/xen/interface/io/protocols.h b/include/hw/xen/interface/io/protocols.h
index 52b4de0..7815e1f 100644
--- a/include/hw/xen/interface/io/protocols.h
+++ b/include/hw/xen/interface/io/protocols.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* protocols.h
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2008, Keir Fraser
*/
diff --git a/include/hw/xen/interface/io/ring.h b/include/hw/xen/interface/io/ring.h
index c486c45..0259392 100644
--- a/include/hw/xen/interface/io/ring.h
+++ b/include/hw/xen/interface/io/ring.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* ring.h
*
* Shared producer-consumer ring macros.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Tim Deegan and Andrew Warfield November 2004.
*/
@@ -95,9 +78,8 @@ typedef unsigned int RING_IDX;
* of the shared memory area (PAGE_SIZE, for instance). To initialise
* the front half:
*
- * mytag_front_ring_t front_ring;
- * SHARED_RING_INIT((mytag_sring_t *)shared_page);
- * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
+ * mytag_front_ring_t ring;
+ * XEN_FRONT_RING_INIT(&ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
*
* Initializing the back follows similarly (note that only the front
* initializes the shared ring):
@@ -184,6 +166,11 @@ typedef struct __name##_back_ring __name##_back_ring_t
#define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size)
+#define XEN_FRONT_RING_INIT(r, s, size) do { \
+ SHARED_RING_INIT(s); \
+ FRONT_RING_INIT(r, s, size); \
+} while (0)
+
#define BACK_RING_ATTACH(_r, _s, _i, __size) do { \
(_r)->rsp_prod_pvt = (_i); \
(_r)->req_cons = (_i); \
@@ -208,11 +195,11 @@ typedef struct __name##_back_ring __name##_back_ring_t
(RING_FREE_REQUESTS(_r) == 0)
/* Test if there are outstanding messages to be processed on a ring. */
-#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
+#define XEN_RING_NR_UNCONSUMED_RESPONSES(_r) \
((_r)->sring->rsp_prod - (_r)->rsp_cons)
#ifdef __GNUC__
-#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \
+#define XEN_RING_NR_UNCONSUMED_REQUESTS(_r) ({ \
unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
unsigned int rsp = RING_SIZE(_r) - \
((_r)->req_cons - (_r)->rsp_prod_pvt); \
@@ -220,13 +207,27 @@ typedef struct __name##_back_ring __name##_back_ring_t
})
#else
/* Same as above, but without the nice GCC ({ ... }) syntax. */
-#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
+#define XEN_RING_NR_UNCONSUMED_REQUESTS(_r) \
((((_r)->sring->req_prod - (_r)->req_cons) < \
(RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \
((_r)->sring->req_prod - (_r)->req_cons) : \
(RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt)))
#endif
+#ifdef XEN_RING_HAS_UNCONSUMED_IS_BOOL
+/*
+ * These variants should only be used in case no caller is abusing them for
+ * obtaining the number of unconsumed responses/requests.
+ */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
+ (!!XEN_RING_NR_UNCONSUMED_RESPONSES(_r))
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
+ (!!XEN_RING_NR_UNCONSUMED_REQUESTS(_r))
+#else
+#define RING_HAS_UNCONSUMED_RESPONSES(_r) XEN_RING_NR_UNCONSUMED_RESPONSES(_r)
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) XEN_RING_NR_UNCONSUMED_REQUESTS(_r)
+#endif
+
/* Direct access to individual ring elements, by index. */
#define RING_GET_REQUEST(_r, _idx) \
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
diff --git a/include/hw/xen/interface/io/usbif.h b/include/hw/xen/interface/io/usbif.h
index c0a552e..875af0d 100644
--- a/include/hw/xen/interface/io/usbif.h
+++ b/include/hw/xen/interface/io/usbif.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
/*
* usbif.h
*
@@ -5,24 +6,6 @@
*
* Copyright (C) 2009, FUJITSU LABORATORIES LTD.
* Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
*/
#ifndef __XEN_PUBLIC_IO_USBIF_H__
diff --git a/include/hw/xen/interface/io/xenbus.h b/include/hw/xen/interface/io/xenbus.h
index 927f9db..9cd0cd7 100644
--- a/include/hw/xen/interface/io/xenbus.h
+++ b/include/hw/xen/interface/io/xenbus.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/*****************************************************************************
* xenbus.h
*
* Xenbus protocol details.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (C) 2005 XenSource Ltd.
*/
diff --git a/include/hw/xen/interface/io/xs_wire.h b/include/hw/xen/interface/io/xs_wire.h
index 4dd6632..04e6849 100644
--- a/include/hw/xen/interface/io/xs_wire.h
+++ b/include/hw/xen/interface/io/xs_wire.h
@@ -1,25 +1,8 @@
+/* SPDX-License-Identifier: MIT */
/*
* Details of the "wire" protocol between Xen Store Daemon and client
* library or guest kernel.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (C) 2005 Rusty Russell IBM Corporation
*/
@@ -71,11 +54,12 @@ struct xsd_errors
#ifdef EINVAL
#define XSD_ERROR(x) { x, #x }
/* LINTED: static unused */
-static struct xsd_errors xsd_errors[]
+static const struct xsd_errors xsd_errors[]
#if defined(__GNUC__)
__attribute__((unused))
#endif
= {
+ /* /!\ New errors should be added at the end of the array. */
XSD_ERROR(EINVAL),
XSD_ERROR(EACCES),
XSD_ERROR(EEXIST),
@@ -90,7 +74,8 @@ __attribute__((unused))
XSD_ERROR(EBUSY),
XSD_ERROR(EAGAIN),
XSD_ERROR(EISCONN),
- XSD_ERROR(E2BIG)
+ XSD_ERROR(E2BIG),
+ XSD_ERROR(EPERM),
};
#endif
@@ -124,6 +109,7 @@ struct xenstore_domain_interface {
XENSTORE_RING_IDX rsp_cons, rsp_prod;
uint32_t server_features; /* Bitmap of features supported by the server */
uint32_t connection;
+ uint32_t error;
};
/* Violating this is very bad. See docs/misc/xenstore.txt. */
@@ -135,10 +121,18 @@ struct xenstore_domain_interface {
/* The ability to reconnect a ring */
#define XENSTORE_SERVER_FEATURE_RECONNECTION 1
+/* The presence of the "error" field in the ring page */
+#define XENSTORE_SERVER_FEATURE_ERROR 2
/* Valid values for the connection field */
#define XENSTORE_CONNECTED 0 /* the steady-state */
-#define XENSTORE_RECONNECT 1 /* guest has initiated a reconnect */
+#define XENSTORE_RECONNECT 1 /* reconnect in progress */
+
+/* Valid values for the error field */
+#define XENSTORE_ERROR_NONE 0 /* No error */
+#define XENSTORE_ERROR_COMM 1 /* Communication problem */
+#define XENSTORE_ERROR_RINGIDX 2 /* Invalid ring index */
+#define XENSTORE_ERROR_PROTO 3 /* Protocol violation (payload too long) */
#endif /* _XS_WIRE_H */
diff --git a/include/hw/xen/interface/memory.h b/include/hw/xen/interface/memory.h
index 383a946..29cf5c8 100644
--- a/include/hw/xen/interface/memory.h
+++ b/include/hw/xen/interface/memory.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* memory.h
*
* Memory reservation and information.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
@@ -541,12 +524,14 @@ struct xen_mem_sharing_op {
uint32_t gref; /* IN: gref to debug */
} u;
} debug;
- struct mem_sharing_op_fork { /* OP_FORK */
+ struct mem_sharing_op_fork { /* OP_FORK{,_RESET} */
domid_t parent_domain; /* IN: parent's domain id */
/* Only makes sense for short-lived forks */
#define XENMEM_FORK_WITH_IOMMU_ALLOWED (1u << 0)
/* Only makes sense for short-lived forks */
#define XENMEM_FORK_BLOCK_INTERRUPTS (1u << 1)
+#define XENMEM_FORK_RESET_STATE (1u << 2)
+#define XENMEM_FORK_RESET_MEMORY (1u << 3)
uint16_t flags; /* IN: optional settings */
uint32_t pad; /* Must be set to 0 */
} fork;
@@ -662,6 +647,13 @@ struct xen_mem_acquire_resource {
* two calls.
*/
uint32_t nr_frames;
+ /*
+ * Padding field, must be zero on input.
+ * In a previous version this was an output field with the lowest bit
+ * named XENMEM_rsrc_acq_caller_owned. Future versions of this interface
+ * will not reuse this bit as an output with the field being zero on
+ * input.
+ */
uint32_t pad;
/*
* IN - the index of the initial frame to be mapped. This parameter
diff --git a/include/hw/xen/interface/physdev.h b/include/hw/xen/interface/physdev.h
index d271766..f0c0d47 100644
--- a/include/hw/xen/interface/physdev.h
+++ b/include/hw/xen/interface/physdev.h
@@ -1,22 +1,5 @@
+/* SPDX-License-Identifier: MIT */
/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2006, Keir Fraser
*/
@@ -211,8 +194,8 @@ struct physdev_manage_pci_ext {
/* IN */
uint8_t bus;
uint8_t devfn;
- unsigned is_extfn;
- unsigned is_virtfn;
+ uint32_t is_extfn;
+ uint32_t is_virtfn;
struct {
uint8_t bus;
uint8_t devfn;
diff --git a/include/hw/xen/interface/sched.h b/include/hw/xen/interface/sched.h
index 811bd87..b4362c6 100644
--- a/include/hw/xen/interface/sched.h
+++ b/include/hw/xen/interface/sched.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* sched.h
*
* Scheduler state interactions
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/include/hw/xen/interface/trace.h b/include/hw/xen/interface/trace.h
index d5fa4ae..62a1799 100644
--- a/include/hw/xen/interface/trace.h
+++ b/include/hw/xen/interface/trace.h
@@ -1,24 +1,7 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* include/public/trace.h
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Mark Williamson, (C) 2004 Intel Research Cambridge
* Copyright (C) 2005 Bin Ren
*/
diff --git a/include/hw/xen/interface/vcpu.h b/include/hw/xen/interface/vcpu.h
index 3623af9..81a3b3a 100644
--- a/include/hw/xen/interface/vcpu.h
+++ b/include/hw/xen/interface/vcpu.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* vcpu.h
*
* VCPU initialisation, query, and hotplug.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/include/hw/xen/interface/version.h b/include/hw/xen/interface/version.h
index 17a81e2..9c78b4f 100644
--- a/include/hw/xen/interface/version.h
+++ b/include/hw/xen/interface/version.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* version.h
*
* Xen version, type, and compile information.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/include/hw/xen/interface/xen-compat.h b/include/hw/xen/interface/xen-compat.h
index e1c027a..97fe698 100644
--- a/include/hw/xen/interface/xen-compat.h
+++ b/include/hw/xen/interface/xen-compat.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* xen-compat.h
*
* Guest OS interface to Xen. Compatibility layer.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2006, Christian Limpach
*/
diff --git a/include/hw/xen/interface/xen.h b/include/hw/xen/interface/xen.h
index e373592..920567e 100644
--- a/include/hw/xen/interface/xen.h
+++ b/include/hw/xen/interface/xen.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: MIT */
/******************************************************************************
* xen.h
*
* Guest OS interface to Xen.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
* Copyright (c) 2004, K A Fraser
*/
diff --git a/include/hw/xen/xen-backend.h b/include/hw/xen/xen-backend.h
index aac2fd4..0f01631 100644
--- a/include/hw/xen/xen-backend.h
+++ b/include/hw/xen/xen-backend.h
@@ -33,6 +33,7 @@ XenDevice *xen_backend_get_device(XenBackendInstance *backend);
void xen_backend_register(const XenBackendInfo *info);
const char **xen_backend_get_types(unsigned int *nr);
+bool xen_backend_exists(const char *type, const char *name);
void xen_backend_device_create(XenBus *xenbus, const char *type,
const char *name, QDict *opts, Error **errp);
bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp);
diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h
index f435898..334ddd1 100644
--- a/include/hw/xen/xen-bus.h
+++ b/include/hw/xen/xen-bus.h
@@ -33,6 +33,7 @@ struct XenDevice {
};
typedef struct XenDevice XenDevice;
+typedef char *(*XenDeviceGetFrontendPath)(XenDevice *xendev, Error **errp);
typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp);
typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp);
typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev,
@@ -46,6 +47,7 @@ struct XenDeviceClass {
/*< public >*/
const char *backend;
const char *device;
+ XenDeviceGetFrontendPath get_frontend_path;
XenDeviceGetName get_name;
XenDeviceRealize realize;
XenDeviceFrontendChanged frontend_changed;
@@ -73,7 +75,7 @@ struct XenBusClass {
OBJECT_DECLARE_TYPE(XenBus, XenBusClass,
XEN_BUS)
-void xen_bus_init(void);
+BusState *xen_bus_init(void);
void xen_device_backend_set_state(XenDevice *xendev,
enum xenbus_state state);
@@ -129,5 +131,6 @@ void xen_device_notify_event_channel(XenDevice *xendev,
void xen_device_unbind_event_channel(XenDevice *xendev,
XenEventChannel *channel,
Error **errp);
+unsigned int xen_event_channel_get_local_port(XenEventChannel *channel);
#endif /* HW_XEN_BUS_H */
diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legacy-backend.h
index 6c307c5..fc42146 100644
--- a/include/hw/xen/xen-legacy-backend.h
+++ b/include/hw/xen/xen-legacy-backend.h
@@ -81,7 +81,6 @@ extern struct XenDevOps xen_usb_ops; /* xen-usb.c */
/* configuration (aka xenbus setup) */
void xen_config_cleanup(void);
-int xen_config_dev_blk(DriveInfo *disk);
int xen_config_dev_nic(NICInfo *nic);
int xen_config_dev_vfb(int vdev, const char *type);
int xen_config_dev_vkbd(int vdev);
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index 8ab1335..d5232f3 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -147,12 +147,10 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
break;
case EXCP_ILL:
- EXCP_DUMP(env, "qemu: EXCP_ILL exception %#x\n", trapnr);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
break;
case EXCP_PRIV_OPR:
/* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */
- EXCP_DUMP(env, "qemu: EXCP_PRIV_OPR exception %#x\n", trapnr);
if (env->cr[CR_IIR] == 0x04000000) {
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
} else {
@@ -160,7 +158,6 @@ void cpu_loop(CPUHPPAState *env)
}
break;
case EXCP_PRIV_REG:
- EXCP_DUMP(env, "qemu: EXCP_PRIV_REG exception %#x\n", trapnr);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f);
break;
case EXCP_OVERFLOW:
@@ -173,7 +170,6 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
break;
case EXCP_BREAK:
- EXCP_DUMP(env, "qemu: EXCP_BREAK exception %#x\n", trapnr);
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f & ~3);
break;
case EXCP_DEBUG:
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index 17920e9..d08a97d 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -86,7 +86,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env)
static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
{
- target_ulong psw;
+ abi_ulong psw;
int i;
__get_user(psw, &sc->sc_gr[0]);
@@ -150,10 +150,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
haddr = ka->_sa_handler;
if (haddr & 2) {
/* Function descriptor. */
- target_ulong *fdesc, dest;
+ abi_ptr *fdesc, dest;
haddr &= -4;
- fdesc = lock_user(VERIFY_READ, haddr, 2 * sizeof(target_ulong), 1);
+ fdesc = lock_user(VERIFY_READ, haddr, 2 * sizeof(abi_ptr), 1);
if (!fdesc) {
goto give_sigsegv;
}
diff --git a/linux-user/hppa/target_elf.h b/linux-user/hppa/target_elf.h
index 82b4e95..19cae8b 100644
--- a/linux-user/hppa/target_elf.h
+++ b/linux-user/hppa/target_elf.h
@@ -9,6 +9,6 @@
#define HPPA_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
- return "any";
+ return "hppa";
}
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index 7809036..3eee3c3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3986,14 +3986,22 @@ ERST
DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
"-initrd file use 'file' as initial ram disk\n", QEMU_ARCH_ALL)
SRST
+
``-initrd file``
Use file as initial ram disk.
``-initrd "file1 arg=foo,file2"``
This syntax is only available with multiboot.
- Use file1 and file2 as modules and pass arg=foo as parameter to the
- first module.
+ Use file1 and file2 as modules and pass ``arg=foo`` as parameter to the
+ first module. Commas can be provided in module parameters by doubling
+ them on the command line to escape them:
+
+``-initrd "bzImage earlyprintk=xen,,keep root=/dev/xvda1,initrd.img"``
+ Multiboot only. Use bzImage as the first module with
+ "``earlyprintk=xen,keep root=/dev/xvda1``" as its command line,
+ and initrd.img as the second module.
+
ERST
DEF("dtb", HAS_ARG, QEMU_OPTION_dtb, \
diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h
index c2791ae..6746869 100644
--- a/target/hppa/cpu-param.h
+++ b/target/hppa/cpu-param.h
@@ -8,26 +8,16 @@
#ifndef HPPA_CPU_PARAM_H
#define HPPA_CPU_PARAM_H
-#ifdef TARGET_HPPA64
-# define TARGET_LONG_BITS 64
-# define TARGET_REGISTER_BITS 64
-# define TARGET_VIRT_ADDR_SPACE_BITS 64
-# define TARGET_PHYS_ADDR_SPACE_BITS 64
-#elif defined(CONFIG_USER_ONLY)
-# define TARGET_LONG_BITS 32
-# define TARGET_REGISTER_BITS 32
-# define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define TARGET_LONG_BITS 64
+
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_ABI32)
# define TARGET_PHYS_ADDR_SPACE_BITS 32
+# define TARGET_VIRT_ADDR_SPACE_BITS 32
#else
-/*
- * In order to form the GVA from space:offset,
- * we need a 64-bit virtual address space.
- */
-# define TARGET_LONG_BITS 64
-# define TARGET_REGISTER_BITS 32
+# define TARGET_PHYS_ADDR_SPACE_BITS 64
# define TARGET_VIRT_ADDR_SPACE_BITS 64
-# define TARGET_PHYS_ADDR_SPACE_BITS 32
#endif
+
#define TARGET_PAGE_BITS 12
#endif
diff --git a/target/hppa/cpu-qom.h b/target/hppa/cpu-qom.h
index b96e031..4a85ebf 100644
--- a/target/hppa/cpu-qom.h
+++ b/target/hppa/cpu-qom.h
@@ -24,6 +24,7 @@
#include "qom/object.h"
#define TYPE_HPPA_CPU "hppa-cpu"
+#define TYPE_HPPA64_CPU "hppa64-cpu"
OBJECT_DECLARE_CPU_TYPE(HPPACPU, HPPACPUClass, HPPA_CPU)
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 1644297..04de168 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -77,9 +77,10 @@ static void hppa_restore_state_to_opc(CPUState *cs,
HPPACPU *cpu = HPPA_CPU(cs);
cpu->env.iaoq_f = data[0];
- if (data[1] != (target_ureg)-1) {
+ if (data[1] != (target_ulong)-1) {
cpu->env.iaoq_b = data[1];
}
+ cpu->env.unwind_breg = data[2];
/*
* Since we were executing the instruction at IAOQ_F, and took some
* sort of action that provoked the cpu_restore_state, we can infer
@@ -137,8 +138,10 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)
#ifndef CONFIG_USER_ONLY
{
HPPACPU *cpu = HPPA_CPU(cs);
+
cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
hppa_cpu_alarm_timer, cpu);
+ hppa_ptlbe(&cpu->env);
}
#endif
}
@@ -156,7 +159,39 @@ static void hppa_cpu_initfn(Object *obj)
static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model)
{
- return object_class_by_name(TYPE_HPPA_CPU);
+ g_autofree char *typename = g_strconcat(cpu_model, "-cpu", NULL);
+ ObjectClass *oc = object_class_by_name(typename);
+
+ if (oc &&
+ !object_class_is_abstract(oc) &&
+ object_class_dynamic_cast(oc, TYPE_HPPA_CPU)) {
+ return oc;
+ }
+ return NULL;
+}
+
+static void hppa_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CPUClass *cc = CPU_CLASS(oc);
+ const char *tname = object_class_get_name(oc);
+ g_autofree char *name = g_strndup(tname, strchr(tname, '-') - tname);
+
+ if (cc->deprecation_note) {
+ qemu_printf(" %s (deprecated)\n", name);
+ } else {
+ qemu_printf(" %s\n", name);
+ }
+}
+
+void hppa_cpu_list(void)
+{
+ GSList *list;
+
+ list = object_class_get_list_sorted(TYPE_HPPA_CPU, false);
+ qemu_printf("Available CPUs:\n");
+ g_slist_foreach(list, hppa_cpu_list_entry, NULL);
+ g_slist_free(list);
}
#ifndef CONFIG_USER_ONLY
@@ -207,20 +242,21 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data)
cc->tcg_ops = &hppa_tcg_ops;
}
-static const TypeInfo hppa_cpu_type_info = {
- .name = TYPE_HPPA_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(HPPACPU),
- .instance_align = __alignof(HPPACPU),
- .instance_init = hppa_cpu_initfn,
- .abstract = false,
- .class_size = sizeof(HPPACPUClass),
- .class_init = hppa_cpu_class_init,
+static const TypeInfo hppa_cpu_type_infos[] = {
+ {
+ .name = TYPE_HPPA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(HPPACPU),
+ .instance_align = __alignof(HPPACPU),
+ .instance_init = hppa_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(HPPACPUClass),
+ .class_init = hppa_cpu_class_init,
+ },
+ {
+ .name = TYPE_HPPA64_CPU,
+ .parent = TYPE_HPPA_CPU,
+ },
};
-static void hppa_cpu_register_types(void)
-{
- type_register_static(&hppa_cpu_type_info);
-}
-
-type_init(hppa_cpu_register_types)
+DEFINE_TYPES(hppa_cpu_type_infos)
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 798d0c2..144794d 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -23,6 +23,7 @@
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "qemu/cpu-float.h"
+#include "qemu/interval-tree.h"
/* PA-RISC 1.x processors have a strong memory model. */
/* ??? While we do not yet implement PA-RISC 2.0, those processors have
@@ -30,21 +31,33 @@
basis. It's probably easier to fall back to a strong memory model. */
#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL
-#define MMU_KERNEL_IDX 11
-#define MMU_PL1_IDX 12
-#define MMU_PL2_IDX 13
-#define MMU_USER_IDX 14
-#define MMU_PHYS_IDX 15
+#define MMU_KERNEL_IDX 7
+#define MMU_KERNEL_P_IDX 8
+#define MMU_PL1_IDX 9
+#define MMU_PL1_P_IDX 10
+#define MMU_PL2_IDX 11
+#define MMU_PL2_P_IDX 12
+#define MMU_USER_IDX 13
+#define MMU_USER_P_IDX 14
+#define MMU_PHYS_IDX 15
-#define PRIV_TO_MMU_IDX(priv) (MMU_KERNEL_IDX + (priv))
-#define MMU_IDX_TO_PRIV(mmu_idx) ((mmu_idx) - MMU_KERNEL_IDX)
+#define MMU_IDX_TO_PRIV(MIDX) (((MIDX) - MMU_KERNEL_IDX) / 2)
+#define MMU_IDX_TO_P(MIDX) (((MIDX) - MMU_KERNEL_IDX) & 1)
+#define PRIV_P_TO_MMU_IDX(PRIV, P) ((PRIV) * 2 + !!(P) + MMU_KERNEL_IDX)
-#define TARGET_INSN_START_EXTRA_WORDS 1
+#define TARGET_INSN_START_EXTRA_WORDS 2
/* No need to flush MMU_PHYS_IDX */
#define HPPA_MMU_FLUSH_MASK \
- (1 << MMU_KERNEL_IDX | 1 << MMU_PL1_IDX | \
- 1 << MMU_PL2_IDX | 1 << MMU_USER_IDX)
+ (1 << MMU_KERNEL_IDX | 1 << MMU_KERNEL_P_IDX | \
+ 1 << MMU_PL1_IDX | 1 << MMU_PL1_P_IDX | \
+ 1 << MMU_PL2_IDX | 1 << MMU_PL2_P_IDX | \
+ 1 << MMU_USER_IDX | 1 << MMU_USER_P_IDX)
+
+/* Indicies to flush for access_id changes. */
+#define HPPA_MMU_FLUSH_P_MASK \
+ (1 << MMU_KERNEL_P_IDX | 1 << MMU_PL1_P_IDX | \
+ 1 << MMU_PL2_P_IDX | 1 << MMU_USER_P_IDX)
/* Hardware exceptions, interrupts, faults, and traps. */
#define EXCP_HPMC 1 /* high priority machine check */
@@ -107,11 +120,7 @@
#define PSW_T 0x01000000
#define PSW_S 0x02000000
#define PSW_E 0x04000000
-#ifdef TARGET_HPPA64
#define PSW_W 0x08000000 /* PA2.0 only */
-#else
-#define PSW_W 0
-#endif
#define PSW_Z 0x40000000 /* PA1.x only */
#define PSW_Y 0x80000000 /* PA1.x only */
@@ -124,15 +133,12 @@
#define PSW_SM_P PSW_P
#define PSW_SM_Q PSW_Q /* Enable Interrupt State Collection */
#define PSW_SM_R PSW_R /* Enable Recover Counter Trap */
-#ifdef TARGET_HPPA64
#define PSW_SM_E 0x100
#define PSW_SM_W 0x200 /* PA2.0 only : Enable Wide Mode */
-#else
-#define PSW_SM_E 0
-#define PSW_SM_W 0
-#endif
#define CR_RC 0
+#define CR_PSW_DEFAULT 6 /* see SeaBIOS PDC_PSW firmware call */
+#define PDC_PSW_WIDE_BIT 2
#define CR_PID1 8
#define CR_PID2 9
#define CR_PID3 12
@@ -150,45 +156,37 @@
#define CR_IPSW 22
#define CR_EIRR 23
-#if TARGET_REGISTER_BITS == 32
-typedef uint32_t target_ureg;
-typedef int32_t target_sreg;
-#define TREG_FMT_lx "%08"PRIx32
-#define TREG_FMT_ld "%"PRId32
-#else
-typedef uint64_t target_ureg;
-typedef int64_t target_sreg;
-#define TREG_FMT_lx "%016"PRIx64
-#define TREG_FMT_ld "%"PRId64
-#endif
+typedef struct HPPATLBEntry {
+ union {
+ IntervalTreeNode itree;
+ struct HPPATLBEntry *unused_next;
+ };
+
+ target_ulong pa;
+
+ unsigned entry_valid : 1;
-typedef struct {
- uint64_t va_b;
- uint64_t va_e;
- target_ureg pa;
unsigned u : 1;
unsigned t : 1;
unsigned d : 1;
unsigned b : 1;
- unsigned page_size : 4;
unsigned ar_type : 3;
unsigned ar_pl1 : 2;
unsigned ar_pl2 : 2;
- unsigned entry_valid : 1;
unsigned access_id : 16;
-} hppa_tlb_entry;
+} HPPATLBEntry;
typedef struct CPUArchState {
- target_ureg iaoq_f; /* front */
- target_ureg iaoq_b; /* back, aka next instruction */
+ target_ulong iaoq_f; /* front */
+ target_ulong iaoq_b; /* back, aka next instruction */
- target_ureg gr[32];
+ target_ulong gr[32];
uint64_t fr[32];
uint64_t sr[8]; /* stored shifted into place for gva */
- target_ureg psw; /* All psw bits except the following: */
- target_ureg psw_n; /* boolean */
- target_sreg psw_v; /* in most significant bit */
+ target_ulong psw; /* All psw bits except the following: */
+ target_ulong psw_n; /* boolean */
+ target_long psw_v; /* in most significant bit */
/* Splitting the carry-borrow field into the MSB and "the rest", allows
* for "the rest" to be deleted when it is unused, but the MSB is in use.
@@ -197,8 +195,8 @@ typedef struct CPUArchState {
* host has the appropriate add-with-carry insn to compute the msb).
* Therefore the carry bits are stored as: cb_msb : cb & 0x11111110.
*/
- target_ureg psw_cb; /* in least significant bit of next nibble */
- target_ureg psw_cb_msb; /* boolean */
+ target_ulong psw_cb; /* in least significant bit of next nibble */
+ target_ulong psw_cb_msb; /* boolean */
uint64_t iasq_f;
uint64_t iasq_b;
@@ -206,24 +204,40 @@ typedef struct CPUArchState {
uint32_t fr0_shadow; /* flags, c, ca/cq, rm, d, enables */
float_status fp_status;
- target_ureg cr[32]; /* control registers */
- target_ureg cr_back[2]; /* back of cr17/cr18 */
- target_ureg shadow[7]; /* shadow registers */
+ target_ulong cr[32]; /* control registers */
+ target_ulong cr_back[2]; /* back of cr17/cr18 */
+ target_ulong shadow[7]; /* shadow registers */
- /* ??? The number of entries isn't specified by the architecture. */
-#ifdef TARGET_HPPA64
-#define HPPA_BTLB_FIXED 0 /* BTLBs are not supported in 64-bit machines */
-#else
-#define HPPA_BTLB_FIXED 16
-#endif
-#define HPPA_BTLB_VARIABLE 0
+ /*
+ * During unwind of a memory insn, the base register of the address.
+ * This is used to construct CR_IOR for pa2.0.
+ */
+ uint32_t unwind_breg;
+
+ /*
+ * ??? The number of entries isn't specified by the architecture.
+ * BTLBs are not supported in 64-bit machines.
+ */
+#define PA10_BTLB_FIXED 16
+#define PA10_BTLB_VARIABLE 0
#define HPPA_TLB_ENTRIES 256
-#define HPPA_BTLB_ENTRIES (HPPA_BTLB_FIXED + HPPA_BTLB_VARIABLE)
- /* ??? Implement a unified itlb/dtlb for the moment. */
- /* ??? We should use a more intelligent data structure. */
- hppa_tlb_entry tlb[HPPA_TLB_ENTRIES];
+ /* Index for round-robin tlb eviction. */
uint32_t tlb_last;
+
+ /*
+ * For pa1.x, the partial initialized, still invalid tlb entry
+ * which has had ITLBA performed, but not yet ITLBP.
+ */
+ HPPATLBEntry *tlb_partial;
+
+ /* Linked list of all invalid (unused) tlb entries. */
+ HPPATLBEntry *tlb_unused;
+
+ /* Root of the search tree for all valid tlb entries. */
+ IntervalTreeRoot tlb_root;
+
+ HPPATLBEntry tlb[HPPA_TLB_ENTRIES];
} CPUHPPAState;
/**
@@ -243,13 +257,23 @@ struct ArchCPU {
#include "exec/cpu-all.h"
+static inline bool hppa_is_pa20(CPUHPPAState *env)
+{
+ return object_dynamic_cast(OBJECT(env_cpu(env)), TYPE_HPPA64_CPU) != NULL;
+}
+
+static inline int HPPA_BTLB_ENTRIES(CPUHPPAState *env)
+{
+ return hppa_is_pa20(env) ? 0 : PA10_BTLB_FIXED + PA10_BTLB_VARIABLE;
+}
+
static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch)
{
#ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
#else
if (env->psw & (ifetch ? PSW_C : PSW_D)) {
- return PRIV_TO_MMU_IDX(env->iaoq_f & 3);
+ return PRIV_P_TO_MMU_IDX(env->iaoq_f & 3, env->psw & PSW_P);
}
return MMU_PHYS_IDX; /* mmu disabled */
#endif
@@ -259,23 +283,26 @@ void hppa_translate_init(void);
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
-static inline target_ulong hppa_form_gva_psw(target_ureg psw, uint64_t spc,
- target_ureg off)
+static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
+ target_ulong off)
{
#ifdef CONFIG_USER_ONLY
return off;
#else
- off &= (psw & PSW_W ? 0x3fffffffffffffffull : 0xffffffffull);
+ off &= psw & PSW_W ? MAKE_64BIT_MASK(0, 62) : MAKE_64BIT_MASK(0, 32);
return spc | off;
#endif
}
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
- target_ureg off)
+ target_ulong off)
{
return hppa_form_gva_psw(env->psw, spc, off);
}
+hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr);
+hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr);
+
/*
* Since PSW_{I,CB} will never need to be in tb->flags, reuse them.
* TB_FLAG_SR_SAME indicates that SR4 through SR7 all contain the
@@ -299,13 +326,12 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
*cs_base = env->iaoq_b & -4;
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
#else
- /* ??? E, T, H, L, B, P bits need to be here, when implemented. */
- flags |= env->psw & (PSW_W | PSW_C | PSW_D);
+ /* ??? E, T, H, L, B bits need to be here, when implemented. */
+ flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P);
flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT;
- *pc = (env->psw & PSW_C
- ? hppa_form_gva_psw(env->psw, env->iasq_f, env->iaoq_f & -4)
- : env->iaoq_f & -4);
+ *pc = hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
+ env->iaoq_f & -4);
*cs_base = env->iasq_f;
/* Insert a difference between IAOQ_B and IAOQ_F within the otherwise zero
@@ -313,8 +339,8 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
which is the primary case we care about -- using goto_tb within a page.
Failure is indicated by a zero difference. */
if (env->iasq_f == env->iasq_b) {
- target_sreg diff = env->iaoq_b - env->iaoq_f;
- if (TARGET_REGISTER_BITS == 32 || diff == (int32_t)diff) {
+ target_long diff = env->iaoq_b - env->iaoq_f;
+ if (diff == (int32_t)diff) {
*cs_base |= (uint32_t)diff;
}
}
@@ -328,8 +354,8 @@ static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
*pflags = flags;
}
-target_ureg cpu_hppa_get_psw(CPUHPPAState *env);
-void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg);
+target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
+void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
#ifdef CONFIG_USER_ONLY
@@ -342,6 +368,7 @@ int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
#ifndef CONFIG_USER_ONLY
+void hppa_ptlbe(CPUHPPAState *env);
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
@@ -350,7 +377,7 @@ void hppa_cpu_do_interrupt(CPUState *cpu);
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
int type, hwaddr *pphys, int *pprot,
- hppa_tlb_entry **tlb_entry);
+ HPPATLBEntry **tlb_entry);
extern const MemoryRegionOps hppa_io_eir_ops;
extern const VMStateDescription vmstate_hppa_cpu;
void hppa_cpu_alarm_timer(void *);
@@ -358,4 +385,9 @@ int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr);
#endif
G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra);
+#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
+
+#define cpu_list hppa_cpu_list
+void hppa_cpu_list(void);
+
#endif /* HPPA_CPU_H */
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
index 48a5143..4a965b3 100644
--- a/target/hppa/gdbstub.c
+++ b/target/hppa/gdbstub.c
@@ -21,11 +21,16 @@
#include "cpu.h"
#include "gdbstub/helpers.h"
+/*
+ * GDB 15 only supports PA1.0 via the remote protocol, and ignores
+ * any provided xml. Which means that any attempt to provide more
+ * data results in "Remote 'g' packet reply is too long".
+ */
+
int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
- HPPACPU *cpu = HPPA_CPU(cs);
- CPUHPPAState *env = &cpu->env;
- target_ureg val;
+ CPUHPPAState *env = cpu_env(cs);
+ uint32_t val;
switch (n) {
case 0:
@@ -139,24 +144,13 @@ int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
break;
}
- if (TARGET_REGISTER_BITS == 64) {
- return gdb_get_reg64(mem_buf, val);
- } else {
- return gdb_get_reg32(mem_buf, val);
- }
+ return gdb_get_reg32(mem_buf, val);
}
int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
- HPPACPU *cpu = HPPA_CPU(cs);
- CPUHPPAState *env = &cpu->env;
- target_ureg val;
-
- if (TARGET_REGISTER_BITS == 64) {
- val = ldq_p(mem_buf);
- } else {
- val = ldl_p(mem_buf);
- }
+ CPUHPPAState *env = cpu_env(cs);
+ uint32_t val = ldl_p(mem_buf);
switch (n) {
case 0:
@@ -166,7 +160,7 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->gr[n] = val;
break;
case 32:
- env->cr[CR_SAR] = val;
+ env->cr[CR_SAR] = val & (hppa_is_pa20(env) ? 63 : 31);
break;
case 33:
env->iaoq_f = val;
@@ -278,5 +272,5 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
}
break;
}
- return sizeof(target_ureg);
+ return 4;
}
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index a8d3f45..859644c 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -25,22 +25,32 @@
#include "exec/helper-proto.h"
#include "qemu/qemu-print.h"
-target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
+target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
{
- target_ureg psw;
+ target_ulong psw;
+ target_ulong mask1 = (target_ulong)-1 / 0xf;
+ target_ulong maskf = (target_ulong)-1 / 0xffff * 0xf;
/* Fold carry bits down to 8 consecutive bits. */
- /* ??? Needs tweaking for hppa64. */
- /* .......b...c...d...e...f...g...h */
- psw = (env->psw_cb >> 4) & 0x01111111;
- /* .......b..bc..cd..de..ef..fg..gh */
+ /* ^^^b^^^c^^^d^^^e^^^f^^^g^^^h^^^i^^^j^^^k^^^l^^^m^^^n^^^o^^^p^^^^ */
+ psw = (env->psw_cb >> 4) & mask1;
+ /* .......b...c...d...e...f...g...h...i...j...k...l...m...n...o...p */
psw |= psw >> 3;
- /* .............bcd............efgh */
- psw |= (psw >> 6) & 0x000f000f;
- /* .........................bcdefgh */
- psw |= (psw >> 12) & 0xf;
- psw |= env->psw_cb_msb << 7;
- psw = (psw & 0xff) << 8;
+ /* .......b..bc..cd..de..ef..fg..gh..hi..ij..jk..kl..lm..mn..no..op */
+ psw |= psw >> 6;
+ psw &= maskf;
+ /* .............bcd............efgh............ijkl............mnop */
+ psw |= psw >> 12;
+ /* .............bcd.........bcdefgh........efghijkl........ijklmnop */
+ psw |= env->psw_cb_msb << 39;
+ /* .............bcd........abcdefgh........efghijkl........ijklmnop */
+
+ /* For hppa64, the two 8-bit fields are discontiguous. */
+ if (hppa_is_pa20(env)) {
+ psw = (psw & 0xff00000000ull) | ((psw & 0xff) << 8);
+ } else {
+ psw = (psw & 0xff) << 8;
+ }
psw |= env->psw_n * PSW_N;
psw |= (env->psw_v < 0) * PSW_V;
@@ -49,16 +59,36 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
return psw;
}
-void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
+void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
{
- target_ureg old_psw = env->psw;
- target_ureg cb = 0;
+ uint64_t reserved;
+ target_ulong cb = 0;
+
+ /* Do not allow reserved bits to be set. */
+ if (hppa_is_pa20(env)) {
+ reserved = MAKE_64BIT_MASK(40, 24) | MAKE_64BIT_MASK(28, 4);
+ reserved |= PSW_G; /* PA1.x only */
+ reserved |= PSW_E; /* not implemented */
+ } else {
+ reserved = MAKE_64BIT_MASK(32, 32) | MAKE_64BIT_MASK(28, 2);
+ reserved |= PSW_O | PSW_W; /* PA2.0 only */
+ reserved |= PSW_E | PSW_Y | PSW_Z; /* not implemented */
+ }
+ psw &= ~reserved;
env->psw = psw & ~(PSW_N | PSW_V | PSW_CB);
env->psw_n = (psw / PSW_N) & 1;
env->psw_v = -((psw / PSW_V) & 1);
- env->psw_cb_msb = (psw >> 15) & 1;
+ env->psw_cb_msb = (psw >> 39) & 1;
+ cb |= ((psw >> 38) & 1) << 60;
+ cb |= ((psw >> 37) & 1) << 56;
+ cb |= ((psw >> 36) & 1) << 52;
+ cb |= ((psw >> 35) & 1) << 48;
+ cb |= ((psw >> 34) & 1) << 44;
+ cb |= ((psw >> 33) & 1) << 40;
+ cb |= ((psw >> 32) & 1) << 36;
+ cb |= ((psw >> 15) & 1) << 32;
cb |= ((psw >> 14) & 1) << 28;
cb |= ((psw >> 13) & 1) << 24;
cb |= ((psw >> 12) & 1) << 20;
@@ -67,29 +97,30 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
-
- /* If PSW_P changes, it affects how we translate addresses. */
- if ((psw ^ old_psw) & PSW_P) {
-#ifndef CONFIG_USER_ONLY
- tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK);
-#endif
- }
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
- HPPACPU *cpu = HPPA_CPU(cs);
- CPUHPPAState *env = &cpu->env;
- target_ureg psw = cpu_hppa_get_psw(env);
- target_ureg psw_cb;
+ CPUHPPAState *env = cpu_env(cs);
+ target_ulong psw = cpu_hppa_get_psw(env);
+ target_ulong psw_cb;
char psw_c[20];
- int i;
+ int i, w;
+ uint64_t m;
+
+ if (hppa_is_pa20(env)) {
+ w = 16;
+ m = UINT64_MAX;
+ } else {
+ w = 8;
+ m = UINT32_MAX;
+ }
qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx
- " IIR " TREG_FMT_lx "\n",
+ " IIR %0*" PRIx64 "\n",
hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b),
- env->cr[CR_IIR]);
+ w, m & env->cr[CR_IIR]);
psw_c[0] = (psw & PSW_W ? 'W' : '-');
psw_c[1] = (psw & PSW_E ? 'E' : '-');
@@ -110,13 +141,15 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
psw_c[16] = (psw & PSW_D ? 'D' : '-');
psw_c[17] = (psw & PSW_I ? 'I' : '-');
psw_c[18] = '\0';
- psw_cb = ((env->psw_cb >> 4) & 0x01111111) | (env->psw_cb_msb << 28);
+ psw_cb = ((env->psw_cb >> 4) & 0x1111111111111111ull)
+ | (env->psw_cb_msb << 60);
- qemu_fprintf(f, "PSW " TREG_FMT_lx " CB " TREG_FMT_lx " %s\n",
- psw, psw_cb, psw_c);
+ qemu_fprintf(f, "PSW %0*" PRIx64 " CB %0*" PRIx64 " %s\n",
+ w, m & psw, w, m & psw_cb, psw_c);
for (i = 0; i < 32; i++) {
- qemu_fprintf(f, "GR%02d " TREG_FMT_lx "%c", i, env->gr[i],
+ qemu_fprintf(f, "GR%02d %0*" PRIx64 "%c",
+ i, w, m & env->gr[i],
(i & 3) == 3 ? '\n' : ' ');
}
#ifndef CONFIG_USER_ONLY
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index 647f043..20698f6 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -1,24 +1,28 @@
-#if TARGET_REGISTER_BITS == 64
-# define dh_alias_tr i64
-# define dh_typecode_tr dh_typecode_i64
-#else
-# define dh_alias_tr i32
-# define dh_typecode_tr dh_typecode_i32
-#endif
-#define dh_ctype_tr target_ureg
-
DEF_HELPER_2(excp, noreturn, env, int)
-DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tr)
-DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tr)
+DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl)
-DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tr)
-DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tr)
-DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tr)
-DEF_HELPER_FLAGS_3(stby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tr)
+DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tl)
+
+DEF_HELPER_FLAGS_3(stdby_b, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stdby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stdby_e, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stdby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tl)
DEF_HELPER_FLAGS_1(ldc_check, TCG_CALL_NO_RWG, void, tl)
-DEF_HELPER_FLAGS_4(probe, TCG_CALL_NO_WG, tr, env, tl, i32, i32)
+DEF_HELPER_FLAGS_2(hadd_ss, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(hadd_us, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(havg, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_3(hshladd, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32)
+DEF_HELPER_FLAGS_3(hshradd, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32)
+DEF_HELPER_FLAGS_2(hsub_ss, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(hsub_us, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+
+DEF_HELPER_FLAGS_4(probe, TCG_CALL_NO_WG, tl, env, tl, i32, i32)
DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
@@ -77,7 +81,7 @@ DEF_HELPER_FLAGS_4(fmpynfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fmpyfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(fmpynfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
-DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tr)
+DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tl)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(halt, noreturn, env)
@@ -85,15 +89,18 @@ DEF_HELPER_1(reset, noreturn, env)
DEF_HELPER_1(getshadowregs, void, env)
DEF_HELPER_1(rfi, void, env)
DEF_HELPER_1(rfi_r, void, env)
-DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr)
-DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tr)
-DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tr)
-DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tr, env, tr)
-DEF_HELPER_FLAGS_3(itlba, TCG_CALL_NO_RWG, void, env, tl, tr)
-DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr)
+DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tl, env, tl)
+DEF_HELPER_FLAGS_3(itlba_pa11, TCG_CALL_NO_RWG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(itlbp_pa11, TCG_CALL_NO_RWG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(idtlbt_pa20, TCG_CALL_NO_RWG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(iitlbt_pa20, TCG_CALL_NO_RWG, void, env, tl, tl)
DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(ptlb_l, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
-DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl)
+DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tl, env, tl)
DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_1(diag_btlb, void, env)
#endif
diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
index aebe03c..f5a3f02 100644
--- a/target/hppa/insns.decode
+++ b/target/hppa/insns.decode
@@ -46,11 +46,16 @@
%im5_0 0:s1 1:4
%im5_16 16:s1 17:4
+%len5 0:5 !function=assemble_6
+%len6_8 8:1 0:5 !function=assemble_6
+%len6_12 12:1 0:5 !function=assemble_6
+%cpos6_11 11:1 5:5
%ma_to_m 5:1 13:1 !function=ma_to_m
%ma2_to_m 2:2 !function=ma_to_m
%pos_to_m 0:1 !function=pos_to_m
%neg_to_m 0:1 !function=neg_to_m
%a_to_m 2:1 !function=neg_to_m
+%cmpbid_c 13:2 !function=cmpbid_c
####
# Argument set definitions
@@ -59,28 +64,43 @@
# All insns that need to form a virtual address should use this set.
&ldst t b x disp sp m scale size
-&rr_cf t r cf
+&rr_cf_d t r cf d
+&rrr t r1 r2
&rrr_cf t r1 r2 cf
-&rrr_cf_sh t r1 r2 cf sh
+&rrr_cf_d t r1 r2 cf d
+&rrr_sh t r1 r2 sh
+&rrr_cf_d_sh t r1 r2 cf d sh
+&rri t r i
&rri_cf t r i cf
+&rri_cf_d t r i cf d
&rrb_c_f disp n c f r1 r2
+&rrb_c_d_f disp n c d f r1 r2
&rib_c_f disp n c f r i
+&rib_c_d_f disp n c d f r i
####
# Format definitions
####
-@rr_cf ...... r:5 ..... cf:4 ....... t:5 &rr_cf
+@rr_cf_d ...... r:5 ..... cf:4 ...... d:1 t:5 &rr_cf_d
+@rrr ...... r2:5 r1:5 .... ....... t:5 &rrr
@rrr_cf ...... r2:5 r1:5 cf:4 ....... t:5 &rrr_cf
-@rrr_cf_sh ...... r2:5 r1:5 cf:4 .... sh:2 . t:5 &rrr_cf_sh
-@rrr_cf_sh0 ...... r2:5 r1:5 cf:4 ....... t:5 &rrr_cf_sh sh=0
+@rrr_cf_d ...... r2:5 r1:5 cf:4 ...... d:1 t:5 &rrr_cf_d
+@rrr_sh ...... r2:5 r1:5 ........ sh:2 . t:5 &rrr_sh
+@rrr_cf_d_sh ...... r2:5 r1:5 cf:4 .... sh:2 d:1 t:5 &rrr_cf_d_sh
+@rrr_cf_d_sh0 ...... r2:5 r1:5 cf:4 ...... d:1 t:5 &rrr_cf_d_sh sh=0
@rri_cf ...... r:5 t:5 cf:4 . ........... &rri_cf i=%lowsign_11
+@rri_cf_d ...... r:5 t:5 cf:4 d:1 ........... &rri_cf_d i=%lowsign_11
@rrb_cf ...... r2:5 r1:5 c:3 ........... n:1 . \
&rrb_c_f disp=%assemble_12
+@rrb_cdf ...... r2:5 r1:5 c:3 ........... n:1 . \
+ &rrb_c_d_f disp=%assemble_12
@rib_cf ...... r:5 ..... c:3 ........... n:1 . \
&rib_c_f disp=%assemble_12 i=%im5_16
+@rib_cdf ...... r:5 ..... c:3 ........... n:1 . \
+ &rib_c_d_f disp=%assemble_12 i=%im5_16
####
# System
@@ -130,6 +150,7 @@ nop_addrx 000001 ..... ..... -- 01001110 . 00000 @addrx # pdc
probe 000001 b:5 ri:5 sp:2 imm:1 100011 write:1 0 t:5
+# pa1.x tlb insert instructions
ixtlbx 000001 b:5 r:5 sp:2 0100000 addr:1 0 00000 data=1
ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
sp=%assemble_sr3x data=0
@@ -137,9 +158,26 @@ ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
# pcxl and pcxl2 Fast TLB Insert instructions
ixtlbxf 000001 00000 r:5 00 0 data:1 01000 addr:1 0 00000
-pxtlbx 000001 b:5 x:5 sp:2 0100100 local:1 m:1 ----- data=1
-pxtlbx 000001 b:5 x:5 ... 000100 local:1 m:1 ----- \
- sp=%assemble_sr3x data=0
+# pa2.0 tlb insert idtlbt and iitlbt instructions
+ixtlbt 000001 r2:5 r1:5 000 data:1 100000 0 00000 # idtlbt
+
+# pdtlb, pitlb
+pxtlb 000001 b:5 x:5 sp:2 01001000 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0
+pxtlb 000001 b:5 x:5 ... 0001000 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x
+
+# ... pa20 local
+pxtlb_l 000001 b:5 x:5 sp:2 01011000 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0
+pxtlb_l 000001 b:5 x:5 ... 0011000 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x
+
+# pdtlbe, pitlbe
+pxtlbe 000001 b:5 x:5 sp:2 01001001 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0
+pxtlbe 000001 b:5 x:5 ... 0001001 m:1 ----- \
+ &ldst disp=0 scale=0 size=0 t=0 sp=%assemble_sr3x
lpa 000001 b:5 x:5 sp:2 01001101 m:1 t:5 \
&ldst disp=0 scale=0 size=0
@@ -150,30 +188,36 @@ lci 000001 ----- ----- -- 01001100 0 t:5
# Arith/Log
####
-andcm 000010 ..... ..... .... 000000 - ..... @rrr_cf
-and 000010 ..... ..... .... 001000 - ..... @rrr_cf
-or 000010 ..... ..... .... 001001 - ..... @rrr_cf
-xor 000010 ..... ..... .... 001010 0 ..... @rrr_cf
-uxor 000010 ..... ..... .... 001110 0 ..... @rrr_cf
+andcm 000010 ..... ..... .... 000000 . ..... @rrr_cf_d
+and 000010 ..... ..... .... 001000 . ..... @rrr_cf_d
+or 000010 ..... ..... .... 001001 . ..... @rrr_cf_d
+xor 000010 ..... ..... .... 001010 . ..... @rrr_cf_d
+uxor 000010 ..... ..... .... 001110 . ..... @rrr_cf_d
ds 000010 ..... ..... .... 010001 0 ..... @rrr_cf
-cmpclr 000010 ..... ..... .... 100010 0 ..... @rrr_cf
-uaddcm 000010 ..... ..... .... 100110 0 ..... @rrr_cf
-uaddcm_tc 000010 ..... ..... .... 100111 0 ..... @rrr_cf
-dcor 000010 ..... 00000 .... 101110 0 ..... @rr_cf
-dcor_i 000010 ..... 00000 .... 101111 0 ..... @rr_cf
-
-add 000010 ..... ..... .... 0110.. - ..... @rrr_cf_sh
-add_l 000010 ..... ..... .... 1010.. 0 ..... @rrr_cf_sh
-add_tsv 000010 ..... ..... .... 1110.. 0 ..... @rrr_cf_sh
-add_c 000010 ..... ..... .... 011100 0 ..... @rrr_cf_sh0
-add_c_tsv 000010 ..... ..... .... 111100 0 ..... @rrr_cf_sh0
-
-sub 000010 ..... ..... .... 010000 - ..... @rrr_cf
-sub_tsv 000010 ..... ..... .... 110000 0 ..... @rrr_cf
-sub_tc 000010 ..... ..... .... 010011 0 ..... @rrr_cf
-sub_tsv_tc 000010 ..... ..... .... 110011 0 ..... @rrr_cf
-sub_b 000010 ..... ..... .... 010100 0 ..... @rrr_cf
-sub_b_tsv 000010 ..... ..... .... 110100 0 ..... @rrr_cf
+cmpclr 000010 ..... ..... .... 100010 . ..... @rrr_cf_d
+uaddcm 000010 ..... ..... .... 100110 . ..... @rrr_cf_d
+uaddcm_tc 000010 ..... ..... .... 100111 . ..... @rrr_cf_d
+dcor 000010 ..... 00000 .... 101110 . ..... @rr_cf_d
+dcor_i 000010 ..... 00000 .... 101111 . ..... @rr_cf_d
+
+add 000010 ..... ..... .... 0110.. . ..... @rrr_cf_d_sh
+add_l 000010 ..... ..... .... 1010.. . ..... @rrr_cf_d_sh
+add_tsv 000010 ..... ..... .... 1110.. . ..... @rrr_cf_d_sh
+{
+ add_c 000010 ..... ..... .... 011100 . ..... @rrr_cf_d_sh0
+ hshladd 000010 ..... ..... 0000 0111.. 0 ..... @rrr_sh
+}
+add_c_tsv 000010 ..... ..... .... 111100 . ..... @rrr_cf_d_sh0
+
+sub 000010 ..... ..... .... 010000 . ..... @rrr_cf_d
+sub_tsv 000010 ..... ..... .... 110000 . ..... @rrr_cf_d
+sub_tc 000010 ..... ..... .... 010011 . ..... @rrr_cf_d
+sub_tsv_tc 000010 ..... ..... .... 110011 . ..... @rrr_cf_d
+{
+ sub_b 000010 ..... ..... .... 010100 . ..... @rrr_cf_d
+ hshradd 000010 ..... ..... 0000 0101.. 0 ..... @rrr_sh
+}
+sub_b_tsv 000010 ..... ..... .... 110100 . ..... @rrr_cf_d
ldil 001000 t:5 ..................... i=%assemble_21
addil 001010 r:5 ..................... i=%assemble_21
@@ -187,7 +231,28 @@ addi_tc_tsv 101100 ..... ..... .... 1 ........... @rri_cf
subi 100101 ..... ..... .... 0 ........... @rri_cf
subi_tsv 100101 ..... ..... .... 1 ........... @rri_cf
-cmpiclr 100100 ..... ..... .... 0 ........... @rri_cf
+cmpiclr 100100 ..... ..... .... . ........... @rri_cf_d
+
+hadd 000010 ..... ..... 00000011 11 0 ..... @rrr
+hadd_ss 000010 ..... ..... 00000011 01 0 ..... @rrr
+hadd_us 000010 ..... ..... 00000011 00 0 ..... @rrr
+
+havg 000010 ..... ..... 00000010 11 0 ..... @rrr
+
+hshl 111110 00000 r:5 100010 i:4 0 t:5 &rri
+hshr_s 111110 r:5 00000 110011 i:4 0 t:5 &rri
+hshr_u 111110 r:5 00000 110010 i:4 0 t:5 &rri
+
+hsub 000010 ..... ..... 00000001 11 0 ..... @rrr
+hsub_ss 000010 ..... ..... 00000001 01 0 ..... @rrr
+hsub_us 000010 ..... ..... 00000001 00 0 ..... @rrr
+
+mixh_l 111110 ..... ..... 1 00 00100000 ..... @rrr
+mixh_r 111110 ..... ..... 1 10 00100000 ..... @rrr
+mixw_l 111110 ..... ..... 1 00 00000000 ..... @rrr
+mixw_r 111110 ..... ..... 1 10 00000000 ..... @rrr
+
+permh 111110 r1:5 r2:5 0 c0:2 0 c1:2 c2:2 c3:2 0 t:5
####
# Index Mem
@@ -204,10 +269,16 @@ ld 000011 ..... ..... .. . 0 -- 00 size:2 ...... @ldstx
st 000011 ..... ..... .. . 1 -- 10 size:2 ...... @stim5
ldc 000011 ..... ..... .. . 1 -- 0111 ...... @ldim5 size=2
ldc 000011 ..... ..... .. . 0 -- 0111 ...... @ldstx size=2
+ldc 000011 ..... ..... .. . 1 -- 0101 ...... @ldim5 size=3
+ldc 000011 ..... ..... .. . 0 -- 0101 ...... @ldstx size=3
lda 000011 ..... ..... .. . 1 -- 0110 ...... @ldim5 size=2
lda 000011 ..... ..... .. . 0 -- 0110 ...... @ldstx size=2
+lda 000011 ..... ..... .. . 1 -- 0100 ...... @ldim5 size=3
+lda 000011 ..... ..... .. . 0 -- 0100 ...... @ldstx size=3
sta 000011 ..... ..... .. . 1 -- 1110 ...... @stim5 size=2
+sta 000011 ..... ..... .. . 1 -- 1111 ...... @stim5 size=3
stby 000011 b:5 r:5 sp:2 a:1 1 -- 1100 m:1 ..... disp=%im5_0
+stdby 000011 b:5 r:5 sp:2 a:1 1 -- 1101 m:1 ..... disp=%im5_0
@fldstwx ...... b:5 x:5 sp:2 scale:1 ....... m:1 ..... \
&ldst t=%rt64 disp=0 size=2
@@ -233,6 +304,8 @@ fstd 001011 ..... ..... .. . 1 -- 100 0 . ..... @fldstdi
# Offset Mem
####
+@ldstim11 ...... b:5 t:5 sp:2 .............. \
+ &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
@ldstim14 ...... b:5 t:5 sp:2 .............. \
&ldst disp=%lowsign_14 x=0 scale=0 m=0
@ldstim14m ...... b:5 t:5 sp:2 .............. \
@@ -264,11 +337,11 @@ fstw 011110 b:5 ..... sp:2 .............. \
fstw 011111 b:5 ..... sp:2 ...........0.. \
&ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2
-fldd 010100 b:5 t:5 sp:2 .......... .. 1 . \
- &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
+ld 010100 ..... ..... .. ............0. @ldstim11
+fldd 010100 ..... ..... .. ............1. @ldstim11
-fstd 011100 b:5 t:5 sp:2 .......... .. 1 . \
- &ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
+st 011100 ..... ..... .. ............0. @ldstim11
+fstd 011100 ..... ..... .. ............1. @ldstim11
####
# Floating-point Multiply Add
@@ -286,16 +359,20 @@ fmpysub_d 100110 ..... ..... ..... ..... 1 ..... @mpyadd
# Conditional Branches
####
-bb_sar 110000 00000 r:5 c:1 10 ........... n:1 . disp=%assemble_12
-bb_imm 110001 p:5 r:5 c:1 10 ........... n:1 . disp=%assemble_12
+bb_sar 110000 00000 r:5 c:1 1 d:1 ........... n:1 . disp=%assemble_12
+bb_imm 110001 p:5 r:5 c:1 1 d:1 ........... n:1 . disp=%assemble_12
movb 110010 ..... ..... ... ........... . . @rrb_cf f=0
movbi 110011 ..... ..... ... ........... . . @rib_cf f=0
-cmpb 100000 ..... ..... ... ........... . . @rrb_cf f=0
-cmpb 100010 ..... ..... ... ........... . . @rrb_cf f=1
-cmpbi 100001 ..... ..... ... ........... . . @rib_cf f=0
-cmpbi 100011 ..... ..... ... ........... . . @rib_cf f=1
+cmpb 100000 ..... ..... ... ........... . . @rrb_cdf d=0 f=0
+cmpb 100010 ..... ..... ... ........... . . @rrb_cdf d=0 f=1
+cmpb 100111 ..... ..... ... ........... . . @rrb_cdf d=1 f=0
+cmpb 101111 ..... ..... ... ........... . . @rrb_cdf d=1 f=1
+cmpbi 100001 ..... ..... ... ........... . . @rib_cdf d=0 f=0
+cmpbi 100011 ..... ..... ... ........... . . @rib_cdf d=0 f=1
+cmpbi 111011 r:5 ..... f:1 .. ........... n:1 . \
+ &rib_c_d_f d=1 disp=%assemble_12 c=%cmpbid_c i=%im5_16
addb 101000 ..... ..... ... ........... . . @rrb_cf f=0
addb 101010 ..... ..... ... ........... . . @rrb_cf f=1
@@ -306,16 +383,28 @@ addbi 101011 ..... ..... ... ........... . . @rib_cf f=1
# Shift, Extract, Deposit
####
-shrpw_sar 110100 r2:5 r1:5 c:3 00 0 00000 t:5
-shrpw_imm 110100 r2:5 r1:5 c:3 01 0 cpos:5 t:5
-
-extrw_sar 110100 r:5 t:5 c:3 10 se:1 00000 clen:5
-extrw_imm 110100 r:5 t:5 c:3 11 se:1 pos:5 clen:5
-
-depw_sar 110101 t:5 r:5 c:3 00 nz:1 00000 clen:5
-depw_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 clen:5
-depwi_sar 110101 t:5 ..... c:3 10 nz:1 00000 clen:5 i=%im5_16
-depwi_imm 110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5 i=%im5_16
+shrp_sar 110100 r2:5 r1:5 c:3 00 0 d:1 0000 t:5
+shrp_imm 110100 r2:5 r1:5 c:3 01 0 cpos:5 t:5 d=0
+shrp_imm 110100 r2:5 r1:5 c:3 0. 1 ..... t:5 \
+ d=1 cpos=%cpos6_11
+
+extr_sar 110100 r:5 t:5 c:3 10 se:1 00 000 ..... d=0 len=%len5
+extr_sar 110100 r:5 t:5 c:3 10 se:1 1. 000 ..... d=1 len=%len6_8
+extr_imm 110100 r:5 t:5 c:3 11 se:1 pos:5 ..... d=0 len=%len5
+extr_imm 110110 r:5 t:5 c:3 .. se:1 ..... ..... \
+ d=1 len=%len6_12 pos=%cpos6_11
+
+dep_sar 110101 t:5 r:5 c:3 00 nz:1 00 000 ..... d=0 len=%len5
+dep_sar 110101 t:5 r:5 c:3 00 nz:1 1. 000 ..... d=1 len=%len6_8
+dep_imm 110101 t:5 r:5 c:3 01 nz:1 cpos:5 ..... d=0 len=%len5
+dep_imm 111100 t:5 r:5 c:3 .. nz:1 ..... ..... \
+ d=1 len=%len6_12 cpos=%cpos6_11
+depi_sar 110101 t:5 ..... c:3 10 nz:1 d:1 . 000 ..... \
+ i=%im5_16 len=%len6_8
+depi_imm 110101 t:5 ..... c:3 11 nz:1 cpos:5 ..... \
+ d=0 i=%im5_16 len=%len5
+depi_imm 111101 t:5 ..... c:3 .. nz:1 ..... ..... \
+ d=1 i=%im5_16 len=%len6_12 cpos=%cpos6_11
####
# Branch External
@@ -343,6 +432,8 @@ bl 111010 ..... ..... 101 ........... n:1 . &BL l=2 \
disp=%assemble_22
b_gate 111010 ..... ..... 001 ........... . . @bl
blr 111010 l:5 x:5 010 00000000000 n:1 0
+nopbts 111010 00000 00000 010 0---------1 0 1 # clrbts/popbts
+nopbts 111010 00000 ----- 010 00000000000 0 1 # pushbts/pushnom
bv 111010 b:5 x:5 110 00000000000 n:1 0
bve 111010 b:5 00000 110 10000000000 n:1 - l=0
bve 111010 b:5 00000 111 10000000000 n:1 - l=2
@@ -384,7 +475,7 @@ fmpyfadd_d 101110 rm1:5 rm2:5 ... 0 1 ..0 0 0 neg:1 t:5 ra3=%rc32
@f0e_f_3 ...... ..... ..... ... .0 110 ..0 ..... \
&fclass3 r1=%ra64 r2=%rb64 t=%rt64
-@f0e_d_3 ...... r1:5 r2:5 ... 01 110 000 t:5
+@f0e_d_3 ...... r1:5 r2:5 ... 01 110 000 t:5 &fclass3
# Floating point class 0
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 3ab9934..467ee7d 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -52,9 +52,17 @@ static void io_eir_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
HPPACPU *cpu = opaque;
- int le_bit = ~data & (TARGET_REGISTER_BITS - 1);
+ CPUHPPAState *env = &cpu->env;
+ int widthm1 = 31;
+ int le_bit;
+
+ /* The default PSW.W controls the width of EIRR. */
+ if (hppa_is_pa20(env) && env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT) {
+ widthm1 = 63;
+ }
+ le_bit = ~data & widthm1;
- cpu->env.cr[CR_EIRR] |= (target_ureg)1 << le_bit;
+ env->cr[CR_EIRR] |= 1ull << le_bit;
eval_interrupt(cpu);
}
@@ -73,7 +81,7 @@ void hppa_cpu_alarm_timer(void *opaque)
io_eir_write(opaque, 0, 0, 4);
}
-void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val)
+void HELPER(write_eirr)(CPUHPPAState *env, target_ulong val)
{
env->cr[CR_EIRR] &= ~val;
qemu_mutex_lock_iothread();
@@ -81,7 +89,7 @@ void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val)
qemu_mutex_unlock_iothread();
}
-void HELPER(write_eiem)(CPUHPPAState *env, target_ureg val)
+void HELPER(write_eiem)(CPUHPPAState *env, target_ulong val)
{
env->cr[CR_EIEM] = val;
qemu_mutex_lock_iothread();
@@ -94,25 +102,37 @@ void hppa_cpu_do_interrupt(CPUState *cs)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
int i = cs->exception_index;
- target_ureg iaoq_f = env->iaoq_f;
- target_ureg iaoq_b = env->iaoq_b;
- uint64_t iasq_f = env->iasq_f;
- uint64_t iasq_b = env->iasq_b;
-
- target_ureg old_psw;
+ uint64_t old_psw;
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
- /* step 2 -- note PSW_W == 0 for !HPPA64. */
- cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0));
+ /* step 2 -- Note PSW_W is masked out again for pa1.x */
+ cpu_hppa_put_psw(env,
+ (env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT ? PSW_W : 0) |
+ (i == EXCP_HPMC ? PSW_M : 0));
/* step 3 */
- env->cr[CR_IIASQ] = iasq_f >> 32;
- env->cr_back[0] = iasq_b >> 32;
- env->cr[CR_IIAOQ] = iaoq_f;
- env->cr_back[1] = iaoq_b;
+ /*
+ * For pa1.x, IIASQ is simply a copy of IASQ.
+ * For pa2.0, IIASQ is the top bits of the virtual address,
+ * or zero if translation is disabled.
+ */
+ if (!hppa_is_pa20(env)) {
+ env->cr[CR_IIASQ] = env->iasq_f >> 32;
+ env->cr_back[0] = env->iasq_b >> 32;
+ } else if (old_psw & PSW_C) {
+ env->cr[CR_IIASQ] =
+ hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
+ env->cr_back[0] =
+ hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
+ } else {
+ env->cr[CR_IIASQ] = 0;
+ env->cr_back[0] = 0;
+ }
+ env->cr[CR_IIAOQ] = env->iaoq_f;
+ env->cr_back[1] = env->iaoq_b;
if (old_psw & PSW_Q) {
/* step 5 */
@@ -145,14 +165,13 @@ void hppa_cpu_do_interrupt(CPUState *cs)
/* ??? An alternate fool-proof method would be to store the
instruction data into the unwind info. That's probably
a bit too much in the way of extra storage required. */
- vaddr vaddr;
- hwaddr paddr;
+ vaddr vaddr = env->iaoq_f & -4;
+ hwaddr paddr = vaddr;
- paddr = vaddr = iaoq_f & -4;
if (old_psw & PSW_C) {
int prot, t;
- vaddr = hppa_form_gva_psw(old_psw, iasq_f, vaddr);
+ vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
0, &paddr, &prot, NULL);
if (t >= 0) {
@@ -182,14 +201,14 @@ void hppa_cpu_do_interrupt(CPUState *cs)
/* step 7 */
if (i == EXCP_TOC) {
- env->iaoq_f = FIRMWARE_START;
+ env->iaoq_f = hppa_form_gva(env, 0, FIRMWARE_START);
/* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
env->gr[24] = env->cr_back[0];
env->gr[25] = env->cr_back[1];
} else {
- env->iaoq_f = env->cr[CR_IVA] + 32 * i;
+ env->iaoq_f = hppa_form_gva(env, 0, env->cr[CR_IVA] + 32 * i);
}
- env->iaoq_b = env->iaoq_f + 4;
+ env->iaoq_b = hppa_form_gva(env, 0, env->iaoq_f + 4);
env->iasq_f = 0;
env->iasq_b = 0;
@@ -239,14 +258,10 @@ void hppa_cpu_do_interrupt(CPUState *cs)
snprintf(unknown, sizeof(unknown), "unknown %d", i);
name = unknown;
}
- qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx
- " -> " TREG_FMT_lx " " TARGET_FMT_lx "\n",
- ++count, name,
- hppa_form_gva(env, iasq_f, iaoq_f),
- hppa_form_gva(env, iasq_b, iaoq_b),
- env->iaoq_f,
- hppa_form_gva(env, (uint64_t)env->cr[CR_ISR] << 32,
- env->cr[CR_IOR]));
+ qemu_log("INT %6d: %s @ " TARGET_FMT_lx ":" TARGET_FMT_lx
+ " for " TARGET_FMT_lx ":" TARGET_FMT_lx "\n",
+ ++count, name, env->cr[CR_IIASQ], env->cr[CR_IIAOQ],
+ env->cr[CR_ISR], env->cr[CR_IOR]);
}
cs->exception_index = -1;
}
diff --git a/target/hppa/machine.c b/target/hppa/machine.c
index 905991d..2f8e8cc 100644
--- a/target/hppa/machine.c
+++ b/target/hppa/machine.c
@@ -21,33 +21,12 @@
#include "cpu.h"
#include "migration/cpu.h"
-#if TARGET_REGISTER_BITS == 64
-#define qemu_put_betr qemu_put_be64
-#define qemu_get_betr qemu_get_be64
-#define VMSTATE_UINTTL_V(_f, _s, _v) \
- VMSTATE_UINT64_V(_f, _s, _v)
-#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
- VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
-#else
-#define qemu_put_betr qemu_put_be32
-#define qemu_get_betr qemu_get_be32
-#define VMSTATE_UINTTR_V(_f, _s, _v) \
- VMSTATE_UINT32_V(_f, _s, _v)
-#define VMSTATE_UINTTR_ARRAY_V(_f, _s, _n, _v) \
- VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
-#endif
-
-#define VMSTATE_UINTTR(_f, _s) \
- VMSTATE_UINTTR_V(_f, _s, 0)
-#define VMSTATE_UINTTR_ARRAY(_f, _s, _n) \
- VMSTATE_UINTTR_ARRAY_V(_f, _s, _n, 0)
-
static int get_psw(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field)
{
CPUHPPAState *env = opaque;
- cpu_hppa_put_psw(env, qemu_get_betr(f));
+ cpu_hppa_put_psw(env, qemu_get_be64(f));
return 0;
}
@@ -55,7 +34,7 @@ static int put_psw(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field, JSONWriter *vmdesc)
{
CPUHPPAState *env = opaque;
- qemu_put_betr(f, cpu_hppa_get_psw(env));
+ qemu_put_be64(f, cpu_hppa_get_psw(env));
return 0;
}
@@ -65,70 +44,138 @@ static const VMStateInfo vmstate_psw = {
.put = put_psw,
};
-/* FIXME: Use the PA2.0 format, which is a superset of the PA1.1 format. */
static int get_tlb(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field)
{
- hppa_tlb_entry *ent = opaque;
- uint32_t val;
-
- memset(ent, 0, sizeof(*ent));
-
- ent->va_b = qemu_get_be64(f);
- ent->pa = qemu_get_betr(f);
- val = qemu_get_be32(f);
-
- ent->entry_valid = extract32(val, 0, 1);
- ent->access_id = extract32(val, 1, 18);
- ent->u = extract32(val, 19, 1);
- ent->ar_pl2 = extract32(val, 20, 2);
- ent->ar_pl1 = extract32(val, 22, 2);
- ent->ar_type = extract32(val, 24, 3);
- ent->b = extract32(val, 27, 1);
- ent->d = extract32(val, 28, 1);
- ent->t = extract32(val, 29, 1);
-
- ent->va_e = ent->va_b + TARGET_PAGE_SIZE - 1;
+ HPPATLBEntry *ent = opaque;
+ uint64_t val;
+
+ ent->itree.start = qemu_get_be64(f);
+ ent->itree.last = qemu_get_be64(f);
+ ent->pa = qemu_get_be64(f);
+ val = qemu_get_be64(f);
+
+ if (val) {
+ ent->t = extract64(val, 61, 1);
+ ent->d = extract64(val, 60, 1);
+ ent->b = extract64(val, 59, 1);
+ ent->ar_type = extract64(val, 56, 3);
+ ent->ar_pl1 = extract64(val, 54, 2);
+ ent->ar_pl2 = extract64(val, 52, 2);
+ ent->u = extract64(val, 51, 1);
+ /* o = bit 50 */
+ /* p = bit 49 */
+ ent->access_id = extract64(val, 1, 31);
+ ent->entry_valid = 1;
+ }
return 0;
}
static int put_tlb(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field, JSONWriter *vmdesc)
{
- hppa_tlb_entry *ent = opaque;
- uint32_t val = 0;
+ HPPATLBEntry *ent = opaque;
+ uint64_t val = 0;
if (ent->entry_valid) {
val = 1;
- val = deposit32(val, 1, 18, ent->access_id);
- val = deposit32(val, 19, 1, ent->u);
- val = deposit32(val, 20, 2, ent->ar_pl2);
- val = deposit32(val, 22, 2, ent->ar_pl1);
- val = deposit32(val, 24, 3, ent->ar_type);
- val = deposit32(val, 27, 1, ent->b);
- val = deposit32(val, 28, 1, ent->d);
- val = deposit32(val, 29, 1, ent->t);
+ val = deposit64(val, 61, 1, ent->t);
+ val = deposit64(val, 60, 1, ent->d);
+ val = deposit64(val, 59, 1, ent->b);
+ val = deposit64(val, 56, 3, ent->ar_type);
+ val = deposit64(val, 54, 2, ent->ar_pl1);
+ val = deposit64(val, 52, 2, ent->ar_pl2);
+ val = deposit64(val, 51, 1, ent->u);
+ /* o = bit 50 */
+ /* p = bit 49 */
+ val = deposit64(val, 1, 31, ent->access_id);
}
- qemu_put_be64(f, ent->va_b);
- qemu_put_betr(f, ent->pa);
- qemu_put_be32(f, val);
+ qemu_put_be64(f, ent->itree.start);
+ qemu_put_be64(f, ent->itree.last);
+ qemu_put_be64(f, ent->pa);
+ qemu_put_be64(f, val);
return 0;
}
-static const VMStateInfo vmstate_tlb = {
+static const VMStateInfo vmstate_tlb_entry = {
.name = "tlb entry",
.get = get_tlb,
.put = put_tlb,
};
-static VMStateField vmstate_env_fields[] = {
- VMSTATE_UINTTR_ARRAY(gr, CPUHPPAState, 32),
+static int tlb_pre_load(void *opaque)
+{
+ CPUHPPAState *env = opaque;
+
+ /*
+ * Zap the entire tlb, on-the-side data structures and all.
+ * Each tlb entry will have data re-filled by put_tlb.
+ */
+ memset(env->tlb, 0, sizeof(env->tlb));
+ memset(&env->tlb_root, 0, sizeof(env->tlb_root));
+ env->tlb_unused = NULL;
+ env->tlb_partial = NULL;
+
+ return 0;
+}
+
+static int tlb_post_load(void *opaque, int version_id)
+{
+ CPUHPPAState *env = opaque;
+ uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env);
+ HPPATLBEntry **unused = &env->tlb_unused;
+ HPPATLBEntry *partial = NULL;
+
+ /*
+ * Re-create the interval tree from the valid entries.
+ * Truely invalid entries should have start == end == 0.
+ * Otherwise it should be the in-flight tlb_partial entry.
+ */
+ for (uint32_t i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
+ HPPATLBEntry *e = &env->tlb[i];
+
+ if (e->entry_valid) {
+ interval_tree_insert(&e->itree, &env->tlb_root);
+ } else if (i < btlb_entries) {
+ /* btlb not in unused list */
+ } else if (partial == NULL && e->itree.start < e->itree.last) {
+ partial = e;
+ } else {
+ *unused = e;
+ unused = &e->unused_next;
+ }
+ }
+ env->tlb_partial = partial;
+ *unused = NULL;
+
+ return 0;
+}
+
+static const VMStateField vmstate_tlb_fields[] = {
+ VMSTATE_ARRAY(tlb, CPUHPPAState,
+ ARRAY_SIZE(((CPUHPPAState *)0)->tlb),
+ 0, vmstate_tlb_entry, HPPATLBEntry),
+ VMSTATE_UINT32(tlb_last, CPUHPPAState),
+ VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_tlb = {
+ .name = "env/tlb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = vmstate_tlb_fields,
+ .pre_load = tlb_pre_load,
+ .post_load = tlb_post_load,
+};
+
+static const VMStateField vmstate_env_fields[] = {
+ VMSTATE_UINT64_ARRAY(gr, CPUHPPAState, 32),
VMSTATE_UINT64_ARRAY(fr, CPUHPPAState, 32),
VMSTATE_UINT64_ARRAY(sr, CPUHPPAState, 8),
- VMSTATE_UINTTR_ARRAY(cr, CPUHPPAState, 32),
- VMSTATE_UINTTR_ARRAY(cr_back, CPUHPPAState, 2),
- VMSTATE_UINTTR_ARRAY(shadow, CPUHPPAState, 7),
+ VMSTATE_UINT64_ARRAY(cr, CPUHPPAState, 32),
+ VMSTATE_UINT64_ARRAY(cr_back, CPUHPPAState, 2),
+ VMSTATE_UINT64_ARRAY(shadow, CPUHPPAState, 7),
/* Save the architecture value of the psw, not the internally
expanded version. Since this architecture value does not
@@ -145,28 +192,29 @@ static VMStateField vmstate_env_fields[] = {
.offset = 0
},
- VMSTATE_UINTTR(iaoq_f, CPUHPPAState),
- VMSTATE_UINTTR(iaoq_b, CPUHPPAState),
+ VMSTATE_UINT64(iaoq_f, CPUHPPAState),
+ VMSTATE_UINT64(iaoq_b, CPUHPPAState),
VMSTATE_UINT64(iasq_f, CPUHPPAState),
VMSTATE_UINT64(iasq_b, CPUHPPAState),
VMSTATE_UINT32(fr0_shadow, CPUHPPAState),
-
- VMSTATE_ARRAY(tlb, CPUHPPAState, ARRAY_SIZE(((CPUHPPAState *)0)->tlb),
- 0, vmstate_tlb, hppa_tlb_entry),
- VMSTATE_UINT32(tlb_last, CPUHPPAState),
-
VMSTATE_END_OF_LIST()
};
+static const VMStateDescription *vmstate_env_subsections[] = {
+ &vmstate_tlb,
+ NULL
+};
+
static const VMStateDescription vmstate_env = {
.name = "env",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = vmstate_env_fields,
+ .subsections = vmstate_env_subsections,
};
-static VMStateField vmstate_cpu_fields[] = {
+static const VMStateField vmstate_cpu_fields[] = {
VMSTATE_CPU(),
VMSTATE_STRUCT(env, HPPACPU, 1, vmstate_env, CPUHPPAState),
VMSTATE_END_OF_LIST()
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index 350485f..858ce6e 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -25,72 +25,136 @@
#include "hw/core/cpu.h"
#include "trace.h"
-static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
+hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
- hppa_tlb_entry *ent = &env->tlb[i];
- if (ent->va_b <= addr && addr <= ent->va_e) {
- trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
- ent->va_b, ent->va_e, ent->pa);
- return ent;
- }
+ if (likely(extract64(addr, 58, 4) != 0xf)) {
+ /* Memory address space */
+ return addr & MAKE_64BIT_MASK(0, 62);
+ }
+ if (extract64(addr, 54, 4) != 0) {
+ /* I/O address space */
+ return addr | MAKE_64BIT_MASK(62, 2);
+ }
+ /* PDC address space */
+ return (addr & MAKE_64BIT_MASK(0, 54)) | MAKE_64BIT_MASK(60, 4);
+}
+
+hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr)
+{
+ if (likely(extract32(addr, 28, 4) != 0xf)) {
+ /* Memory address space */
+ return addr & MAKE_64BIT_MASK(0, 32);
+ }
+ if (extract32(addr, 24, 4) != 0) {
+ /* I/O address space */
+ return addr | MAKE_64BIT_MASK(32, 32);
+ }
+ /* PDC address space */
+ return (addr & MAKE_64BIT_MASK(0, 24)) | MAKE_64BIT_MASK(60, 4);
+}
+
+static hwaddr hppa_abs_to_phys(CPUHPPAState *env, vaddr addr)
+{
+ if (!hppa_is_pa20(env)) {
+ return addr;
+ } else if (env->psw & PSW_W) {
+ return hppa_abs_to_phys_pa2_w1(addr);
+ } else {
+ return hppa_abs_to_phys_pa2_w0(addr);
+ }
+}
+
+static HPPATLBEntry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
+{
+ IntervalTreeNode *i = interval_tree_iter_first(&env->tlb_root, addr, addr);
+
+ if (i) {
+ HPPATLBEntry *ent = container_of(i, HPPATLBEntry, itree);
+ trace_hppa_tlb_find_entry(env, ent, ent->entry_valid,
+ ent->itree.start, ent->itree.last, ent->pa);
+ return ent;
}
trace_hppa_tlb_find_entry_not_found(env, addr);
return NULL;
}
-static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent,
+static void hppa_flush_tlb_ent(CPUHPPAState *env, HPPATLBEntry *ent,
bool force_flush_btlb)
{
CPUState *cs = env_cpu(env);
+ bool is_btlb;
if (!ent->entry_valid) {
return;
}
- trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa);
+ trace_hppa_tlb_flush_ent(env, ent, ent->itree.start,
+ ent->itree.last, ent->pa);
- tlb_flush_range_by_mmuidx(cs, ent->va_b,
- ent->va_e - ent->va_b + 1,
- HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS);
+ tlb_flush_range_by_mmuidx(cs, ent->itree.start,
+ ent->itree.last - ent->itree.start + 1,
+ HPPA_MMU_FLUSH_MASK, TARGET_LONG_BITS);
- /* never clear BTLBs, unless forced to do so. */
- if (ent < &env->tlb[HPPA_BTLB_ENTRIES] && !force_flush_btlb) {
+ /* Never clear BTLBs, unless forced to do so. */
+ is_btlb = ent < &env->tlb[HPPA_BTLB_ENTRIES(env)];
+ if (is_btlb && !force_flush_btlb) {
return;
}
+ interval_tree_remove(&ent->itree, &env->tlb_root);
memset(ent, 0, sizeof(*ent));
- ent->va_b = -1;
+
+ if (!is_btlb) {
+ ent->unused_next = env->tlb_unused;
+ env->tlb_unused = ent;
+ }
}
-static hppa_tlb_entry *hppa_alloc_tlb_ent(CPUHPPAState *env)
+static void hppa_flush_tlb_range(CPUHPPAState *env, vaddr va_b, vaddr va_e)
{
- hppa_tlb_entry *ent;
- uint32_t i;
+ IntervalTreeNode *i, *n;
- if (env->tlb_last < HPPA_BTLB_ENTRIES || env->tlb_last >= ARRAY_SIZE(env->tlb)) {
- i = HPPA_BTLB_ENTRIES;
- env->tlb_last = HPPA_BTLB_ENTRIES + 1;
- } else {
- i = env->tlb_last;
- env->tlb_last++;
+ i = interval_tree_iter_first(&env->tlb_root, va_b, va_e);
+ for (; i ; i = n) {
+ HPPATLBEntry *ent = container_of(i, HPPATLBEntry, itree);
+
+ /*
+ * Find the next entry now: In the normal case the current entry
+ * will be removed, but in the BTLB case it will remain.
+ */
+ n = interval_tree_iter_next(i, va_b, va_e);
+ hppa_flush_tlb_ent(env, ent, false);
}
+}
+
+static HPPATLBEntry *hppa_alloc_tlb_ent(CPUHPPAState *env)
+{
+ HPPATLBEntry *ent = env->tlb_unused;
+
+ if (ent == NULL) {
+ uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env);
+ uint32_t i = env->tlb_last;
- ent = &env->tlb[i];
+ if (i < btlb_entries || i >= ARRAY_SIZE(env->tlb)) {
+ i = btlb_entries;
+ }
+ env->tlb_last = i + 1;
- hppa_flush_tlb_ent(env, ent, false);
+ ent = &env->tlb[i];
+ hppa_flush_tlb_ent(env, ent, false);
+ }
+
+ env->tlb_unused = ent->unused_next;
return ent;
}
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
int type, hwaddr *pphys, int *pprot,
- hppa_tlb_entry **tlb_entry)
+ HPPATLBEntry **tlb_entry)
{
hwaddr phys;
int prot, r_prot, w_prot, x_prot, priv;
- hppa_tlb_entry *ent;
+ HPPATLBEntry *ent;
int ret = -1;
if (tlb_entry) {
@@ -106,7 +170,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
/* Find a valid tlb entry that matches the virtual address. */
ent = hppa_find_tlb(env, addr);
- if (ent == NULL || !ent->entry_valid) {
+ if (ent == NULL) {
phys = 0;
prot = 0;
ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
@@ -118,7 +182,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
}
/* We now know the physical address. */
- phys = ent->pa + (addr - ent->va_b);
+ phys = ent->pa + (addr - ent->itree.start);
/* Map TLB access_rights field to QEMU protection. */
priv = MMU_IDX_TO_PRIV(mmu_idx);
@@ -144,7 +208,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
}
/* access_id == 0 means public page and no check is performed */
- if ((env->psw & PSW_P) && ent->access_id) {
+ if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
/* If bits [31:1] match, and bit 0 is set, suppress write. */
int match = ent->access_id * 2 + 1;
@@ -197,7 +261,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
}
egress:
- *pphys = phys;
+ *pphys = phys = hppa_abs_to_phys(env, phys);
*pprot = prot;
trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
return ret;
@@ -213,7 +277,7 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
/* ??? We really ought to know if the code mmu is disabled too,
in order to get the correct debugging dumps. */
if (!(cpu->env.psw & PSW_D)) {
- return addr;
+ return hppa_abs_to_phys(&cpu->env, addr);
}
excp = hppa_get_physical_address(&cpu->env, addr, MMU_KERNEL_IDX, 0,
@@ -225,13 +289,60 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
return excp == EXCP_DTLB_MISS ? -1 : phys;
}
+G_NORETURN static void
+raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr,
+ vaddr addr, bool mmu_disabled)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = excp;
+
+ if (env->psw & PSW_Q) {
+ /*
+ * For pa1.x, the offset and space never overlap, and so we
+ * simply extract the high and low part of the virtual address.
+ *
+ * For pa2.0, the formation of these are described in section
+ * "Interruption Parameter Registers", page 2-15.
+ */
+ env->cr[CR_IOR] = (uint32_t)addr;
+ env->cr[CR_ISR] = addr >> 32;
+
+ if (hppa_is_pa20(env)) {
+ if (mmu_disabled) {
+ /*
+ * If data translation was disabled, the ISR contains
+ * the upper portion of the abs address, zero-extended.
+ */
+ env->cr[CR_ISR] &= 0x3fffffff;
+ } else {
+ /*
+ * If data translation was enabled, the upper two bits
+ * of the IOR (the b field) are equal to the two space
+ * bits from the base register used to form the gva.
+ */
+ uint64_t b;
+
+ cpu_restore_state(cs, retaddr);
+
+ b = env->gr[env->unwind_breg];
+ b >>= (env->psw & PSW_W ? 62 : 30);
+ env->cr[CR_IOR] |= b << 62;
+
+ cpu_loop_exit(cs);
+ }
+ }
+ }
+ cpu_loop_exit_restore(cs, retaddr);
+}
+
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
MMUAccessType type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
- hppa_tlb_entry *ent;
+ HPPATLBEntry *ent;
int prot, excp, a_prot;
hwaddr phys;
@@ -254,56 +365,51 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
return false;
}
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
+
/* Failure. Raise the indicated exception. */
- cs->exception_index = excp;
- if (cpu->env.psw & PSW_Q) {
- /* ??? Needs tweaking for hppa64. */
- cpu->env.cr[CR_IOR] = addr;
- cpu->env.cr[CR_ISR] = addr >> 32;
- }
- cpu_loop_exit_restore(cs, retaddr);
+ raise_exception_with_ior(env, excp, retaddr,
+ addr, mmu_idx == MMU_PHYS_IDX);
}
trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
phys & TARGET_PAGE_MASK, size, type, mmu_idx);
- /* Success! Store the translation into the QEMU TLB. */
+
+ /*
+ * Success! Store the translation into the QEMU TLB.
+ * Note that we always install a single-page entry, because that
+ * is what works best with softmmu -- anything else will trigger
+ * the large page protection mask. We do not require this,
+ * because we record the large page here in the hppa tlb.
+ */
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
- prot, mmu_idx, TARGET_PAGE_SIZE << (ent ? 2 * ent->page_size : 0));
+ prot, mmu_idx, TARGET_PAGE_SIZE);
return true;
}
/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
-void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
+void HELPER(itlba_pa11)(CPUHPPAState *env, target_ulong addr, target_ulong reg)
{
- hppa_tlb_entry *empty = NULL;
- int i;
-
- /* Zap any old entries covering ADDR; notice empty entries on the way. */
- for (i = HPPA_BTLB_ENTRIES; i < ARRAY_SIZE(env->tlb); ++i) {
- hppa_tlb_entry *ent = &env->tlb[i];
- if (ent->va_b <= addr && addr <= ent->va_e) {
- if (ent->entry_valid) {
- hppa_flush_tlb_ent(env, ent, false);
- }
- if (!empty) {
- empty = ent;
- }
- }
- }
+ HPPATLBEntry *ent;
- /* If we didn't see an empty entry, evict one. */
- if (empty == NULL) {
- empty = hppa_alloc_tlb_ent(env);
+ /* Zap any old entries covering ADDR. */
+ addr &= TARGET_PAGE_MASK;
+ hppa_flush_tlb_range(env, addr, addr + TARGET_PAGE_SIZE - 1);
+
+ ent = env->tlb_partial;
+ if (ent == NULL) {
+ ent = hppa_alloc_tlb_ent(env);
+ env->tlb_partial = ent;
}
- /* Note that empty->entry_valid == 0 already. */
- empty->va_b = addr & TARGET_PAGE_MASK;
- empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
- empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
- trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa);
+ /* Note that ent->entry_valid == 0 already. */
+ ent->itree.start = addr;
+ ent->itree.last = addr + TARGET_PAGE_SIZE - 1;
+ ent->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
+ trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa);
}
-static void set_access_bits(CPUHPPAState *env, hppa_tlb_entry *ent, target_ureg reg)
+static void set_access_bits_pa11(CPUHPPAState *env, HPPATLBEntry *ent,
+ target_ulong reg)
{
ent->access_id = extract32(reg, 1, 18);
ent->u = extract32(reg, 19, 1);
@@ -314,49 +420,153 @@ static void set_access_bits(CPUHPPAState *env, hppa_tlb_entry *ent, target_ureg
ent->d = extract32(reg, 28, 1);
ent->t = extract32(reg, 29, 1);
ent->entry_valid = 1;
+
+ interval_tree_insert(&ent->itree, &env->tlb_root);
trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2,
ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t);
}
/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
-void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
+void HELPER(itlbp_pa11)(CPUHPPAState *env, target_ulong addr, target_ulong reg)
{
- hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
+ HPPATLBEntry *ent = env->tlb_partial;
- if (unlikely(ent == NULL)) {
- qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
- return;
+ if (ent) {
+ env->tlb_partial = NULL;
+ if (ent->itree.start <= addr && addr <= ent->itree.last) {
+ set_access_bits_pa11(env, ent, reg);
+ return;
+ }
}
+ qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
+}
+
+static void itlbt_pa20(CPUHPPAState *env, target_ulong r1,
+ target_ulong r2, vaddr va_b)
+{
+ HPPATLBEntry *ent;
+ vaddr va_e;
+ uint64_t va_size;
+ int mask_shift;
+
+ mask_shift = 2 * (r1 & 0xf);
+ va_size = TARGET_PAGE_SIZE << mask_shift;
+ va_b &= -va_size;
+ va_e = va_b + va_size - 1;
+
+ hppa_flush_tlb_range(env, va_b, va_e);
+ ent = hppa_alloc_tlb_ent(env);
+
+ ent->itree.start = va_b;
+ ent->itree.last = va_e;
+ ent->pa = (r1 << 7) & (TARGET_PAGE_MASK << mask_shift);
+ ent->t = extract64(r2, 61, 1);
+ ent->d = extract64(r2, 60, 1);
+ ent->b = extract64(r2, 59, 1);
+ ent->ar_type = extract64(r2, 56, 3);
+ ent->ar_pl1 = extract64(r2, 54, 2);
+ ent->ar_pl2 = extract64(r2, 52, 2);
+ ent->u = extract64(r2, 51, 1);
+ /* o = bit 50 */
+ /* p = bit 49 */
+ ent->access_id = extract64(r2, 1, 31);
+ ent->entry_valid = 1;
- set_access_bits(env, ent, reg);
+ interval_tree_insert(&ent->itree, &env->tlb_root);
+ trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa);
+ trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u,
+ ent->ar_pl2, ent->ar_pl1, ent->ar_type,
+ ent->b, ent->d, ent->t);
}
-/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
- synchronous across all processors. */
+void HELPER(idtlbt_pa20)(CPUHPPAState *env, target_ulong r1, target_ulong r2)
+{
+ vaddr va_b = deposit64(env->cr[CR_IOR], 32, 32, env->cr[CR_ISR]);
+ itlbt_pa20(env, r1, r2, va_b);
+}
+
+void HELPER(iitlbt_pa20)(CPUHPPAState *env, target_ulong r1, target_ulong r2)
+{
+ vaddr va_b = deposit64(env->cr[CR_IIAOQ], 32, 32, env->cr[CR_IIASQ]);
+ itlbt_pa20(env, r1, r2, va_b);
+}
+
+/* Purge (Insn/Data) TLB. */
static void ptlb_work(CPUState *cpu, run_on_cpu_data data)
{
CPUHPPAState *env = cpu_env(cpu);
- target_ulong addr = (target_ulong) data.target_ptr;
- hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
+ vaddr start = data.target_ptr;
+ vaddr end;
+
+ /*
+ * PA2.0 allows a range of pages encoded into GR[b], which we have
+ * copied into the bottom bits of the otherwise page-aligned address.
+ * PA1.x will always provide zero here, for a single page flush.
+ */
+ end = start & 0xf;
+ start &= TARGET_PAGE_MASK;
+ end = TARGET_PAGE_SIZE << (2 * end);
+ end = start + end - 1;
+
+ hppa_flush_tlb_range(env, start, end);
+}
- if (ent && ent->entry_valid) {
- hppa_flush_tlb_ent(env, ent, false);
- }
+/* This is local to the current cpu. */
+void HELPER(ptlb_l)(CPUHPPAState *env, target_ulong addr)
+{
+ trace_hppa_tlb_ptlb_local(env);
+ ptlb_work(env_cpu(env), RUN_ON_CPU_TARGET_PTR(addr));
}
+/* This is synchronous across all processors. */
void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
{
CPUState *src = env_cpu(env);
CPUState *cpu;
+ bool wait = false;
+
trace_hppa_tlb_ptlb(env);
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
CPU_FOREACH(cpu) {
if (cpu != src) {
async_run_on_cpu(cpu, ptlb_work, data);
+ wait = true;
}
}
- async_safe_run_on_cpu(src, ptlb_work, data);
+ if (wait) {
+ async_safe_run_on_cpu(src, ptlb_work, data);
+ } else {
+ ptlb_work(src, data);
+ }
+}
+
+void hppa_ptlbe(CPUHPPAState *env)
+{
+ uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env);
+ uint32_t i;
+
+ /* Zap the (non-btlb) tlb entries themselves. */
+ memset(&env->tlb[btlb_entries], 0,
+ sizeof(env->tlb) - btlb_entries * sizeof(env->tlb[0]));
+ env->tlb_last = btlb_entries;
+ env->tlb_partial = NULL;
+
+ /* Put them all onto the unused list. */
+ env->tlb_unused = &env->tlb[btlb_entries];
+ for (i = btlb_entries; i < ARRAY_SIZE(env->tlb) - 1; ++i) {
+ env->tlb[i].unused_next = &env->tlb[i + 1];
+ }
+
+ /* Re-initialize the interval tree with only the btlb entries. */
+ memset(&env->tlb_root, 0, sizeof(env->tlb_root));
+ for (i = 0; i < btlb_entries; ++i) {
+ if (env->tlb[i].entry_valid) {
+ interval_tree_insert(&env->tlb[i].itree, &env->tlb_root);
+ }
+ }
+
+ tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK);
}
/* Purge (Insn/Data) TLB entry. This affects an implementation-defined
@@ -365,17 +575,12 @@ void HELPER(ptlbe)(CPUHPPAState *env)
{
trace_hppa_tlb_ptlbe(env);
qemu_log_mask(CPU_LOG_MMU, "FLUSH ALL TLB ENTRIES\n");
- memset(&env->tlb[HPPA_BTLB_ENTRIES], 0,
- sizeof(env->tlb) - HPPA_BTLB_ENTRIES * sizeof(env->tlb[0]));
- env->tlb_last = HPPA_BTLB_ENTRIES;
- tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK);
+ hppa_ptlbe(env);
}
void cpu_hppa_change_prot_id(CPUHPPAState *env)
{
- if (env->psw & PSW_P) {
- tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK);
- }
+ tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_P_MASK);
}
void HELPER(change_prot_id)(CPUHPPAState *env)
@@ -383,7 +588,7 @@ void HELPER(change_prot_id)(CPUHPPAState *env)
cpu_hppa_change_prot_id(env);
}
-target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
+target_ulong HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
{
hwaddr phys;
int prot, excp;
@@ -391,16 +596,11 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
&phys, &prot, NULL);
if (excp >= 0) {
- if (env->psw & PSW_Q) {
- /* ??? Needs tweaking for hppa64. */
- env->cr[CR_IOR] = addr;
- env->cr[CR_ISR] = addr >> 32;
- }
if (excp == EXCP_DTLB_MISS) {
excp = EXCP_NA_DTLB_MISS;
}
trace_hppa_tlb_lpa_failed(env, addr);
- hppa_dynamic_excp(env, excp, GETPC());
+ raise_exception_with_ior(env, excp, GETPC(), addr, false);
}
trace_hppa_tlb_lpa_success(env, addr, phys);
return phys;
@@ -409,7 +609,7 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
/* Return the ar_type of the TLB at VADDR, or -1. */
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
{
- hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr);
+ HPPATLBEntry *ent = hppa_find_tlb(env, vaddr);
return ent ? ent->ar_type : -1;
}
@@ -424,15 +624,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
unsigned int phys_page, len, slot;
int mmu_idx = cpu_mmu_index(env, 0);
uintptr_t ra = GETPC();
- hppa_tlb_entry *btlb;
+ HPPATLBEntry *btlb;
uint64_t virt_page;
uint32_t *vaddr;
+ uint32_t btlb_entries = HPPA_BTLB_ENTRIES(env);
-#ifdef TARGET_HPPA64
/* BTLBs are not supported on 64-bit CPUs */
- env->gr[28] = -1; /* nonexistent procedure */
- return;
-#endif
+ if (btlb_entries == 0) {
+ env->gr[28] = -1; /* nonexistent procedure */
+ return;
+ }
+
env->gr[28] = 0; /* PDC_OK */
switch (env->gr[25]) {
@@ -446,8 +648,8 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
} else {
vaddr[0] = cpu_to_be32(1);
vaddr[1] = cpu_to_be32(16 * 1024);
- vaddr[2] = cpu_to_be32(HPPA_BTLB_FIXED);
- vaddr[3] = cpu_to_be32(HPPA_BTLB_VARIABLE);
+ vaddr[2] = cpu_to_be32(PA10_BTLB_FIXED);
+ vaddr[3] = cpu_to_be32(PA10_BTLB_VARIABLE);
}
break;
case 1:
@@ -464,15 +666,17 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
(long long) virt_page << TARGET_PAGE_BITS,
(long long) (virt_page + len) << TARGET_PAGE_BITS,
(long long) virt_page, phys_page, len, slot);
- if (slot < HPPA_BTLB_ENTRIES) {
+ if (slot < btlb_entries) {
btlb = &env->tlb[slot];
- /* force flush of possibly existing BTLB entry */
+
+ /* Force flush of possibly existing BTLB entry. */
hppa_flush_tlb_ent(env, btlb, true);
- /* create new BTLB entry */
- btlb->va_b = virt_page << TARGET_PAGE_BITS;
- btlb->va_e = btlb->va_b + len * TARGET_PAGE_SIZE - 1;
+
+ /* Create new BTLB entry */
+ btlb->itree.start = virt_page << TARGET_PAGE_BITS;
+ btlb->itree.last = btlb->itree.start + len * TARGET_PAGE_SIZE - 1;
btlb->pa = phys_page << TARGET_PAGE_BITS;
- set_access_bits(env, btlb, env->gr[20]);
+ set_access_bits_pa11(env, btlb, env->gr[20]);
btlb->t = 0;
btlb->d = 1;
} else {
@@ -484,7 +688,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
slot = env->gr[22];
qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE slot %d\n",
slot);
- if (slot < HPPA_BTLB_ENTRIES) {
+ if (slot < btlb_entries) {
btlb = &env->tlb[slot];
hppa_flush_tlb_ent(env, btlb, true);
} else {
@@ -494,7 +698,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
case 3:
/* Purge all BTLB entries */
qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_PURGE_ALL\n");
- for (slot = 0; slot < HPPA_BTLB_ENTRIES; slot++) {
+ for (slot = 0; slot < btlb_entries; slot++) {
btlb = &env->tlb[slot];
hppa_flush_tlb_ent(env, btlb, true);
}
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 837e2b3..a0e31c0 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -42,25 +42,25 @@ G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra)
cpu_loop_exit_restore(cs, ra);
}
-void HELPER(tsv)(CPUHPPAState *env, target_ureg cond)
+void HELPER(tsv)(CPUHPPAState *env, target_ulong cond)
{
- if (unlikely((target_sreg)cond < 0)) {
+ if (unlikely((target_long)cond < 0)) {
hppa_dynamic_excp(env, EXCP_OVERFLOW, GETPC());
}
}
-void HELPER(tcond)(CPUHPPAState *env, target_ureg cond)
+void HELPER(tcond)(CPUHPPAState *env, target_ulong cond)
{
if (unlikely(cond)) {
hppa_dynamic_excp(env, EXCP_COND, GETPC());
}
}
-static void atomic_store_3(CPUHPPAState *env, target_ulong addr,
- uint32_t val, uintptr_t ra)
+static void atomic_store_mask32(CPUHPPAState *env, target_ulong addr,
+ uint32_t val, uint32_t mask, uintptr_t ra)
{
int mmu_idx = cpu_mmu_index(env, 0);
- uint32_t old, new, cmp, mask, *haddr;
+ uint32_t old, new, cmp, *haddr;
void *vaddr;
vaddr = probe_access(env, addr, 3, MMU_DATA_STORE, mmu_idx, ra);
@@ -81,7 +81,36 @@ static void atomic_store_3(CPUHPPAState *env, target_ulong addr,
}
}
-static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val,
+static void atomic_store_mask64(CPUHPPAState *env, target_ulong addr,
+ uint64_t val, uint64_t mask,
+ int size, uintptr_t ra)
+{
+#ifdef CONFIG_ATOMIC64
+ int mmu_idx = cpu_mmu_index(env, 0);
+ uint64_t old, new, cmp, *haddr;
+ void *vaddr;
+
+ vaddr = probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, ra);
+ if (vaddr == NULL) {
+ cpu_loop_exit_atomic(env_cpu(env), ra);
+ }
+ haddr = (uint64_t *)((uintptr_t)vaddr & -8);
+
+ old = *haddr;
+ while (1) {
+ new = be32_to_cpu((cpu_to_be32(old) & ~mask) | (val & mask));
+ cmp = qatomic_cmpxchg__nocheck(haddr, old, new);
+ if (cmp == old) {
+ return;
+ }
+ old = cmp;
+ }
+#else
+ cpu_loop_exit_atomic(env_cpu(env), ra);
+#endif
+}
+
+static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ulong val,
bool parallel, uintptr_t ra)
{
switch (addr & 3) {
@@ -94,7 +123,7 @@ static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val,
case 1:
/* The 3 byte store must appear atomic. */
if (parallel) {
- atomic_store_3(env, addr, val, ra);
+ atomic_store_mask32(env, addr, val, 0x00ffffffu, ra);
} else {
cpu_stb_data_ra(env, addr, val >> 16, ra);
cpu_stw_data_ra(env, addr + 1, val, ra);
@@ -106,25 +135,153 @@ static void do_stby_b(CPUHPPAState *env, target_ulong addr, target_ureg val,
}
}
-void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ureg val)
+static void do_stdby_b(CPUHPPAState *env, target_ulong addr, uint64_t val,
+ bool parallel, uintptr_t ra)
+{
+ switch (addr & 7) {
+ case 7:
+ cpu_stb_data_ra(env, addr, val, ra);
+ break;
+ case 6:
+ cpu_stw_data_ra(env, addr, val, ra);
+ break;
+ case 5:
+ /* The 3 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask32(env, addr, val, 0x00ffffffu, ra);
+ } else {
+ cpu_stb_data_ra(env, addr, val >> 16, ra);
+ cpu_stw_data_ra(env, addr + 1, val, ra);
+ }
+ break;
+ case 4:
+ cpu_stl_data_ra(env, addr, val, ra);
+ break;
+ case 3:
+ /* The 5 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr, val, 0x000000ffffffffffull, 5, ra);
+ } else {
+ cpu_stb_data_ra(env, addr, val >> 32, ra);
+ cpu_stl_data_ra(env, addr + 1, val, ra);
+ }
+ break;
+ case 2:
+ /* The 6 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr, val, 0x0000ffffffffffffull, 6, ra);
+ } else {
+ cpu_stw_data_ra(env, addr, val >> 32, ra);
+ cpu_stl_data_ra(env, addr + 2, val, ra);
+ }
+ break;
+ case 1:
+ /* The 7 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr, val, 0x00ffffffffffffffull, 7, ra);
+ } else {
+ cpu_stb_data_ra(env, addr, val >> 48, ra);
+ cpu_stw_data_ra(env, addr + 1, val >> 32, ra);
+ cpu_stl_data_ra(env, addr + 3, val, ra);
+ }
+ break;
+ default:
+ cpu_stq_data_ra(env, addr, val, ra);
+ break;
+ }
+}
+
+void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val)
{
do_stby_b(env, addr, val, false, GETPC());
}
void HELPER(stby_b_parallel)(CPUHPPAState *env, target_ulong addr,
- target_ureg val)
+ target_ulong val)
{
do_stby_b(env, addr, val, true, GETPC());
}
-static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val,
+void HELPER(stdby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val)
+{
+ do_stdby_b(env, addr, val, false, GETPC());
+}
+
+void HELPER(stdby_b_parallel)(CPUHPPAState *env, target_ulong addr,
+ target_ulong val)
+{
+ do_stdby_b(env, addr, val, true, GETPC());
+}
+
+static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ulong val,
bool parallel, uintptr_t ra)
{
switch (addr & 3) {
case 3:
/* The 3 byte store must appear atomic. */
if (parallel) {
- atomic_store_3(env, addr - 3, val, ra);
+ atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra);
+ } else {
+ cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
+ cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
+ }
+ break;
+ case 2:
+ cpu_stw_data_ra(env, addr - 2, val >> 16, ra);
+ break;
+ case 1:
+ cpu_stb_data_ra(env, addr - 1, val >> 24, ra);
+ break;
+ default:
+ /* Nothing is stored, but protection is checked and the
+ cacheline is marked dirty. */
+ probe_write(env, addr, 0, cpu_mmu_index(env, 0), ra);
+ break;
+ }
+}
+
+static void do_stdby_e(CPUHPPAState *env, target_ulong addr, uint64_t val,
+ bool parallel, uintptr_t ra)
+{
+ switch (addr & 7) {
+ case 7:
+ /* The 7 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr - 7, val,
+ 0xffffffffffffff00ull, 7, ra);
+ } else {
+ cpu_stl_data_ra(env, addr - 7, val >> 32, ra);
+ cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
+ cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
+ }
+ break;
+ case 6:
+ /* The 6 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr - 6, val,
+ 0xffffffffffff0000ull, 6, ra);
+ } else {
+ cpu_stl_data_ra(env, addr - 6, val >> 32, ra);
+ cpu_stw_data_ra(env, addr - 2, val >> 16, ra);
+ }
+ break;
+ case 5:
+ /* The 5 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask64(env, addr - 5, val,
+ 0xffffffffff000000ull, 5, ra);
+ } else {
+ cpu_stl_data_ra(env, addr - 5, val >> 32, ra);
+ cpu_stb_data_ra(env, addr - 1, val >> 24, ra);
+ }
+ break;
+ case 4:
+ cpu_stl_data_ra(env, addr - 4, val >> 32, ra);
+ break;
+ case 3:
+ /* The 3 byte store must appear atomic. */
+ if (parallel) {
+ atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra);
} else {
cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
@@ -144,17 +301,28 @@ static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val,
}
}
-void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ureg val)
+void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val)
{
do_stby_e(env, addr, val, false, GETPC());
}
void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr,
- target_ureg val)
+ target_ulong val)
{
do_stby_e(env, addr, val, true, GETPC());
}
+void HELPER(stdby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val)
+{
+ do_stdby_e(env, addr, val, false, GETPC());
+}
+
+void HELPER(stdby_e_parallel)(CPUHPPAState *env, target_ulong addr,
+ target_ulong val)
+{
+ do_stdby_e(env, addr, val, true, GETPC());
+}
+
void HELPER(ldc_check)(target_ulong addr)
{
if (unlikely(addr & 0xf)) {
@@ -164,7 +332,7 @@ void HELPER(ldc_check)(target_ulong addr)
}
}
-target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
+target_ulong HELPER(probe)(CPUHPPAState *env, target_ulong addr,
uint32_t level, uint32_t want)
{
#ifdef CONFIG_USER_ONLY
@@ -196,7 +364,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
#endif
}
-target_ureg HELPER(read_interval_timer)(void)
+target_ulong HELPER(read_interval_timer)(void)
{
#ifdef CONFIG_USER_ONLY
/* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist.
@@ -209,3 +377,113 @@ target_ureg HELPER(read_interval_timer)(void)
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2;
#endif
}
+
+uint64_t HELPER(hadd_ss)(uint64_t r1, uint64_t r2)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = sextract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = f1 + f2;
+
+ fr = MIN(fr, INT16_MAX);
+ fr = MAX(fr, INT16_MIN);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
+
+uint64_t HELPER(hadd_us)(uint64_t r1, uint64_t r2)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = extract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = f1 + f2;
+
+ fr = MIN(fr, UINT16_MAX);
+ fr = MAX(fr, 0);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
+
+uint64_t HELPER(havg)(uint64_t r1, uint64_t r2)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = extract64(r1, i, 16);
+ int f2 = extract64(r2, i, 16);
+ int fr = f1 + f2;
+
+ ret = deposit64(ret, i, 16, (fr >> 1) | (fr & 1));
+ }
+ return ret;
+}
+
+uint64_t HELPER(hsub_ss)(uint64_t r1, uint64_t r2)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = sextract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = f1 - f2;
+
+ fr = MIN(fr, INT16_MAX);
+ fr = MAX(fr, INT16_MIN);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
+
+uint64_t HELPER(hsub_us)(uint64_t r1, uint64_t r2)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = extract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = f1 - f2;
+
+ fr = MIN(fr, UINT16_MAX);
+ fr = MAX(fr, 0);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
+
+uint64_t HELPER(hshladd)(uint64_t r1, uint64_t r2, uint32_t sh)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = sextract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = (f1 << sh) + f2;
+
+ fr = MIN(fr, INT16_MAX);
+ fr = MAX(fr, INT16_MIN);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
+
+uint64_t HELPER(hshradd)(uint64_t r1, uint64_t r2, uint32_t sh)
+{
+ uint64_t ret = 0;
+
+ for (int i = 0; i < 64; i += 16) {
+ int f1 = sextract64(r1, i, 16);
+ int f2 = sextract64(r2, i, 16);
+ int fr = (f1 >> sh) + f2;
+
+ fr = MIN(fr, INT16_MAX);
+ fr = MAX(fr, INT16_MIN);
+ ret = deposit64(ret, i, 16, fr);
+ }
+ return ret;
+}
diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c
index 4bb4cf6..a59245e 100644
--- a/target/hppa/sys_helper.c
+++ b/target/hppa/sys_helper.c
@@ -24,7 +24,7 @@
#include "qemu/timer.h"
#include "sysemu/runstate.h"
-void HELPER(write_interval_timer)(CPUHPPAState *env, target_ureg val)
+void HELPER(write_interval_timer)(CPUHPPAState *env, target_ulong val)
{
HPPACPU *cpu = env_archcpu(env);
uint64_t current = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -58,7 +58,7 @@ void HELPER(reset)(CPUHPPAState *env)
helper_excp(env, EXCP_HLT);
}
-target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
+target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
{
target_ulong psw = env->psw;
/*
@@ -80,6 +80,16 @@ void HELPER(rfi)(CPUHPPAState *env)
env->iasq_b = (uint64_t)env->cr_back[0] << 32;
env->iaoq_f = env->cr[CR_IIAOQ];
env->iaoq_b = env->cr_back[1];
+
+ /*
+ * For pa2.0, IIASQ is the top bits of the virtual address.
+ * To recreate the space identifier, remove the offset bits.
+ */
+ if (hppa_is_pa20(env)) {
+ env->iasq_f &= ~env->iaoq_f;
+ env->iasq_b &= ~env->iaoq_b;
+ }
+
cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
}
diff --git a/target/hppa/trace-events b/target/hppa/trace-events
index 8931517..a10ba73 100644
--- a/target/hppa/trace-events
+++ b/target/hppa/trace-events
@@ -10,6 +10,7 @@ disable hppa_tlb_fill_success(void *env, uint64_t addr, uint64_t phys, int size,
disable hppa_tlb_itlba(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx"
disable hppa_tlb_itlbp(void *env, void *ent, int access_id, int u, int pl2, int pl1, int type, int b, int d, int t) "env=%p ent=%p access_id=%x u=%d pl2=%d pl1=%d type=%d b=%d d=%d t=%d"
disable hppa_tlb_ptlb(void *env) "env=%p"
+disable hppa_tlb_ptlb_local(void *env) "env=%p"
disable hppa_tlb_ptlbe(void *env) "env=%p"
disable hppa_tlb_lpa_success(void *env, uint64_t addr, uint64_t phys) "env=%p addr=0x%lx phys=0x%lx"
disable hppa_tlb_lpa_failed(void *env, uint64_t addr) "env=%p addr=0x%lx"
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 9f3ba9f..bcce65d 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -23,6 +23,7 @@
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "exec/translator.h"
@@ -32,240 +33,35 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
-
-/* Since we have a distinction between register size and address size,
- we need to redefine all of these. */
-
-#undef TCGv
+/* Choose to use explicit sizes within this file. */
#undef tcg_temp_new
-#undef tcg_global_mem_new
-
-#if TARGET_LONG_BITS == 64
-#define TCGv_tl TCGv_i64
-#define tcg_temp_new_tl tcg_temp_new_i64
-#if TARGET_REGISTER_BITS == 64
-#define tcg_gen_extu_reg_tl tcg_gen_mov_i64
-#else
-#define tcg_gen_extu_reg_tl tcg_gen_extu_i32_i64
-#endif
-#else
-#define TCGv_tl TCGv_i32
-#define tcg_temp_new_tl tcg_temp_new_i32
-#define tcg_gen_extu_reg_tl tcg_gen_mov_i32
-#endif
-
-#if TARGET_REGISTER_BITS == 64
-#define TCGv_reg TCGv_i64
-
-#define tcg_temp_new tcg_temp_new_i64
-#define tcg_global_mem_new tcg_global_mem_new_i64
-
-#define tcg_gen_movi_reg tcg_gen_movi_i64
-#define tcg_gen_mov_reg tcg_gen_mov_i64
-#define tcg_gen_ld8u_reg tcg_gen_ld8u_i64
-#define tcg_gen_ld8s_reg tcg_gen_ld8s_i64
-#define tcg_gen_ld16u_reg tcg_gen_ld16u_i64
-#define tcg_gen_ld16s_reg tcg_gen_ld16s_i64
-#define tcg_gen_ld32u_reg tcg_gen_ld32u_i64
-#define tcg_gen_ld32s_reg tcg_gen_ld32s_i64
-#define tcg_gen_ld_reg tcg_gen_ld_i64
-#define tcg_gen_st8_reg tcg_gen_st8_i64
-#define tcg_gen_st16_reg tcg_gen_st16_i64
-#define tcg_gen_st32_reg tcg_gen_st32_i64
-#define tcg_gen_st_reg tcg_gen_st_i64
-#define tcg_gen_add_reg tcg_gen_add_i64
-#define tcg_gen_addi_reg tcg_gen_addi_i64
-#define tcg_gen_sub_reg tcg_gen_sub_i64
-#define tcg_gen_neg_reg tcg_gen_neg_i64
-#define tcg_gen_subfi_reg tcg_gen_subfi_i64
-#define tcg_gen_subi_reg tcg_gen_subi_i64
-#define tcg_gen_and_reg tcg_gen_and_i64
-#define tcg_gen_andi_reg tcg_gen_andi_i64
-#define tcg_gen_or_reg tcg_gen_or_i64
-#define tcg_gen_ori_reg tcg_gen_ori_i64
-#define tcg_gen_xor_reg tcg_gen_xor_i64
-#define tcg_gen_xori_reg tcg_gen_xori_i64
-#define tcg_gen_not_reg tcg_gen_not_i64
-#define tcg_gen_shl_reg tcg_gen_shl_i64
-#define tcg_gen_shli_reg tcg_gen_shli_i64
-#define tcg_gen_shr_reg tcg_gen_shr_i64
-#define tcg_gen_shri_reg tcg_gen_shri_i64
-#define tcg_gen_sar_reg tcg_gen_sar_i64
-#define tcg_gen_sari_reg tcg_gen_sari_i64
-#define tcg_gen_brcond_reg tcg_gen_brcond_i64
-#define tcg_gen_brcondi_reg tcg_gen_brcondi_i64
-#define tcg_gen_setcond_reg tcg_gen_setcond_i64
-#define tcg_gen_setcondi_reg tcg_gen_setcondi_i64
-#define tcg_gen_mul_reg tcg_gen_mul_i64
-#define tcg_gen_muli_reg tcg_gen_muli_i64
-#define tcg_gen_div_reg tcg_gen_div_i64
-#define tcg_gen_rem_reg tcg_gen_rem_i64
-#define tcg_gen_divu_reg tcg_gen_divu_i64
-#define tcg_gen_remu_reg tcg_gen_remu_i64
-#define tcg_gen_discard_reg tcg_gen_discard_i64
-#define tcg_gen_trunc_reg_i32 tcg_gen_extrl_i64_i32
-#define tcg_gen_trunc_i64_reg tcg_gen_mov_i64
-#define tcg_gen_extu_i32_reg tcg_gen_extu_i32_i64
-#define tcg_gen_ext_i32_reg tcg_gen_ext_i32_i64
-#define tcg_gen_extu_reg_i64 tcg_gen_mov_i64
-#define tcg_gen_ext_reg_i64 tcg_gen_mov_i64
-#define tcg_gen_ext8u_reg tcg_gen_ext8u_i64
-#define tcg_gen_ext8s_reg tcg_gen_ext8s_i64
-#define tcg_gen_ext16u_reg tcg_gen_ext16u_i64
-#define tcg_gen_ext16s_reg tcg_gen_ext16s_i64
-#define tcg_gen_ext32u_reg tcg_gen_ext32u_i64
-#define tcg_gen_ext32s_reg tcg_gen_ext32s_i64
-#define tcg_gen_bswap16_reg tcg_gen_bswap16_i64
-#define tcg_gen_bswap32_reg tcg_gen_bswap32_i64
-#define tcg_gen_bswap64_reg tcg_gen_bswap64_i64
-#define tcg_gen_concat_reg_i64 tcg_gen_concat32_i64
-#define tcg_gen_andc_reg tcg_gen_andc_i64
-#define tcg_gen_eqv_reg tcg_gen_eqv_i64
-#define tcg_gen_nand_reg tcg_gen_nand_i64
-#define tcg_gen_nor_reg tcg_gen_nor_i64
-#define tcg_gen_orc_reg tcg_gen_orc_i64
-#define tcg_gen_clz_reg tcg_gen_clz_i64
-#define tcg_gen_ctz_reg tcg_gen_ctz_i64
-#define tcg_gen_clzi_reg tcg_gen_clzi_i64
-#define tcg_gen_ctzi_reg tcg_gen_ctzi_i64
-#define tcg_gen_clrsb_reg tcg_gen_clrsb_i64
-#define tcg_gen_ctpop_reg tcg_gen_ctpop_i64
-#define tcg_gen_rotl_reg tcg_gen_rotl_i64
-#define tcg_gen_rotli_reg tcg_gen_rotli_i64
-#define tcg_gen_rotr_reg tcg_gen_rotr_i64
-#define tcg_gen_rotri_reg tcg_gen_rotri_i64
-#define tcg_gen_deposit_reg tcg_gen_deposit_i64
-#define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i64
-#define tcg_gen_extract_reg tcg_gen_extract_i64
-#define tcg_gen_sextract_reg tcg_gen_sextract_i64
-#define tcg_gen_extract2_reg tcg_gen_extract2_i64
-#define tcg_constant_reg tcg_constant_i64
-#define tcg_gen_movcond_reg tcg_gen_movcond_i64
-#define tcg_gen_add2_reg tcg_gen_add2_i64
-#define tcg_gen_sub2_reg tcg_gen_sub2_i64
-#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i64
-#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i64
-#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i64
-#define tcg_gen_trunc_reg_ptr tcg_gen_trunc_i64_ptr
-#else
-#define TCGv_reg TCGv_i32
-#define tcg_temp_new tcg_temp_new_i32
-#define tcg_global_mem_new tcg_global_mem_new_i32
-
-#define tcg_gen_movi_reg tcg_gen_movi_i32
-#define tcg_gen_mov_reg tcg_gen_mov_i32
-#define tcg_gen_ld8u_reg tcg_gen_ld8u_i32
-#define tcg_gen_ld8s_reg tcg_gen_ld8s_i32
-#define tcg_gen_ld16u_reg tcg_gen_ld16u_i32
-#define tcg_gen_ld16s_reg tcg_gen_ld16s_i32
-#define tcg_gen_ld32u_reg tcg_gen_ld_i32
-#define tcg_gen_ld32s_reg tcg_gen_ld_i32
-#define tcg_gen_ld_reg tcg_gen_ld_i32
-#define tcg_gen_st8_reg tcg_gen_st8_i32
-#define tcg_gen_st16_reg tcg_gen_st16_i32
-#define tcg_gen_st32_reg tcg_gen_st32_i32
-#define tcg_gen_st_reg tcg_gen_st_i32
-#define tcg_gen_add_reg tcg_gen_add_i32
-#define tcg_gen_addi_reg tcg_gen_addi_i32
-#define tcg_gen_sub_reg tcg_gen_sub_i32
-#define tcg_gen_neg_reg tcg_gen_neg_i32
-#define tcg_gen_subfi_reg tcg_gen_subfi_i32
-#define tcg_gen_subi_reg tcg_gen_subi_i32
-#define tcg_gen_and_reg tcg_gen_and_i32
-#define tcg_gen_andi_reg tcg_gen_andi_i32
-#define tcg_gen_or_reg tcg_gen_or_i32
-#define tcg_gen_ori_reg tcg_gen_ori_i32
-#define tcg_gen_xor_reg tcg_gen_xor_i32
-#define tcg_gen_xori_reg tcg_gen_xori_i32
-#define tcg_gen_not_reg tcg_gen_not_i32
-#define tcg_gen_shl_reg tcg_gen_shl_i32
-#define tcg_gen_shli_reg tcg_gen_shli_i32
-#define tcg_gen_shr_reg tcg_gen_shr_i32
-#define tcg_gen_shri_reg tcg_gen_shri_i32
-#define tcg_gen_sar_reg tcg_gen_sar_i32
-#define tcg_gen_sari_reg tcg_gen_sari_i32
-#define tcg_gen_brcond_reg tcg_gen_brcond_i32
-#define tcg_gen_brcondi_reg tcg_gen_brcondi_i32
-#define tcg_gen_setcond_reg tcg_gen_setcond_i32
-#define tcg_gen_setcondi_reg tcg_gen_setcondi_i32
-#define tcg_gen_mul_reg tcg_gen_mul_i32
-#define tcg_gen_muli_reg tcg_gen_muli_i32
-#define tcg_gen_div_reg tcg_gen_div_i32
-#define tcg_gen_rem_reg tcg_gen_rem_i32
-#define tcg_gen_divu_reg tcg_gen_divu_i32
-#define tcg_gen_remu_reg tcg_gen_remu_i32
-#define tcg_gen_discard_reg tcg_gen_discard_i32
-#define tcg_gen_trunc_reg_i32 tcg_gen_mov_i32
-#define tcg_gen_trunc_i64_reg tcg_gen_extrl_i64_i32
-#define tcg_gen_extu_i32_reg tcg_gen_mov_i32
-#define tcg_gen_ext_i32_reg tcg_gen_mov_i32
-#define tcg_gen_extu_reg_i64 tcg_gen_extu_i32_i64
-#define tcg_gen_ext_reg_i64 tcg_gen_ext_i32_i64
-#define tcg_gen_ext8u_reg tcg_gen_ext8u_i32
-#define tcg_gen_ext8s_reg tcg_gen_ext8s_i32
-#define tcg_gen_ext16u_reg tcg_gen_ext16u_i32
-#define tcg_gen_ext16s_reg tcg_gen_ext16s_i32
-#define tcg_gen_ext32u_reg tcg_gen_mov_i32
-#define tcg_gen_ext32s_reg tcg_gen_mov_i32
-#define tcg_gen_bswap16_reg tcg_gen_bswap16_i32
-#define tcg_gen_bswap32_reg tcg_gen_bswap32_i32
-#define tcg_gen_concat_reg_i64 tcg_gen_concat_i32_i64
-#define tcg_gen_andc_reg tcg_gen_andc_i32
-#define tcg_gen_eqv_reg tcg_gen_eqv_i32
-#define tcg_gen_nand_reg tcg_gen_nand_i32
-#define tcg_gen_nor_reg tcg_gen_nor_i32
-#define tcg_gen_orc_reg tcg_gen_orc_i32
-#define tcg_gen_clz_reg tcg_gen_clz_i32
-#define tcg_gen_ctz_reg tcg_gen_ctz_i32
-#define tcg_gen_clzi_reg tcg_gen_clzi_i32
-#define tcg_gen_ctzi_reg tcg_gen_ctzi_i32
-#define tcg_gen_clrsb_reg tcg_gen_clrsb_i32
-#define tcg_gen_ctpop_reg tcg_gen_ctpop_i32
-#define tcg_gen_rotl_reg tcg_gen_rotl_i32
-#define tcg_gen_rotli_reg tcg_gen_rotli_i32
-#define tcg_gen_rotr_reg tcg_gen_rotr_i32
-#define tcg_gen_rotri_reg tcg_gen_rotri_i32
-#define tcg_gen_deposit_reg tcg_gen_deposit_i32
-#define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i32
-#define tcg_gen_extract_reg tcg_gen_extract_i32
-#define tcg_gen_sextract_reg tcg_gen_sextract_i32
-#define tcg_gen_extract2_reg tcg_gen_extract2_i32
-#define tcg_constant_reg tcg_constant_i32
-#define tcg_gen_movcond_reg tcg_gen_movcond_i32
-#define tcg_gen_add2_reg tcg_gen_add2_i32
-#define tcg_gen_sub2_reg tcg_gen_sub2_i32
-#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i32
-#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i32
-#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i32
-#define tcg_gen_trunc_reg_ptr tcg_gen_ext_i32_ptr
-#endif /* TARGET_REGISTER_BITS */
typedef struct DisasCond {
TCGCond c;
- TCGv_reg a0, a1;
+ TCGv_i64 a0, a1;
} DisasCond;
typedef struct DisasContext {
DisasContextBase base;
CPUState *cs;
+ TCGOp *insn_start;
- target_ureg iaoq_f;
- target_ureg iaoq_b;
- target_ureg iaoq_n;
- TCGv_reg iaoq_n_var;
-
- int ntempr, ntempl;
- TCGv_reg tempr[8];
- TCGv_tl templ[4];
+ uint64_t iaoq_f;
+ uint64_t iaoq_b;
+ uint64_t iaoq_n;
+ TCGv_i64 iaoq_n_var;
DisasCond null_cond;
TCGLabel *null_lab;
+ TCGv_i64 zero;
+
uint32_t insn;
uint32_t tb_flags;
int mmu_idx;
int privilege;
bool psw_n_nonzero;
+ bool is_pa20;
#ifdef CONFIG_USER_ONLY
MemOp unalign;
@@ -332,6 +128,23 @@ static int expand_shl11(DisasContext *ctx, int val)
return val << 11;
}
+static int assemble_6(DisasContext *ctx, int val)
+{
+ /*
+ * Officially, 32 * x + 32 - y.
+ * Here, x is already in bit 5, and y is [4:0].
+ * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
+ * with the overflow from bit 4 summing with x.
+ */
+ return (val ^ 31) + 1;
+}
+
+/* Translate CMPI doubleword conditions to standard. */
+static int cmpbid_c(DisasContext *ctx, int val)
+{
+ return val ? val : 4; /* 0 == "*<<" */
+}
+
/* Include the auto-generated decoder. */
#include "decode-insns.c.inc"
@@ -350,24 +163,24 @@ static int expand_shl11(DisasContext *ctx, int val)
#define DISAS_EXIT DISAS_TARGET_3
/* global register indexes */
-static TCGv_reg cpu_gr[32];
+static TCGv_i64 cpu_gr[32];
static TCGv_i64 cpu_sr[4];
static TCGv_i64 cpu_srH;
-static TCGv_reg cpu_iaoq_f;
-static TCGv_reg cpu_iaoq_b;
+static TCGv_i64 cpu_iaoq_f;
+static TCGv_i64 cpu_iaoq_b;
static TCGv_i64 cpu_iasq_f;
static TCGv_i64 cpu_iasq_b;
-static TCGv_reg cpu_sar;
-static TCGv_reg cpu_psw_n;
-static TCGv_reg cpu_psw_v;
-static TCGv_reg cpu_psw_cb;
-static TCGv_reg cpu_psw_cb_msb;
+static TCGv_i64 cpu_sar;
+static TCGv_i64 cpu_psw_n;
+static TCGv_i64 cpu_psw_v;
+static TCGv_i64 cpu_psw_cb;
+static TCGv_i64 cpu_psw_cb_msb;
void hppa_translate_init(void)
{
#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
- typedef struct { TCGv_reg *var; const char *name; int ofs; } GlobalVar;
+ typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
static const GlobalVar vars[] = {
{ &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
DEF_VAR(psw_n),
@@ -422,6 +235,13 @@ void hppa_translate_init(void)
"iasq_b");
}
+static void set_insn_breg(DisasContext *ctx, int breg)
+{
+ assert(ctx->insn_start != NULL);
+ tcg_set_insn_start_param(ctx->insn_start, 2, breg);
+ ctx->insn_start = NULL;
+}
+
static DisasCond cond_make_f(void)
{
return (DisasCond){
@@ -445,36 +265,36 @@ static DisasCond cond_make_n(void)
return (DisasCond){
.c = TCG_COND_NE,
.a0 = cpu_psw_n,
- .a1 = tcg_constant_reg(0)
+ .a1 = tcg_constant_i64(0)
};
}
-static DisasCond cond_make_0_tmp(TCGCond c, TCGv_reg a0)
+static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
{
assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
- return (DisasCond){
- .c = c, .a0 = a0, .a1 = tcg_constant_reg(0)
- };
+ return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
}
-static DisasCond cond_make_0(TCGCond c, TCGv_reg a0)
+static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
{
- TCGv_reg tmp = tcg_temp_new();
- tcg_gen_mov_reg(tmp, a0);
- return cond_make_0_tmp(c, tmp);
+ return cond_make_tmp(c, a0, tcg_constant_i64(0));
}
-static DisasCond cond_make(TCGCond c, TCGv_reg a0, TCGv_reg a1)
+static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
{
- DisasCond r = { .c = c };
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_mov_i64(tmp, a0);
+ return cond_make_0_tmp(c, tmp);
+}
- assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
- r.a0 = tcg_temp_new();
- tcg_gen_mov_reg(r.a0, a0);
- r.a1 = tcg_temp_new();
- tcg_gen_mov_reg(r.a1, a1);
+static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
+{
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
- return r;
+ tcg_gen_mov_i64(t0, a0);
+ tcg_gen_mov_i64(t1, a1);
+ return cond_make_tmp(c, t0, t1);
}
static void cond_free(DisasCond *cond)
@@ -492,60 +312,35 @@ static void cond_free(DisasCond *cond)
}
}
-static TCGv_reg get_temp(DisasContext *ctx)
-{
- unsigned i = ctx->ntempr++;
- g_assert(i < ARRAY_SIZE(ctx->tempr));
- return ctx->tempr[i] = tcg_temp_new();
-}
-
-#ifndef CONFIG_USER_ONLY
-static TCGv_tl get_temp_tl(DisasContext *ctx)
-{
- unsigned i = ctx->ntempl++;
- g_assert(i < ARRAY_SIZE(ctx->templ));
- return ctx->templ[i] = tcg_temp_new_tl();
-}
-#endif
-
-static TCGv_reg load_const(DisasContext *ctx, target_sreg v)
-{
- TCGv_reg t = get_temp(ctx);
- tcg_gen_movi_reg(t, v);
- return t;
-}
-
-static TCGv_reg load_gpr(DisasContext *ctx, unsigned reg)
+static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
{
if (reg == 0) {
- TCGv_reg t = get_temp(ctx);
- tcg_gen_movi_reg(t, 0);
- return t;
+ return ctx->zero;
} else {
return cpu_gr[reg];
}
}
-static TCGv_reg dest_gpr(DisasContext *ctx, unsigned reg)
+static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
{
if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
- return get_temp(ctx);
+ return tcg_temp_new_i64();
} else {
return cpu_gr[reg];
}
}
-static void save_or_nullify(DisasContext *ctx, TCGv_reg dest, TCGv_reg t)
+static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
{
if (ctx->null_cond.c != TCG_COND_NEVER) {
- tcg_gen_movcond_reg(ctx->null_cond.c, dest, ctx->null_cond.a0,
+ tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
ctx->null_cond.a1, dest, t);
} else {
- tcg_gen_mov_reg(dest, t);
+ tcg_gen_mov_i64(dest, t);
}
}
-static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t)
+static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
{
if (reg != 0) {
save_or_nullify(ctx, cpu_gr[reg], t);
@@ -653,18 +448,18 @@ static void nullify_over(DisasContext *ctx)
/* If we're using PSW[N], copy it to a temp because... */
if (ctx->null_cond.a0 == cpu_psw_n) {
- ctx->null_cond.a0 = tcg_temp_new();
- tcg_gen_mov_reg(ctx->null_cond.a0, cpu_psw_n);
+ ctx->null_cond.a0 = tcg_temp_new_i64();
+ tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
}
/* ... we clear it before branching over the implementation,
so that (1) it's clear after nullifying this insn and
(2) if this insn nullifies the next, PSW[N] is valid. */
if (ctx->psw_n_nonzero) {
ctx->psw_n_nonzero = false;
- tcg_gen_movi_reg(cpu_psw_n, 0);
+ tcg_gen_movi_i64(cpu_psw_n, 0);
}
- tcg_gen_brcond_reg(ctx->null_cond.c, ctx->null_cond.a0,
+ tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
ctx->null_cond.a1, ctx->null_lab);
cond_free(&ctx->null_cond);
}
@@ -675,12 +470,12 @@ static void nullify_save(DisasContext *ctx)
{
if (ctx->null_cond.c == TCG_COND_NEVER) {
if (ctx->psw_n_nonzero) {
- tcg_gen_movi_reg(cpu_psw_n, 0);
+ tcg_gen_movi_i64(cpu_psw_n, 0);
}
return;
}
if (ctx->null_cond.a0 != cpu_psw_n) {
- tcg_gen_setcond_reg(ctx->null_cond.c, cpu_psw_n,
+ tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
ctx->null_cond.a0, ctx->null_cond.a1);
ctx->psw_n_nonzero = true;
}
@@ -693,7 +488,7 @@ static void nullify_save(DisasContext *ctx)
static void nullify_set(DisasContext *ctx, bool x)
{
if (ctx->psw_n_nonzero || x) {
- tcg_gen_movi_reg(cpu_psw_n, x);
+ tcg_gen_movi_i64(cpu_psw_n, x);
}
}
@@ -736,16 +531,36 @@ static bool nullify_end(DisasContext *ctx)
return true;
}
-static void copy_iaoq_entry(TCGv_reg dest, target_ureg ival, TCGv_reg vval)
+static uint64_t gva_offset_mask(DisasContext *ctx)
+{
+ return (ctx->tb_flags & PSW_W
+ ? MAKE_64BIT_MASK(0, 62)
+ : MAKE_64BIT_MASK(0, 32));
+}
+
+static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
+ uint64_t ival, TCGv_i64 vval)
{
- if (unlikely(ival == -1)) {
- tcg_gen_mov_reg(dest, vval);
+ uint64_t mask = gva_offset_mask(ctx);
+
+ if (ival != -1) {
+ tcg_gen_movi_i64(dest, ival & mask);
+ return;
+ }
+ tcg_debug_assert(vval != NULL);
+
+ /*
+ * We know that the IAOQ is already properly masked.
+ * This optimization is primarily for "iaoq_f = iaoq_b".
+ */
+ if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
+ tcg_gen_mov_i64(dest, vval);
} else {
- tcg_gen_movi_reg(dest, ival);
+ tcg_gen_andi_i64(dest, vval, mask);
}
}
-static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp)
+static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
{
return ctx->iaoq_f + disp + 8;
}
@@ -757,8 +572,8 @@ static void gen_excp_1(int exception)
static void gen_excp(DisasContext *ctx, int exception)
{
- copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
- copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
nullify_save(ctx);
gen_excp_1(exception);
ctx->base.is_jmp = DISAS_NORETURN;
@@ -767,7 +582,7 @@ static void gen_excp(DisasContext *ctx, int exception)
static bool gen_excp_iir(DisasContext *ctx, int exc)
{
nullify_over(ctx);
- tcg_gen_st_reg(tcg_constant_reg(ctx->insn),
+ tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
gen_excp(ctx, exc);
return nullify_end(ctx);
@@ -790,7 +605,7 @@ static bool gen_illegal(DisasContext *ctx)
} while (0)
#endif
-static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
+static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
{
return translator_use_goto_tb(&ctx->base, dest);
}
@@ -806,16 +621,16 @@ static bool use_nullify_skip(DisasContext *ctx)
}
static void gen_goto_tb(DisasContext *ctx, int which,
- target_ureg f, target_ureg b)
+ uint64_t f, uint64_t b)
{
if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
tcg_gen_goto_tb(which);
- tcg_gen_movi_reg(cpu_iaoq_f, f);
- tcg_gen_movi_reg(cpu_iaoq_b, b);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
tcg_gen_exit_tb(ctx->base.tb, which);
} else {
- copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
- copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
tcg_gen_lookup_and_goto_ptr();
}
}
@@ -830,27 +645,41 @@ static bool cond_need_cb(int c)
return c == 4 || c == 5;
}
+/* Need extensions from TCGv_i32 to TCGv_i64. */
+static bool cond_need_ext(DisasContext *ctx, bool d)
+{
+ return !(ctx->is_pa20 && d);
+}
+
/*
* Compute conditional for arithmetic. See Page 5-3, Table 5-1, of
* the Parisc 1.1 Architecture Reference Manual for details.
*/
-static DisasCond do_cond(unsigned cf, TCGv_reg res,
- TCGv_reg cb_msb, TCGv_reg sv)
+static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
+ TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
{
DisasCond cond;
- TCGv_reg tmp;
+ TCGv_i64 tmp;
switch (cf >> 1) {
case 0: /* Never / TR (0 / 1) */
cond = cond_make_f();
break;
case 1: /* = / <> (Z / !Z) */
+ if (cond_need_ext(ctx, d)) {
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ext32u_i64(tmp, res);
+ res = tmp;
+ }
cond = cond_make_0(TCG_COND_EQ, res);
break;
case 2: /* < / >= (N ^ V / !(N ^ V) */
- tmp = tcg_temp_new();
- tcg_gen_xor_reg(tmp, res, sv);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_xor_i64(tmp, res, sv);
+ if (cond_need_ext(ctx, d)) {
+ tcg_gen_ext32s_i64(tmp, tmp);
+ }
cond = cond_make_0_tmp(TCG_COND_LT, tmp);
break;
case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */
@@ -863,27 +692,42 @@ static DisasCond do_cond(unsigned cf, TCGv_reg res,
* !(~(res ^ sv) >> 31) | !res
* !(~(res ^ sv) >> 31 & res)
*/
- tmp = tcg_temp_new();
- tcg_gen_eqv_reg(tmp, res, sv);
- tcg_gen_sari_reg(tmp, tmp, TARGET_REGISTER_BITS - 1);
- tcg_gen_and_reg(tmp, tmp, res);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_eqv_i64(tmp, res, sv);
+ if (cond_need_ext(ctx, d)) {
+ tcg_gen_sextract_i64(tmp, tmp, 31, 1);
+ tcg_gen_and_i64(tmp, tmp, res);
+ tcg_gen_ext32u_i64(tmp, tmp);
+ } else {
+ tcg_gen_sari_i64(tmp, tmp, 63);
+ tcg_gen_and_i64(tmp, tmp, res);
+ }
cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
break;
case 4: /* NUV / UV (!C / C) */
+ /* Only bit 0 of cb_msb is ever set. */
cond = cond_make_0(TCG_COND_EQ, cb_msb);
break;
case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
- tmp = tcg_temp_new();
- tcg_gen_neg_reg(tmp, cb_msb);
- tcg_gen_and_reg(tmp, tmp, res);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_neg_i64(tmp, cb_msb);
+ tcg_gen_and_i64(tmp, tmp, res);
+ if (cond_need_ext(ctx, d)) {
+ tcg_gen_ext32u_i64(tmp, tmp);
+ }
cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
break;
case 6: /* SV / NSV (V / !V) */
+ if (cond_need_ext(ctx, d)) {
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ext32s_i64(tmp, sv);
+ sv = tmp;
+ }
cond = cond_make_0(TCG_COND_LT, sv);
break;
case 7: /* OD / EV */
- tmp = tcg_temp_new();
- tcg_gen_andi_reg(tmp, res, 1);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_andi_i64(tmp, res, 1);
cond = cond_make_0_tmp(TCG_COND_NE, tmp);
break;
default:
@@ -900,35 +744,55 @@ static DisasCond do_cond(unsigned cf, TCGv_reg res,
can use the inputs directly. This can allow other computation to be
deleted as unused. */
-static DisasCond do_sub_cond(unsigned cf, TCGv_reg res,
- TCGv_reg in1, TCGv_reg in2, TCGv_reg sv)
+static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
+ TCGv_i64 res, TCGv_i64 in1,
+ TCGv_i64 in2, TCGv_i64 sv)
{
- DisasCond cond;
+ TCGCond tc;
+ bool ext_uns;
switch (cf >> 1) {
case 1: /* = / <> */
- cond = cond_make(TCG_COND_EQ, in1, in2);
+ tc = TCG_COND_EQ;
+ ext_uns = true;
break;
case 2: /* < / >= */
- cond = cond_make(TCG_COND_LT, in1, in2);
+ tc = TCG_COND_LT;
+ ext_uns = false;
break;
case 3: /* <= / > */
- cond = cond_make(TCG_COND_LE, in1, in2);
+ tc = TCG_COND_LE;
+ ext_uns = false;
break;
case 4: /* << / >>= */
- cond = cond_make(TCG_COND_LTU, in1, in2);
+ tc = TCG_COND_LTU;
+ ext_uns = true;
break;
case 5: /* <<= / >> */
- cond = cond_make(TCG_COND_LEU, in1, in2);
+ tc = TCG_COND_LEU;
+ ext_uns = true;
break;
default:
- return do_cond(cf, res, NULL, sv);
+ return do_cond(ctx, cf, d, res, NULL, sv);
}
+
if (cf & 1) {
- cond.c = tcg_invert_cond(cond.c);
+ tc = tcg_invert_cond(tc);
}
+ if (cond_need_ext(ctx, d)) {
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
- return cond;
+ if (ext_uns) {
+ tcg_gen_ext32u_i64(t1, in1);
+ tcg_gen_ext32u_i64(t2, in2);
+ } else {
+ tcg_gen_ext32s_i64(t1, in1);
+ tcg_gen_ext32s_i64(t2, in2);
+ }
+ return cond_make_tmp(tc, t1, t2);
+ }
+ return cond_make(tc, in1, in2);
}
/*
@@ -940,8 +804,12 @@ static DisasCond do_sub_cond(unsigned cf, TCGv_reg res,
* how cases c={2,3} are treated.
*/
-static DisasCond do_log_cond(unsigned cf, TCGv_reg res)
+static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
+ TCGv_i64 res)
{
+ TCGCond tc;
+ bool ext_uns;
+
switch (cf) {
case 0: /* never */
case 9: /* undef, C */
@@ -956,30 +824,55 @@ static DisasCond do_log_cond(unsigned cf, TCGv_reg res)
return cond_make_t();
case 2: /* == */
- return cond_make_0(TCG_COND_EQ, res);
+ tc = TCG_COND_EQ;
+ ext_uns = true;
+ break;
case 3: /* <> */
- return cond_make_0(TCG_COND_NE, res);
+ tc = TCG_COND_NE;
+ ext_uns = true;
+ break;
case 4: /* < */
- return cond_make_0(TCG_COND_LT, res);
+ tc = TCG_COND_LT;
+ ext_uns = false;
+ break;
case 5: /* >= */
- return cond_make_0(TCG_COND_GE, res);
+ tc = TCG_COND_GE;
+ ext_uns = false;
+ break;
case 6: /* <= */
- return cond_make_0(TCG_COND_LE, res);
+ tc = TCG_COND_LE;
+ ext_uns = false;
+ break;
case 7: /* > */
- return cond_make_0(TCG_COND_GT, res);
+ tc = TCG_COND_GT;
+ ext_uns = false;
+ break;
case 14: /* OD */
case 15: /* EV */
- return do_cond(cf, res, NULL, NULL);
+ return do_cond(ctx, cf, d, res, NULL, NULL);
default:
g_assert_not_reached();
}
+
+ if (cond_need_ext(ctx, d)) {
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ if (ext_uns) {
+ tcg_gen_ext32u_i64(tmp, res);
+ } else {
+ tcg_gen_ext32s_i64(tmp, res);
+ }
+ return cond_make_0_tmp(tc, tmp);
+ }
+ return cond_make_0(tc, res);
}
/* Similar, but for shift/extract/deposit conditions. */
-static DisasCond do_sed_cond(unsigned orig, TCGv_reg res)
+static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
+ TCGv_i64 res)
{
unsigned c, f;
@@ -992,28 +885,29 @@ static DisasCond do_sed_cond(unsigned orig, TCGv_reg res)
}
f = (orig & 4) / 4;
- return do_log_cond(c * 2 + f, res);
+ return do_log_cond(ctx, c * 2 + f, d, res);
}
/* Similar, but for unit conditions. */
-static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
- TCGv_reg in1, TCGv_reg in2)
+static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
+ TCGv_i64 in1, TCGv_i64 in2)
{
DisasCond cond;
- TCGv_reg tmp, cb = NULL;
+ TCGv_i64 tmp, cb = NULL;
+ uint64_t d_repl = d ? 0x0000000100000001ull : 1;
if (cf & 8) {
/* Since we want to test lots of carry-out bits all at once, do not
* do our normal thing and compute carry-in of bit B+1 since that
* leaves us with carry bits spread across two words.
*/
- cb = tcg_temp_new();
- tmp = tcg_temp_new();
- tcg_gen_or_reg(cb, in1, in2);
- tcg_gen_and_reg(tmp, in1, in2);
- tcg_gen_andc_reg(cb, cb, res);
- tcg_gen_or_reg(cb, cb, tmp);
+ cb = tcg_temp_new_i64();
+ tmp = tcg_temp_new_i64();
+ tcg_gen_or_i64(cb, in1, in2);
+ tcg_gen_and_i64(tmp, in1, in2);
+ tcg_gen_andc_i64(cb, cb, res);
+ tcg_gen_or_i64(cb, cb, tmp);
}
switch (cf >> 1) {
@@ -1027,33 +921,33 @@ static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
/* See hasless(v,1) from
* https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
*/
- tmp = tcg_temp_new();
- tcg_gen_subi_reg(tmp, res, 0x01010101u);
- tcg_gen_andc_reg(tmp, tmp, res);
- tcg_gen_andi_reg(tmp, tmp, 0x80808080u);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
+ tcg_gen_andc_i64(tmp, tmp, res);
+ tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
cond = cond_make_0(TCG_COND_NE, tmp);
break;
case 3: /* SHZ / NHZ */
- tmp = tcg_temp_new();
- tcg_gen_subi_reg(tmp, res, 0x00010001u);
- tcg_gen_andc_reg(tmp, tmp, res);
- tcg_gen_andi_reg(tmp, tmp, 0x80008000u);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
+ tcg_gen_andc_i64(tmp, tmp, res);
+ tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
cond = cond_make_0(TCG_COND_NE, tmp);
break;
case 4: /* SDC / NDC */
- tcg_gen_andi_reg(cb, cb, 0x88888888u);
+ tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
cond = cond_make_0(TCG_COND_NE, cb);
break;
case 6: /* SBC / NBC */
- tcg_gen_andi_reg(cb, cb, 0x80808080u);
+ tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
cond = cond_make_0(TCG_COND_NE, cb);
break;
case 7: /* SHC / NHC */
- tcg_gen_andi_reg(cb, cb, 0x80008000u);
+ tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
cond = cond_make_0(TCG_COND_NE, cb);
break;
@@ -1067,68 +961,87 @@ static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
return cond;
}
+static TCGv_i64 get_carry(DisasContext *ctx, bool d,
+ TCGv_i64 cb, TCGv_i64 cb_msb)
+{
+ if (cond_need_ext(ctx, d)) {
+ TCGv_i64 t = tcg_temp_new_i64();
+ tcg_gen_extract_i64(t, cb, 32, 1);
+ return t;
+ }
+ return cb_msb;
+}
+
+static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
+{
+ return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
+}
+
/* Compute signed overflow for addition. */
-static TCGv_reg do_add_sv(DisasContext *ctx, TCGv_reg res,
- TCGv_reg in1, TCGv_reg in2)
+static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
+ TCGv_i64 in1, TCGv_i64 in2)
{
- TCGv_reg sv = get_temp(ctx);
- TCGv_reg tmp = tcg_temp_new();
+ TCGv_i64 sv = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
- tcg_gen_xor_reg(sv, res, in1);
- tcg_gen_xor_reg(tmp, in1, in2);
- tcg_gen_andc_reg(sv, sv, tmp);
+ tcg_gen_xor_i64(sv, res, in1);
+ tcg_gen_xor_i64(tmp, in1, in2);
+ tcg_gen_andc_i64(sv, sv, tmp);
return sv;
}
/* Compute signed overflow for subtraction. */
-static TCGv_reg do_sub_sv(DisasContext *ctx, TCGv_reg res,
- TCGv_reg in1, TCGv_reg in2)
+static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
+ TCGv_i64 in1, TCGv_i64 in2)
{
- TCGv_reg sv = get_temp(ctx);
- TCGv_reg tmp = tcg_temp_new();
+ TCGv_i64 sv = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
- tcg_gen_xor_reg(sv, res, in1);
- tcg_gen_xor_reg(tmp, in1, in2);
- tcg_gen_and_reg(sv, sv, tmp);
+ tcg_gen_xor_i64(sv, res, in1);
+ tcg_gen_xor_i64(tmp, in1, in2);
+ tcg_gen_and_i64(sv, sv, tmp);
return sv;
}
-static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1,
- TCGv_reg in2, unsigned shift, bool is_l,
- bool is_tsv, bool is_tc, bool is_c, unsigned cf)
+static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
+ TCGv_i64 in2, unsigned shift, bool is_l,
+ bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
{
- TCGv_reg dest, cb, cb_msb, sv, tmp;
+ TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
unsigned c = cf >> 1;
DisasCond cond;
- dest = tcg_temp_new();
+ dest = tcg_temp_new_i64();
cb = NULL;
cb_msb = NULL;
+ cb_cond = NULL;
if (shift) {
- tmp = get_temp(ctx);
- tcg_gen_shli_reg(tmp, in1, shift);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_shli_i64(tmp, in1, shift);
in1 = tmp;
}
if (!is_l || cond_need_cb(c)) {
- TCGv_reg zero = tcg_constant_reg(0);
- cb_msb = get_temp(ctx);
- tcg_gen_add2_reg(dest, cb_msb, in1, zero, in2, zero);
+ cb_msb = tcg_temp_new_i64();
+ cb = tcg_temp_new_i64();
+
+ tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
if (is_c) {
- tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
+ tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
+ get_psw_carry(ctx, d), ctx->zero);
}
- if (!is_l) {
- cb = get_temp(ctx);
- tcg_gen_xor_reg(cb, in1, in2);
- tcg_gen_xor_reg(cb, cb, dest);
+ tcg_gen_xor_i64(cb, in1, in2);
+ tcg_gen_xor_i64(cb, cb, dest);
+ if (cond_need_cb(c)) {
+ cb_cond = get_carry(ctx, d, cb, cb_msb);
}
} else {
- tcg_gen_add_reg(dest, in1, in2);
+ tcg_gen_add_i64(dest, in1, in2);
if (is_c) {
- tcg_gen_add_reg(dest, dest, cpu_psw_cb_msb);
+ tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
}
}
@@ -1143,10 +1056,10 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1,
}
/* Emit any conditional trap before any writeback. */
- cond = do_cond(cf, dest, cb_msb, sv);
+ cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
if (is_tc) {
- tmp = tcg_temp_new();
- tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
gen_helper_tcond(tcg_env, tmp);
}
@@ -1162,61 +1075,65 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1,
ctx->null_cond = cond;
}
-static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_sh *a,
+static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
bool is_l, bool is_tsv, bool is_tc, bool is_c)
{
- TCGv_reg tcg_r1, tcg_r2;
+ TCGv_i64 tcg_r1, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, is_tsv, is_tc, is_c, a->cf);
+ do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
+ is_tsv, is_tc, is_c, a->cf, a->d);
return nullify_end(ctx);
}
static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
bool is_tsv, bool is_tc)
{
- TCGv_reg tcg_im, tcg_r2;
+ TCGv_i64 tcg_im, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
- tcg_im = load_const(ctx, a->i);
+ tcg_im = tcg_constant_i64(a->i);
tcg_r2 = load_gpr(ctx, a->r);
- do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf);
+ /* All ADDI conditions are 32-bit. */
+ do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
return nullify_end(ctx);
}
-static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1,
- TCGv_reg in2, bool is_tsv, bool is_b,
- bool is_tc, unsigned cf)
+static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
+ TCGv_i64 in2, bool is_tsv, bool is_b,
+ bool is_tc, unsigned cf, bool d)
{
- TCGv_reg dest, sv, cb, cb_msb, zero, tmp;
+ TCGv_i64 dest, sv, cb, cb_msb, tmp;
unsigned c = cf >> 1;
DisasCond cond;
- dest = tcg_temp_new();
- cb = tcg_temp_new();
- cb_msb = tcg_temp_new();
+ dest = tcg_temp_new_i64();
+ cb = tcg_temp_new_i64();
+ cb_msb = tcg_temp_new_i64();
- zero = tcg_constant_reg(0);
if (is_b) {
/* DEST,C = IN1 + ~IN2 + C. */
- tcg_gen_not_reg(cb, in2);
- tcg_gen_add2_reg(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
- tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cb, zero);
- tcg_gen_xor_reg(cb, cb, in1);
- tcg_gen_xor_reg(cb, cb, dest);
+ tcg_gen_not_i64(cb, in2);
+ tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
+ get_psw_carry(ctx, d), ctx->zero);
+ tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
+ tcg_gen_xor_i64(cb, cb, in1);
+ tcg_gen_xor_i64(cb, cb, dest);
} else {
- /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
- operations by seeding the high word with 1 and subtracting. */
- tcg_gen_movi_reg(cb_msb, 1);
- tcg_gen_sub2_reg(dest, cb_msb, in1, cb_msb, in2, zero);
- tcg_gen_eqv_reg(cb, in1, in2);
- tcg_gen_xor_reg(cb, cb, dest);
+ /*
+ * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
+ * operations by seeding the high word with 1 and subtracting.
+ */
+ TCGv_i64 one = tcg_constant_i64(1);
+ tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
+ tcg_gen_eqv_i64(cb, in1, in2);
+ tcg_gen_xor_i64(cb, cb, dest);
}
/* Compute signed overflow if required. */
@@ -1230,15 +1147,15 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1,
/* Compute the condition. We cannot use the special case for borrow. */
if (!is_b) {
- cond = do_sub_cond(cf, dest, in1, in2, sv);
+ cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
} else {
- cond = do_cond(cf, dest, cb_msb, sv);
+ cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
}
/* Emit any conditional trap before any writeback. */
if (is_tc) {
- tmp = tcg_temp_new();
- tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
gen_helper_tcond(tcg_env, tmp);
}
@@ -1252,41 +1169,42 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1,
ctx->null_cond = cond;
}
-static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf *a,
+static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
bool is_tsv, bool is_b, bool is_tc)
{
- TCGv_reg tcg_r1, tcg_r2;
+ TCGv_i64 tcg_r1, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf);
+ do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
return nullify_end(ctx);
}
static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
{
- TCGv_reg tcg_im, tcg_r2;
+ TCGv_i64 tcg_im, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
- tcg_im = load_const(ctx, a->i);
+ tcg_im = tcg_constant_i64(a->i);
tcg_r2 = load_gpr(ctx, a->r);
- do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf);
+ /* All SUBI conditions are 32-bit. */
+ do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
return nullify_end(ctx);
}
-static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1,
- TCGv_reg in2, unsigned cf)
+static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
+ TCGv_i64 in2, unsigned cf, bool d)
{
- TCGv_reg dest, sv;
+ TCGv_i64 dest, sv;
DisasCond cond;
- dest = tcg_temp_new();
- tcg_gen_sub_reg(dest, in1, in2);
+ dest = tcg_temp_new_i64();
+ tcg_gen_sub_i64(dest, in1, in2);
/* Compute signed overflow if required. */
sv = NULL;
@@ -1295,10 +1213,10 @@ static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1,
}
/* Form the condition for the compare. */
- cond = do_sub_cond(cf, dest, in1, in2, sv);
+ cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
/* Clear. */
- tcg_gen_movi_reg(dest, 0);
+ tcg_gen_movi_i64(dest, 0);
save_gpr(ctx, rt, dest);
/* Install the new nullification. */
@@ -1306,11 +1224,11 @@ static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1,
ctx->null_cond = cond;
}
-static void do_log(DisasContext *ctx, unsigned rt, TCGv_reg in1,
- TCGv_reg in2, unsigned cf,
- void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
+static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
+ TCGv_i64 in2, unsigned cf, bool d,
+ void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
{
- TCGv_reg dest = dest_gpr(ctx, rt);
+ TCGv_i64 dest = dest_gpr(ctx, rt);
/* Perform the operation, and writeback. */
fn(dest, in1, in2);
@@ -1319,29 +1237,29 @@ static void do_log(DisasContext *ctx, unsigned rt, TCGv_reg in1,
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (cf) {
- ctx->null_cond = do_log_cond(cf, dest);
+ ctx->null_cond = do_log_cond(ctx, cf, d, dest);
}
}
-static bool do_log_reg(DisasContext *ctx, arg_rrr_cf *a,
- void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
+static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
+ void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
{
- TCGv_reg tcg_r1, tcg_r2;
+ TCGv_i64 tcg_r1, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, fn);
+ do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
return nullify_end(ctx);
}
-static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1,
- TCGv_reg in2, unsigned cf, bool is_tc,
- void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
+static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
+ TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
+ void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
{
- TCGv_reg dest;
+ TCGv_i64 dest;
DisasCond cond;
if (cf == 0) {
@@ -1350,14 +1268,14 @@ static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1,
save_gpr(ctx, rt, dest);
cond_free(&ctx->null_cond);
} else {
- dest = tcg_temp_new();
+ dest = tcg_temp_new_i64();
fn(dest, in1, in2);
- cond = do_unit_cond(cf, dest, in1, in2);
+ cond = do_unit_cond(cf, d, dest, in1, in2);
if (is_tc) {
- TCGv_reg tmp = tcg_temp_new();
- tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
gen_helper_tcond(tcg_env, tmp);
}
save_gpr(ctx, rt, dest);
@@ -1372,17 +1290,17 @@ static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1,
from the top 2 bits of the base register. There are a few system
instructions that have a 3-bit space specifier, for which SR0 is
not special. To handle this, pass ~SP. */
-static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base)
+static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
{
TCGv_ptr ptr;
- TCGv_reg tmp;
+ TCGv_i64 tmp;
TCGv_i64 spc;
if (sp != 0) {
if (sp < 0) {
sp = ~sp;
}
- spc = get_temp_tl(ctx);
+ spc = tcg_temp_new_i64();
load_spr(ctx, spc, sp);
return spc;
}
@@ -1391,12 +1309,13 @@ static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base)
}
ptr = tcg_temp_new_ptr();
- tmp = tcg_temp_new();
- spc = get_temp_tl(ctx);
+ tmp = tcg_temp_new_i64();
+ spc = tcg_temp_new_i64();
- tcg_gen_shri_reg(tmp, base, TARGET_REGISTER_BITS - 5);
- tcg_gen_andi_reg(tmp, tmp, 030);
- tcg_gen_trunc_reg_ptr(ptr, tmp);
+ /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
+ tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
+ tcg_gen_andi_i64(tmp, tmp, 030);
+ tcg_gen_trunc_i64_ptr(ptr, tmp);
tcg_gen_add_ptr(ptr, ptr, tcg_env);
tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
@@ -1405,38 +1324,35 @@ static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base)
}
#endif
-static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs,
- unsigned rb, unsigned rx, int scale, target_sreg disp,
+static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
+ unsigned rb, unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, bool is_phys)
{
- TCGv_reg base = load_gpr(ctx, rb);
- TCGv_reg ofs;
+ TCGv_i64 base = load_gpr(ctx, rb);
+ TCGv_i64 ofs;
+ TCGv_i64 addr;
+
+ set_insn_breg(ctx, rb);
/* Note that RX is mutually exclusive with DISP. */
if (rx) {
- ofs = get_temp(ctx);
- tcg_gen_shli_reg(ofs, cpu_gr[rx], scale);
- tcg_gen_add_reg(ofs, ofs, base);
+ ofs = tcg_temp_new_i64();
+ tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
+ tcg_gen_add_i64(ofs, ofs, base);
} else if (disp || modify) {
- ofs = get_temp(ctx);
- tcg_gen_addi_reg(ofs, base, disp);
+ ofs = tcg_temp_new_i64();
+ tcg_gen_addi_i64(ofs, base, disp);
} else {
ofs = base;
}
*pofs = ofs;
-#ifdef CONFIG_USER_ONLY
- *pgva = (modify <= 0 ? ofs : base);
-#else
- TCGv_tl addr = get_temp_tl(ctx);
- tcg_gen_extu_reg_tl(addr, modify <= 0 ? ofs : base);
- if (ctx->tb_flags & PSW_W) {
- tcg_gen_andi_tl(addr, addr, 0x3fffffffffffffffull);
- }
+ *pgva = addr = tcg_temp_new_i64();
+ tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
+#ifndef CONFIG_USER_ONLY
if (!is_phys) {
- tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
+ tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
}
- *pgva = addr;
#endif
}
@@ -1446,29 +1362,29 @@ static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs,
* = 0 for no base register update.
*/
static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, MemOp mop)
{
- TCGv_reg ofs;
- TCGv_tl addr;
+ TCGv_i64 ofs;
+ TCGv_i64 addr;
/* Caller uses nullify_over/nullify_end. */
assert(ctx->null_cond.c == TCG_COND_NEVER);
form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
ctx->mmu_idx == MMU_PHYS_IDX);
- tcg_gen_qemu_ld_reg(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
+ tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
if (modify) {
save_gpr(ctx, rb, ofs);
}
}
static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, MemOp mop)
{
- TCGv_reg ofs;
- TCGv_tl addr;
+ TCGv_i64 ofs;
+ TCGv_i64 addr;
/* Caller uses nullify_over/nullify_end. */
assert(ctx->null_cond.c == TCG_COND_NEVER);
@@ -1482,11 +1398,11 @@ static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
}
static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, MemOp mop)
{
- TCGv_reg ofs;
- TCGv_tl addr;
+ TCGv_i64 ofs;
+ TCGv_i64 addr;
/* Caller uses nullify_over/nullify_end. */
assert(ctx->null_cond.c == TCG_COND_NEVER);
@@ -1500,11 +1416,11 @@ static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
}
static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, MemOp mop)
{
- TCGv_reg ofs;
- TCGv_tl addr;
+ TCGv_i64 ofs;
+ TCGv_i64 addr;
/* Caller uses nullify_over/nullify_end. */
assert(ctx->null_cond.c == TCG_COND_NEVER);
@@ -1517,19 +1433,11 @@ static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
}
}
-#if TARGET_REGISTER_BITS == 64
-#define do_load_reg do_load_64
-#define do_store_reg do_store_64
-#else
-#define do_load_reg do_load_32
-#define do_store_reg do_store_32
-#endif
-
static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify, MemOp mop)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
nullify_over(ctx);
@@ -1538,16 +1446,16 @@ static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
dest = dest_gpr(ctx, rt);
} else {
/* Make sure if RT == RB, we see the result of the load. */
- dest = get_temp(ctx);
+ dest = tcg_temp_new_i64();
}
- do_load_reg(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
+ do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
save_gpr(ctx, rt, dest);
return nullify_end(ctx);
}
static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify)
{
TCGv_i32 tmp;
@@ -1572,7 +1480,7 @@ static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
}
static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify)
{
TCGv_i64 tmp;
@@ -1597,16 +1505,16 @@ static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
}
static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
- target_sreg disp, unsigned sp,
+ int64_t disp, unsigned sp,
int modify, MemOp mop)
{
nullify_over(ctx);
- do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
+ do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
return nullify_end(ctx);
}
static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify)
{
TCGv_i32 tmp;
@@ -1626,7 +1534,7 @@ static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
}
static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
- unsigned rx, int scale, target_sreg disp,
+ unsigned rx, int scale, int64_t disp,
unsigned sp, int modify)
{
TCGv_i64 tmp;
@@ -1739,12 +1647,12 @@ static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
/* Emit an unconditional branch to a direct target, which may or may not
have already had nullification handled. */
-static bool do_dbranch(DisasContext *ctx, target_ureg dest,
+static bool do_dbranch(DisasContext *ctx, uint64_t dest,
unsigned link, bool is_n)
{
if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
if (link != 0) {
- copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
}
ctx->iaoq_n = dest;
if (is_n) {
@@ -1754,7 +1662,7 @@ static bool do_dbranch(DisasContext *ctx, target_ureg dest,
nullify_over(ctx);
if (link != 0) {
- copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
}
if (is_n && use_nullify_skip(ctx)) {
@@ -1776,10 +1684,10 @@ static bool do_dbranch(DisasContext *ctx, target_ureg dest,
/* Emit a conditional branch to a direct target. If the branch itself
is nullified, we should have already used nullify_over. */
-static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
+static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
DisasCond *cond)
{
- target_ureg dest = iaoq_dest(ctx, disp);
+ uint64_t dest = iaoq_dest(ctx, disp);
TCGLabel *taken = NULL;
TCGCond c = cond->c;
bool n;
@@ -1795,7 +1703,7 @@ static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
}
taken = gen_new_label();
- tcg_gen_brcond_reg(c, cond->a0, cond->a1, taken);
+ tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
cond_free(cond);
/* Not taken: Condition not satisfied; nullify on backward branches. */
@@ -1812,7 +1720,7 @@ static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
if (ctx->iaoq_n == -1) {
/* The temporary iaoq_n_var died at the branch above.
Regenerate it here instead of saving it. */
- tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
+ tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
}
gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
}
@@ -1842,24 +1750,25 @@ static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
/* Emit an unconditional branch to an indirect target. This handles
nullification of the branch itself. */
-static bool do_ibranch(DisasContext *ctx, TCGv_reg dest,
+static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
unsigned link, bool is_n)
{
- TCGv_reg a0, a1, next, tmp;
+ TCGv_i64 a0, a1, next, tmp;
TCGCond c;
assert(ctx->null_lab == NULL);
if (ctx->null_cond.c == TCG_COND_NEVER) {
if (link != 0) {
- copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
}
- next = get_temp(ctx);
- tcg_gen_mov_reg(next, dest);
+ next = tcg_temp_new_i64();
+ tcg_gen_mov_i64(next, dest);
if (is_n) {
if (use_nullify_skip(ctx)) {
- tcg_gen_mov_reg(cpu_iaoq_f, next);
- tcg_gen_addi_reg(cpu_iaoq_b, next, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
+ tcg_gen_addi_i64(next, next, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
nullify_set(ctx, 0);
ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
return true;
@@ -1881,12 +1790,14 @@ static bool do_ibranch(DisasContext *ctx, TCGv_reg dest,
/* We do have to handle the non-local temporary, DEST, before
branching. Since IOAQ_F is not really live at this point, we
can simply store DEST optimistically. Similarly with IAOQ_B. */
- tcg_gen_mov_reg(cpu_iaoq_f, dest);
- tcg_gen_addi_reg(cpu_iaoq_b, dest, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
+ next = tcg_temp_new_i64();
+ tcg_gen_addi_i64(next, dest, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
nullify_over(ctx);
if (link != 0) {
- tcg_gen_movi_reg(cpu_gr[link], ctx->iaoq_n);
+ copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
}
tcg_gen_lookup_and_goto_ptr();
return nullify_end(ctx);
@@ -1895,23 +1806,23 @@ static bool do_ibranch(DisasContext *ctx, TCGv_reg dest,
a0 = ctx->null_cond.a0;
a1 = ctx->null_cond.a1;
- tmp = tcg_temp_new();
- next = get_temp(ctx);
+ tmp = tcg_temp_new_i64();
+ next = tcg_temp_new_i64();
- copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
- tcg_gen_movcond_reg(c, next, a0, a1, tmp, dest);
+ copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
+ tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
ctx->iaoq_n = -1;
ctx->iaoq_n_var = next;
if (link != 0) {
- tcg_gen_movcond_reg(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
+ tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
}
if (is_n) {
/* The branch nullifies the next insn, which means the state of N
after the branch is the inverse of the state of N that applied
to the branch. */
- tcg_gen_setcond_reg(tcg_invert_cond(c), cpu_psw_n, a0, a1);
+ tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
cond_free(&ctx->null_cond);
ctx->null_cond = cond_make_n();
ctx->psw_n_nonzero = true;
@@ -1929,23 +1840,23 @@ static bool do_ibranch(DisasContext *ctx, TCGv_reg dest,
* IAOQ_Next{30..31} ← IAOQ_Front{30..31};
* which keeps the privilege level from being increased.
*/
-static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset)
+static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
switch (ctx->privilege) {
case 0:
/* Privilege 0 is maximum and is allowed to decrease. */
return offset;
case 3:
/* Privilege 3 is minimum and is never allowed to increase. */
- dest = get_temp(ctx);
- tcg_gen_ori_reg(dest, offset, 3);
+ dest = tcg_temp_new_i64();
+ tcg_gen_ori_i64(dest, offset, 3);
break;
default:
- dest = get_temp(ctx);
- tcg_gen_andi_reg(dest, offset, -4);
- tcg_gen_ori_reg(dest, dest, ctx->privilege);
- tcg_gen_movcond_reg(TCG_COND_GTU, dest, dest, offset, dest, offset);
+ dest = tcg_temp_new_i64();
+ tcg_gen_andi_i64(dest, offset, -4);
+ tcg_gen_ori_i64(dest, dest, ctx->privilege);
+ tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
break;
}
return dest;
@@ -1961,6 +1872,8 @@ static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset)
aforementioned BE. */
static void do_page_zero(DisasContext *ctx)
{
+ TCGv_i64 tmp;
+
/* If by some means we get here with PSW[N]=1, that implies that
the B,GATE instruction would be skipped, and we'd fault on the
next insn within the privileged page. */
@@ -1968,7 +1881,7 @@ static void do_page_zero(DisasContext *ctx)
case TCG_COND_NEVER:
break;
case TCG_COND_ALWAYS:
- tcg_gen_movi_reg(cpu_psw_n, 0);
+ tcg_gen_movi_i64(cpu_psw_n, 0);
goto do_sigill;
default:
/* Since this is always the first (and only) insn within the
@@ -1996,9 +1909,12 @@ static void do_page_zero(DisasContext *ctx)
break;
case 0xe0: /* SET_THREAD_POINTER */
- tcg_gen_st_reg(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
- tcg_gen_ori_reg(cpu_iaoq_f, cpu_gr[31], 3);
- tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
+ tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
+ tcg_gen_addi_i64(tmp, tmp, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
break;
@@ -2039,8 +1955,8 @@ static bool trans_sync(DisasContext *ctx, arg_sync *a)
static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
{
unsigned rt = a->t;
- TCGv_reg tmp = dest_gpr(ctx, rt);
- tcg_gen_movi_reg(tmp, ctx->iaoq_f);
+ TCGv_i64 tmp = dest_gpr(ctx, rt);
+ tcg_gen_movi_i64(tmp, ctx->iaoq_f);
save_gpr(ctx, rt, tmp);
cond_free(&ctx->null_cond);
@@ -2052,13 +1968,11 @@ static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
unsigned rt = a->t;
unsigned rs = a->sp;
TCGv_i64 t0 = tcg_temp_new_i64();
- TCGv_reg t1 = tcg_temp_new();
load_spr(ctx, t0, rs);
tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_reg(t1, t0);
- save_gpr(ctx, rt, t1);
+ save_gpr(ctx, rt, t0);
cond_free(&ctx->null_cond);
return true;
@@ -2068,19 +1982,17 @@ static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
{
unsigned rt = a->t;
unsigned ctl = a->r;
- TCGv_reg tmp;
+ TCGv_i64 tmp;
switch (ctl) {
case CR_SAR:
-#ifdef TARGET_HPPA64
if (a->e == 0) {
/* MFSAR without ,W masks low 5 bits. */
tmp = dest_gpr(ctx, rt);
- tcg_gen_andi_reg(tmp, cpu_sar, 31);
+ tcg_gen_andi_i64(tmp, cpu_sar, 31);
save_gpr(ctx, rt, tmp);
goto done;
}
-#endif
save_gpr(ctx, rt, cpu_sar);
goto done;
case CR_IT: /* Interval Timer */
@@ -2104,8 +2016,8 @@ static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
break;
}
- tmp = get_temp(ctx);
- tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
save_gpr(ctx, rt, tmp);
done:
@@ -2117,22 +2029,21 @@ static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
{
unsigned rr = a->r;
unsigned rs = a->sp;
- TCGv_i64 t64;
+ TCGv_i64 tmp;
if (rs >= 5) {
CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
}
nullify_over(ctx);
- t64 = tcg_temp_new_i64();
- tcg_gen_extu_reg_i64(t64, load_gpr(ctx, rr));
- tcg_gen_shli_i64(t64, t64, 32);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
if (rs >= 4) {
- tcg_gen_st_i64(t64, tcg_env, offsetof(CPUHPPAState, sr[rs]));
+ tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
ctx->tb_flags &= ~TB_FLAG_SR_SAME;
} else {
- tcg_gen_mov_i64(cpu_sr[rs], t64);
+ tcg_gen_mov_i64(cpu_sr[rs], tmp);
}
return nullify_end(ctx);
@@ -2141,13 +2052,13 @@ static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
{
unsigned ctl = a->t;
- TCGv_reg reg;
- TCGv_reg tmp;
+ TCGv_i64 reg;
+ TCGv_i64 tmp;
if (ctl == CR_SAR) {
reg = load_gpr(ctx, a->r);
- tmp = tcg_temp_new();
- tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
save_or_nullify(ctx, cpu_sar, tmp);
cond_free(&ctx->null_cond);
@@ -2159,7 +2070,13 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
#ifndef CONFIG_USER_ONLY
nullify_over(ctx);
- reg = load_gpr(ctx, a->r);
+
+ if (ctx->is_pa20) {
+ reg = load_gpr(ctx, a->r);
+ } else {
+ reg = tcg_temp_new_i64();
+ tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
+ }
switch (ctl) {
case CR_IT:
@@ -2177,11 +2094,11 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
case CR_IIAOQ:
/* FIXME: Respect PSW_Q bit */
/* The write advances the queue and stores to the back element. */
- tmp = get_temp(ctx);
- tcg_gen_ld_reg(tmp, tcg_env,
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ld_i64(tmp, tcg_env,
offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
- tcg_gen_st_reg(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
- tcg_gen_st_reg(reg, tcg_env,
+ tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
+ tcg_gen_st_i64(reg, tcg_env,
offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
break;
@@ -2189,14 +2106,14 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
case CR_PID2:
case CR_PID3:
case CR_PID4:
- tcg_gen_st_reg(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
+ tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
#ifndef CONFIG_USER_ONLY
gen_helper_change_prot_id(tcg_env);
#endif
break;
default:
- tcg_gen_st_reg(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
+ tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
break;
}
return nullify_end(ctx);
@@ -2205,10 +2122,10 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
{
- TCGv_reg tmp = tcg_temp_new();
+ TCGv_i64 tmp = tcg_temp_new_i64();
- tcg_gen_not_reg(tmp, load_gpr(ctx, a->r));
- tcg_gen_andi_reg(tmp, tmp, TARGET_REGISTER_BITS - 1);
+ tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
+ tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
save_or_nullify(ctx, cpu_sar, tmp);
cond_free(&ctx->null_cond);
@@ -2217,17 +2134,14 @@ static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
{
- TCGv_reg dest = dest_gpr(ctx, a->t);
+ TCGv_i64 dest = dest_gpr(ctx, a->t);
#ifdef CONFIG_USER_ONLY
/* We don't implement space registers in user mode. */
- tcg_gen_movi_reg(dest, 0);
+ tcg_gen_movi_i64(dest, 0);
#else
- TCGv_i64 t0 = tcg_temp_new_i64();
-
- tcg_gen_mov_i64(t0, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
- tcg_gen_shri_i64(t0, t0, 32);
- tcg_gen_trunc_i64_reg(dest, t0);
+ tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
+ tcg_gen_shri_i64(dest, dest, 32);
#endif
save_gpr(ctx, a->t, dest);
@@ -2239,13 +2153,13 @@ static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_reg tmp;
+ TCGv_i64 tmp;
nullify_over(ctx);
- tmp = get_temp(ctx);
- tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, psw));
- tcg_gen_andi_reg(tmp, tmp, ~a->i);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
+ tcg_gen_andi_i64(tmp, tmp, ~a->i);
gen_helper_swap_system_mask(tmp, tcg_env, tmp);
save_gpr(ctx, a->t, tmp);
@@ -2259,13 +2173,13 @@ static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_reg tmp;
+ TCGv_i64 tmp;
nullify_over(ctx);
- tmp = get_temp(ctx);
- tcg_gen_ld_reg(tmp, tcg_env, offsetof(CPUHPPAState, psw));
- tcg_gen_ori_reg(tmp, tmp, a->i);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
+ tcg_gen_ori_i64(tmp, tmp, a->i);
gen_helper_swap_system_mask(tmp, tcg_env, tmp);
save_gpr(ctx, a->t, tmp);
@@ -2279,11 +2193,11 @@ static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_reg tmp, reg;
+ TCGv_i64 tmp, reg;
nullify_over(ctx);
reg = load_gpr(ctx, a->r);
- tmp = get_temp(ctx);
+ tmp = tcg_temp_new_i64();
gen_helper_swap_system_mask(tmp, tcg_env, reg);
/* Exit the TB to recognize new interrupts. */
@@ -2356,12 +2270,12 @@ static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
{
if (a->m) {
- TCGv_reg dest = dest_gpr(ctx, a->b);
- TCGv_reg src1 = load_gpr(ctx, a->b);
- TCGv_reg src2 = load_gpr(ctx, a->x);
+ TCGv_i64 dest = dest_gpr(ctx, a->b);
+ TCGv_i64 src1 = load_gpr(ctx, a->b);
+ TCGv_i64 src2 = load_gpr(ctx, a->x);
/* The only thing we need to do is the base register modification. */
- tcg_gen_add_reg(dest, src1, src2);
+ tcg_gen_add_i64(dest, src1, src2);
save_gpr(ctx, a->b, dest);
}
cond_free(&ctx->null_cond);
@@ -2370,9 +2284,9 @@ static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
static bool trans_probe(DisasContext *ctx, arg_probe *a)
{
- TCGv_reg dest, ofs;
+ TCGv_i64 dest, ofs;
TCGv_i32 level, want;
- TCGv_tl addr;
+ TCGv_i64 addr;
nullify_over(ctx);
@@ -2383,7 +2297,7 @@ static bool trans_probe(DisasContext *ctx, arg_probe *a)
level = tcg_constant_i32(a->ri);
} else {
level = tcg_temp_new_i32();
- tcg_gen_trunc_reg_i32(level, load_gpr(ctx, a->ri));
+ tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
tcg_gen_andi_i32(level, level, 3);
}
want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
@@ -2396,19 +2310,22 @@ static bool trans_probe(DisasContext *ctx, arg_probe *a)
static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
{
+ if (ctx->is_pa20) {
+ return false;
+ }
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_tl addr;
- TCGv_reg ofs, reg;
+ TCGv_i64 addr;
+ TCGv_i64 ofs, reg;
nullify_over(ctx);
form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
reg = load_gpr(ctx, a->r);
if (a->addr) {
- gen_helper_itlba(tcg_env, addr, reg);
+ gen_helper_itlba_pa11(tcg_env, addr, reg);
} else {
- gen_helper_itlbp(tcg_env, addr, reg);
+ gen_helper_itlbp_pa11(tcg_env, addr, reg);
}
/* Exit TB for TLB change if mmu is enabled. */
@@ -2419,25 +2336,63 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
#endif
}
-static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
+static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_tl addr;
- TCGv_reg ofs;
+ TCGv_i64 addr;
+ TCGv_i64 ofs;
nullify_over(ctx);
form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
- if (a->m) {
- save_gpr(ctx, a->b, ofs);
+
+ /*
+ * Page align now, rather than later, so that we can add in the
+ * page_size field from pa2.0 from the low 4 bits of GR[b].
+ */
+ tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
+ if (ctx->is_pa20) {
+ tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
}
- if (a->local) {
- gen_helper_ptlbe(tcg_env);
+
+ if (local) {
+ gen_helper_ptlb_l(tcg_env, addr);
} else {
gen_helper_ptlb(tcg_env, addr);
}
+ if (a->m) {
+ save_gpr(ctx, a->b, ofs);
+ }
+
+ /* Exit TB for TLB change if mmu is enabled. */
+ if (ctx->tb_flags & PSW_C) {
+ ctx->base.is_jmp = DISAS_IAQ_N_STALE;
+ }
+ return nullify_end(ctx);
+#endif
+}
+
+static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
+{
+ return do_pxtlb(ctx, a, false);
+}
+
+static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
+{
+ return ctx->is_pa20 && do_pxtlb(ctx, a, true);
+}
+
+static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
+{
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+#ifndef CONFIG_USER_ONLY
+ nullify_over(ctx);
+
+ trans_nop_addrx(ctx, a);
+ gen_helper_ptlbe(tcg_env);
+
/* Exit TB for TLB change if mmu is enabled. */
if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
@@ -2454,10 +2409,13 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
*/
static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
{
+ if (ctx->is_pa20) {
+ return false;
+ }
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_tl addr, atl, stl;
- TCGv_reg reg;
+ TCGv_i64 addr, atl, stl;
+ TCGv_i64 reg;
nullify_over(ctx);
@@ -2465,13 +2423,11 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
* FIXME:
* if (not (pcxl or pcxl2))
* return gen_illegal(ctx);
- *
- * Note for future: these are 32-bit systems; no hppa64.
*/
- atl = tcg_temp_new_tl();
- stl = tcg_temp_new_tl();
- addr = tcg_temp_new_tl();
+ atl = tcg_temp_new_i64();
+ stl = tcg_temp_new_i64();
+ addr = tcg_temp_new_i64();
tcg_gen_ld32u_i64(stl, tcg_env,
a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
@@ -2480,13 +2436,13 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
: offsetof(CPUHPPAState, cr[CR_IIAOQ]));
tcg_gen_shli_i64(stl, stl, 32);
- tcg_gen_or_tl(addr, atl, stl);
+ tcg_gen_or_i64(addr, atl, stl);
reg = load_gpr(ctx, a->r);
if (a->addr) {
- gen_helper_itlba(tcg_env, addr, reg);
+ gen_helper_itlba_pa11(tcg_env, addr, reg);
} else {
- gen_helper_itlbp(tcg_env, addr, reg);
+ gen_helper_itlbp_pa11(tcg_env, addr, reg);
}
/* Exit TB for TLB change if mmu is enabled. */
@@ -2497,18 +2453,44 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
#endif
}
+static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
+{
+ if (!ctx->is_pa20) {
+ return false;
+ }
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+#ifndef CONFIG_USER_ONLY
+ nullify_over(ctx);
+ {
+ TCGv_i64 src1 = load_gpr(ctx, a->r1);
+ TCGv_i64 src2 = load_gpr(ctx, a->r2);
+
+ if (a->data) {
+ gen_helper_idtlbt_pa20(tcg_env, src1, src2);
+ } else {
+ gen_helper_iitlbt_pa20(tcg_env, src1, src2);
+ }
+ }
+ /* Exit TB for TLB change if mmu is enabled. */
+ if (ctx->tb_flags & PSW_C) {
+ ctx->base.is_jmp = DISAS_IAQ_N_STALE;
+ }
+ return nullify_end(ctx);
+#endif
+}
+
static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
- TCGv_tl vaddr;
- TCGv_reg ofs, paddr;
+ TCGv_i64 vaddr;
+ TCGv_i64 ofs, paddr;
nullify_over(ctx);
form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
- paddr = tcg_temp_new();
+ paddr = tcg_temp_new_i64();
gen_helper_lpa(paddr, tcg_env, vaddr);
/* Note that physical address result overrides base modification. */
@@ -2529,78 +2511,78 @@ static bool trans_lci(DisasContext *ctx, arg_lci *a)
physical address. Two addresses with the same CI have a coherent
view of the cache. Our implementation is to return 0 for all,
since the entire address space is coherent. */
- save_gpr(ctx, a->t, tcg_constant_reg(0));
+ save_gpr(ctx, a->t, ctx->zero);
cond_free(&ctx->null_cond);
return true;
}
-static bool trans_add(DisasContext *ctx, arg_rrr_cf_sh *a)
+static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
{
return do_add_reg(ctx, a, false, false, false, false);
}
-static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_sh *a)
+static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
{
return do_add_reg(ctx, a, true, false, false, false);
}
-static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_sh *a)
+static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
{
return do_add_reg(ctx, a, false, true, false, false);
}
-static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_sh *a)
+static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
{
return do_add_reg(ctx, a, false, false, false, true);
}
-static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_sh *a)
+static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
{
return do_add_reg(ctx, a, false, true, false, true);
}
-static bool trans_sub(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, false, false, false);
}
-static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, true, false, false);
}
-static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, false, false, true);
}
-static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, true, false, true);
}
-static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, false, true, false);
}
-static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_sub_reg(ctx, a, true, true, false);
}
-static bool trans_andcm(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
{
- return do_log_reg(ctx, a, tcg_gen_andc_reg);
+ return do_log_reg(ctx, a, tcg_gen_andc_i64);
}
-static bool trans_and(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
{
- return do_log_reg(ctx, a, tcg_gen_and_reg);
+ return do_log_reg(ctx, a, tcg_gen_and_i64);
}
-static bool trans_or(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
{
if (a->cf == 0) {
unsigned r2 = a->r2;
@@ -2613,8 +2595,8 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a)
}
if (r2 == 0) { /* COPY */
if (r1 == 0) {
- TCGv_reg dest = dest_gpr(ctx, rt);
- tcg_gen_movi_reg(dest, 0);
+ TCGv_i64 dest = dest_gpr(ctx, rt);
+ tcg_gen_movi_i64(dest, 0);
save_gpr(ctx, rt, dest);
} else {
save_gpr(ctx, rt, cpu_gr[r1]);
@@ -2635,8 +2617,8 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a)
nullify_over(ctx);
/* Advance the instruction queue. */
- copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
- copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
nullify_set(ctx, 0);
/* Tell the qemu main loop to halt until this cpu has work. */
@@ -2649,142 +2631,146 @@ static bool trans_or(DisasContext *ctx, arg_rrr_cf *a)
}
#endif
}
- return do_log_reg(ctx, a, tcg_gen_or_reg);
+ return do_log_reg(ctx, a, tcg_gen_or_i64);
}
-static bool trans_xor(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
{
- return do_log_reg(ctx, a, tcg_gen_xor_reg);
+ return do_log_reg(ctx, a, tcg_gen_xor_i64);
}
-static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
{
- TCGv_reg tcg_r1, tcg_r2;
+ TCGv_i64 tcg_r1, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf);
+ do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
return nullify_end(ctx);
}
-static bool trans_uxor(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
{
- TCGv_reg tcg_r1, tcg_r2;
+ TCGv_i64 tcg_r1, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, false, tcg_gen_xor_reg);
+ do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
return nullify_end(ctx);
}
-static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf *a, bool is_tc)
+static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
{
- TCGv_reg tcg_r1, tcg_r2, tmp;
+ TCGv_i64 tcg_r1, tcg_r2, tmp;
if (a->cf) {
nullify_over(ctx);
}
tcg_r1 = load_gpr(ctx, a->r1);
tcg_r2 = load_gpr(ctx, a->r2);
- tmp = get_temp(ctx);
- tcg_gen_not_reg(tmp, tcg_r2);
- do_unit(ctx, a->t, tcg_r1, tmp, a->cf, is_tc, tcg_gen_add_reg);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_not_i64(tmp, tcg_r2);
+ do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
return nullify_end(ctx);
}
-static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_uaddcm(ctx, a, false);
}
-static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf *a)
+static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
{
return do_uaddcm(ctx, a, true);
}
-static bool do_dcor(DisasContext *ctx, arg_rr_cf *a, bool is_i)
+static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
{
- TCGv_reg tmp;
+ TCGv_i64 tmp;
nullify_over(ctx);
- tmp = get_temp(ctx);
- tcg_gen_shri_reg(tmp, cpu_psw_cb, 3);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
if (!is_i) {
- tcg_gen_not_reg(tmp, tmp);
+ tcg_gen_not_i64(tmp, tmp);
}
- tcg_gen_andi_reg(tmp, tmp, 0x11111111);
- tcg_gen_muli_reg(tmp, tmp, 6);
- do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, false,
- is_i ? tcg_gen_add_reg : tcg_gen_sub_reg);
+ tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
+ tcg_gen_muli_i64(tmp, tmp, 6);
+ do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
+ is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
return nullify_end(ctx);
}
-static bool trans_dcor(DisasContext *ctx, arg_rr_cf *a)
+static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
{
return do_dcor(ctx, a, false);
}
-static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf *a)
+static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
{
return do_dcor(ctx, a, true);
}
static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
{
- TCGv_reg dest, add1, add2, addc, zero, in1, in2;
+ TCGv_i64 dest, add1, add2, addc, in1, in2;
+ TCGv_i64 cout;
nullify_over(ctx);
in1 = load_gpr(ctx, a->r1);
in2 = load_gpr(ctx, a->r2);
- add1 = tcg_temp_new();
- add2 = tcg_temp_new();
- addc = tcg_temp_new();
- dest = tcg_temp_new();
- zero = tcg_constant_reg(0);
+ add1 = tcg_temp_new_i64();
+ add2 = tcg_temp_new_i64();
+ addc = tcg_temp_new_i64();
+ dest = tcg_temp_new_i64();
/* Form R1 << 1 | PSW[CB]{8}. */
- tcg_gen_add_reg(add1, in1, in1);
- tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb);
-
- /* Add or subtract R2, depending on PSW[V]. Proper computation of
- carry{8} requires that we subtract via + ~R2 + 1, as described in
- the manual. By extracting and masking V, we can produce the
- proper inputs to the addition without movcond. */
- tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1);
- tcg_gen_xor_reg(add2, in2, addc);
- tcg_gen_andi_reg(addc, addc, 1);
- /* ??? This is only correct for 32-bit. */
- tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
- tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
+ tcg_gen_add_i64(add1, in1, in1);
+ tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
+
+ /*
+ * Add or subtract R2, depending on PSW[V]. Proper computation of
+ * carry requires that we subtract via + ~R2 + 1, as described in
+ * the manual. By extracting and masking V, we can produce the
+ * proper inputs to the addition without movcond.
+ */
+ tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
+ tcg_gen_xor_i64(add2, in2, addc);
+ tcg_gen_andi_i64(addc, addc, 1);
+
+ tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
+ tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
+ addc, ctx->zero);
/* Write back the result register. */
save_gpr(ctx, a->t, dest);
/* Write back PSW[CB]. */
- tcg_gen_xor_reg(cpu_psw_cb, add1, add2);
- tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest);
+ tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
+ tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
/* Write back PSW[V] for the division step. */
- tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb);
- tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2);
+ cout = get_psw_carry(ctx, false);
+ tcg_gen_neg_i64(cpu_psw_v, cout);
+ tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
/* Install the new nullification. */
if (a->cf) {
- TCGv_reg sv = NULL;
+ TCGv_i64 sv = NULL;
if (cond_need_sv(a->cf >> 1)) {
/* ??? The lshift is supposed to contribute to overflow. */
sv = do_add_sv(ctx, dest, add1, add2);
}
- ctx->null_cond = do_cond(a->cf, dest, cpu_psw_cb_msb, sv);
+ ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
}
return nullify_end(ctx);
@@ -2820,53 +2806,270 @@ static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
return do_sub_imm(ctx, a, true);
}
-static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf *a)
+static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
{
- TCGv_reg tcg_im, tcg_r2;
+ TCGv_i64 tcg_im, tcg_r2;
if (a->cf) {
nullify_over(ctx);
}
- tcg_im = load_const(ctx, a->i);
+ tcg_im = tcg_constant_i64(a->i);
tcg_r2 = load_gpr(ctx, a->r);
- do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf);
+ do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
+
+ return nullify_end(ctx);
+}
+
+static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
+ void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+ TCGv_i64 r1, r2, dest;
+
+ if (!ctx->is_pa20) {
+ return false;
+ }
+
+ nullify_over(ctx);
+
+ r1 = load_gpr(ctx, a->r1);
+ r2 = load_gpr(ctx, a->r2);
+ dest = dest_gpr(ctx, a->t);
+
+ fn(dest, r1, r2);
+ save_gpr(ctx, a->t, dest);
return nullify_end(ctx);
}
+static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
+ void (*fn)(TCGv_i64, TCGv_i64, int64_t))
+{
+ TCGv_i64 r, dest;
+
+ if (!ctx->is_pa20) {
+ return false;
+ }
+
+ nullify_over(ctx);
+
+ r = load_gpr(ctx, a->r);
+ dest = dest_gpr(ctx, a->t);
+
+ fn(dest, r, a->i);
+ save_gpr(ctx, a->t, dest);
+
+ return nullify_end(ctx);
+}
+
+static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
+ void (*fn)(TCGv_i64, TCGv_i64,
+ TCGv_i64, TCGv_i32))
+{
+ TCGv_i64 r1, r2, dest;
+
+ if (!ctx->is_pa20) {
+ return false;
+ }
+
+ nullify_over(ctx);
+
+ r1 = load_gpr(ctx, a->r1);
+ r2 = load_gpr(ctx, a->r2);
+ dest = dest_gpr(ctx, a->t);
+
+ fn(dest, r1, r2, tcg_constant_i32(a->sh));
+ save_gpr(ctx, a->t, dest);
+
+ return nullify_end(ctx);
+}
+
+static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
+}
+
+static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_helper_hadd_ss);
+}
+
+static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_helper_hadd_us);
+}
+
+static bool trans_havg(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_helper_havg);
+}
+
+static bool trans_hshl(DisasContext *ctx, arg_rri *a)
+{
+ return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
+}
+
+static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
+{
+ return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
+}
+
+static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
+{
+ return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
+}
+
+static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
+{
+ return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
+}
+
+static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
+{
+ return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
+}
+
+static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
+}
+
+static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_helper_hsub_ss);
+}
+
+static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_helper_hsub_us);
+}
+
+static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
+{
+ uint64_t mask = 0xffff0000ffff0000ull;
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ tcg_gen_andi_i64(tmp, r2, mask);
+ tcg_gen_andi_i64(dst, r1, mask);
+ tcg_gen_shri_i64(tmp, tmp, 16);
+ tcg_gen_or_i64(dst, dst, tmp);
+}
+
+static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_mixh_l);
+}
+
+static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
+{
+ uint64_t mask = 0x0000ffff0000ffffull;
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ tcg_gen_andi_i64(tmp, r1, mask);
+ tcg_gen_andi_i64(dst, r2, mask);
+ tcg_gen_shli_i64(tmp, tmp, 16);
+ tcg_gen_or_i64(dst, dst, tmp);
+}
+
+static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_mixh_r);
+}
+
+static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
+{
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ tcg_gen_shri_i64(tmp, r2, 32);
+ tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
+}
+
+static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_mixw_l);
+}
+
+static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
+{
+ tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
+}
+
+static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
+{
+ return do_multimedia(ctx, a, gen_mixw_r);
+}
+
+static bool trans_permh(DisasContext *ctx, arg_permh *a)
+{
+ TCGv_i64 r, t0, t1, t2, t3;
+
+ if (!ctx->is_pa20) {
+ return false;
+ }
+
+ nullify_over(ctx);
+
+ r = load_gpr(ctx, a->r1);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ t3 = tcg_temp_new_i64();
+
+ tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
+ tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
+ tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
+ tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
+
+ tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
+ tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
+ tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
+
+ save_gpr(ctx, a->t, t0);
+ return nullify_end(ctx);
+}
+
static bool trans_ld(DisasContext *ctx, arg_ldst *a)
{
- if (unlikely(TARGET_REGISTER_BITS == 32 && a->size > MO_32)) {
+ if (ctx->is_pa20) {
+ /*
+ * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
+ * Any base modification still occurs.
+ */
+ if (a->t == 0) {
+ return trans_nop_addrx(ctx, a);
+ }
+ } else if (a->size > MO_32) {
return gen_illegal(ctx);
- } else {
- return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
- a->disp, a->sp, a->m, a->size | MO_TE);
}
+ return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
+ a->disp, a->sp, a->m, a->size | MO_TE);
}
static bool trans_st(DisasContext *ctx, arg_ldst *a)
{
assert(a->x == 0 && a->scale == 0);
- if (unlikely(TARGET_REGISTER_BITS == 32 && a->size > MO_32)) {
+ if (!ctx->is_pa20 && a->size > MO_32) {
return gen_illegal(ctx);
- } else {
- return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
}
+ return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
}
static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
{
MemOp mop = MO_TE | MO_ALIGN | a->size;
- TCGv_reg zero, dest, ofs;
- TCGv_tl addr;
+ TCGv_i64 dest, ofs;
+ TCGv_i64 addr;
+
+ if (!ctx->is_pa20 && a->size > MO_32) {
+ return gen_illegal(ctx);
+ }
nullify_over(ctx);
if (a->m) {
/* Base register modification. Make sure if RT == RB,
we see the result of the load. */
- dest = get_temp(ctx);
+ dest = tcg_temp_new_i64();
} else {
dest = dest_gpr(ctx, a->t);
}
@@ -2884,8 +3087,7 @@ static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
*/
gen_helper_ldc_check(addr);
- zero = tcg_constant_reg(0);
- tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop);
+ tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
if (a->m) {
save_gpr(ctx, a->b, ofs);
@@ -2897,8 +3099,8 @@ static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
static bool trans_stby(DisasContext *ctx, arg_stby *a)
{
- TCGv_reg ofs, val;
- TCGv_tl addr;
+ TCGv_i64 ofs, val;
+ TCGv_i64 addr;
nullify_over(ctx);
@@ -2919,7 +3121,41 @@ static bool trans_stby(DisasContext *ctx, arg_stby *a)
}
}
if (a->m) {
- tcg_gen_andi_reg(ofs, ofs, ~3);
+ tcg_gen_andi_i64(ofs, ofs, ~3);
+ save_gpr(ctx, a->b, ofs);
+ }
+
+ return nullify_end(ctx);
+}
+
+static bool trans_stdby(DisasContext *ctx, arg_stby *a)
+{
+ TCGv_i64 ofs, val;
+ TCGv_i64 addr;
+
+ if (!ctx->is_pa20) {
+ return false;
+ }
+ nullify_over(ctx);
+
+ form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
+ ctx->mmu_idx == MMU_PHYS_IDX);
+ val = load_gpr(ctx, a->r);
+ if (a->a) {
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ gen_helper_stdby_e_parallel(tcg_env, addr, val);
+ } else {
+ gen_helper_stdby_e(tcg_env, addr, val);
+ }
+ } else {
+ if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
+ gen_helper_stdby_b_parallel(tcg_env, addr, val);
+ } else {
+ gen_helper_stdby_b(tcg_env, addr, val);
+ }
+ }
+ if (a->m) {
+ tcg_gen_andi_i64(ofs, ofs, ~7);
save_gpr(ctx, a->b, ofs);
}
@@ -2950,9 +3186,9 @@ static bool trans_sta(DisasContext *ctx, arg_ldst *a)
static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
{
- TCGv_reg tcg_rt = dest_gpr(ctx, a->t);
+ TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
- tcg_gen_movi_reg(tcg_rt, a->i);
+ tcg_gen_movi_i64(tcg_rt, a->i);
save_gpr(ctx, a->t, tcg_rt);
cond_free(&ctx->null_cond);
return true;
@@ -2960,10 +3196,10 @@ static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
static bool trans_addil(DisasContext *ctx, arg_addil *a)
{
- TCGv_reg tcg_rt = load_gpr(ctx, a->r);
- TCGv_reg tcg_r1 = dest_gpr(ctx, 1);
+ TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
+ TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
- tcg_gen_addi_reg(tcg_r1, tcg_rt, a->i);
+ tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
save_gpr(ctx, 1, tcg_r1);
cond_free(&ctx->null_cond);
return true;
@@ -2971,75 +3207,100 @@ static bool trans_addil(DisasContext *ctx, arg_addil *a)
static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
{
- TCGv_reg tcg_rt = dest_gpr(ctx, a->t);
+ TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
/* Special case rb == 0, for the LDI pseudo-op.
- The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
+ The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */
if (a->b == 0) {
- tcg_gen_movi_reg(tcg_rt, a->i);
+ tcg_gen_movi_i64(tcg_rt, a->i);
} else {
- tcg_gen_addi_reg(tcg_rt, cpu_gr[a->b], a->i);
+ tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
}
save_gpr(ctx, a->t, tcg_rt);
cond_free(&ctx->null_cond);
return true;
}
-static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_reg in1,
- unsigned c, unsigned f, unsigned n, int disp)
+static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
+ unsigned c, unsigned f, bool d, unsigned n, int disp)
{
- TCGv_reg dest, in2, sv;
+ TCGv_i64 dest, in2, sv;
DisasCond cond;
in2 = load_gpr(ctx, r);
- dest = get_temp(ctx);
+ dest = tcg_temp_new_i64();
- tcg_gen_sub_reg(dest, in1, in2);
+ tcg_gen_sub_i64(dest, in1, in2);
sv = NULL;
if (cond_need_sv(c)) {
sv = do_sub_sv(ctx, dest, in1, in2);
}
- cond = do_sub_cond(c * 2 + f, dest, in1, in2, sv);
+ cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
return do_cbranch(ctx, disp, n, &cond);
}
static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
{
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
nullify_over(ctx);
- return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
+ return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
+ a->c, a->f, a->d, a->n, a->disp);
}
static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
{
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
nullify_over(ctx);
- return do_cmpb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp);
+ return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
+ a->c, a->f, a->d, a->n, a->disp);
}
-static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
+static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
unsigned c, unsigned f, unsigned n, int disp)
{
- TCGv_reg dest, in2, sv, cb_msb;
+ TCGv_i64 dest, in2, sv, cb_cond;
DisasCond cond;
+ bool d = false;
+
+ /*
+ * For hppa64, the ADDB conditions change with PSW.W,
+ * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
+ */
+ if (ctx->tb_flags & PSW_W) {
+ d = c >= 5;
+ if (d) {
+ c &= 3;
+ }
+ }
in2 = load_gpr(ctx, r);
- dest = tcg_temp_new();
+ dest = tcg_temp_new_i64();
sv = NULL;
- cb_msb = NULL;
+ cb_cond = NULL;
if (cond_need_cb(c)) {
- cb_msb = get_temp(ctx);
- tcg_gen_movi_reg(cb_msb, 0);
- tcg_gen_add2_reg(dest, cb_msb, in1, cb_msb, in2, cb_msb);
+ TCGv_i64 cb = tcg_temp_new_i64();
+ TCGv_i64 cb_msb = tcg_temp_new_i64();
+
+ tcg_gen_movi_i64(cb_msb, 0);
+ tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
+ tcg_gen_xor_i64(cb, in1, in2);
+ tcg_gen_xor_i64(cb, cb, dest);
+ cb_cond = get_carry(ctx, d, cb, cb_msb);
} else {
- tcg_gen_add_reg(dest, in1, in2);
+ tcg_gen_add_i64(dest, in1, in2);
}
if (cond_need_sv(c)) {
sv = do_add_sv(ctx, dest, in1, in2);
}
- cond = do_cond(c * 2 + f, dest, cb_msb, sv);
+ cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
save_gpr(ctx, r, dest);
return do_cbranch(ctx, disp, n, &cond);
}
@@ -3053,34 +3314,42 @@ static bool trans_addb(DisasContext *ctx, arg_addb *a)
static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
{
nullify_over(ctx);
- return do_addb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp);
+ return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
}
static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
{
- TCGv_reg tmp, tcg_r;
+ TCGv_i64 tmp, tcg_r;
DisasCond cond;
nullify_over(ctx);
- tmp = tcg_temp_new();
+ tmp = tcg_temp_new_i64();
tcg_r = load_gpr(ctx, a->r);
- tcg_gen_shl_reg(tmp, tcg_r, cpu_sar);
+ if (cond_need_ext(ctx, a->d)) {
+ /* Force shift into [32,63] */
+ tcg_gen_ori_i64(tmp, cpu_sar, 32);
+ tcg_gen_shl_i64(tmp, tcg_r, tmp);
+ } else {
+ tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
+ }
- cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
+ cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
return do_cbranch(ctx, a->disp, a->n, &cond);
}
static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
{
- TCGv_reg tmp, tcg_r;
+ TCGv_i64 tmp, tcg_r;
DisasCond cond;
+ int p;
nullify_over(ctx);
- tmp = tcg_temp_new();
+ tmp = tcg_temp_new_i64();
tcg_r = load_gpr(ctx, a->r);
- tcg_gen_shli_reg(tmp, tcg_r, a->p);
+ p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
+ tcg_gen_shli_i64(tmp, tcg_r, p);
cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
return do_cbranch(ctx, a->disp, a->n, &cond);
@@ -3088,178 +3357,246 @@ static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
static bool trans_movb(DisasContext *ctx, arg_movb *a)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
DisasCond cond;
nullify_over(ctx);
dest = dest_gpr(ctx, a->r2);
if (a->r1 == 0) {
- tcg_gen_movi_reg(dest, 0);
+ tcg_gen_movi_i64(dest, 0);
} else {
- tcg_gen_mov_reg(dest, cpu_gr[a->r1]);
+ tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
}
- cond = do_sed_cond(a->c, dest);
+ /* All MOVB conditions are 32-bit. */
+ cond = do_sed_cond(ctx, a->c, false, dest);
return do_cbranch(ctx, a->disp, a->n, &cond);
}
static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
DisasCond cond;
nullify_over(ctx);
dest = dest_gpr(ctx, a->r);
- tcg_gen_movi_reg(dest, a->i);
+ tcg_gen_movi_i64(dest, a->i);
- cond = do_sed_cond(a->c, dest);
+ /* All MOVBI conditions are 32-bit. */
+ cond = do_sed_cond(ctx, a->c, false, dest);
return do_cbranch(ctx, a->disp, a->n, &cond);
}
-static bool trans_shrpw_sar(DisasContext *ctx, arg_shrpw_sar *a)
+static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
{
- TCGv_reg dest;
+ TCGv_i64 dest, src2;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
dest = dest_gpr(ctx, a->t);
+ src2 = load_gpr(ctx, a->r2);
if (a->r1 == 0) {
- tcg_gen_ext32u_reg(dest, load_gpr(ctx, a->r2));
- tcg_gen_shr_reg(dest, dest, cpu_sar);
+ if (a->d) {
+ tcg_gen_shr_i64(dest, src2, cpu_sar);
+ } else {
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ tcg_gen_ext32u_i64(dest, src2);
+ tcg_gen_andi_i64(tmp, cpu_sar, 31);
+ tcg_gen_shr_i64(dest, dest, tmp);
+ }
} else if (a->r1 == a->r2) {
- TCGv_i32 t32 = tcg_temp_new_i32();
- tcg_gen_trunc_reg_i32(t32, load_gpr(ctx, a->r2));
- tcg_gen_rotr_i32(t32, t32, cpu_sar);
- tcg_gen_extu_i32_reg(dest, t32);
+ if (a->d) {
+ tcg_gen_rotr_i64(dest, src2, cpu_sar);
+ } else {
+ TCGv_i32 t32 = tcg_temp_new_i32();
+ TCGv_i32 s32 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t32, src2);
+ tcg_gen_extrl_i64_i32(s32, cpu_sar);
+ tcg_gen_andi_i32(s32, s32, 31);
+ tcg_gen_rotr_i32(t32, t32, s32);
+ tcg_gen_extu_i32_i64(dest, t32);
+ }
} else {
- TCGv_i64 t = tcg_temp_new_i64();
- TCGv_i64 s = tcg_temp_new_i64();
+ TCGv_i64 src1 = load_gpr(ctx, a->r1);
+
+ if (a->d) {
+ TCGv_i64 t = tcg_temp_new_i64();
+ TCGv_i64 n = tcg_temp_new_i64();
+
+ tcg_gen_xori_i64(n, cpu_sar, 63);
+ tcg_gen_shl_i64(t, src2, n);
+ tcg_gen_shli_i64(t, t, 1);
+ tcg_gen_shr_i64(dest, src1, cpu_sar);
+ tcg_gen_or_i64(dest, dest, t);
+ } else {
+ TCGv_i64 t = tcg_temp_new_i64();
+ TCGv_i64 s = tcg_temp_new_i64();
- tcg_gen_concat_reg_i64(t, load_gpr(ctx, a->r2), load_gpr(ctx, a->r1));
- tcg_gen_extu_reg_i64(s, cpu_sar);
- tcg_gen_shr_i64(t, t, s);
- tcg_gen_trunc_i64_reg(dest, t);
+ tcg_gen_concat32_i64(t, src2, src1);
+ tcg_gen_andi_i64(s, cpu_sar, 31);
+ tcg_gen_shr_i64(dest, t, s);
+ }
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
}
return nullify_end(ctx);
}
-static bool trans_shrpw_imm(DisasContext *ctx, arg_shrpw_imm *a)
+static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
{
- unsigned sa = 31 - a->cpos;
- TCGv_reg dest, t2;
+ unsigned width, sa;
+ TCGv_i64 dest, t2;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
+ width = a->d ? 64 : 32;
+ sa = width - 1 - a->cpos;
+
dest = dest_gpr(ctx, a->t);
t2 = load_gpr(ctx, a->r2);
if (a->r1 == 0) {
- tcg_gen_extract_reg(dest, t2, sa, 32 - sa);
- } else if (TARGET_REGISTER_BITS == 32) {
- tcg_gen_extract2_reg(dest, t2, cpu_gr[a->r1], sa);
- } else if (a->r1 == a->r2) {
- TCGv_i32 t32 = tcg_temp_new_i32();
- tcg_gen_trunc_reg_i32(t32, t2);
- tcg_gen_rotri_i32(t32, t32, sa);
- tcg_gen_extu_i32_reg(dest, t32);
+ tcg_gen_extract_i64(dest, t2, sa, width - sa);
+ } else if (width == TARGET_LONG_BITS) {
+ tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
} else {
- TCGv_i64 t64 = tcg_temp_new_i64();
- tcg_gen_concat_reg_i64(t64, t2, cpu_gr[a->r1]);
- tcg_gen_shri_i64(t64, t64, sa);
- tcg_gen_trunc_i64_reg(dest, t64);
+ assert(!a->d);
+ if (a->r1 == a->r2) {
+ TCGv_i32 t32 = tcg_temp_new_i32();
+ tcg_gen_extrl_i64_i32(t32, t2);
+ tcg_gen_rotri_i32(t32, t32, sa);
+ tcg_gen_extu_i32_i64(dest, t32);
+ } else {
+ tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
+ tcg_gen_extract_i64(dest, dest, sa, 32);
+ }
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
}
return nullify_end(ctx);
}
-static bool trans_extrw_sar(DisasContext *ctx, arg_extrw_sar *a)
+static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
{
- unsigned len = 32 - a->clen;
- TCGv_reg dest, src, tmp;
+ unsigned widthm1 = a->d ? 63 : 31;
+ TCGv_i64 dest, src, tmp;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
dest = dest_gpr(ctx, a->t);
src = load_gpr(ctx, a->r);
- tmp = tcg_temp_new();
+ tmp = tcg_temp_new_i64();
/* Recall that SAR is using big-endian bit numbering. */
- tcg_gen_xori_reg(tmp, cpu_sar, TARGET_REGISTER_BITS - 1);
+ tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
+ tcg_gen_xori_i64(tmp, tmp, widthm1);
+
if (a->se) {
- tcg_gen_sar_reg(dest, src, tmp);
- tcg_gen_sextract_reg(dest, dest, 0, len);
+ if (!a->d) {
+ tcg_gen_ext32s_i64(dest, src);
+ src = dest;
+ }
+ tcg_gen_sar_i64(dest, src, tmp);
+ tcg_gen_sextract_i64(dest, dest, 0, a->len);
} else {
- tcg_gen_shr_reg(dest, src, tmp);
- tcg_gen_extract_reg(dest, dest, 0, len);
+ if (!a->d) {
+ tcg_gen_ext32u_i64(dest, src);
+ src = dest;
+ }
+ tcg_gen_shr_i64(dest, src, tmp);
+ tcg_gen_extract_i64(dest, dest, 0, a->len);
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
}
return nullify_end(ctx);
}
-static bool trans_extrw_imm(DisasContext *ctx, arg_extrw_imm *a)
+static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
{
- unsigned len = 32 - a->clen;
- unsigned cpos = 31 - a->pos;
- TCGv_reg dest, src;
+ unsigned len, cpos, width;
+ TCGv_i64 dest, src;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
+ len = a->len;
+ width = a->d ? 64 : 32;
+ cpos = width - 1 - a->pos;
+ if (cpos + len > width) {
+ len = width - cpos;
+ }
+
dest = dest_gpr(ctx, a->t);
src = load_gpr(ctx, a->r);
if (a->se) {
- tcg_gen_sextract_reg(dest, src, cpos, len);
+ tcg_gen_sextract_i64(dest, src, cpos, len);
} else {
- tcg_gen_extract_reg(dest, src, cpos, len);
+ tcg_gen_extract_i64(dest, src, cpos, len);
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
}
return nullify_end(ctx);
}
-static bool trans_depwi_imm(DisasContext *ctx, arg_depwi_imm *a)
+static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
{
- unsigned len = 32 - a->clen;
- target_sreg mask0, mask1;
- TCGv_reg dest;
+ unsigned len, width;
+ uint64_t mask0, mask1;
+ TCGv_i64 dest;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
- if (a->cpos + len > 32) {
- len = 32 - a->cpos;
+
+ len = a->len;
+ width = a->d ? 64 : 32;
+ if (a->cpos + len > width) {
+ len = width - a->cpos;
}
dest = dest_gpr(ctx, a->t);
@@ -3267,110 +3604,122 @@ static bool trans_depwi_imm(DisasContext *ctx, arg_depwi_imm *a)
mask1 = deposit64(-1, a->cpos, len, a->i);
if (a->nz) {
- TCGv_reg src = load_gpr(ctx, a->t);
- if (mask1 != -1) {
- tcg_gen_andi_reg(dest, src, mask1);
- src = dest;
- }
- tcg_gen_ori_reg(dest, src, mask0);
+ TCGv_i64 src = load_gpr(ctx, a->t);
+ tcg_gen_andi_i64(dest, src, mask1);
+ tcg_gen_ori_i64(dest, dest, mask0);
} else {
- tcg_gen_movi_reg(dest, mask0);
+ tcg_gen_movi_i64(dest, mask0);
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
}
return nullify_end(ctx);
}
-static bool trans_depw_imm(DisasContext *ctx, arg_depw_imm *a)
+static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
{
unsigned rs = a->nz ? a->t : 0;
- unsigned len = 32 - a->clen;
- TCGv_reg dest, val;
+ unsigned len, width;
+ TCGv_i64 dest, val;
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
- if (a->cpos + len > 32) {
- len = 32 - a->cpos;
+
+ len = a->len;
+ width = a->d ? 64 : 32;
+ if (a->cpos + len > width) {
+ len = width - a->cpos;
}
dest = dest_gpr(ctx, a->t);
val = load_gpr(ctx, a->r);
if (rs == 0) {
- tcg_gen_deposit_z_reg(dest, val, a->cpos, len);
+ tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
} else {
- tcg_gen_deposit_reg(dest, cpu_gr[rs], val, a->cpos, len);
+ tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
}
save_gpr(ctx, a->t, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (a->c) {
- ctx->null_cond = do_sed_cond(a->c, dest);
+ ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
}
return nullify_end(ctx);
}
-static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c,
- unsigned nz, unsigned clen, TCGv_reg val)
+static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
+ bool d, bool nz, unsigned len, TCGv_i64 val)
{
unsigned rs = nz ? rt : 0;
- unsigned len = 32 - clen;
- TCGv_reg mask, tmp, shift, dest;
- unsigned msb = 1U << (len - 1);
+ unsigned widthm1 = d ? 63 : 31;
+ TCGv_i64 mask, tmp, shift, dest;
+ uint64_t msb = 1ULL << (len - 1);
dest = dest_gpr(ctx, rt);
- shift = tcg_temp_new();
- tmp = tcg_temp_new();
+ shift = tcg_temp_new_i64();
+ tmp = tcg_temp_new_i64();
/* Convert big-endian bit numbering in SAR to left-shift. */
- tcg_gen_xori_reg(shift, cpu_sar, TARGET_REGISTER_BITS - 1);
+ tcg_gen_andi_i64(shift, cpu_sar, widthm1);
+ tcg_gen_xori_i64(shift, shift, widthm1);
- mask = tcg_temp_new();
- tcg_gen_movi_reg(mask, msb + (msb - 1));
- tcg_gen_and_reg(tmp, val, mask);
+ mask = tcg_temp_new_i64();
+ tcg_gen_movi_i64(mask, msb + (msb - 1));
+ tcg_gen_and_i64(tmp, val, mask);
if (rs) {
- tcg_gen_shl_reg(mask, mask, shift);
- tcg_gen_shl_reg(tmp, tmp, shift);
- tcg_gen_andc_reg(dest, cpu_gr[rs], mask);
- tcg_gen_or_reg(dest, dest, tmp);
+ tcg_gen_shl_i64(mask, mask, shift);
+ tcg_gen_shl_i64(tmp, tmp, shift);
+ tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
+ tcg_gen_or_i64(dest, dest, tmp);
} else {
- tcg_gen_shl_reg(dest, tmp, shift);
+ tcg_gen_shl_i64(dest, tmp, shift);
}
save_gpr(ctx, rt, dest);
/* Install the new nullification. */
cond_free(&ctx->null_cond);
if (c) {
- ctx->null_cond = do_sed_cond(c, dest);
+ ctx->null_cond = do_sed_cond(ctx, c, d, dest);
}
return nullify_end(ctx);
}
-static bool trans_depw_sar(DisasContext *ctx, arg_depw_sar *a)
+static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
{
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
- return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_gpr(ctx, a->r));
+ return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
+ load_gpr(ctx, a->r));
}
-static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a)
+static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
{
+ if (!ctx->is_pa20 && a->d) {
+ return false;
+ }
if (a->c) {
nullify_over(ctx);
}
- return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i));
+ return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
+ tcg_constant_i64(a->i));
}
static bool trans_be(DisasContext *ctx, arg_be *a)
{
- TCGv_reg tmp;
+ TCGv_i64 tmp;
#ifdef CONFIG_USER_ONLY
/* ??? It seems like there should be a good way of using
@@ -3388,8 +3737,8 @@ static bool trans_be(DisasContext *ctx, arg_be *a)
nullify_over(ctx);
#endif
- tmp = get_temp(ctx);
- tcg_gen_addi_reg(tmp, load_gpr(ctx, a->b), a->disp);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
tmp = do_ibranch_priv(ctx, tmp);
#ifdef CONFIG_USER_ONLY
@@ -3399,20 +3748,21 @@ static bool trans_be(DisasContext *ctx, arg_be *a)
load_spr(ctx, new_spc, a->sp);
if (a->l) {
- copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
}
if (a->n && use_nullify_skip(ctx)) {
- tcg_gen_mov_reg(cpu_iaoq_f, tmp);
- tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
+ tcg_gen_addi_i64(tmp, tmp, 4);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
tcg_gen_mov_i64(cpu_iasq_f, new_spc);
tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
} else {
- copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
if (ctx->iaoq_b == -1) {
tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
}
- tcg_gen_mov_reg(cpu_iaoq_b, tmp);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
tcg_gen_mov_i64(cpu_iasq_b, new_spc);
nullify_set(ctx, a->n);
}
@@ -3429,7 +3779,7 @@ static bool trans_bl(DisasContext *ctx, arg_bl *a)
static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
{
- target_ureg dest = iaoq_dest(ctx, a->disp);
+ uint64_t dest = iaoq_dest(ctx, a->disp);
nullify_over(ctx);
@@ -3471,11 +3821,11 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
#endif
if (a->l) {
- TCGv_reg tmp = dest_gpr(ctx, a->l);
+ TCGv_i64 tmp = dest_gpr(ctx, a->l);
if (ctx->privilege < 3) {
- tcg_gen_andi_reg(tmp, tmp, -4);
+ tcg_gen_andi_i64(tmp, tmp, -4);
}
- tcg_gen_ori_reg(tmp, tmp, ctx->privilege);
+ tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
save_gpr(ctx, a->l, tmp);
}
@@ -3485,9 +3835,9 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
static bool trans_blr(DisasContext *ctx, arg_blr *a)
{
if (a->x) {
- TCGv_reg tmp = get_temp(ctx);
- tcg_gen_shli_reg(tmp, load_gpr(ctx, a->x), 3);
- tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
+ tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
/* The computation here never changes privilege level. */
return do_ibranch(ctx, tmp, a->l, a->n);
} else {
@@ -3498,14 +3848,14 @@ static bool trans_blr(DisasContext *ctx, arg_blr *a)
static bool trans_bv(DisasContext *ctx, arg_bv *a)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
if (a->x == 0) {
dest = load_gpr(ctx, a->b);
} else {
- dest = get_temp(ctx);
- tcg_gen_shli_reg(dest, load_gpr(ctx, a->x), 3);
- tcg_gen_add_reg(dest, dest, load_gpr(ctx, a->b));
+ dest = tcg_temp_new_i64();
+ tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
+ tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
}
dest = do_ibranch_priv(ctx, dest);
return do_ibranch(ctx, dest, 0, a->n);
@@ -3513,7 +3863,7 @@ static bool trans_bv(DisasContext *ctx, arg_bv *a)
static bool trans_bve(DisasContext *ctx, arg_bve *a)
{
- TCGv_reg dest;
+ TCGv_i64 dest;
#ifdef CONFIG_USER_ONLY
dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
@@ -3522,14 +3872,14 @@ static bool trans_bve(DisasContext *ctx, arg_bve *a)
nullify_over(ctx);
dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
- copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
if (ctx->iaoq_b == -1) {
tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
}
- copy_iaoq_entry(cpu_iaoq_b, -1, dest);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
if (a->l) {
- copy_iaoq_entry(cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
}
nullify_set(ctx, a->n);
tcg_gen_lookup_and_goto_ptr();
@@ -3538,6 +3888,12 @@ static bool trans_bve(DisasContext *ctx, arg_bve *a)
#endif
}
+static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
+{
+ /* All branch target stack instructions implement as nop. */
+ return ctx->is_pa20;
+}
+
/*
* Float class 0
*/
@@ -3551,7 +3907,7 @@ static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
{
uint64_t ret;
- if (TARGET_REGISTER_BITS == 64) {
+ if (ctx->is_pa20) {
ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
} else {
ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
@@ -3830,12 +4186,12 @@ static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
{
- TCGv_reg t;
+ TCGv_i64 t;
nullify_over(ctx);
- t = get_temp(ctx);
- tcg_gen_ld32u_reg(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
+ t = tcg_temp_new_i64();
+ tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
if (a->y == 1) {
int mask;
@@ -3843,7 +4199,7 @@ static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
switch (a->c) {
case 0: /* simple */
- tcg_gen_andi_reg(t, t, 0x4000000);
+ tcg_gen_andi_i64(t, t, 0x4000000);
ctx->null_cond = cond_make_0(TCG_COND_NE, t);
goto done;
case 2: /* rej */
@@ -3872,17 +4228,17 @@ static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
return true;
}
if (inv) {
- TCGv_reg c = load_const(ctx, mask);
- tcg_gen_or_reg(t, t, c);
+ TCGv_i64 c = tcg_constant_i64(mask);
+ tcg_gen_or_i64(t, t, c);
ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
} else {
- tcg_gen_andi_reg(t, t, mask);
+ tcg_gen_andi_i64(t, t, mask);
ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
}
} else {
unsigned cbit = (a->y ^ 1) - 1;
- tcg_gen_extract_reg(t, t, 21 - cbit, 1);
+ tcg_gen_extract_i64(t, t, 21 - cbit, 1);
ctx->null_cond = cond_make_0(TCG_COND_NE, t);
}
@@ -4062,6 +4418,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->cs = cs;
ctx->tb_flags = ctx->base.tb->flags;
+ ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
#ifdef CONFIG_USER_ONLY
ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
@@ -4071,8 +4428,9 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
#else
ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
- ctx->mmu_idx = (ctx->tb_flags & PSW_D ?
- PRIV_TO_MMU_IDX(ctx->privilege) : MMU_PHYS_IDX);
+ ctx->mmu_idx = (ctx->tb_flags & PSW_D
+ ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
+ : MMU_PHYS_IDX);
/* Recover the IAOQ values from the GVA + PRIV. */
uint64_t cs_base = ctx->base.tb->cs_base;
@@ -4085,14 +4443,11 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->iaoq_n = -1;
ctx->iaoq_n_var = NULL;
+ ctx->zero = tcg_constant_i64(0);
+
/* Bound the number of instructions by those left on the page. */
bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
-
- ctx->ntempr = 0;
- ctx->ntempl = 0;
- memset(ctx->tempr, 0, sizeof(ctx->tempr));
- memset(ctx->templ, 0, sizeof(ctx->templ));
}
static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
@@ -4113,7 +4468,8 @@ static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
- tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
+ tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
+ ctx->insn_start = tcg_last_op();
}
static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
@@ -4121,7 +4477,6 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUHPPAState *env = cpu_env(cs);
DisasJumpType ret;
- int i, n;
/* Execute one insn. */
#ifdef CONFIG_USER_ONLY
@@ -4140,8 +4495,8 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
This will be overwritten by a branch. */
if (ctx->iaoq_b == -1) {
ctx->iaoq_n = -1;
- ctx->iaoq_n_var = get_temp(ctx);
- tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
+ ctx->iaoq_n_var = tcg_temp_new_i64();
+ tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
} else {
ctx->iaoq_n = ctx->iaoq_b + 4;
ctx->iaoq_n_var = NULL;
@@ -4160,16 +4515,6 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
}
}
- /* Forget any temporaries allocated. */
- for (i = 0, n = ctx->ntempr; i < n; ++i) {
- ctx->tempr[i] = NULL;
- }
- for (i = 0, n = ctx->ntempl; i < n; ++i) {
- ctx->templ[i] = NULL;
- }
- ctx->ntempr = 0;
- ctx->ntempl = 0;
-
/* Advance the insn queue. Note that this check also detects
a priority change within the instruction queue. */
if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
@@ -4197,8 +4542,8 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
case DISAS_IAQ_N_STALE:
case DISAS_IAQ_N_STALE_EXIT:
if (ctx->iaoq_f == -1) {
- tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b);
- copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
#ifndef CONFIG_USER_ONLY
tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
#endif
@@ -4207,7 +4552,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
? DISAS_EXIT
: DISAS_IAQ_N_UPDATED);
} else if (ctx->iaoq_b == -1) {
- tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
}
break;
@@ -4227,8 +4572,8 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
case DISAS_TOO_MANY:
case DISAS_IAQ_N_STALE:
case DISAS_IAQ_N_STALE_EXIT:
- copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
- copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
+ copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
+ copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
nullify_save(ctx);
/* FALLTHRU */
case DISAS_IAQ_N_UPDATED:
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 770e81d..11b8177 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1837,6 +1837,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->eax |= XEN_HVM_CPUID_VCPU_ID_PRESENT;
c->ebx = cs->cpu_index;
}
+
+ if (cs->kvm_state->xen_version >= XEN_VERSION(4, 17)) {
+ c->eax |= XEN_HVM_CPUID_UPCALL_VECTOR;
+ }
}
r = kvm_xen_init_vcpu(cs);
diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c
index 75b2c55..c0631f9 100644
--- a/target/i386/kvm/xen-emu.c
+++ b/target/i386/kvm/xen-emu.c
@@ -28,6 +28,7 @@
#include "hw/i386/kvm/xen_overlay.h"
#include "hw/i386/kvm/xen_evtchn.h"
#include "hw/i386/kvm/xen_gnttab.h"
+#include "hw/i386/kvm/xen_primary_console.h"
#include "hw/i386/kvm/xen_xenstore.h"
#include "hw/xen/interface/version.h"
@@ -182,7 +183,8 @@ int kvm_xen_init(KVMState *s, uint32_t hypercall_msr)
return ret;
}
- /* The page couldn't be overlaid until KVM was initialized */
+ /* The pages couldn't be overlaid until KVM was initialized */
+ xen_primary_console_reset();
xen_xenstore_reset();
return 0;
@@ -812,11 +814,23 @@ static bool handle_get_param(struct kvm_xen_exit *exit, X86CPU *cpu,
case HVM_PARAM_STORE_EVTCHN:
hp.value = xen_xenstore_get_port();
break;
+ case HVM_PARAM_CONSOLE_PFN:
+ hp.value = xen_primary_console_get_pfn();
+ if (!hp.value) {
+ err = -EINVAL;
+ }
+ break;
+ case HVM_PARAM_CONSOLE_EVTCHN:
+ hp.value = xen_primary_console_get_port();
+ if (!hp.value) {
+ err = -EINVAL;
+ }
+ break;
default:
return false;
}
- if (kvm_copy_to_gva(cs, arg, &hp, sizeof(hp))) {
+ if (!err && kvm_copy_to_gva(cs, arg, &hp, sizeof(hp))) {
err = -EFAULT;
}
out:
@@ -1077,17 +1091,13 @@ static int vcpuop_stop_periodic_timer(CPUState *target)
* Must always be called with xen_timers_lock held.
*/
static int do_set_singleshot_timer(CPUState *cs, uint64_t timeout_abs,
- bool future, bool linux_wa)
+ bool linux_wa)
{
CPUX86State *env = &X86_CPU(cs)->env;
int64_t now = kvm_get_current_ns();
int64_t qemu_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
int64_t delta = timeout_abs - now;
- if (future && timeout_abs < now) {
- return -ETIME;
- }
-
if (linux_wa && unlikely((int64_t)timeout_abs < 0 ||
(delta > 0 && (uint32_t)(delta >> 50) != 0))) {
/*
@@ -1129,9 +1139,13 @@ static int vcpuop_set_singleshot_timer(CPUState *cs, uint64_t arg)
}
QEMU_LOCK_GUARD(&X86_CPU(cs)->env.xen_timers_lock);
- return do_set_singleshot_timer(cs, sst.timeout_abs_ns,
- !!(sst.flags & VCPU_SSHOTTMR_future),
- false);
+
+ /*
+ * We ignore the VCPU_SSHOTTMR_future flag, just as Xen now does.
+ * The only guest that ever used it, got it wrong.
+ * https://xenbits.xen.org/gitweb/?p=xen.git;a=commitdiff;h=19c6cbd909
+ */
+ return do_set_singleshot_timer(cs, sst.timeout_abs_ns, false);
}
static int vcpuop_stop_singleshot_timer(CPUState *cs)
@@ -1156,7 +1170,7 @@ static bool kvm_xen_hcall_set_timer_op(struct kvm_xen_exit *exit, X86CPU *cpu,
err = vcpuop_stop_singleshot_timer(CPU(cpu));
} else {
QEMU_LOCK_GUARD(&X86_CPU(cpu)->env.xen_timers_lock);
- err = do_set_singleshot_timer(CPU(cpu), timeout, false, true);
+ err = do_set_singleshot_timer(CPU(cpu), timeout, true);
}
exit->u.hcall.result = err;
return true;
@@ -1427,6 +1441,11 @@ int kvm_xen_soft_reset(void)
return err;
}
+ err = xen_primary_console_reset();
+ if (err) {
+ return err;
+ }
+
err = xen_xenstore_reset();
if (err) {
return err;
@@ -1844,7 +1863,7 @@ int kvm_put_xen_state(CPUState *cs)
QEMU_LOCK_GUARD(&env->xen_timers_lock);
if (env->xen_singleshot_timer_ns) {
ret = do_set_singleshot_timer(cs, env->xen_singleshot_timer_ns,
- false, false);
+ false);
if (ret < 0) {
return ret;
}