summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--MAINTAINERS8
-rw-r--r--audio/audio_template.h2
-rw-r--r--bootdevice.c73
-rw-r--r--exec.c13
-rw-r--r--hw/Makefile.objs1
-rw-r--r--hw/arm/boot.c98
-rw-r--r--hw/arm/exynos4210.c11
-rw-r--r--hw/arm/highbank.c12
-rw-r--r--hw/arm/integratorcp.c31
-rw-r--r--hw/arm/nseries.c2
-rw-r--r--hw/arm/pxa2xx.c4
-rw-r--r--hw/arm/realview.c14
-rw-r--r--hw/arm/versatilepb.c34
-rw-r--r--hw/arm/vexpress.c141
-rw-r--r--hw/arm/virt.c97
-rw-r--r--hw/arm/xilinx_zynq.c12
-rw-r--r--hw/core/loader.c30
-rw-r--r--hw/core/machine.c50
-rw-r--r--hw/i386/pc.c33
-rw-r--r--hw/i386/pc_piix.c2
-rw-r--r--hw/i386/pc_q35.c2
-rw-r--r--hw/input/milkymist-softusb.c19
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/nvram/fw_cfg.c250
-rw-r--r--hw/ppc/mac_newworld.c38
-rw-r--r--hw/ppc/mac_oldworld.c9
-rw-r--r--hw/ppc/prep.c2
-rw-r--r--hw/ppc/spapr.c6
-rw-r--r--hw/ppc/spapr_pci_vfio.c2
-rw-r--r--hw/sparc/sun4m.c6
-rw-r--r--hw/sparc64/sun4u.c6
-rw-r--r--hw/vfio/Makefile.objs4
-rw-r--r--hw/vfio/common.c959
-rw-r--r--hw/vfio/pci.c (renamed from hw/misc/vfio.c)1723
-rw-r--r--include/hw/arm/arm.h9
-rw-r--r--include/hw/boards.h2
-rw-r--r--include/hw/hw.h6
-rw-r--r--include/hw/loader.h9
-rw-r--r--include/hw/nvram/fw_cfg.h6
-rw-r--r--include/hw/vfio/vfio-common.h151
-rw-r--r--include/hw/vfio/vfio.h (renamed from include/hw/misc/vfio.h)0
-rw-r--r--include/qemu/typedefs.h2
-rw-r--r--include/sysemu/sysemu.h11
-rw-r--r--monitor.c14
-rw-r--r--target-arm/cpu-qom.h2
-rw-r--r--target-arm/cpu.c32
-rw-r--r--target-arm/helper.c55
-rw-r--r--target-tricore/helper.h59
-rw-r--r--target-tricore/op_helper.c1086
-rw-r--r--target-tricore/translate.c1034
-rw-r--r--target-tricore/tricore-opcodes.h19
-rw-r--r--trace-events81
-rw-r--r--vl.c208
54 files changed, 4639 insertions, 1844 deletions
diff --git a/LICENSE b/LICENSE
index da70e94932..0e0b4b9553 100644
--- a/LICENSE
+++ b/LICENSE
@@ -11,7 +11,7 @@ option) any later version.
As of July 2013, contributions under version 2 of the GNU General Public
License (and no later version) are only accepted for the following files
-or directories: bsd-user/, linux-user/, hw/misc/vfio.c, hw/xen/xen_pt*.
+or directories: bsd-user/, linux-user/, hw/vfio/, hw/xen/xen_pt*.
3) The Tiny Code Generator (TCG) is released under the BSD license
(see license headers in files).
diff --git a/MAINTAINERS b/MAINTAINERS
index d72d6e37d0..7fc3cdb1d6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -98,8 +98,12 @@ LM32
M: Michael Walle <michael@walle.cc>
S: Maintained
F: target-lm32/
+F: disas/lm32.c
F: hw/lm32/
-F: hw/char/lm32_*
+F: hw/*/lm32_*
+F: hw/*/milkymist-*
+F: include/hw/char/lm32_juart.h
+F: include/hw/lm32/
F: tests/tcg/lm32/
M68K
@@ -657,7 +661,7 @@ F: hw/usb/dev-serial.c
VFIO
M: Alex Williamson <alex.williamson@redhat.com>
S: Supported
-F: hw/misc/vfio.c
+F: hw/vfio/*
vhost
M: Michael S. Tsirkin <mst@redhat.com>
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 817318853c..584e536fac 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -191,9 +191,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
audio_detach_capture (hw);
#endif
QLIST_REMOVE (hw, entries);
+ glue (hw->pcm_ops->fini_, TYPE) (hw);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
- glue (hw->pcm_ops->fini_, TYPE) (hw);
g_free (hw);
*hwp = NULL;
}
diff --git a/bootdevice.c b/bootdevice.c
index b29970c7a3..5914417027 100644
--- a/bootdevice.c
+++ b/bootdevice.c
@@ -25,6 +25,7 @@
#include "sysemu/sysemu.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
+#include "hw/hw.h"
typedef struct FWBootEntry FWBootEntry;
@@ -37,6 +38,78 @@ struct FWBootEntry {
static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
QTAILQ_HEAD_INITIALIZER(fw_boot_order);
+static QEMUBootSetHandler *boot_set_handler;
+static void *boot_set_opaque;
+
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
+{
+ boot_set_handler = func;
+ boot_set_opaque = opaque;
+}
+
+void qemu_boot_set(const char *boot_order, Error **errp)
+{
+ Error *local_err = NULL;
+
+ if (!boot_set_handler) {
+ error_setg(errp, "no function defined to set boot device list for"
+ " this architecture");
+ return;
+ }
+
+ validate_bootdevices(boot_order, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ boot_set_handler(boot_set_opaque, boot_order, errp);
+}
+
+void validate_bootdevices(const char *devices, Error **errp)
+{
+ /* We just do some generic consistency checks */
+ const char *p;
+ int bitmap = 0;
+
+ for (p = devices; *p != '\0'; p++) {
+ /* Allowed boot devices are:
+ * a-b: floppy disk drives
+ * c-f: IDE disk drives
+ * g-m: machine implementation dependent drives
+ * n-p: network devices
+ * It's up to each machine implementation to check if the given boot
+ * devices match the actual hardware implementation and firmware
+ * features.
+ */
+ if (*p < 'a' || *p > 'p') {
+ error_setg(errp, "Invalid boot device '%c'", *p);
+ return;
+ }
+ if (bitmap & (1 << (*p - 'a'))) {
+ error_setg(errp, "Boot device '%c' was given twice", *p);
+ return;
+ }
+ bitmap |= 1 << (*p - 'a');
+ }
+}
+
+void restore_boot_order(void *opaque)
+{
+ char *normal_boot_order = opaque;
+ static int first = 1;
+
+ /* Restore boot order and remove ourselves after the first boot */
+ if (first) {
+ first = 0;
+ return;
+ }
+
+ qemu_boot_set(normal_boot_order, NULL);
+
+ qemu_unregister_reset(restore_boot_order, normal_boot_order);
+ g_free(normal_boot_order);
+}
void check_boot_index(int32_t bootindex, Error **errp)
{
diff --git a/exec.c b/exec.c
index c2ed10a2d6..9c3f3047d3 100644
--- a/exec.c
+++ b/exec.c
@@ -1768,7 +1768,7 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
unsigned len)
{
subpage_t *subpage = opaque;
- uint8_t buf[4];
+ uint8_t buf[8];
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
@@ -1782,6 +1782,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
return lduw_p(buf);
case 4:
return ldl_p(buf);
+ case 8:
+ return ldq_p(buf);
default:
abort();
}
@@ -1791,7 +1793,7 @@ static void subpage_write(void *opaque, hwaddr addr,
uint64_t value, unsigned len)
{
subpage_t *subpage = opaque;
- uint8_t buf[4];
+ uint8_t buf[8];
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
@@ -1808,6 +1810,9 @@ static void subpage_write(void *opaque, hwaddr addr,
case 4:
stl_p(buf, value);
break;
+ case 8:
+ stq_p(buf, value);
+ break;
default:
abort();
}
@@ -1830,6 +1835,10 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
static const MemoryRegionOps subpage_ops = {
.read = subpage_read,
.write = subpage_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 8,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
.valid.accepts = subpage_accepts,
.endianness = DEVICE_NATIVE_ENDIAN,
};
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 52a1464051..73afa41b32 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -26,6 +26,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += ssi/
devices-dirs-$(CONFIG_SOFTMMU) += timer/
devices-dirs-$(CONFIG_TPM) += tpm/
devices-dirs-$(CONFIG_SOFTMMU) += usb/
+devices-dirs-$(CONFIG_SOFTMMU) += vfio/
devices-dirs-$(CONFIG_VIRTIO) += virtio/
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index e6a3c5bcfb..52ebd8be9b 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -457,6 +457,16 @@ static void do_cpu_reset(void *opaque)
env->thumb = info->entry & 1;
}
} else {
+ /* If we are booting Linux then we need to check whether we are
+ * booting into secure or non-secure state and adjust the state
+ * accordingly. Out of reset, ARM is defined to be in secure state
+ * (SCR.NS = 0), we change that here if non-secure boot has been
+ * requested.
+ */
+ if (arm_feature(env, ARM_FEATURE_EL3) && !info->secure_boot) {
+ env->cp15.scr_el3 |= SCR_NS;
+ }
+
if (CPU(cpu) == first_cpu) {
if (env->aarch64) {
env->pc = info->loader_start;
@@ -478,6 +488,55 @@ static void do_cpu_reset(void *opaque)
}
}
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ * by key.
+ * @fw_cfg: The firmware config instance to store the data in.
+ * @size_key: The firmware config key to store the size of the loaded
+ * data under, with fw_cfg_add_i32().
+ * @data_key: The firmware config key to store the loaded data under,
+ * with fw_cfg_add_bytes().
+ * @image_name: The name of the image file to load. If it is NULL, the
+ * function returns without doing anything.
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
+ * adding it to fw_cfg. If decompression fails, the image is
+ * loaded as-is.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+ uint16_t data_key, const char *image_name,
+ bool try_decompress)
+{
+ size_t size = -1;
+ uint8_t *data;
+
+ if (image_name == NULL) {
+ return;
+ }
+
+ if (try_decompress) {
+ size = load_image_gzipped_buffer(image_name,
+ LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+ }
+
+ if (size == (size_t)-1) {
+ gchar *contents;
+ gsize length;
+
+ if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+ fprintf(stderr, "failed to load \"%s\"\n", image_name);
+ exit(1);
+ }
+ size = length;
+ data = (uint8_t *)contents;
+ }
+
+ fw_cfg_add_i32(fw_cfg, size_key, size);
+ fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
CPUState *cs;
@@ -500,19 +559,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
/* Load the kernel. */
- if (!info->kernel_filename) {
+ if (!info->kernel_filename || info->firmware_loaded) {
if (have_dtb(info)) {
- /* If we have a device tree blob, but no kernel to supply it to,
- * copy it to the base of RAM for a bootloader to pick up.
+ /* If we have a device tree blob, but no kernel to supply it to (or
+ * the kernel is supposed to be loaded by the bootloader), copy the
+ * DTB to the base of RAM for the bootloader to pick up.
*/
if (load_dtb(info->loader_start, info, 0) < 0) {
exit(1);
}
}
- /* If no kernel specified, do nothing; we will start from address 0
- * (typically a boot ROM image) in the same way as hardware.
+ if (info->kernel_filename) {
+ FWCfgState *fw_cfg;
+ bool try_decompressing_kernel;
+
+ fw_cfg = fw_cfg_find();
+ try_decompressing_kernel = arm_feature(&cpu->env,
+ ARM_FEATURE_AARCH64);
+
+ /* Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ try_decompressing_kernel);
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+
+ if (info->kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(info->kernel_cmdline) + 1);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+ info->kernel_cmdline);
+ }
+ }
+
+ /* We will start from address 0 (typically a boot ROM image) in the
+ * same way as hardware.
*/
return;
}
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 582794c19f..97dafca49a 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -152,6 +152,17 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ /* By default A9 CPUs have EL3 enabled. This board does not currently
+ * support EL3 so the CPU EL3 property is disabled before realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
s->cpu[n] = ARM_CPU(cpuobj);
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
"reset-cbar", &error_abort);
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 30f744a1bd..f67570a7ee 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -241,6 +241,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
cpuobj = object_new(object_class_get_name(oc));
cpu = ARM_CPU(cpuobj);
+ /* By default A9 and A15 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
"reset-cbar", &error_abort);
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 266ec18fb3..8c48b68a34 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -15,6 +15,7 @@
#include "net/net.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
#define TYPE_INTEGRATOR_CM "integrator_core"
#define INTEGRATOR_CM(obj) \
@@ -469,6 +470,8 @@ static void integratorcp_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
+ ObjectClass *cpu_oc;
+ Object *cpuobj;
ARMCPU *cpu;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -476,16 +479,40 @@ static void integratorcp_init(MachineState *machine)
qemu_irq pic[32];
DeviceState *dev;
int i;
+ Error *err = NULL;
if (!cpu_model) {
cpu_model = "arm926";
}
- cpu = cpu_arm_init(cpu_model);
- if (!cpu) {
+
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
+ if (!cpu_oc) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+ cpuobj = object_new(object_class_get_name(cpu_oc));
+
+ /* By default ARM1176 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
+ object_property_set_bool(cpuobj, true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ cpu = ARM_CPU(cpuobj);
+
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
vmstate_register_ram_global(ram);
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index c7ebaa6abc..4d7be5e740 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -1344,7 +1344,7 @@ static void n8x0_init(MachineState *machine,
n8x0_dss_setup(s);
n8x0_cbus_setup(s);
n8x0_uart_setup(s);
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
n8x0_usb_setup(s);
}
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 8967cc4e0b..165ba2a169 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -2143,7 +2143,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
sysbus_create_simple("sysbus-ohci", 0x4c000000,
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
}
@@ -2276,7 +2276,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
sysbus_create_simple("sysbus-ohci", 0x4c000000,
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
}
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index d41ec97a23..50cb93d8ac 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -101,6 +101,18 @@ static void realview_init(MachineState *machine,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ /* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
+ * does not currently support EL3 so the CPU EL3 property is disabled
+ * before realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
if (is_pb && is_mpcore) {
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
if (err) {
@@ -249,7 +261,7 @@ static void realview_init(MachineState *machine,
sysbus_connect_irq(busdev, 2, pic[50]);
sysbus_connect_irq(busdev, 3, pic[51]);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
n = drive_get_max_bus(IF_SCSI);
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index e6ef0a2e7e..b1dae77604 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -18,6 +18,7 @@
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/block/flash.h"
+#include "qemu/error-report.h"
#define VERSATILE_FLASH_ADDR 0x34000000
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
@@ -175,6 +176,8 @@ static struct arm_boot_info versatile_binfo;
static void versatile_init(MachineState *machine, int board_id)
{
+ ObjectClass *cpu_oc;
+ Object *cpuobj;
ARMCPU *cpu;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -189,15 +192,40 @@ static void versatile_init(MachineState *machine, int board_id)
int n;
int done_smc = 0;
DriveInfo *dinfo;
+ Error *err = NULL;
if (!machine->cpu_model) {
machine->cpu_model = "arm926";
}
- cpu = cpu_arm_init(machine->cpu_model);
- if (!cpu) {
+
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
+ if (!cpu_oc) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+
+ cpuobj = object_new(object_class_get_name(cpu_oc));
+
+ /* By default ARM1176 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
+ object_property_set_bool(cpuobj, true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ cpu = ARM_CPU(cpuobj);
+
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
&error_abort);
vmstate_register_ram_global(ram);
@@ -253,7 +281,7 @@ static void versatile_init(MachineState *machine, int board_id)
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
}
}
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
n = drive_get_max_bus(IF_SCSI);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 7cbd13f182..84415c8b0a 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -157,7 +157,27 @@ static hwaddr motherboard_aseries_map[] = {
typedef struct VEDBoardInfo VEDBoardInfo;
-typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
+typedef struct {
+ MachineClass parent;
+ VEDBoardInfo *daughterboard;
+} VexpressMachineClass;
+
+typedef struct {
+ MachineState parent;
+ bool secure;
+} VexpressMachineState;
+
+#define TYPE_VEXPRESS_MACHINE "vexpress"
+#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9"
+#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15"
+#define VEXPRESS_MACHINE(obj) \
+ OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
+#define VEXPRESS_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
+#define VEXPRESS_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
+
+typedef void DBoardInitFn(const VexpressMachineState *machine,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic);
@@ -176,7 +196,7 @@ struct VEDBoardInfo {
};
static void init_cpus(const char *cpu_model, const char *privdev,
- hwaddr periphbase, qemu_irq *pic)
+ hwaddr periphbase, qemu_irq *pic, bool secure)
{
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
DeviceState *dev;
@@ -193,6 +213,10 @@ static void init_cpus(const char *cpu_model, const char *privdev,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ if (!secure) {
+ object_property_set_bool(cpuobj, false, "has_el3", NULL);
+ }
+
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, periphbase,
"reset-cbar", &error_abort);
@@ -232,7 +256,7 @@ static void init_cpus(const char *cpu_model, const char *privdev,
}
}
-static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
+static void a9_daughterboard_init(const VexpressMachineState *vms,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic)
@@ -268,7 +292,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
memory_region_add_subregion(sysmem, 0x60000000, ram);
/* 0x1e000000 A9MPCore (SCU) private memory region */
- init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
+ init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
@@ -322,7 +346,7 @@ static VEDBoardInfo a9_daughterboard = {
.init = a9_daughterboard_init,
};
-static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
+static void a15_daughterboard_init(const VexpressMachineState *vms,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic)
@@ -354,7 +378,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
memory_region_add_subregion(sysmem, 0x80000000, ram);
/* 0x2c000000 A15MPCore private memory region (GIC) */
- init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
+ init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
/* A15 daughterboard peripherals: */
@@ -513,9 +537,11 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
}
-static void vexpress_common_init(VEDBoardInfo *daughterboard,
- MachineState *machine)
+static void vexpress_common_init(MachineState *machine)
{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
+ VEDBoardInfo *daughterboard = vmc->daughterboard;;
DeviceState *dev, *sysctl, *pl041;
qemu_irq pic[64];
uint32_t sys_id;
@@ -530,8 +556,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
const hwaddr *map = daughterboard->motherboard_map;
int i;
- daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
- pic);
+ daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
/*
* If a bios file was provided, attempt to map it into memory
@@ -678,39 +703,99 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
+ /* Indicate that when booting Linux we should be in secure state */
+ daughterboard->bootinfo.secure_boot = true;
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}
-static void vexpress_a9_init(MachineState *machine)
+static bool vexpress_get_secure(Object *obj, Error **errp)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ return vms->secure;
+}
+
+static void vexpress_set_secure(Object *obj, bool value, Error **errp)
{
- vexpress_common_init(&a9_daughterboard, machine);
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ vms->secure = value;
+}
+
+static void vexpress_instance_init(Object *obj)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ /* EL3 is enabled by default on vexpress */
+ vms->secure = true;
+ object_property_add_bool(obj, "secure", vexpress_get_secure,
+ vexpress_set_secure, NULL);
+ object_property_set_description(obj, "secure",
+ "Set on/off to enable/disable the ARM "
+ "Security Extensions (TrustZone)",
+ NULL);
}
-static void vexpress_a15_init(MachineState *machine)
+static void vexpress_class_init(ObjectClass *oc, void *data)
{
- vexpress_common_init(&a15_daughterboard, machine);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_MACHINE;
+ mc->desc = "ARM Versatile Express";
+ mc->init = vexpress_common_init;
+ mc->block_default_type = IF_SCSI;
+ mc->max_cpus = 4;
}
-static QEMUMachine vexpress_a9_machine = {
- .name = "vexpress-a9",
- .desc = "ARM Versatile Express for Cortex-A9",
- .init = vexpress_a9_init,
- .block_default_type = IF_SCSI,
- .max_cpus = 4,
+static void vexpress_a9_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_A9_MACHINE;
+ mc->desc = "ARM Versatile Express for Cortex-A9";
+
+ vmc->daughterboard = &a9_daughterboard;;
+}
+
+static void vexpress_a15_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_A15_MACHINE;
+ mc->desc = "ARM Versatile Express for Cortex-A15";
+
+ vmc->daughterboard = &a15_daughterboard;
+}
+
+static const TypeInfo vexpress_info = {
+ .name = TYPE_VEXPRESS_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(VexpressMachineState),
+ .instance_init = vexpress_instance_init,
+ .class_size = sizeof(VexpressMachineClass),
+ .class_init = vexpress_class_init,
+};
+
+static const TypeInfo vexpress_a9_info = {
+ .name = TYPE_VEXPRESS_A9_MACHINE,
+ .parent = TYPE_VEXPRESS_MACHINE,
+ .class_init = vexpress_a9_class_init,
};
-static QEMUMachine vexpress_a15_machine = {
- .name = "vexpress-a15",
- .desc = "ARM Versatile Express for Cortex-A15",
- .init = vexpress_a15_init,
- .block_default_type = IF_SCSI,
- .max_cpus = 4,
+static const TypeInfo vexpress_a15_info = {
+ .name = TYPE_VEXPRESS_A15_MACHINE,
+ .parent = TYPE_VEXPRESS_MACHINE,
+ .class_init = vexpress_a15_class_init,
};
static void vexpress_machine_init(void)
{
- qemu_register_machine(&vexpress_a9_machine);
- qemu_register_machine(&vexpress_a15_machine);
+ type_register_static(&vexpress_info);
+ type_register_static(&vexpress_a9_info);
+ type_register_static(&vexpress_a15_info);
}
machine_init(vexpress_machine_init);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 314e55b563..235344034d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -68,6 +68,7 @@ enum {
VIRT_UART,
VIRT_MMIO,
VIRT_RTC,
+ VIRT_FW_CFG,
};
typedef struct MemMapEntry {
@@ -86,6 +87,24 @@ typedef struct VirtBoardInfo {
uint32_t clock_phandle;
} VirtBoardInfo;
+typedef struct {
+ MachineClass parent;
+ VirtBoardInfo *daughterboard;
+} VirtMachineClass;
+
+typedef struct {
+ MachineState parent;
+ bool secure;
+} VirtMachineState;
+
+#define TYPE_VIRT_MACHINE "virt"
+#define VIRT_MACHINE(obj) \
+ OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
+#define VIRT_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
+#define VIRT_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
+
/* Addresses and sizes of our components.
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
* 128MB..256MB is used for miscellaneous device I/O.
@@ -107,6 +126,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
+ [VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
@@ -519,6 +539,23 @@ static void create_flash(const VirtBoardInfo *vbi)
g_free(nodename);
}
+static void create_fw_cfg(const VirtBoardInfo *vbi)
+{
+ hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
+ hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
+ char *nodename;
+
+ fw_cfg_init_mem_wide(base + 8, base, 8);
+
+ nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop_string(vbi->fdt, nodename,
+ "compatible", "qemu,fw-cfg-mmio");
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base, 2, size);
+ g_free(nodename);
+}
+
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -529,6 +566,7 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
static void machvirt_init(MachineState *machine)
{
+ VirtMachineState *vms = VIRT_MACHINE(machine);
qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory();
int n;
@@ -566,6 +604,10 @@ static void machvirt_init(MachineState *machine)
}
cpuobj = object_new(object_class_get_name(oc));
+ if (!vms->secure) {
+ object_property_set_bool(cpuobj, false, "has_el3", NULL);
+ }
+
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
NULL);
@@ -604,6 +646,8 @@ static void machvirt_init(MachineState *machine)
*/
create_virtio_devices(vbi, pic);
+ create_fw_cfg(vbi);
+
vbi->bootinfo.ram_size = machine->ram_size;
vbi->bootinfo.kernel_filename = machine->kernel_filename;
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
@@ -612,19 +656,60 @@ static void machvirt_init(MachineState *machine)
vbi->bootinfo.board_id = -1;
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
vbi->bootinfo.get_dtb = machvirt_dtb;
+ vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
}
-static QEMUMachine machvirt_a15_machine = {
- .name = "virt",
- .desc = "ARM Virtual Machine",
- .init = machvirt_init,
- .max_cpus = 8,
+static bool virt_get_secure(Object *obj, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ return vms->secure;
+}
+
+static void virt_set_secure(Object *obj, bool value, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ vms->secure = value;
+}
+
+static void virt_instance_init(Object *obj)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ /* EL3 is enabled by default on virt */
+ vms->secure = true;
+ object_property_add_bool(obj, "secure", virt_get_secure,
+ virt_set_secure, NULL);
+ object_property_set_description(obj, "secure",
+ "Set on/off to enable/disable the ARM "
+ "Security Extensions (TrustZone)",
+ NULL);
+}
+
+static void virt_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VIRT_MACHINE;
+ mc->desc = "ARM Virtual Machine",
+ mc->init = machvirt_init;
+ mc->max_cpus = 8;
+}
+
+static const TypeInfo machvirt_info = {
+ .name = TYPE_VIRT_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(VirtMachineState),
+ .instance_init = virt_instance_init,
+ .class_size = sizeof(VirtMachineClass),
+ .class_init = virt_class_init,
};
static void machvirt_machine_init(void)
{
- qemu_register_machine(&machvirt_a15_machine);
+ type_register_static(&machvirt_info);
}
machine_init(machvirt_machine_init);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index b59039297a..06e6e24da1 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -126,6 +126,18 @@ static void zynq_init(MachineState *machine)
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
+ /* By default A9 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
+ object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
if (err) {
error_report("%s", error_get_pretty(err));
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 7527fd3036..f2b34da240 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -614,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
NULL, NULL);
}
-/* This simply prevents g_malloc in the function below from allocating
- * a huge amount of memory, by placing a limit on the maximum
- * uncompressed image size that load_image_gzipped will read.
- */
-#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
-
-/* Load a gzip-compressed kernel. */
-int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+ uint8_t **buffer)
{
uint8_t *compressed_data = NULL;
uint8_t *data = NULL;
@@ -653,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
goto out;
}
- rom_add_blob_fixed(filename, data, bytes, addr);
+ /* trim to actual size and return to caller */
+ *buffer = g_realloc(data, bytes);
ret = bytes;
+ /* ownership has been transferred to caller */
+ data = NULL;
out:
g_free(compressed_data);
@@ -662,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
return ret;
}
+/* Load a gzip-compressed kernel. */
+int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+{
+ int bytes;
+ uint8_t *data;
+
+ bytes = load_image_gzipped_buffer(filename, max_sz, &data);
+ if (bytes != -1) {
+ rom_add_blob_fixed(filename, data, bytes, addr);
+ g_free(data);
+ }
+ return bytes;
+}
+
/*
* Functions for reboot-persistent memory regions.
* - used for vga bios and option roms.
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 19d3e3a707..fbd91be575 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -291,48 +291,93 @@ static void machine_initfn(Object *obj)
object_property_add_str(obj, "accel",
machine_get_accel, machine_set_accel, NULL);
+ object_property_set_description(obj, "accel",
+ "Accelerator list",
+ NULL);
object_property_add_bool(obj, "kernel-irqchip",
machine_get_kernel_irqchip,
machine_set_kernel_irqchip,
NULL);
+ object_property_set_description(obj, "kernel-irqchip",
+ "Use KVM in-kernel irqchip",
+ NULL);
object_property_add(obj, "kvm-shadow-mem", "int",
machine_get_kvm_shadow_mem,
machine_set_kvm_shadow_mem,
NULL, NULL, NULL);
+ object_property_set_description(obj, "kvm-shadow-mem",
+ "KVM shadow MMU size",
+ NULL);
object_property_add_str(obj, "kernel",
machine_get_kernel, machine_set_kernel, NULL);
+ object_property_set_description(obj, "kernel",
+ "Linux kernel image file",
+ NULL);
object_property_add_str(obj, "initrd",
machine_get_initrd, machine_set_initrd, NULL);
+ object_property_set_description(obj, "initrd",
+ "Linux initial ramdisk file",
+ NULL);
object_property_add_str(obj, "append",
machine_get_append, machine_set_append, NULL);
+ object_property_set_description(obj, "append",
+ "Linux kernel command line",
+ NULL);
object_property_add_str(obj, "dtb",
machine_get_dtb, machine_set_dtb, NULL);
+ object_property_set_description(obj, "dtb",
+ "Linux kernel device tree file",
+ NULL);
object_property_add_str(obj, "dumpdtb",
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
+ object_property_set_description(obj, "dumpdtb",
+ "Dump current dtb to a file and quit",
+ NULL);
object_property_add(obj, "phandle-start", "int",
machine_get_phandle_start,
machine_set_phandle_start,
NULL, NULL, NULL);
+ object_property_set_description(obj, "phandle-start",
+ "The first phandle ID we may generate dynamically",
+ NULL);
object_property_add_str(obj, "dt-compatible",
machine_get_dt_compatible,
machine_set_dt_compatible,
NULL);
+ object_property_set_description(obj, "dt-compatible",
+ "Overrides the \"compatible\" property of the dt root node",
+ NULL);
object_property_add_bool(obj, "dump-guest-core",
machine_get_dump_guest_core,
machine_set_dump_guest_core,
NULL);
+ object_property_set_description(obj, "dump-guest-core",
+ "Include guest memory in a core dump",
+ NULL);
object_property_add_bool(obj, "mem-merge",
machine_get_mem_merge,
machine_set_mem_merge, NULL);
+ object_property_set_description(obj, "mem-merge",
+ "Enable/disable memory merge support",
+ NULL);
object_property_add_bool(obj, "usb",
machine_get_usb,
machine_set_usb, NULL);
+ object_property_set_description(obj, "usb",
+ "Set on/off to enable/disable usb",
+ NULL);
object_property_add_str(obj, "firmware",
machine_get_firmware,
machine_set_firmware, NULL);
+ object_property_set_description(obj, "firmware",
+ "Firmware image",
+ NULL);
object_property_add_bool(obj, "iommu",
machine_get_iommu,
machine_set_iommu, NULL);
+ object_property_set_description(obj, "iommu",
+ "Set on/off to enable/disable Intel IOMMU (VT-d)",
+ NULL);
/* Register notifier when init is done for sysbus sanity checks */
ms->sysbus_notifier.notify = machine_init_notify;
@@ -353,6 +398,11 @@ static void machine_finalize(Object *obj)
g_free(ms->firmware);
}
+bool machine_usb(MachineState *machine)
+{
+ return machine->usb;
+}
+
static const TypeInfo machine_info = {
.name = TYPE_MACHINE,
.parent = TYPE_OBJECT,
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c0e55a6446..e07f1fac56 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -282,7 +282,7 @@ static int boot_device2nibble(char boot_device)
return 0;
}
-static int set_boot_dev(ISADevice *s, const char *boot_device)
+static void set_boot_dev(ISADevice *s, const char *boot_device, Error **errp)
{
#define PC_MAX_BOOT_DEVICES 3
int nbds, bds[3] = { 0, };
@@ -290,25 +290,24 @@ static int set_boot_dev(ISADevice *s, const char *boot_device)
nbds = strlen(boot_device);
if (nbds > PC_MAX_BOOT_DEVICES) {
- error_report("Too many boot devices for PC");
- return(1);
+ error_setg(errp, "Too many boot devices for PC");
+ return;
}
for (i = 0; i < nbds; i++) {
bds[i] = boot_device2nibble(boot_device[i]);
if (bds[i] == 0) {
- error_report("Invalid boot device for PC: '%c'",
- boot_device[i]);
- return(1);
+ error_setg(errp, "Invalid boot device for PC: '%c'",
+ boot_device[i]);
+ return;
}
}
rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
- return(0);
}
-static int pc_boot_set(void *opaque, const char *boot_device)
+static void pc_boot_set(void *opaque, const char *boot_device, Error **errp)
{
- return set_boot_dev(opaque, boot_device);
+ set_boot_dev(opaque, boot_device, errp);
}
typedef struct pc_cmos_init_late_arg {
@@ -365,6 +364,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
static pc_cmos_init_late_arg arg;
PCMachineState *pc_machine = PC_MACHINE(machine);
+ Error *local_err = NULL;
/* various important CMOS locations needed by PC/Bochs bios */
@@ -412,7 +412,9 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
object_property_set_link(OBJECT(machine), OBJECT(s),
"rtc_state", &error_abort);
- if (set_boot_dev(s, boot_device)) {
+ set_boot_dev(s, boot_device, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
exit(1);
}
@@ -647,7 +649,7 @@ static FWCfgState *bochs_bios_init(void)
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
*
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
@@ -1168,7 +1170,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename,
assert(kernel_filename != NULL);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
rom_set_fw(fw_cfg);
load_linux(fw_cfg, kernel_filename, initrd_filename,
@@ -1803,17 +1805,24 @@ static void pc_machine_initfn(Object *obj)
object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
pc_machine_get_hotplug_memory_region_size,
NULL, NULL, NULL, NULL);
+
pcms->max_ram_below_4g = 1ULL << 32; /* 4G */
object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
pc_machine_get_max_ram_below_4g,
pc_machine_set_max_ram_below_4g,
NULL, NULL, NULL);
+ object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G,
+ "Maximum ram below the 4G boundary (32bit boundary)",
+ NULL);
pcms->vmport = ON_OFF_AUTO_AUTO;
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
pc_machine_get_vmport,
pc_machine_set_vmport,
NULL, NULL, NULL);
+ object_property_set_description(obj, PC_MACHINE_VMPORT,
+ "Enable vmport (pc & q35)",
+ NULL);
pcms->enforce_aligned_dimm = true;
object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 220f7415fa..f0a3201e19 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -274,7 +274,7 @@ static void pc_init1(MachineState *machine,
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
machine, floppy, idebus[0], idebus[1], rtc_state);
- if (pci_enabled && usb_enabled(false)) {
+ if (pci_enabled && usb_enabled()) {
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 7ba05353aa..a432944f02 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -265,7 +265,7 @@ static void pc_q35_init(MachineState *machine)
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
ahci_ide_create_devs(ahci, hd);
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
/* Should we create 6 UHCI according to ich9 spec? */
ehci_create_ich9_with_companions(host_bus, 0x1d);
}
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
index 5a427f0b33..7b0f4db88d 100644
--- a/hw/input/milkymist-softusb.c
+++ b/hw/input/milkymist-softusb.c
@@ -194,10 +194,13 @@ static void softusb_kbd_hid_datain(HIDState *hs)
return;
}
- len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
+ while (hid_has_events(hs)) {
+ len = hid_keyboard_poll(hs, s->kbd_hid_buffer,
+ sizeof(s->kbd_hid_buffer));
- if (len == 8) {
- softusb_kbd_changed(s);
+ if (len == 8) {
+ softusb_kbd_changed(s);
+ }
}
}
@@ -212,11 +215,13 @@ static void softusb_mouse_hid_datain(HIDState *hs)
return;
}
- len = hid_pointer_poll(hs, s->mouse_hid_buffer,
- sizeof(s->mouse_hid_buffer));
+ while (hid_has_events(hs)) {
+ len = hid_pointer_poll(hs, s->mouse_hid_buffer,
+ sizeof(s->mouse_hid_buffer));
- if (len == 4) {
- softusb_mouse_changed(s);
+ if (len == 4) {
+ softusb_mouse_changed(s);
+ }
}
}
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 979e532fdf..e47fea8530 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -21,7 +21,6 @@ common-obj-$(CONFIG_MACIO) += macio/
ifeq ($(CONFIG_PCI), y)
obj-$(CONFIG_KVM) += ivshmem.o
-obj-$(CONFIG_LINUX) += vfio.o
endif
obj-$(CONFIG_REALVIEW) += arm_sysctl.o
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index c4b78ed36c..fcdf821c31 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -31,11 +31,16 @@
#include "qemu/config-file.h"
#define FW_CFG_SIZE 2
-#define FW_CFG_DATA_SIZE 1
-#define TYPE_FW_CFG "fw_cfg"
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
-#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
+
+#define TYPE_FW_CFG "fw_cfg"
+#define TYPE_FW_CFG_IO "fw_cfg_io"
+#define TYPE_FW_CFG_MEM "fw_cfg_mem"
+
+#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
+#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
+#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
typedef struct FWCfgEntry {
uint32_t len;
@@ -50,8 +55,6 @@ struct FWCfgState {
SysBusDevice parent_obj;
/*< public >*/
- MemoryRegion ctl_iomem, data_iomem, comb_iomem;
- uint32_t ctl_iobase, data_iobase;
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
FWCfgFiles *files;
uint16_t cur_entry;
@@ -59,6 +62,25 @@ struct FWCfgState {
Notifier machine_ready;
};
+struct FWCfgIoState {
+ /*< private >*/
+ FWCfgState parent_obj;
+ /*< public >*/
+
+ MemoryRegion comb_iomem;
+ uint32_t iobase;
+};
+
+struct FWCfgMemState {
+ /*< private >*/
+ FWCfgState parent_obj;
+ /*< public >*/
+
+ MemoryRegion ctl_iomem, data_iomem;
+ uint32_t data_width;
+ MemoryRegionOps wide_data_ops;
+};
+
#define JPG_FILE 0
#define BMP_FILE 1
@@ -264,13 +286,58 @@ static uint8_t fw_cfg_read(FWCfgState *s)
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
unsigned size)
{
- return fw_cfg_read(opaque);
+ FWCfgState *s = opaque;
+ uint8_t buf[8];
+ unsigned i;
+
+ for (i = 0; i < size; ++i) {
+ buf[i] = fw_cfg_read(s);
+ }
+ switch (size) {
+ case 1:
+ return buf[0];
+ case 2:
+ return lduw_he_p(buf);
+ case 4:
+ return (uint32_t)ldl_he_p(buf);
+ case 8:
+ return ldq_he_p(buf);
+ }
+ abort();
}
static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- fw_cfg_write(opaque, (uint8_t)value);
+ FWCfgState *s = opaque;
+ uint8_t buf[8];
+ unsigned i;
+
+ switch (size) {
+ case 1:
+ buf[0] = value;
+ break;
+ case 2:
+ stw_he_p(buf, value);
+ break;
+ case 4:
+ stl_he_p(buf, value);
+ break;
+ case 8:
+ stq_he_p(buf, value);
+ break;
+ default:
+ abort();
+ }
+ for (i = 0; i < size; ++i) {
+ fw_cfg_write(s, buf[i]);
+ }
+}
+
+static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
+ unsigned size, bool is_write)
+{
+ return addr == 0;
}
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
@@ -312,17 +379,18 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
.write = fw_cfg_ctl_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid.accepts = fw_cfg_ctl_mem_valid,
};
static const MemoryRegionOps fw_cfg_data_mem_ops = {
.read = fw_cfg_data_mem_read,
.write = fw_cfg_data_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 1,
+ .accepts = fw_cfg_data_mem_valid,
},
};
@@ -560,19 +628,11 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
qemu_register_reset(fw_cfg_machine_reset, s);
}
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
- hwaddr ctl_addr, hwaddr data_addr)
-{
- DeviceState *dev;
- SysBusDevice *d;
- FWCfgState *s;
- dev = qdev_create(NULL, TYPE_FW_CFG);
- qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
- qdev_prop_set_uint32(dev, "data_iobase", data_port);
- d = SYS_BUS_DEVICE(dev);
- s = FW_CFG(dev);
+static void fw_cfg_init1(DeviceState *dev)
+{
+ FWCfgState *s = FW_CFG(dev);
assert(!object_resolve_path(FW_CFG_PATH, NULL));
@@ -580,12 +640,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
qdev_init_nofail(dev);
- if (ctl_addr) {
- sysbus_mmio_map(d, 0, ctl_addr);
- }
- if (data_addr) {
- sysbus_mmio_map(d, 1, data_addr);
- }
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
@@ -596,48 +650,43 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
s->machine_ready.notify = fw_cfg_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);
-
- return s;
}
-static void fw_cfg_initfn(Object *obj)
+FWCfgState *fw_cfg_init_io(uint32_t iobase)
{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- FWCfgState *s = FW_CFG(obj);
+ DeviceState *dev;
- memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, s,
- "fwcfg.ctl", FW_CFG_SIZE);
- sysbus_init_mmio(sbd, &s->ctl_iomem);
- memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, s,
- "fwcfg.data", FW_CFG_DATA_SIZE);
- sysbus_init_mmio(sbd, &s->data_iomem);
- /* In case ctl and data overlap: */
- memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, s,
- "fwcfg", FW_CFG_SIZE);
+ dev = qdev_create(NULL, TYPE_FW_CFG_IO);
+ qdev_prop_set_uint32(dev, "iobase", iobase);
+ fw_cfg_init1(dev);
+
+ return FW_CFG(dev);
}
-static void fw_cfg_realize(DeviceState *dev, Error **errp)
+FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
+ uint32_t data_width)
{
- FWCfgState *s = FW_CFG(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ DeviceState *dev;
+ SysBusDevice *sbd;
- if (s->ctl_iobase + 1 == s->data_iobase) {
- sysbus_add_io(sbd, s->ctl_iobase, &s->comb_iomem);
- } else {
- if (s->ctl_iobase) {
- sysbus_add_io(sbd, s->ctl_iobase, &s->ctl_iomem);
- }
- if (s->data_iobase) {
- sysbus_add_io(sbd, s->data_iobase, &s->data_iomem);
- }
- }
+ dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
+ qdev_prop_set_uint32(dev, "data_width", data_width);
+
+ fw_cfg_init1(dev);
+
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbd, 0, ctl_addr);
+ sysbus_mmio_map(sbd, 1, data_addr);
+
+ return FW_CFG(dev);
+}
+
+FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
+{
+ return fw_cfg_init_mem_wide(ctl_addr, data_addr,
+ fw_cfg_data_mem_ops.valid.max_access_size);
}
-static Property fw_cfg_properties[] = {
- DEFINE_PROP_UINT32("ctl_iobase", FWCfgState, ctl_iobase, -1),
- DEFINE_PROP_UINT32("data_iobase", FWCfgState, data_iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
FWCfgState *fw_cfg_find(void)
{
@@ -648,23 +697,102 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = fw_cfg_realize;
dc->reset = fw_cfg_reset;
dc->vmsd = &vmstate_fw_cfg;
- dc->props = fw_cfg_properties;
}
static const TypeInfo fw_cfg_info = {
.name = TYPE_FW_CFG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FWCfgState),
- .instance_init = fw_cfg_initfn,
.class_init = fw_cfg_class_init,
};
+
+static Property fw_cfg_io_properties[] = {
+ DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
+{
+ FWCfgIoState *s = FW_CFG_IO(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
+ FW_CFG(s), "fwcfg", FW_CFG_SIZE);
+ sysbus_add_io(sbd, s->iobase, &s->comb_iomem);
+}
+
+static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = fw_cfg_io_realize;
+ dc->props = fw_cfg_io_properties;
+}
+
+static const TypeInfo fw_cfg_io_info = {
+ .name = TYPE_FW_CFG_IO,
+ .parent = TYPE_FW_CFG,
+ .instance_size = sizeof(FWCfgIoState),
+ .class_init = fw_cfg_io_class_init,
+};
+
+
+static Property fw_cfg_mem_properties[] = {
+ DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
+{
+ FWCfgMemState *s = FW_CFG_MEM(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
+
+ memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
+ FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE);
+ sysbus_init_mmio(sbd, &s->ctl_iomem);
+
+ if (s->data_width > data_ops->valid.max_access_size) {
+ /* memberwise copy because the "old_mmio" member is const */
+ s->wide_data_ops.read = data_ops->read;
+ s->wide_data_ops.write = data_ops->write;
+ s->wide_data_ops.endianness = data_ops->endianness;
+ s->wide_data_ops.valid = data_ops->valid;
+ s->wide_data_ops.impl = data_ops->impl;
+
+ s->wide_data_ops.valid.max_access_size = s->data_width;
+ s->wide_data_ops.impl.max_access_size = s->data_width;
+ data_ops = &s->wide_data_ops;
+ }
+ memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s),
+ "fwcfg.data", data_ops->valid.max_access_size);
+ sysbus_init_mmio(sbd, &s->data_iomem);
+}
+
+static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = fw_cfg_mem_realize;
+ dc->props = fw_cfg_mem_properties;
+}
+
+static const TypeInfo fw_cfg_mem_info = {
+ .name = TYPE_FW_CFG_MEM,
+ .parent = TYPE_FW_CFG,
+ .instance_size = sizeof(FWCfgMemState),
+ .class_init = fw_cfg_mem_class_init,
+};
+
+
static void fw_cfg_register_types(void)
{
type_register_static(&fw_cfg_info);
+ type_register_static(&fw_cfg_io_info);
+ type_register_static(&fw_cfg_mem_info);
}
type_init(fw_cfg_register_types)
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 89aee716d4..c3770121e2 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -116,10 +116,10 @@ static const MemoryRegionOps unin_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+ Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
- return 0;
}
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
@@ -371,6 +371,7 @@ static void ppc_core99_init(MachineState *machine)
/* 970 gets a U3 bus */
pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
machine_arch = ARCH_MAC99_U3;
+ machine->usb |= defaults_enabled();
} else {
pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
machine_arch = ARCH_MAC99;
@@ -417,7 +418,7 @@ static void ppc_core99_init(MachineState *machine)
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
qdev_init_nofail(dev);
- if (usb_enabled(machine_arch == ARCH_MAC99_U3)) {
+ if (machine->usb) {
pci_create_simple(pci_bus, -1, "pci-ohci");
/* U3 needs to use USB for input because Linux doesn't support via-cuda
on PPC64 */
@@ -454,7 +455,7 @@ static void ppc_core99_init(MachineState *machine)
pmac_format_nvram_partition(nvr, 0x2000);
/* No PCI init: the BIOS will do it */
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
@@ -501,18 +502,27 @@ static int core99_kvm_type(const char *arg)
return 2;
}
-static QEMUMachine core99_machine = {
- .name = "mac99",
- .desc = "Mac99 based PowerMAC",
- .init = ppc_core99_init,
- .max_cpus = MAX_CPUS,
- .default_boot_order = "cd",
- .kvm_type = core99_kvm_type,
+static void core99_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = "mac99";
+ mc->desc = "Mac99 based PowerMAC";
+ mc->init = ppc_core99_init;
+ mc->max_cpus = MAX_CPUS;
+ mc->default_boot_order = "cd";
+ mc->kvm_type = core99_kvm_type;
+}
+
+static const TypeInfo core99_machine_info = {
+ .name = "mac99-machine",
+ .parent = TYPE_MACHINE,
+ .class_init = core99_machine_class_init,
};
-static void core99_machine_init(void)
+static void mac_machine_register_types(void)
{
- qemu_register_machine(&core99_machine);
+ type_register_static(&core99_machine_info);
}
-machine_init(core99_machine_init);
+type_init(mac_machine_register_types)
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 32c21a4286..3079510058 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -49,13 +49,12 @@
#define CLOCKFREQ 266000000UL
#define BUSFREQ 66000000UL
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+ Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
- return 0;
}
-
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
{
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
@@ -305,7 +304,7 @@ static void ppc_heathrow_init(MachineState *machine)
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
qdev_init_nofail(dev);
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
@@ -314,7 +313,7 @@ static void ppc_heathrow_init(MachineState *machine)
/* No PCI init: the BIOS will do it */
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index dd8433d0c9..15df7f3dae 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -539,7 +539,7 @@ static void ppc_prep_init(MachineState *machine)
memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
#endif
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 30de25de5c..53c4116ed3 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1484,9 +1484,10 @@ static void ppc_spapr_init(MachineState *machine)
/* Graphics */
if (spapr_vga_init(phb->bus)) {
spapr->has_graphics = true;
+ machine->usb |= defaults_enabled();
}
- if (usb_enabled(spapr->has_graphics)) {
+ if (machine->usb) {
pci_create_simple(phb->bus, -1, "pci-ohci");
if (spapr->has_graphics) {
usbdevice_create("keyboard");
@@ -1655,6 +1656,9 @@ static void spapr_machine_initfn(Object *obj)
{
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
+ object_property_set_description(obj, "kvm-type",
+ "Specifies the KVM virtualization mode (HV, PR)",
+ NULL);
}
static void ppc_cpu_do_nmi_on_cpu(void *arg)
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
index d3bddf2887..144912bf54 100644
--- a/hw/ppc/spapr_pci_vfio.c
+++ b/hw/ppc/spapr_pci_vfio.c
@@ -20,7 +20,7 @@
#include "hw/ppc/spapr.h"
#include "hw/pci-host/spapr.h"
#include "linux/vfio.h"
-#include "hw/misc/vfio.h"
+#include "hw/vfio/vfio.h"
static Property spapr_phb_vfio_properties[] = {
DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1),
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 8273199f11..ecd9dc1414 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -121,10 +121,10 @@ void DMA_register_channel (int nchan,
{
}
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+ Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
- return 0;
}
static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
@@ -1084,7 +1084,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
ecc_init(hwdef->ecc_base, slavio_irq[28],
hwdef->ecc_version);
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index f42112c1b2..3ff5bd8871 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -124,10 +124,10 @@ void DMA_register_channel (int nchan,
{
}
-static int fw_cfg_boot_set(void *opaque, const char *boot_device)
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+ Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
- return 0;
}
static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
@@ -892,7 +892,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
graphic_width, graphic_height, graphic_depth,
(uint8_t *)&nd_table[0].macaddr);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs
new file mode 100644
index 0000000000..e31f30ec09
--- /dev/null
+++ b/hw/vfio/Makefile.objs
@@ -0,0 +1,4 @@
+ifeq ($(CONFIG_LINUX), y)
+obj-$(CONFIG_SOFTMMU) += common.o
+obj-$(CONFIG_PCI) += pci.o
+endif
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
new file mode 100644
index 0000000000..cf483fffa9
--- /dev/null
+++ b/hw/vfio/common.c
@@ -0,0 +1,959 @@
+/*
+ * generic functions used by VFIO devices
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on qemu-kvm device-assignment:
+ * Adapted for KVM by Qumranet.
+ * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/vfio.h>
+
+#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/hw.h"
+#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
+#include "trace.h"
+
+struct vfio_group_head vfio_group_list =
+ QLIST_HEAD_INITIALIZER(vfio_address_spaces);
+struct vfio_as_head vfio_address_spaces =
+ QLIST_HEAD_INITIALIZER(vfio_address_spaces);
+
+#ifdef CONFIG_KVM
+/*
+ * We have a single VFIO pseudo device per KVM VM. Once created it lives
+ * for the life of the VM. Closing the file descriptor only drops our
+ * reference to it and the device's reference to kvm. Therefore once
+ * initialized, this file descriptor is only released on QEMU exit and
+ * we'll re-use it should another vfio device be attached before then.
+ */
+static int vfio_kvm_device_fd = -1;
+#endif
+
+/*
+ * Common VFIO interrupt disable
+ */
+void vfio_disable_irqindex(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
+ .index = index,
+ .start = 0,
+ .count = 0,
+ };
+
+ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+
+void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+
+ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+
+void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+
+ ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+
+/*
+ * IO Port/MMIO - Beware of the endians, VFIO is always little endian
+ */
+void vfio_region_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIORegion *region = opaque;
+ VFIODevice *vbasedev = region->vbasedev;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+
+ switch (size) {
+ case 1:
+ buf.byte = data;
+ break;
+ case 2:
+ buf.word = cpu_to_le16(data);
+ break;
+ case 4:
+ buf.dword = cpu_to_le32(data);
+ break;
+ default:
+ hw_error("vfio: unsupported write size, %d bytes", size);
+ break;
+ }
+
+ if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
+ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64
+ ",%d) failed: %m",
+ __func__, vbasedev->name, region->nr,
+ addr, data, size);
+ }
+
+ trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size);
+
+ /*
+ * A read or write to a BAR always signals an INTx EOI. This will
+ * do nothing if not pending (including not in INTx mode). We assume
+ * that a BAR access is in response to an interrupt and that BAR
+ * accesses will service the interrupt. Unfortunately, we don't know
+ * which access will service the interrupt, so we're potentially
+ * getting quite a few host interrupts per guest interrupt.
+ */
+ vbasedev->ops->vfio_eoi(vbasedev);
+}
+
+uint64_t vfio_region_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIORegion *region = opaque;
+ VFIODevice *vbasedev = region->vbasedev;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ uint64_t data = 0;
+
+ if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
+ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m",
+ __func__, vbasedev->name, region->nr,
+ addr, size);
+ return (uint64_t)-1;
+ }
+ switch (size) {
+ case 1:
+ data = buf.byte;
+ break;
+ case 2:
+ data = le16_to_cpu(buf.word);
+ break;
+ case 4:
+ data = le32_to_cpu(buf.dword);
+ break;
+ default:
+ hw_error("vfio: unsupported read size, %d bytes", size);
+ break;
+ }
+
+ trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data);
+
+ /* Same as write above */
+ vbasedev->ops->vfio_eoi(vbasedev);
+
+ return data;
+}
+
+const MemoryRegionOps vfio_region_ops = {
+ .read = vfio_region_read,
+ .write = vfio_region_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
+ */
+static int vfio_dma_unmap(VFIOContainer *container,
+ hwaddr iova, ram_addr_t size)
+{
+ struct vfio_iommu_type1_dma_unmap unmap = {
+ .argsz = sizeof(unmap),
+ .flags = 0,
+ .iova = iova,
+ .size = size,
+ };
+
+ if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
+ error_report("VFIO_UNMAP_DMA: %d\n", -errno);
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
+ ram_addr_t size, void *vaddr, bool readonly)
+{
+ struct vfio_iommu_type1_dma_map map = {
+ .argsz = sizeof(map),
+ .flags = VFIO_DMA_MAP_FLAG_READ,
+ .vaddr = (__u64)(uintptr_t)vaddr,
+ .iova = iova,
+ .size = size,
+ };
+
+ if (!readonly) {
+ map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
+ }
+
+ /*
+ * Try the mapping, if it fails with EBUSY, unmap the region and try
+ * again. This shouldn't be necessary, but we sometimes see it in
+ * the the VGA ROM space.
+ */
+ if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
+ (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
+ ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
+ return 0;
+ }
+
+ error_report("VFIO_MAP_DMA: %d\n", -errno);
+ return -errno;
+}
+
+static bool vfio_listener_skipped_section(MemoryRegionSection *section)
+{
+ return (!memory_region_is_ram(section->mr) &&
+ !memory_region_is_iommu(section->mr)) ||
+ /*
+ * Sizing an enabled 64-bit BAR can cause spurious mappings to
+ * addresses in the upper part of the 64-bit address space. These
+ * are never accessed by the CPU and beyond the address width of
+ * some IOMMU hardware. TODO: VFIO should tell us the IOMMU width.
+ */
+ section->offset_within_address_space & (1ULL << 63);
+}
+
+static void vfio_iommu_map_notify(Notifier *n, void *data)
+{
+ VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
+ VFIOContainer *container = giommu->container;
+ IOMMUTLBEntry *iotlb = data;
+ MemoryRegion *mr;
+ hwaddr xlat;
+ hwaddr len = iotlb->addr_mask + 1;
+ void *vaddr;
+ int ret;
+
+ trace_vfio_iommu_map_notify(iotlb->iova,
+ iotlb->iova + iotlb->addr_mask);
+
+ /*
+ * The IOMMU TLB entry we have just covers translation through
+ * this IOMMU to its immediate target. We need to translate
+ * it the rest of the way through to memory.
+ */
+ mr = address_space_translate(&address_space_memory,
+ iotlb->translated_addr,
+ &xlat, &len, iotlb->perm & IOMMU_WO);
+ if (!memory_region_is_ram(mr)) {
+ error_report("iommu map to non memory area %"HWADDR_PRIx"\n",
+ xlat);
+ return;
+ }
+ /*
+ * Translation truncates length to the IOMMU page size,
+ * check that it did not truncate too much.
+ */
+ if (len & iotlb->addr_mask) {
+ error_report("iommu has granularity incompatible with target AS\n");
+ return;
+ }
+
+ if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
+ vaddr = memory_region_get_ram_ptr(mr) + xlat;
+ ret = vfio_dma_map(container, iotlb->iova,
+ iotlb->addr_mask + 1, vaddr,
+ !(iotlb->perm & IOMMU_WO) || mr->readonly);
+ if (ret) {
+ error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx", %p) = %d (%m)",
+ container, iotlb->iova,
+ iotlb->addr_mask + 1, vaddr, ret);
+ }
+ } else {
+ ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1);
+ if (ret) {
+ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx") = %d (%m)",
+ container, iotlb->iova,
+ iotlb->addr_mask + 1, ret);
+ }
+ }
+}
+
+static void vfio_listener_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ VFIOContainer *container = container_of(listener, VFIOContainer,
+ iommu_data.type1.listener);
+ hwaddr iova, end;
+ Int128 llend;
+ void *vaddr;
+ int ret;
+
+ if (vfio_listener_skipped_section(section)) {
+ trace_vfio_listener_region_add_skip(
+ section->offset_within_address_space,
+ section->offset_within_address_space +
+ int128_get64(int128_sub(section->size, int128_one())));
+ return;
+ }
+
+ if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
+ (section->offset_within_region & ~TARGET_PAGE_MASK))) {
+ error_report("%s received unaligned region", __func__);
+ return;
+ }
+
+ iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
+ llend = int128_make64(section->offset_within_address_space);
+ llend = int128_add(llend, section->size);
+ llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
+
+ if (int128_ge(int128_make64(iova), llend)) {
+ return;
+ }
+
+ memory_region_ref(section->mr);
+
+ if (memory_region_is_iommu(section->mr)) {
+ VFIOGuestIOMMU *giommu;
+
+ trace_vfio_listener_region_add_iommu(iova,
+ int128_get64(int128_sub(llend, int128_one())));
+ /*
+ * FIXME: We should do some checking to see if the
+ * capabilities of the host VFIO IOMMU are adequate to model
+ * the guest IOMMU
+ *
+ * FIXME: For VFIO iommu types which have KVM acceleration to
+ * avoid bouncing all map/unmaps through qemu this way, this
+ * would be the right place to wire that up (tell the KVM
+ * device emulation the VFIO iommu handles to use).
+ */
+ /*
+ * This assumes that the guest IOMMU is empty of
+ * mappings at this point.
+ *
+ * One way of doing this is:
+ * 1. Avoid sharing IOMMUs between emulated devices or different
+ * IOMMU groups.
+ * 2. Implement VFIO_IOMMU_ENABLE in the host kernel to fail if
+ * there are some mappings in IOMMU.
+ *
+ * VFIO on SPAPR does that. Other IOMMU models may do that different,
+ * they must make sure there are no existing mappings or
+ * loop through existing mappings to map them into VFIO.
+ */
+ giommu = g_malloc0(sizeof(*giommu));
+ giommu->iommu = section->mr;
+ giommu->container = container;
+ giommu->n.notify = vfio_iommu_map_notify;
+ QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
+ memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
+
+ return;
+ }
+
+ /* Here we assume that memory_region_is_ram(section->mr)==true */
+
+ end = int128_get64(llend);
+ vaddr = memory_region_get_ram_ptr(section->mr) +
+ section->offset_within_region +
+ (iova - section->offset_within_address_space);
+
+ trace_vfio_listener_region_add_ram(iova, end - 1, vaddr);
+
+ ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
+ if (ret) {
+ error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx", %p) = %d (%m)",
+ container, iova, end - iova, vaddr, ret);
+
+ /*
+ * On the initfn path, store the first error in the container so we
+ * can gracefully fail. Runtime, there's not much we can do other
+ * than throw a hardware error.
+ */
+ if (!container->iommu_data.type1.initialized) {
+ if (!container->iommu_data.type1.error) {
+ container->iommu_data.type1.error = ret;
+ }
+ } else {
+ hw_error("vfio: DMA mapping failed, unable to continue");
+ }
+ }
+}
+
+static void vfio_listener_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ VFIOContainer *container = container_of(listener, VFIOContainer,
+ iommu_data.type1.listener);
+ hwaddr iova, end;
+ int ret;
+
+ if (vfio_listener_skipped_section(section)) {
+ trace_vfio_listener_region_del_skip(
+ section->offset_within_address_space,
+ section->offset_within_address_space +
+ int128_get64(int128_sub(section->size, int128_one())));
+ return;
+ }
+
+ if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
+ (section->offset_within_region & ~TARGET_PAGE_MASK))) {
+ error_report("%s received unaligned region", __func__);
+ return;
+ }
+
+ if (memory_region_is_iommu(section->mr)) {
+ VFIOGuestIOMMU *giommu;
+
+ QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
+ if (giommu->iommu == section->mr) {
+ memory_region_unregister_iommu_notifier(&giommu->n);
+ QLIST_REMOVE(giommu, giommu_next);
+ g_free(giommu);
+ break;
+ }
+ }
+
+ /*
+ * FIXME: We assume the one big unmap below is adequate to
+ * remove any individual page mappings in the IOMMU which
+ * might have been copied into VFIO. This works for a page table
+ * based IOMMU where a big unmap flattens a large range of IO-PTEs.
+ * That may not be true for all IOMMU types.
+ */
+ }
+
+ iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
+ end = (section->offset_within_address_space + int128_get64(section->size)) &
+ TARGET_PAGE_MASK;
+
+ if (iova >= end) {
+ return;
+ }
+
+ trace_vfio_listener_region_del(iova, end - 1);
+
+ ret = vfio_dma_unmap(container, iova, end - iova);
+ memory_region_unref(section->mr);
+ if (ret) {
+ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx") = %d (%m)",
+ container, iova, end - iova, ret);
+ }
+}
+
+const MemoryListener vfio_memory_listener = {
+ .region_add = vfio_listener_region_add,
+ .region_del = vfio_listener_region_del,
+};
+
+void vfio_listener_release(VFIOContainer *container)
+{
+ memory_listener_unregister(&container->iommu_data.type1.listener);
+}
+
+int vfio_mmap_region(Object *obj, VFIORegion *region,
+ MemoryRegion *mem, MemoryRegion *submem,
+ void **map, size_t size, off_t offset,
+ const char *name)
+{
+ int ret = 0;
+ VFIODevice *vbasedev = region->vbasedev;
+
+ if (VFIO_ALLOW_MMAP && size && region->flags &
+ VFIO_REGION_INFO_FLAG_MMAP) {
+ int prot = 0;
+
+ if (region->flags & VFIO_REGION_INFO_FLAG_READ) {
+ prot |= PROT_READ;
+ }
+
+ if (region->flags & VFIO_REGION_INFO_FLAG_WRITE) {
+ prot |= PROT_WRITE;
+ }
+
+ *map = mmap(NULL, size, prot, MAP_SHARED,
+ vbasedev->fd,
+ region->fd_offset + offset);
+ if (*map == MAP_FAILED) {
+ *map = NULL;
+ ret = -errno;
+ goto empty_region;
+ }
+
+ memory_region_init_ram_ptr(submem, obj, name, size, *map);
+ memory_region_set_skip_dump(submem);
+ } else {
+empty_region:
+ /* Create a zero sized sub-region to make cleanup easy. */
+ memory_region_init(submem, obj, name, 0);
+ }
+
+ memory_region_add_subregion(mem, offset, submem);
+
+ return ret;
+}
+
+void vfio_reset_handler(void *opaque)
+{
+ VFIOGroup *group;
+ VFIODevice *vbasedev;
+
+ QLIST_FOREACH(group, &vfio_group_list, next) {
+ QLIST_FOREACH(vbasedev, &group->device_list, next) {
+ vbasedev->ops->vfio_compute_needs_reset(vbasedev);
+ }
+ }
+
+ QLIST_FOREACH(group, &vfio_group_list, next) {
+ QLIST_FOREACH(vbasedev, &group->device_list, next) {
+ if (vbasedev->needs_reset) {
+ vbasedev->ops->vfio_hot_reset_multi(vbasedev);
+ }
+ }
+ }
+}
+
+static void vfio_kvm_device_add_group(VFIOGroup *group)
+{
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_GROUP,
+ .attr = KVM_DEV_VFIO_GROUP_ADD,
+ .addr = (uint64_t)(unsigned long)&group->fd,
+ };
+
+ if (!kvm_enabled()) {
+ return;
+ }
+
+ if (vfio_kvm_device_fd < 0) {
+ struct kvm_create_device cd = {
+ .type = KVM_DEV_TYPE_VFIO,
+ };
+
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
+ error_report("Failed to create KVM VFIO device: %m\n");
+ return;
+ }
+
+ vfio_kvm_device_fd = cd.fd;
+ }
+
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to add group %d to KVM VFIO device: %m",
+ group->groupid);
+ }
+#endif
+}
+
+static void vfio_kvm_device_del_group(VFIOGroup *group)
+{
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_GROUP,
+ .attr = KVM_DEV_VFIO_GROUP_DEL,
+ .addr = (uint64_t)(unsigned long)&group->fd,
+ };
+
+ if (vfio_kvm_device_fd < 0) {
+ return;
+ }
+
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_report("Failed to remove group %d from KVM VFIO device: %m",
+ group->groupid);
+ }
+#endif
+}
+
+static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as)
+{
+ VFIOAddressSpace *space;
+
+ QLIST_FOREACH(space, &vfio_address_spaces, list) {
+ if (space->as == as) {
+ return space;
+ }
+ }
+
+ /* No suitable VFIOAddressSpace, create a new one */
+ space = g_malloc0(sizeof(*space));
+ space->as = as;
+ QLIST_INIT(&space->containers);
+
+ QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
+
+ return space;
+}
+
+static void vfio_put_address_space(VFIOAddressSpace *space)
+{
+ if (QLIST_EMPTY(&space->containers)) {
+ QLIST_REMOVE(space, list);
+ g_free(space);
+ }
+}
+
+static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
+{
+ VFIOContainer *container;
+ int ret, fd;
+ VFIOAddressSpace *space;
+
+ space = vfio_get_address_space(as);
+
+ QLIST_FOREACH(container, &space->containers, next) {
+ if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
+ group->container = container;
+ QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+ return 0;
+ }
+ }
+
+ fd = qemu_open("/dev/vfio/vfio", O_RDWR);
+ if (fd < 0) {
+ error_report("vfio: failed to open /dev/vfio/vfio: %m");
+ ret = -errno;
+ goto put_space_exit;
+ }
+
+ ret = ioctl(fd, VFIO_GET_API_VERSION);
+ if (ret != VFIO_API_VERSION) {
+ error_report("vfio: supported vfio version: %d, "
+ "reported version: %d", VFIO_API_VERSION, ret);
+ ret = -EINVAL;
+ goto close_fd_exit;
+ }
+
+ container = g_malloc0(sizeof(*container));
+ container->space = space;
+ container->fd = fd;
+ if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
+ ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
+ if (ret) {
+ error_report("vfio: failed to set group container: %m");
+ ret = -errno;
+ goto free_container_exit;
+ }
+
+ ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
+ if (ret) {
+ error_report("vfio: failed to set iommu for container: %m");
+ ret = -errno;
+ goto free_container_exit;
+ }
+
+ container->iommu_data.type1.listener = vfio_memory_listener;
+ container->iommu_data.release = vfio_listener_release;
+
+ memory_listener_register(&container->iommu_data.type1.listener,
+ container->space->as);
+
+ if (container->iommu_data.type1.error) {
+ ret = container->iommu_data.type1.error;
+ error_report("vfio: memory listener initialization failed for container");
+ goto listener_release_exit;
+ }
+
+ container->iommu_data.type1.initialized = true;
+
+ } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) {
+ ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
+ if (ret) {
+ error_report("vfio: failed to set group container: %m");
+ ret = -errno;
+ goto free_container_exit;
+ }
+ ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU);
+ if (ret) {
+ error_report("vfio: failed to set iommu for container: %m");
+ ret = -errno;
+ goto free_container_exit;
+ }
+
+ /*
+ * The host kernel code implementing VFIO_IOMMU_DISABLE is called
+ * when container fd is closed so we do not call it explicitly
+ * in this file.
+ */
+ ret = ioctl(fd, VFIO_IOMMU_ENABLE);
+ if (ret) {
+ error_report("vfio: failed to enable container: %m");
+ ret = -errno;
+ goto free_container_exit;
+ }
+
+ container->iommu_data.type1.listener = vfio_memory_listener;
+ container->iommu_data.release = vfio_listener_release;
+
+ memory_listener_register(&container->iommu_data.type1.listener,
+ container->space->as);
+
+ } else {
+ error_report("vfio: No available IOMMU models");
+ ret = -EINVAL;
+ goto free_container_exit;
+ }
+
+ QLIST_INIT(&container->group_list);
+ QLIST_INSERT_HEAD(&space->containers, container, next);
+
+ group->container = container;
+ QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+
+ return 0;
+listener_release_exit:
+ vfio_listener_release(container);
+
+free_container_exit:
+ g_free(container);
+
+close_fd_exit:
+ close(fd);
+
+put_space_exit:
+ vfio_put_address_space(space);
+
+ return ret;
+}
+
+static void vfio_disconnect_container(VFIOGroup *group)
+{
+ VFIOContainer *container = group->container;
+
+ if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
+ error_report("vfio: error disconnecting group %d from container",
+ group->groupid);
+ }
+
+ QLIST_REMOVE(group, container_next);
+ group->container = NULL;
+
+ if (QLIST_EMPTY(&container->group_list)) {
+ VFIOAddressSpace *space = container->space;
+
+ if (container->iommu_data.release) {
+ container->iommu_data.release(container);
+ }
+ QLIST_REMOVE(container, next);
+ trace_vfio_disconnect_container(container->fd);
+ close(container->fd);
+ g_free(container);
+
+ vfio_put_address_space(space);
+ }
+}
+
+VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
+{
+ VFIOGroup *group;
+ char path[32];
+ struct vfio_group_status status = { .argsz = sizeof(status) };
+
+ QLIST_FOREACH(group, &vfio_group_list, next) {
+ if (group->groupid == groupid) {
+ /* Found it. Now is it already in the right context? */
+ if (group->container->space->as == as) {
+ return group;
+ } else {
+ error_report("vfio: group %d used in multiple address spaces",
+ group->groupid);
+ return NULL;
+ }
+ }
+ }
+
+ group = g_malloc0(sizeof(*group));
+
+ snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
+ group->fd = qemu_open(path, O_RDWR);
+ if (group->fd < 0) {
+ error_report("vfio: error opening %s: %m", path);
+ goto free_group_exit;
+ }
+
+ if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
+ error_report("vfio: error getting group status: %m");
+ goto close_fd_exit;
+ }
+
+ if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
+ error_report("vfio: error, group %d is not viable, please ensure "
+ "all devices within the iommu_group are bound to their "
+ "vfio bus driver.", groupid);
+ goto close_fd_exit;
+ }
+
+ group->groupid = groupid;
+ QLIST_INIT(&group->device_list);
+
+ if (vfio_connect_container(group, as)) {
+ error_report("vfio: failed to setup container for group %d", groupid);
+ goto close_fd_exit;
+ }
+
+ if (QLIST_EMPTY(&vfio_group_list)) {
+ qemu_register_reset(vfio_reset_handler, NULL);
+ }
+
+ QLIST_INSERT_HEAD(&vfio_group_list, group, next);
+
+ vfio_kvm_device_add_group(group);
+
+ return group;
+
+close_fd_exit:
+ close(group->fd);
+
+free_group_exit:
+ g_free(group);
+
+ return NULL;
+}
+
+void vfio_put_group(VFIOGroup *group)
+{
+ if (!QLIST_EMPTY(&group->device_list)) {
+ return;
+ }
+
+ vfio_kvm_device_del_group(group);
+ vfio_disconnect_container(group);
+ QLIST_REMOVE(group, next);
+ trace_vfio_put_group(group->fd);
+ close(group->fd);
+ g_free(group);
+
+ if (QLIST_EMPTY(&vfio_group_list)) {
+ qemu_unregister_reset(vfio_reset_handler, NULL);
+ }
+}
+
+int vfio_get_device(VFIOGroup *group, const char *name,
+ VFIODevice *vbasedev)
+{
+ struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
+ int ret;
+
+ ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
+ if (ret < 0) {
+ error_report("vfio: error getting device %s from group %d: %m",
+ name, group->groupid);
+ error_printf("Verify all devices in group %d are bound to vfio-<bus> "
+ "or pci-stub and not already in use\n", group->groupid);
+ return ret;
+ }
+
+ vbasedev->fd = ret;
+ vbasedev->group = group;
+ QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_INFO, &dev_info);
+ if (ret) {
+ error_report("vfio: error getting device info: %m");
+ goto error;
+ }
+
+ vbasedev->num_irqs = dev_info.num_irqs;
+ vbasedev->num_regions = dev_info.num_regions;
+ vbasedev->flags = dev_info.flags;
+
+ trace_vfio_get_device(name, dev_info.flags, dev_info.num_regions,
+ dev_info.num_irqs);
+
+ vbasedev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
+
+ ret = vbasedev->ops->vfio_populate_device(vbasedev);
+
+error:
+ if (ret) {
+ vfio_put_base_device(vbasedev);
+ }
+ return ret;
+}
+
+void vfio_put_base_device(VFIODevice *vbasedev)
+{
+ QLIST_REMOVE(vbasedev, next);
+ vbasedev->group = NULL;
+ trace_vfio_put_base_device(vbasedev->fd);
+ close(vbasedev->fd);
+}
+
+static int vfio_container_do_ioctl(AddressSpace *as, int32_t groupid,
+ int req, void *param)
+{
+ VFIOGroup *group;
+ VFIOContainer *container;
+ int ret = -1;
+
+ group = vfio_get_group(groupid, as);
+ if (!group) {
+ error_report("vfio: group %d not registered", groupid);
+ return ret;
+ }
+
+ container = group->container;
+ if (group->container) {
+ ret = ioctl(container->fd, req, param);
+ if (ret < 0) {
+ error_report("vfio: failed to ioctl container: ret=%d, %s",
+ ret, strerror(errno));
+ }
+ }
+
+ vfio_put_group(group);
+
+ return ret;
+}
+
+int vfio_container_ioctl(AddressSpace *as, int32_t groupid,
+ int req, void *param)
+{
+ /* We allow only certain ioctls to the container */
+ switch (req) {
+ case VFIO_CHECK_EXTENSION:
+ case VFIO_IOMMU_SPAPR_TCE_GET_INFO:
+ break;
+ default:
+ /* Return an error on unknown requests */
+ error_report("vfio: unsupported ioctl %X", req);
+ return -1;
+ }
+
+ return vfio_container_do_ioctl(as, groupid, req, param);
+}
diff --git a/hw/misc/vfio.c b/hw/vfio/pci.c
index a315c3acdc..b4e73d1f35 100644
--- a/hw/misc/vfio.c
+++ b/hw/vfio/pci.c
@@ -39,28 +39,15 @@
#include "qemu/range.h"
#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
-#include "hw/misc/vfio.h"
+#include "trace.h"
+#include "hw/vfio/vfio.h"
+#include "hw/vfio/vfio-common.h"
-/* #define DEBUG_VFIO */
-#ifdef DEBUG_VFIO
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-/* Extra debugging, trap acceleration paths for more logging */
-#define VFIO_ALLOW_MMAP 1
-#define VFIO_ALLOW_KVM_INTX 1
-#define VFIO_ALLOW_KVM_MSI 1
-#define VFIO_ALLOW_KVM_MSIX 1
-
-struct VFIODevice;
+struct VFIOPCIDevice;
typedef struct VFIOQuirk {
MemoryRegion mem;
- struct VFIODevice *vdev;
+ struct VFIOPCIDevice *vdev;
QLIST_ENTRY(VFIOQuirk) next;
struct {
uint32_t base_offset:TARGET_PAGE_BITS;
@@ -82,14 +69,7 @@ typedef struct VFIOQuirk {
} VFIOQuirk;
typedef struct VFIOBAR {
- off_t fd_offset; /* offset of BAR within device fd */
- int fd; /* device fd, allows us to pass VFIOBAR as opaque data */
- MemoryRegion mem; /* slow, read/write access */
- MemoryRegion mmap_mem; /* direct mapped access */
- void *mmap;
- size_t size;
- uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
- uint8_t nr; /* cache the BAR number for debug */
+ VFIORegion region;
bool ioport;
bool mem64;
QLIST_HEAD(, VFIOQuirk) quirks;
@@ -131,7 +111,7 @@ typedef struct VFIOMSIVector {
*/
EventNotifier interrupt;
EventNotifier kvm_interrupt;
- struct VFIODevice *vdev; /* back pointer to device */
+ struct VFIOPCIDevice *vdev; /* back pointer to device */
int virq;
bool use;
} VFIOMSIVector;
@@ -143,45 +123,6 @@ enum {
VFIO_INT_MSIX = 3,
};
-typedef struct VFIOAddressSpace {
- AddressSpace *as;
- QLIST_HEAD(, VFIOContainer) containers;
- QLIST_ENTRY(VFIOAddressSpace) list;
-} VFIOAddressSpace;
-
-static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
- QLIST_HEAD_INITIALIZER(vfio_address_spaces);
-
-struct VFIOGroup;
-
-typedef struct VFIOType1 {
- MemoryListener listener;
- int error;
- bool initialized;
-} VFIOType1;
-
-typedef struct VFIOContainer {
- VFIOAddressSpace *space;
- int fd; /* /dev/vfio/vfio, empowered by the attached groups */
- struct {
- /* enable abstraction to support various iommu backends */
- union {
- VFIOType1 type1;
- };
- void (*release)(struct VFIOContainer *);
- } iommu_data;
- QLIST_HEAD(, VFIOGuestIOMMU) giommu_list;
- QLIST_HEAD(, VFIOGroup) group_list;
- QLIST_ENTRY(VFIOContainer) next;
-} VFIOContainer;
-
-typedef struct VFIOGuestIOMMU {
- VFIOContainer *container;
- MemoryRegion *iommu;
- Notifier n;
- QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
-} VFIOGuestIOMMU;
-
/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */
typedef struct VFIOMSIXInfo {
uint8_t table_bar;
@@ -193,9 +134,9 @@ typedef struct VFIOMSIXInfo {
void *mmap;
} VFIOMSIXInfo;
-typedef struct VFIODevice {
+typedef struct VFIOPCIDevice {
PCIDevice pdev;
- int fd;
+ VFIODevice vbasedev;
VFIOINTx intx;
unsigned int config_size;
uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
@@ -211,31 +152,18 @@ typedef struct VFIODevice {
VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
PCIHostDeviceAddress host;
- QLIST_ENTRY(VFIODevice) next;
- struct VFIOGroup *group;
EventNotifier err_notifier;
uint32_t features;
#define VFIO_FEATURE_ENABLE_VGA_BIT 0
#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
int32_t bootindex;
uint8_t pm_cap;
- bool reset_works;
bool has_vga;
bool pci_aer;
bool has_flr;
bool has_pm_reset;
- bool needs_reset;
bool rom_read_failed;
-} VFIODevice;
-
-typedef struct VFIOGroup {
- int fd;
- int groupid;
- VFIOContainer *container;
- QLIST_HEAD(, VFIODevice) device_list;
- QLIST_ENTRY(VFIOGroup) next;
- QLIST_ENTRY(VFIOGroup) container_next;
-} VFIOGroup;
+} VFIOPCIDevice;
typedef struct VFIORomBlacklistEntry {
uint16_t vendor_id;
@@ -262,72 +190,12 @@ static const VFIORomBlacklistEntry romblacklist[] = {
#define MSIX_CAP_LENGTH 12
-static QLIST_HEAD(, VFIOGroup)
- group_list = QLIST_HEAD_INITIALIZER(group_list);
-
-#ifdef CONFIG_KVM
-/*
- * We have a single VFIO pseudo device per KVM VM. Once created it lives
- * for the life of the VM. Closing the file descriptor only drops our
- * reference to it and the device's reference to kvm. Therefore once
- * initialized, this file descriptor is only released on QEMU exit and
- * we'll re-use it should another vfio device be attached before then.
- */
-static int vfio_kvm_device_fd = -1;
-#endif
-
-static void vfio_disable_interrupts(VFIODevice *vdev);
+static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
uint32_t val, int len);
-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled);
-
-/*
- * Common VFIO interrupt disable
- */
-static void vfio_disable_irqindex(VFIODevice *vdev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
- .index = index,
- .start = 0,
- .count = 0,
- };
-
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-/*
- * INTx
- */
-static void vfio_unmask_intx(VFIODevice *vdev)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
- .index = VFIO_PCI_INTX_IRQ_INDEX,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */
-static void vfio_mask_intx(VFIODevice *vdev)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
- .index = VFIO_PCI_INTX_IRQ_INDEX,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-#endif
+static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
+static int vfio_populate_device(VFIODevice *vbasedev);
/*
* Disabling BAR mmaping can be slow, but toggling it around INTx can
@@ -346,7 +214,7 @@ static void vfio_mask_intx(VFIODevice *vdev)
*/
static void vfio_intx_mmap_enable(void *opaque)
{
- VFIODevice *vdev = opaque;
+ VFIOPCIDevice *vdev = opaque;
if (vdev->intx.pending) {
timer_mod(vdev->intx.mmap_timer,
@@ -359,15 +227,13 @@ static void vfio_intx_mmap_enable(void *opaque)
static void vfio_intx_interrupt(void *opaque)
{
- VFIODevice *vdev = opaque;
+ VFIOPCIDevice *vdev = opaque;
if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) {
return;
}
- DPRINTF("%s(%04x:%02x:%02x.%x) Pin %c\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- 'A' + vdev->intx.pin);
+ trace_vfio_intx_interrupt(vdev->vbasedev.name, 'A' + vdev->intx.pin);
vdev->intx.pending = true;
pci_irq_assert(&vdev->pdev);
@@ -378,21 +244,22 @@ static void vfio_intx_interrupt(void *opaque)
}
}
-static void vfio_eoi(VFIODevice *vdev)
+static void vfio_eoi(VFIODevice *vbasedev)
{
+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
+
if (!vdev->intx.pending) {
return;
}
- DPRINTF("%s(%04x:%02x:%02x.%x) EOI\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_eoi(vbasedev->name);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
- vfio_unmask_intx(vdev);
+ vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
}
-static void vfio_enable_intx_kvm(VFIODevice *vdev)
+static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev)
{
#ifdef CONFIG_KVM
struct kvm_irqfd irqfd = {
@@ -412,7 +279,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev)
/* Get to a known interrupt state */
qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev);
- vfio_mask_intx(vdev);
+ vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
@@ -442,7 +309,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev)
*pfd = irqfd.resamplefd;
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
error_report("vfio: Error: Failed to setup INTx unmask fd: %m");
@@ -450,13 +317,11 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev)
}
/* Let'em rip */
- vfio_unmask_intx(vdev);
+ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.kvm_accel = true;
- DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n",
- __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function);
+ trace_vfio_enable_intx_kvm(vdev->vbasedev.name);
return;
@@ -467,11 +332,11 @@ fail_irqfd:
event_notifier_cleanup(&vdev->intx.unmask);
fail:
qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
- vfio_unmask_intx(vdev);
+ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
#endif
}
-static void vfio_disable_intx_kvm(VFIODevice *vdev)
+static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev)
{
#ifdef CONFIG_KVM
struct kvm_irqfd irqfd = {
@@ -488,7 +353,7 @@ static void vfio_disable_intx_kvm(VFIODevice *vdev)
* Get to a known state, hardware masked, QEMU ready to accept new
* interrupts, QEMU IRQ de-asserted.
*/
- vfio_mask_intx(vdev);
+ vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
@@ -506,17 +371,15 @@ static void vfio_disable_intx_kvm(VFIODevice *vdev)
vdev->intx.kvm_accel = false;
/* If we've missed an event, let it re-fire through QEMU */
- vfio_unmask_intx(vdev);
+ vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
- DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n",
- __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function);
+ trace_vfio_disable_intx_kvm(vdev->vbasedev.name);
#endif
}
static void vfio_update_irq(PCIDevice *pdev)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
PCIINTxRoute route;
if (vdev->interrupt != VFIO_INT_INTx) {
@@ -529,9 +392,8 @@ static void vfio_update_irq(PCIDevice *pdev)
return; /* Nothing changed */
}
- DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, vdev->intx.route.irq, route.irq);
+ trace_vfio_update_irq(vdev->vbasedev.name,
+ vdev->intx.route.irq, route.irq);
vfio_disable_intx_kvm(vdev);
@@ -544,10 +406,10 @@ static void vfio_update_irq(PCIDevice *pdev)
vfio_enable_intx_kvm(vdev);
/* Re-enable the interrupt in cased we missed an EOI */
- vfio_eoi(vdev);
+ vfio_eoi(&vdev->vbasedev);
}
-static int vfio_enable_intx(VFIODevice *vdev)
+static int vfio_enable_intx(VFIOPCIDevice *vdev)
{
uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
int ret, argsz;
@@ -593,7 +455,7 @@ static int vfio_enable_intx(VFIODevice *vdev)
*pfd = event_notifier_get_fd(&vdev->intx.interrupt);
qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev);
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
error_report("vfio: Error: Failed to setup INTx fd: %m");
@@ -606,19 +468,18 @@ static int vfio_enable_intx(VFIODevice *vdev)
vdev->interrupt = VFIO_INT_INTx;
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_enable_intx(vdev->vbasedev.name);
return 0;
}
-static void vfio_disable_intx(VFIODevice *vdev)
+static void vfio_disable_intx(VFIOPCIDevice *vdev)
{
int fd;
timer_del(vdev->intx.mmap_timer);
vfio_disable_intx_kvm(vdev);
- vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
vfio_mmap_set_enabled(vdev, true);
@@ -629,8 +490,7 @@ static void vfio_disable_intx(VFIODevice *vdev)
vdev->interrupt = VFIO_INT_NONE;
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_disable_intx(vdev->vbasedev.name);
}
/*
@@ -639,7 +499,7 @@ static void vfio_disable_intx(VFIODevice *vdev)
static void vfio_msi_interrupt(void *opaque)
{
VFIOMSIVector *vector = opaque;
- VFIODevice *vdev = vector->vdev;
+ VFIOPCIDevice *vdev = vector->vdev;
int nr = vector - vdev->msi_vectors;
if (!event_notifier_test_and_clear(&vector->interrupt)) {
@@ -657,9 +517,7 @@ static void vfio_msi_interrupt(void *opaque)
abort();
}
- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d 0x%"PRIx64"/0x%x\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, nr, msg.address, msg.data);
+ trace_vfio_msi_interrupt(vbasedev->name, nr, msg.address, msg.data);
#endif
if (vdev->interrupt == VFIO_INT_MSIX) {
@@ -671,7 +529,7 @@ static void vfio_msi_interrupt(void *opaque)
}
}
-static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
+static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix)
{
struct vfio_irq_set *irq_set;
int ret = 0, i, argsz;
@@ -708,7 +566,7 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
fds[i] = fd;
}
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
@@ -762,13 +620,11 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg)
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
MSIMessage *msg, IOHandler *handler)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
VFIOMSIVector *vector;
int ret;
- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d used\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, nr);
+ trace_vfio_msix_vector_do_use(vdev->vbasedev.name, nr);
vector = &vdev->msi_vectors[nr];
@@ -805,7 +661,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
* increase them as needed.
*/
if (vdev->nr_vectors < nr + 1) {
- vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
+ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
vdev->nr_vectors = nr + 1;
ret = vfio_enable_vectors(vdev, true);
if (ret) {
@@ -833,7 +689,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
*pfd = event_notifier_get_fd(&vector->interrupt);
}
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
error_report("vfio: failed to modify vector, %d", ret);
@@ -851,12 +707,10 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
VFIOMSIVector *vector = &vdev->msi_vectors[nr];
- DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, nr);
+ trace_vfio_msix_vector_release(vdev->vbasedev.name, nr);
/*
* There are still old guests that mask and unmask vectors on every
@@ -884,13 +738,13 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
*pfd = event_notifier_get_fd(&vector->interrupt);
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
}
}
-static void vfio_enable_msix(VFIODevice *vdev)
+static void vfio_enable_msix(VFIOPCIDevice *vdev)
{
vfio_disable_interrupts(vdev);
@@ -919,11 +773,10 @@ static void vfio_enable_msix(VFIODevice *vdev)
error_report("vfio: msix_set_vector_notifiers failed");
}
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_enable_msix(vdev->vbasedev.name);
}
-static void vfio_enable_msi(VFIODevice *vdev)
+static void vfio_enable_msi(VFIOPCIDevice *vdev)
{
int ret, i;
@@ -996,12 +849,10 @@ retry:
return;
}
- DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, vdev->nr_vectors);
+ trace_vfio_enable_msi(vdev->vbasedev.name, vdev->nr_vectors);
}
-static void vfio_disable_msi_common(VFIODevice *vdev)
+static void vfio_disable_msi_common(VFIOPCIDevice *vdev)
{
int i;
@@ -1025,7 +876,7 @@ static void vfio_disable_msi_common(VFIODevice *vdev)
vfio_enable_intx(vdev);
}
-static void vfio_disable_msix(VFIODevice *vdev)
+static void vfio_disable_msix(VFIOPCIDevice *vdev)
{
int i;
@@ -1043,25 +894,23 @@ static void vfio_disable_msix(VFIODevice *vdev)
}
if (vdev->nr_vectors) {
- vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
+ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
}
vfio_disable_msi_common(vdev);
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_disable_msix(vdev->vbasedev.name);
}
-static void vfio_disable_msi(VFIODevice *vdev)
+static void vfio_disable_msi(VFIOPCIDevice *vdev)
{
- vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX);
+ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX);
vfio_disable_msi_common(vdev);
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_disable_msi(vdev->vbasedev.name);
}
-static void vfio_update_msi(VFIODevice *vdev)
+static void vfio_update_msi(VFIOPCIDevice *vdev)
{
int i;
@@ -1078,119 +927,7 @@ static void vfio_update_msi(VFIODevice *vdev)
}
}
-/*
- * IO Port/MMIO - Beware of the endians, VFIO is always little endian
- */
-static void vfio_bar_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOBAR *bar = opaque;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
-
- switch (size) {
- case 1:
- buf.byte = data;
- break;
- case 2:
- buf.word = cpu_to_le16(data);
- break;
- case 4:
- buf.dword = cpu_to_le32(data);
- break;
- default:
- hw_error("vfio: unsupported write size, %d bytes", size);
- break;
- }
-
- if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
- error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
- __func__, addr, data, size);
- }
-
-#ifdef DEBUG_VFIO
- {
- VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64
- ", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, bar->nr, addr,
- data, size);
- }
-#endif
-
- /*
- * A read or write to a BAR always signals an INTx EOI. This will
- * do nothing if not pending (including not in INTx mode). We assume
- * that a BAR access is in response to an interrupt and that BAR
- * accesses will service the interrupt. Unfortunately, we don't know
- * which access will service the interrupt, so we're potentially
- * getting quite a few host interrupts per guest interrupt.
- */
- vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
-}
-
-static uint64_t vfio_bar_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOBAR *bar = opaque;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
- uint64_t data = 0;
-
- if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
- error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
- __func__, addr, size);
- return (uint64_t)-1;
- }
-
- switch (size) {
- case 1:
- data = buf.byte;
- break;
- case 2:
- data = le16_to_cpu(buf.word);
- break;
- case 4:
- data = le32_to_cpu(buf.dword);
- break;
- default:
- hw_error("vfio: unsupported read size, %d bytes", size);
- break;
- }
-
-#ifdef DEBUG_VFIO
- {
- VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
-
- DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx
- ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- bar->nr, addr, size, data);
- }
-#endif
-
- /* Same as write above */
- vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
-
- return data;
-}
-
-static const MemoryRegionOps vfio_bar_ops = {
- .read = vfio_bar_read,
- .write = vfio_bar_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_pci_load_rom(VFIODevice *vdev)
+static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
{
struct vfio_region_info reg_info = {
.argsz = sizeof(reg_info),
@@ -1200,16 +937,14 @@ static void vfio_pci_load_rom(VFIODevice *vdev)
off_t off = 0;
size_t bytes;
- if (ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info)) {
+ if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info)) {
error_report("vfio: Error getting ROM info: %m");
return;
}
- DPRINTF("Device %04x:%02x:%02x.%x ROM:\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
- DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
- (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
- (unsigned long)reg_info.flags);
+ trace_vfio_pci_load_rom(vdev->vbasedev.name, (unsigned long)reg_info.size,
+ (unsigned long)reg_info.offset,
+ (unsigned long)reg_info.flags);
vdev->rom_size = size = reg_info.size;
vdev->rom_offset = reg_info.offset;
@@ -1217,9 +952,7 @@ static void vfio_pci_load_rom(VFIODevice *vdev)
if (!vdev->rom_size) {
vdev->rom_read_failed = true;
error_report("vfio-pci: Cannot read device rom at "
- "%04x:%02x:%02x.%x",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ "%s", vdev->vbasedev.name);
error_printf("Device option ROM contents are probably invalid "
"(check dmesg).\nSkip option ROM probe with rombar=0, "
"or load from file with romfile=\n");
@@ -1230,7 +963,8 @@ static void vfio_pci_load_rom(VFIODevice *vdev)
memset(vdev->rom, 0xff, size);
while (size) {
- bytes = pread(vdev->fd, vdev->rom + off, size, vdev->rom_offset + off);
+ bytes = pread(vdev->vbasedev.fd, vdev->rom + off,
+ size, vdev->rom_offset + off);
if (bytes == 0) {
break;
} else if (bytes > 0) {
@@ -1248,7 +982,7 @@ static void vfio_pci_load_rom(VFIODevice *vdev)
static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size)
{
- VFIODevice *vdev = opaque;
+ VFIOPCIDevice *vdev = opaque;
union {
uint8_t byte;
uint16_t word;
@@ -1280,9 +1014,7 @@ static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size)
break;
}
- DPRINTF("%s(%04x:%02x:%02x.%x, 0x%"HWADDR_PRIx", 0x%x) = 0x%"PRIx64"\n",
- __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, addr, size, data);
+ trace_vfio_rom_read(vdev->vbasedev.name, addr, size, data);
return data;
}
@@ -1298,7 +1030,7 @@ static const MemoryRegionOps vfio_rom_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static bool vfio_blacklist_opt_rom(VFIODevice *vdev)
+static bool vfio_blacklist_opt_rom(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
uint16_t vendor_id, device_id;
@@ -1318,12 +1050,13 @@ static bool vfio_blacklist_opt_rom(VFIODevice *vdev)
return false;
}
-static void vfio_pci_size_rom(VFIODevice *vdev)
+static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
{
uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK);
off_t offset = vdev->config_offset + PCI_ROM_ADDRESS;
DeviceState *dev = DEVICE(vdev);
char name[32];
+ int fd = vdev->vbasedev.fd;
if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
/* Since pci handles romfile, just print a message and return */
@@ -1342,10 +1075,10 @@ static void vfio_pci_size_rom(VFIODevice *vdev)
* Use the same size ROM BAR as the physical device. The contents
* will get filled in later when the guest tries to read it.
*/
- if (pread(vdev->fd, &orig, 4, offset) != 4 ||
- pwrite(vdev->fd, &size, 4, offset) != 4 ||
- pread(vdev->fd, &size, 4, offset) != 4 ||
- pwrite(vdev->fd, &orig, 4, offset) != 4) {
+ if (pread(fd, &orig, 4, offset) != 4 ||
+ pwrite(fd, &size, 4, offset) != 4 ||
+ pread(fd, &size, 4, offset) != 4 ||
+ pwrite(fd, &orig, 4, offset) != 4) {
error_report("%s(%04x:%02x:%02x.%x) failed: %m",
__func__, vdev->host.domain, vdev->host.bus,
vdev->host.slot, vdev->host.function);
@@ -1378,8 +1111,7 @@ static void vfio_pci_size_rom(VFIODevice *vdev)
}
}
- DPRINTF("%04x:%02x:%02x.%x ROM size 0x%x\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function, size);
+ trace_vfio_pci_size_rom(vdev->vbasedev.name, size);
snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom",
vdev->host.domain, vdev->host.bus, vdev->host.slot,
@@ -1428,8 +1160,7 @@ static void vfio_vga_write(void *opaque, hwaddr addr,
__func__, region->offset + addr, data, size);
}
- DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
- __func__, region->offset + addr, data, size);
+ trace_vfio_vga_write(region->offset + addr, data, size);
}
static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
@@ -1466,8 +1197,7 @@ static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
break;
}
- DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
- __func__, region->offset + addr, size, data);
+ trace_vfio_vga_read(region->offset + addr, size, data);
return data;
}
@@ -1497,7 +1227,7 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque,
hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
uint64_t data;
if (vfio_flags_enabled(quirk->data.flags, quirk->data.read_flags) &&
@@ -1514,13 +1244,13 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque,
data = vfio_pci_read_config(&vdev->pdev,
quirk->data.address_val + offset, size);
- DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"
- PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- quirk->data.bar, addr, size, data);
+ trace_vfio_generic_window_quirk_read(memory_region_name(&quirk->mem),
+ vdev->vbasedev.name,
+ quirk->data.bar,
+ addr, size, data);
} else {
- data = vfio_bar_read(&vdev->bars[quirk->data.bar],
- addr + quirk->data.base_offset, size);
+ data = vfio_region_read(&vdev->bars[quirk->data.bar].region,
+ addr + quirk->data.base_offset, size);
}
return data;
@@ -1530,7 +1260,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
if (ranges_overlap(addr, size,
quirk->data.address_offset, quirk->data.address_size)) {
@@ -1563,14 +1293,14 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr,
vfio_pci_write_config(&vdev->pdev,
quirk->data.address_val + offset, data, size);
- DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"
- PRIx64", %d)\n", memory_region_name(&quirk->mem),
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, quirk->data.bar, addr, data, size);
+ trace_vfio_generic_window_quirk_write(memory_region_name(&quirk->mem),
+ vdev->vbasedev.name,
+ quirk->data.bar,
+ addr, data, size);
return;
}
- vfio_bar_write(&vdev->bars[quirk->data.bar],
+ vfio_region_write(&vdev->bars[quirk->data.bar].region,
addr + quirk->data.base_offset, data, size);
}
@@ -1584,7 +1314,7 @@ static uint64_t vfio_generic_quirk_read(void *opaque,
hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK;
uint64_t data;
@@ -1599,12 +1329,12 @@ static uint64_t vfio_generic_quirk_read(void *opaque,
data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
- DPRINTF("%s read(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"
- PRIx64"\n", memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- quirk->data.bar, addr + base, size, data);
+ trace_vfio_generic_quirk_read(memory_region_name(&quirk->mem),
+ vdev->vbasedev.name, quirk->data.bar,
+ addr + base, size, data);
} else {
- data = vfio_bar_read(&vdev->bars[quirk->data.bar], addr + base, size);
+ data = vfio_region_read(&vdev->bars[quirk->data.bar].region,
+ addr + base, size);
}
return data;
@@ -1614,7 +1344,7 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK;
@@ -1628,12 +1358,12 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr,
vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
- DPRINTF("%s write(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"
- PRIx64", %d)\n", memory_region_name(&quirk->mem),
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, quirk->data.bar, addr + base, data, size);
+ trace_vfio_generic_quirk_write(memory_region_name(&quirk->mem),
+ vdev->vbasedev.name, quirk->data.bar,
+ addr + base, data, size);
} else {
- vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size);
+ vfio_region_write(&vdev->bars[quirk->data.bar].region,
+ addr + base, data, size);
}
}
@@ -1659,11 +1389,11 @@ static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
uint64_t data = vfio_pci_read_config(&vdev->pdev,
PCI_BASE_ADDRESS_0 + (4 * 4) + 1,
size);
- DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
+ trace_vfio_ati_3c3_quirk_read(data);
return data;
}
@@ -1673,7 +1403,7 @@ static const MemoryRegionOps vfio_ati_3c3_quirk = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
+static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -1686,7 +1416,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
* As long as the BAR is >= 256 bytes it will be aligned such that the
* lower byte is always zero. Filter out anything else, if it exists.
*/
- if (!vdev->bars[4].ioport || vdev->bars[4].size < 256) {
+ if (!vdev->bars[4].ioport || vdev->bars[4].region.size < 256) {
return;
}
@@ -1701,9 +1431,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
quirk, next);
- DPRINTF("Enabled ATI/AMD quirk 0x3c3 BAR4for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_vga_probe_ati_3c3_quirk(vdev->vbasedev.name);
}
/*
@@ -1716,7 +1444,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
* that only read-only access is provided, but we drop writes when the window
* is enabled to config space nonetheless.
*/
-static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -1739,14 +1467,12 @@ static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev),
&vfio_generic_window_quirk, quirk,
"vfio-ati-bar4-window-quirk", 8);
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
quirk->data.base_offset, &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled ATI/AMD BAR4 window quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_ati_bar4_window_quirk(vdev->vbasedev.name);
}
#define PCI_VENDOR_ID_REALTEK 0x10ec
@@ -1778,14 +1504,14 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
switch (addr) {
case 4: /* address */
if (quirk->data.flags) {
- DPRINTF("%s fake read(%04x:%02x:%02x.%d)\n",
- memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_rtl8168_window_quirk_read_fake(
+ memory_region_name(&quirk->mem),
+ vdev->vbasedev.name);
return quirk->data.address_match ^ 0x10000000U;
}
@@ -1794,9 +1520,9 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
if (quirk->data.flags) {
uint64_t val;
- DPRINTF("%s MSI-X table read(%04x:%02x:%02x.%d)\n",
- memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_rtl8168_window_quirk_read_table(
+ memory_region_name(&quirk->mem),
+ vdev->vbasedev.name);
if (!(vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
return 0;
@@ -1809,18 +1535,18 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
}
}
- DPRINTF("%s direct read(%04x:%02x:%02x.%d)\n",
- memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_rtl8168_window_quirk_read_direct(memory_region_name(&quirk->mem),
+ vdev->vbasedev.name);
- return vfio_bar_read(&vdev->bars[quirk->data.bar], addr + 0x70, size);
+ return vfio_region_read(&vdev->bars[quirk->data.bar].region,
+ addr + 0x70, size);
}
static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
switch (addr) {
case 4: /* address */
@@ -1828,9 +1554,9 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
if (data & 0x10000000U &&
vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
- DPRINTF("%s MSI-X table write(%04x:%02x:%02x.%d)\n",
- memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_rtl8168_window_quirk_write_table(
+ memory_region_name(&quirk->mem),
+ vdev->vbasedev.name);
io_mem_write(&vdev->pdev.msix_table_mmio,
(hwaddr)(quirk->data.address_match & 0xfff),
@@ -1849,11 +1575,12 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
break;
}
- DPRINTF("%s direct write(%04x:%02x:%02x.%d)\n",
- memory_region_name(&quirk->mem), vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_rtl8168_window_quirk_write_direct(
+ memory_region_name(&quirk->mem),
+ vdev->vbasedev.name);
- vfio_bar_write(&vdev->bars[quirk->data.bar], addr + 0x70, data, size);
+ vfio_region_write(&vdev->bars[quirk->data.bar].region,
+ addr + 0x70, data, size);
}
static const MemoryRegionOps vfio_rtl8168_window_quirk = {
@@ -1867,7 +1594,7 @@ static const MemoryRegionOps vfio_rtl8168_window_quirk = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void vfio_probe_rtl8168_bar2_window_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -1883,19 +1610,17 @@ static void vfio_probe_rtl8168_bar2_window_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk,
quirk, "vfio-rtl8168-window-quirk", 8);
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
0x70, &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled RTL8168 BAR2 window quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_rtl8168_bar2_window_quirk(vdev->vbasedev.name);
}
/*
* Trap the BAR2 MMIO window to config space as well.
*/
-static void vfio_probe_ati_bar2_4000_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -1916,15 +1641,13 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
"vfio-ati-bar2-4000-quirk",
TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
quirk->data.address_match & TARGET_PAGE_MASK,
&quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled ATI/AMD BAR2 0x4000 quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_ati_bar2_4000_quirk(vdev->vbasedev.name);
}
/*
@@ -1963,14 +1686,14 @@ static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
hwaddr addr, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
addr + quirk->data.base_offset, size);
if (quirk->data.flags == NV_3D0_READ && addr == quirk->data.data_offset) {
data = vfio_pci_read_config(pdev, quirk->data.address_val, size);
- DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data);
+ trace_vfio_nvidia_3d0_quirk_read(size, data);
}
quirk->data.flags = NV_3D0_NONE;
@@ -1982,7 +1705,7 @@ static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
switch (quirk->data.flags) {
@@ -2013,7 +1736,7 @@ static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
quirk->data.flags = NV_3D0_NONE;
if (addr == quirk->data.data_offset) {
vfio_pci_write_config(pdev, quirk->data.address_val, data, size);
- DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size);
+ trace_vfio_nvidia_3d0_quirk_write(data, size);
return;
}
break;
@@ -2029,13 +1752,13 @@ static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
+static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA ||
- !vdev->bars[1].size) {
+ !vdev->bars[1].region.size) {
return;
}
@@ -2057,9 +1780,7 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
quirk, next);
- DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_vga_probe_nvidia_3d0_quirk(vdev->vbasedev.name);
}
/*
@@ -2121,7 +1842,7 @@ static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -2143,20 +1864,19 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev),
&vfio_nvidia_bar5_window_quirk, quirk,
"vfio-nvidia-bar5-window-quirk", 16);
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
+ 0, &quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_nvidia_bar5_window_quirk(vdev->vbasedev.name);
}
static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
VFIOQuirk *quirk = opaque;
- VFIODevice *vdev = quirk->vdev;
+ VFIOPCIDevice *vdev = quirk->vdev;
PCIDevice *pdev = &vdev->pdev;
hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
@@ -2170,7 +1890,8 @@ static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
*/
if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
- vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size);
+ vfio_region_write(&vdev->bars[quirk->data.bar].region,
+ addr + base, data, size);
}
}
@@ -2189,7 +1910,7 @@ static const MemoryRegionOps vfio_nvidia_88000_quirk = {
*
* Here's offset 0x88000...
*/
-static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -2213,21 +1934,19 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk,
quirk, "vfio-nvidia-bar0-88000-quirk",
TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
quirk->data.address_match & TARGET_PAGE_MASK,
&quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_nvidia_bar0_88000_quirk(vdev->vbasedev.name);
}
/*
* And here's the same for BAR0 offset 0x1800...
*/
-static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
+static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr)
{
PCIDevice *pdev = &vdev->pdev;
VFIOQuirk *quirk;
@@ -2238,8 +1957,9 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
}
/* Log the chipset ID */
- DPRINTF("Nvidia NV%02x\n",
- (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff);
+ trace_vfio_probe_nvidia_bar0_1800_quirk_id(
+ (unsigned int)(vfio_region_read(&vdev->bars[0].region, 0, 4) >> 20)
+ & 0xff);
quirk = g_malloc0(sizeof(*quirk));
quirk->vdev = vdev;
@@ -2251,15 +1971,13 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk,
"vfio-nvidia-bar0-1800-quirk",
TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
- memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
quirk->data.address_match & TARGET_PAGE_MASK,
&quirk->mem, 1);
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
- DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_probe_nvidia_bar0_1800_quirk(vdev->vbasedev.name);
}
/*
@@ -2271,13 +1989,13 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
/*
* Common quirk probe entry points.
*/
-static void vfio_vga_quirk_setup(VFIODevice *vdev)
+static void vfio_vga_quirk_setup(VFIOPCIDevice *vdev)
{
vfio_vga_probe_ati_3c3_quirk(vdev);
vfio_vga_probe_nvidia_3d0_quirk(vdev);
}
-static void vfio_vga_quirk_teardown(VFIODevice *vdev)
+static void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev)
{
int i;
@@ -2292,7 +2010,7 @@ static void vfio_vga_quirk_teardown(VFIODevice *vdev)
}
}
-static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
+static void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
{
vfio_probe_ati_bar4_window_quirk(vdev, nr);
vfio_probe_ati_bar2_4000_quirk(vdev, nr);
@@ -2302,13 +2020,13 @@ static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
vfio_probe_rtl8168_bar2_window_quirk(vdev, nr);
}
-static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
+static void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
while (!QLIST_EMPTY(&bar->quirks)) {
VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
- memory_region_del_subregion(&bar->mem, &quirk->mem);
+ memory_region_del_subregion(&bar->region.mem, &quirk->mem);
object_unparent(OBJECT(&quirk->mem));
QLIST_REMOVE(quirk, next);
g_free(quirk);
@@ -2320,7 +2038,7 @@ static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
*/
static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
@@ -2333,7 +2051,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
ssize_t ret;
- ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr);
+ ret = pread(vdev->vbasedev.fd, &phys_val, len,
+ vdev->config_offset + addr);
if (ret != len) {
error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
__func__, vdev->host.domain, vdev->host.bus,
@@ -2345,9 +2064,7 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
val = (emu_val & emu_bits) | (phys_val & ~emu_bits);
- DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, addr, len, val);
+ trace_vfio_pci_read_config(vdev->vbasedev.name, addr, len, val);
return val;
}
@@ -2355,15 +2072,14 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
uint32_t val, int len)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
uint32_t val_le = cpu_to_le32(val);
- DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__,
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, addr, val, len);
+ trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len);
/* Write everything to VFIO, let it filter out what we can't write */
- if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) {
+ if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr)
+ != len) {
error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m",
__func__, vdev->host.domain, vdev->host.bus,
vdev->host.slot, vdev->host.function, addr, val, len);
@@ -2409,310 +2125,9 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
}
/*
- * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
- */
-static int vfio_dma_unmap(VFIOContainer *container,
- hwaddr iova, ram_addr_t size)
-{
- struct vfio_iommu_type1_dma_unmap unmap = {
- .argsz = sizeof(unmap),
- .flags = 0,
- .iova = iova,
- .size = size,
- };
-
- if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
- DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno);
- return -errno;
- }
-
- return 0;
-}
-
-static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
- ram_addr_t size, void *vaddr, bool readonly)
-{
- struct vfio_iommu_type1_dma_map map = {
- .argsz = sizeof(map),
- .flags = VFIO_DMA_MAP_FLAG_READ,
- .vaddr = (__u64)(uintptr_t)vaddr,
- .iova = iova,
- .size = size,
- };
-
- if (!readonly) {
- map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
- }
-
- /*
- * Try the mapping, if it fails with EBUSY, unmap the region and try
- * again. This shouldn't be necessary, but we sometimes see it in
- * the the VGA ROM space.
- */
- if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
- (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
- ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
- return 0;
- }
-
- DPRINTF("VFIO_MAP_DMA: %d\n", -errno);
- return -errno;
-}
-
-static bool vfio_listener_skipped_section(MemoryRegionSection *section)
-{
- return (!memory_region_is_ram(section->mr) &&
- !memory_region_is_iommu(section->mr)) ||
- /*
- * Sizing an enabled 64-bit BAR can cause spurious mappings to
- * addresses in the upper part of the 64-bit address space. These
- * are never accessed by the CPU and beyond the address width of
- * some IOMMU hardware. TODO: VFIO should tell us the IOMMU width.
- */
- section->offset_within_address_space & (1ULL << 63);
-}
-
-static void vfio_iommu_map_notify(Notifier *n, void *data)
-{
- VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
- VFIOContainer *container = giommu->container;
- IOMMUTLBEntry *iotlb = data;
- MemoryRegion *mr;
- hwaddr xlat;
- hwaddr len = iotlb->addr_mask + 1;
- void *vaddr;
- int ret;
-
- DPRINTF("iommu map @ %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
- iotlb->iova, iotlb->iova + iotlb->addr_mask);
-
- /*
- * The IOMMU TLB entry we have just covers translation through
- * this IOMMU to its immediate target. We need to translate
- * it the rest of the way through to memory.
- */
- mr = address_space_translate(&address_space_memory,
- iotlb->translated_addr,
- &xlat, &len, iotlb->perm & IOMMU_WO);
- if (!memory_region_is_ram(mr)) {
- DPRINTF("iommu map to non memory area %"HWADDR_PRIx"\n",
- xlat);
- return;
- }
- /*
- * Translation truncates length to the IOMMU page size,
- * check that it did not truncate too much.
- */
- if (len & iotlb->addr_mask) {
- DPRINTF("iommu has granularity incompatible with target AS\n");
- return;
- }
-
- if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
- vaddr = memory_region_get_ram_ptr(mr) + xlat;
-
- ret = vfio_dma_map(container, iotlb->iova,
- iotlb->addr_mask + 1, vaddr,
- !(iotlb->perm & IOMMU_WO) || mr->readonly);
- if (ret) {
- error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx", %p) = %d (%m)",
- container, iotlb->iova,
- iotlb->addr_mask + 1, vaddr, ret);
- }
- } else {
- ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1);
- if (ret) {
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%m)",
- container, iotlb->iova,
- iotlb->addr_mask + 1, ret);
- }
- }
-}
-
-static void vfio_listener_region_add(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- VFIOContainer *container = container_of(listener, VFIOContainer,
- iommu_data.type1.listener);
- hwaddr iova, end;
- Int128 llend;
- void *vaddr;
- int ret;
-
- if (vfio_listener_skipped_section(section)) {
- DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
- section->offset_within_address_space,
- section->offset_within_address_space +
- int128_get64(int128_sub(section->size, int128_one())));
- return;
- }
-
- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
- (section->offset_within_region & ~TARGET_PAGE_MASK))) {
- error_report("%s received unaligned region", __func__);
- return;
- }
-
- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
- llend = int128_make64(section->offset_within_address_space);
- llend = int128_add(llend, section->size);
- llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
-
- if (int128_ge(int128_make64(iova), llend)) {
- return;
- }
-
- memory_region_ref(section->mr);
-
- if (memory_region_is_iommu(section->mr)) {
- VFIOGuestIOMMU *giommu;
-
- DPRINTF("region_add [iommu] %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
- iova, int128_get64(int128_sub(llend, int128_one())));
- /*
- * FIXME: We should do some checking to see if the
- * capabilities of the host VFIO IOMMU are adequate to model
- * the guest IOMMU
- *
- * FIXME: For VFIO iommu types which have KVM acceleration to
- * avoid bouncing all map/unmaps through qemu this way, this
- * would be the right place to wire that up (tell the KVM
- * device emulation the VFIO iommu handles to use).
- */
- /*
- * This assumes that the guest IOMMU is empty of
- * mappings at this point.
- *
- * One way of doing this is:
- * 1. Avoid sharing IOMMUs between emulated devices or different
- * IOMMU groups.
- * 2. Implement VFIO_IOMMU_ENABLE in the host kernel to fail if
- * there are some mappings in IOMMU.
- *
- * VFIO on SPAPR does that. Other IOMMU models may do that different,
- * they must make sure there are no existing mappings or
- * loop through existing mappings to map them into VFIO.
- */
- giommu = g_malloc0(sizeof(*giommu));
- giommu->iommu = section->mr;
- giommu->container = container;
- giommu->n.notify = vfio_iommu_map_notify;
- QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
- memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
-
- return;
- }
-
- /* Here we assume that memory_region_is_ram(section->mr)==true */
-
- end = int128_get64(llend);
- vaddr = memory_region_get_ram_ptr(section->mr) +
- section->offset_within_region +
- (iova - section->offset_within_address_space);
-
- DPRINTF("region_add [ram] %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
- iova, end - 1, vaddr);
-
- ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
- if (ret) {
- error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx", %p) = %d (%m)",
- container, iova, end - iova, vaddr, ret);
-
- /*
- * On the initfn path, store the first error in the container so we
- * can gracefully fail. Runtime, there's not much we can do other
- * than throw a hardware error.
- */
- if (!container->iommu_data.type1.initialized) {
- if (!container->iommu_data.type1.error) {
- container->iommu_data.type1.error = ret;
- }
- } else {
- hw_error("vfio: DMA mapping failed, unable to continue");
- }
- }
-}
-
-static void vfio_listener_region_del(MemoryListener *listener,
- MemoryRegionSection *section)
-{
- VFIOContainer *container = container_of(listener, VFIOContainer,
- iommu_data.type1.listener);
- hwaddr iova, end;
- int ret;
-
- if (vfio_listener_skipped_section(section)) {
- DPRINTF("SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n",
- section->offset_within_address_space,
- section->offset_within_address_space +
- int128_get64(int128_sub(section->size, int128_one())));
- return;
- }
-
- if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
- (section->offset_within_region & ~TARGET_PAGE_MASK))) {
- error_report("%s received unaligned region", __func__);
- return;
- }
-
- if (memory_region_is_iommu(section->mr)) {
- VFIOGuestIOMMU *giommu;
-
- QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
- if (giommu->iommu == section->mr) {
- memory_region_unregister_iommu_notifier(&giommu->n);
- QLIST_REMOVE(giommu, giommu_next);
- g_free(giommu);
- break;
- }
- }
-
- /*
- * FIXME: We assume the one big unmap below is adequate to
- * remove any individual page mappings in the IOMMU which
- * might have been copied into VFIO. This works for a page table
- * based IOMMU where a big unmap flattens a large range of IO-PTEs.
- * That may not be true for all IOMMU types.
- */
- }
-
- iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
- end = (section->offset_within_address_space + int128_get64(section->size)) &
- TARGET_PAGE_MASK;
-
- if (iova >= end) {
- return;
- }
-
- DPRINTF("region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
- iova, end - 1);
-
- ret = vfio_dma_unmap(container, iova, end - iova);
- memory_region_unref(section->mr);
- if (ret) {
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%m)",
- container, iova, end - iova, ret);
- }
-}
-
-static MemoryListener vfio_memory_listener = {
- .region_add = vfio_listener_region_add,
- .region_del = vfio_listener_region_del,
-};
-
-static void vfio_listener_release(VFIOContainer *container)
-{
- memory_listener_unregister(&container->iommu_data.type1.listener);
-}
-
-/*
* Interrupt setup
*/
-static void vfio_disable_interrupts(VFIODevice *vdev)
+static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
{
switch (vdev->interrupt) {
case VFIO_INT_INTx:
@@ -2727,13 +2142,13 @@ static void vfio_disable_interrupts(VFIODevice *vdev)
}
}
-static int vfio_setup_msi(VFIODevice *vdev, int pos)
+static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos)
{
uint16_t ctrl;
bool msi_64bit, msi_maskbit;
int ret, entries;
- if (pread(vdev->fd, &ctrl, sizeof(ctrl),
+ if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
return -errno;
}
@@ -2743,8 +2158,7 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos)
msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
- DPRINTF("%04x:%02x:%02x.%x PCI MSI CAP @0x%x\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function, pos);
+ trace_vfio_setup_msi(vdev->vbasedev.name, pos);
ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit);
if (ret < 0) {
@@ -2767,28 +2181,29 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos)
* need to first look for where the MSI-X table lives. So we
* unfortunately split MSI-X setup across two functions.
*/
-static int vfio_early_setup_msix(VFIODevice *vdev)
+static int vfio_early_setup_msix(VFIOPCIDevice *vdev)
{
uint8_t pos;
uint16_t ctrl;
uint32_t table, pba;
+ int fd = vdev->vbasedev.fd;
pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
if (!pos) {
return 0;
}
- if (pread(vdev->fd, &ctrl, sizeof(ctrl),
+ if (pread(fd, &ctrl, sizeof(ctrl),
vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
return -errno;
}
- if (pread(vdev->fd, &table, sizeof(table),
+ if (pread(fd, &table, sizeof(table),
vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
return -errno;
}
- if (pread(vdev->fd, &pba, sizeof(pba),
+ if (pread(fd, &pba, sizeof(pba),
vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
return -errno;
}
@@ -2804,23 +2219,22 @@ static int vfio_early_setup_msix(VFIODevice *vdev)
vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
- DPRINTF("%04x:%02x:%02x.%x "
- "PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, pos, vdev->msix->table_bar,
- vdev->msix->table_offset, vdev->msix->entries);
+ trace_vfio_early_setup_msix(vdev->vbasedev.name, pos,
+ vdev->msix->table_bar,
+ vdev->msix->table_offset,
+ vdev->msix->entries);
return 0;
}
-static int vfio_setup_msix(VFIODevice *vdev, int pos)
+static int vfio_setup_msix(VFIOPCIDevice *vdev, int pos)
{
int ret;
ret = msix_init(&vdev->pdev, vdev->msix->entries,
- &vdev->bars[vdev->msix->table_bar].mem,
+ &vdev->bars[vdev->msix->table_bar].region.mem,
vdev->msix->table_bar, vdev->msix->table_offset,
- &vdev->bars[vdev->msix->pba_bar].mem,
+ &vdev->bars[vdev->msix->pba_bar].region.mem,
vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
if (ret < 0) {
if (ret == -ENOTSUP) {
@@ -2833,99 +2247,61 @@ static int vfio_setup_msix(VFIODevice *vdev, int pos)
return 0;
}
-static void vfio_teardown_msi(VFIODevice *vdev)
+static void vfio_teardown_msi(VFIOPCIDevice *vdev)
{
msi_uninit(&vdev->pdev);
if (vdev->msix) {
- msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem,
- &vdev->bars[vdev->msix->pba_bar].mem);
+ msix_uninit(&vdev->pdev,
+ &vdev->bars[vdev->msix->table_bar].region.mem,
+ &vdev->bars[vdev->msix->pba_bar].region.mem);
}
}
/*
* Resource setup
*/
-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled)
+static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled)
{
int i;
for (i = 0; i < PCI_ROM_SLOT; i++) {
VFIOBAR *bar = &vdev->bars[i];
- if (!bar->size) {
+ if (!bar->region.size) {
continue;
}
- memory_region_set_enabled(&bar->mmap_mem, enabled);
+ memory_region_set_enabled(&bar->region.mmap_mem, enabled);
if (vdev->msix && vdev->msix->table_bar == i) {
memory_region_set_enabled(&vdev->msix->mmap_mem, enabled);
}
}
}
-static void vfio_unmap_bar(VFIODevice *vdev, int nr)
+static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
- if (!bar->size) {
+ if (!bar->region.size) {
return;
}
vfio_bar_quirk_teardown(vdev, nr);
- memory_region_del_subregion(&bar->mem, &bar->mmap_mem);
- munmap(bar->mmap, memory_region_size(&bar->mmap_mem));
+ memory_region_del_subregion(&bar->region.mem, &bar->region.mmap_mem);
+ munmap(bar->region.mmap, memory_region_size(&bar->region.mmap_mem));
if (vdev->msix && vdev->msix->table_bar == nr) {
- memory_region_del_subregion(&bar->mem, &vdev->msix->mmap_mem);
+ memory_region_del_subregion(&bar->region.mem, &vdev->msix->mmap_mem);
munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem));
}
}
-static int vfio_mmap_bar(VFIODevice *vdev, VFIOBAR *bar,
- MemoryRegion *mem, MemoryRegion *submem,
- void **map, size_t size, off_t offset,
- const char *name)
-{
- int ret = 0;
-
- if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) {
- int prot = 0;
-
- if (bar->flags & VFIO_REGION_INFO_FLAG_READ) {
- prot |= PROT_READ;
- }
-
- if (bar->flags & VFIO_REGION_INFO_FLAG_WRITE) {
- prot |= PROT_WRITE;
- }
-
- *map = mmap(NULL, size, prot, MAP_SHARED,
- bar->fd, bar->fd_offset + offset);
- if (*map == MAP_FAILED) {
- *map = NULL;
- ret = -errno;
- goto empty_region;
- }
-
- memory_region_init_ram_ptr(submem, OBJECT(vdev), name, size, *map);
- memory_region_set_skip_dump(submem);
- } else {
-empty_region:
- /* Create a zero sized sub-region to make cleanup easy. */
- memory_region_init(submem, OBJECT(vdev), name, 0);
- }
-
- memory_region_add_subregion(mem, offset, submem);
-
- return ret;
-}
-
-static void vfio_map_bar(VFIODevice *vdev, int nr)
+static void vfio_map_bar(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
- unsigned size = bar->size;
+ unsigned size = bar->region.size;
char name[64];
uint32_t pci_bar;
uint8_t type;
@@ -2941,7 +2317,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
vdev->host.function, nr);
/* Determine what type of BAR this is for registration */
- ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar),
+ ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar),
vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr));
if (ret != sizeof(pci_bar)) {
error_report("vfio: Failed to read BAR %d (%m)", nr);
@@ -2955,9 +2331,9 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
~PCI_BASE_ADDRESS_MEM_MASK);
/* A "slow" read/write mapping underlies all BARs */
- memory_region_init_io(&bar->mem, OBJECT(vdev), &vfio_bar_ops,
+ memory_region_init_io(&bar->region.mem, OBJECT(vdev), &vfio_region_ops,
bar, name, size);
- pci_register_bar(&vdev->pdev, nr, type, &bar->mem);
+ pci_register_bar(&vdev->pdev, nr, type, &bar->region.mem);
/*
* We can't mmap areas overlapping the MSIX vector table, so we
@@ -2968,8 +2344,9 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
}
strncat(name, " mmap", sizeof(name) - strlen(name) - 1);
- if (vfio_mmap_bar(vdev, bar, &bar->mem,
- &bar->mmap_mem, &bar->mmap, size, 0, name)) {
+ if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem,
+ &bar->region.mmap_mem, &bar->region.mmap,
+ size, 0, name)) {
error_report("%s unsupported. Performance may be slow", name);
}
@@ -2979,10 +2356,11 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
start = HOST_PAGE_ALIGN(vdev->msix->table_offset +
(vdev->msix->entries * PCI_MSIX_ENTRY_SIZE));
- size = start < bar->size ? bar->size - start : 0;
+ size = start < bar->region.size ? bar->region.size - start : 0;
strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1);
/* VFIOMSIXInfo contains another MemoryRegion for this mapping */
- if (vfio_mmap_bar(vdev, bar, &bar->mem, &vdev->msix->mmap_mem,
+ if (vfio_mmap_region(OBJECT(vdev), &bar->region, &bar->region.mem,
+ &vdev->msix->mmap_mem,
&vdev->msix->mmap, size, start, name)) {
error_report("%s unsupported. Performance may be slow", name);
}
@@ -2991,7 +2369,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
vfio_bar_quirk_setup(vdev, nr);
}
-static void vfio_map_bars(VFIODevice *vdev)
+static void vfio_map_bars(VFIOPCIDevice *vdev)
{
int i;
@@ -3023,7 +2401,7 @@ static void vfio_map_bars(VFIODevice *vdev)
}
}
-static void vfio_unmap_bars(VFIODevice *vdev)
+static void vfio_unmap_bars(VFIOPCIDevice *vdev)
{
int i;
@@ -3059,7 +2437,7 @@ static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask)
pci_set_word(buf, (pci_get_word(buf) & ~mask) | val);
}
-static void vfio_add_emulated_word(VFIODevice *vdev, int pos,
+static void vfio_add_emulated_word(VFIOPCIDevice *vdev, int pos,
uint16_t val, uint16_t mask)
{
vfio_set_word_bits(vdev->pdev.config + pos, val, mask);
@@ -3072,7 +2450,7 @@ static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask)
pci_set_long(buf, (pci_get_long(buf) & ~mask) | val);
}
-static void vfio_add_emulated_long(VFIODevice *vdev, int pos,
+static void vfio_add_emulated_long(VFIOPCIDevice *vdev, int pos,
uint32_t val, uint32_t mask)
{
vfio_set_long_bits(vdev->pdev.config + pos, val, mask);
@@ -3080,7 +2458,7 @@ static void vfio_add_emulated_long(VFIODevice *vdev, int pos,
vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
}
-static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size)
+static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size)
{
uint16_t flags;
uint8_t type;
@@ -3172,43 +2550,37 @@ static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size)
return pos;
}
-static void vfio_check_pcie_flr(VFIODevice *vdev, uint8_t pos)
+static void vfio_check_pcie_flr(VFIOPCIDevice *vdev, uint8_t pos)
{
uint32_t cap = pci_get_long(vdev->pdev.config + pos + PCI_EXP_DEVCAP);
if (cap & PCI_EXP_DEVCAP_FLR) {
- DPRINTF("%04x:%02x:%02x.%x Supports FLR via PCIe cap\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_check_pcie_flr(vdev->vbasedev.name);
vdev->has_flr = true;
}
}
-static void vfio_check_pm_reset(VFIODevice *vdev, uint8_t pos)
+static void vfio_check_pm_reset(VFIOPCIDevice *vdev, uint8_t pos)
{
uint16_t csr = pci_get_word(vdev->pdev.config + pos + PCI_PM_CTRL);
if (!(csr & PCI_PM_CTRL_NO_SOFT_RESET)) {
- DPRINTF("%04x:%02x:%02x.%x Supports PM reset\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_check_pm_reset(vdev->vbasedev.name);
vdev->has_pm_reset = true;
}
}
-static void vfio_check_af_flr(VFIODevice *vdev, uint8_t pos)
+static void vfio_check_af_flr(VFIOPCIDevice *vdev, uint8_t pos)
{
uint8_t cap = pci_get_byte(vdev->pdev.config + pos + PCI_AF_CAP);
if ((cap & PCI_AF_CAP_TP) && (cap & PCI_AF_CAP_FLR)) {
- DPRINTF("%04x:%02x:%02x.%x Supports FLR via AF cap\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_check_af_flr(vdev->vbasedev.name);
vdev->has_flr = true;
}
}
-static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
+static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
{
PCIDevice *pdev = &vdev->pdev;
uint8_t cap_id, next, size;
@@ -3283,7 +2655,7 @@ static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
return 0;
}
-static int vfio_add_capabilities(VFIODevice *vdev)
+static int vfio_add_capabilities(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
@@ -3295,7 +2667,7 @@ static int vfio_add_capabilities(VFIODevice *vdev)
return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
}
-static void vfio_pci_pre_reset(VFIODevice *vdev)
+static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
uint16_t cmd;
@@ -3332,7 +2704,7 @@ static void vfio_pci_pre_reset(VFIODevice *vdev)
vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
}
-static void vfio_pci_post_reset(VFIODevice *vdev)
+static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
{
vfio_enable_intx(vdev);
}
@@ -3344,7 +2716,7 @@ static bool vfio_pci_host_match(PCIHostDeviceAddress *host1,
host1->slot == host2->slot && host1->function == host2->function);
}
-static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
+static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
{
VFIOGroup *group;
struct vfio_pci_hot_reset_info *info;
@@ -3354,17 +2726,15 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
int ret, i, count;
bool multi = false;
- DPRINTF("%s(%04x:%02x:%02x.%x) %s\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- single ? "one" : "multi");
+ trace_vfio_pci_hot_reset(vdev->vbasedev.name, single ? "one" : "multi");
vfio_pci_pre_reset(vdev);
- vdev->needs_reset = false;
+ vdev->vbasedev.needs_reset = false;
info = g_malloc0(sizeof(*info));
info->argsz = sizeof(*info);
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
if (ret && errno != ENOSPC) {
ret = -errno;
if (!vdev->has_pm_reset) {
@@ -3380,35 +2750,34 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
info->argsz = sizeof(*info) + (count * sizeof(*devices));
devices = &info->devices[0];
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
if (ret) {
ret = -errno;
error_report("vfio: hot reset info failed: %m");
goto out_single;
}
- DPRINTF("%04x:%02x:%02x.%x: hot reset dependent devices:\n",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ trace_vfio_pci_hot_reset_has_dep_devices(vdev->vbasedev.name);
/* Verify that we have all the groups required */
for (i = 0; i < info->count; i++) {
PCIHostDeviceAddress host;
- VFIODevice *tmp;
+ VFIOPCIDevice *tmp;
+ VFIODevice *vbasedev_iter;
host.domain = devices[i].segment;
host.bus = devices[i].bus;
host.slot = PCI_SLOT(devices[i].devfn);
host.function = PCI_FUNC(devices[i].devfn);
- DPRINTF("\t%04x:%02x:%02x.%x group %d\n", host.domain,
+ trace_vfio_pci_hot_reset_dep_devices(host.domain,
host.bus, host.slot, host.function, devices[i].group_id);
if (vfio_pci_host_match(&host, &vdev->host)) {
continue;
}
- QLIST_FOREACH(group, &group_list, next) {
+ QLIST_FOREACH(group, &vfio_group_list, next) {
if (group->groupid == devices[i].group_id) {
break;
}
@@ -3416,27 +2785,27 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
if (!group) {
if (!vdev->has_pm_reset) {
- error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, "
+ error_report("vfio: Cannot reset device %s, "
"depends on group %d which is not owned.",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function, devices[i].group_id);
+ vdev->vbasedev.name, devices[i].group_id);
}
ret = -EPERM;
goto out;
}
/* Prep dependent devices for reset and clear our marker. */
- QLIST_FOREACH(tmp, &group->device_list, next) {
+ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
+ if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ continue;
+ }
+ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
if (vfio_pci_host_match(&host, &tmp->host)) {
if (single) {
- DPRINTF("vfio: found another in-use device "
- "%04x:%02x:%02x.%x\n", host.domain, host.bus,
- host.slot, host.function);
ret = -EINVAL;
goto out_single;
}
vfio_pci_pre_reset(tmp);
- tmp->needs_reset = false;
+ tmp->vbasedev.needs_reset = false;
multi = true;
break;
}
@@ -3444,14 +2813,13 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
}
if (!single && !multi) {
- DPRINTF("vfio: No other in-use devices for multi hot reset\n");
ret = -EINVAL;
goto out_single;
}
/* Determine how many group fds need to be passed */
count = 0;
- QLIST_FOREACH(group, &group_list, next) {
+ QLIST_FOREACH(group, &vfio_group_list, next) {
for (i = 0; i < info->count; i++) {
if (group->groupid == devices[i].group_id) {
count++;
@@ -3465,7 +2833,7 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
fds = &reset->group_fds[0];
/* Fill in group fds */
- QLIST_FOREACH(group, &group_list, next) {
+ QLIST_FOREACH(group, &vfio_group_list, next) {
for (i = 0; i < info->count; i++) {
if (group->groupid == devices[i].group_id) {
fds[reset->count++] = group->fd;
@@ -3475,18 +2843,18 @@ static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
}
/* Bus reset! */
- ret = ioctl(vdev->fd, VFIO_DEVICE_PCI_HOT_RESET, reset);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset);
g_free(reset);
- DPRINTF("%04x:%02x:%02x.%x hot reset: %s\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function,
- ret ? "%m" : "Success");
+ trace_vfio_pci_hot_reset_result(vdev->vbasedev.name,
+ ret ? "%m" : "Success");
out:
/* Re-enable INTx on affected devices */
for (i = 0; i < info->count; i++) {
PCIHostDeviceAddress host;
- VFIODevice *tmp;
+ VFIOPCIDevice *tmp;
+ VFIODevice *vbasedev_iter;
host.domain = devices[i].segment;
host.bus = devices[i].bus;
@@ -3497,7 +2865,7 @@ out:
continue;
}
- QLIST_FOREACH(group, &group_list, next) {
+ QLIST_FOREACH(group, &vfio_group_list, next) {
if (group->groupid == devices[i].group_id) {
break;
}
@@ -3507,7 +2875,11 @@ out:
break;
}
- QLIST_FOREACH(tmp, &group->device_list, next) {
+ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
+ if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ continue;
+ }
+ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
if (vfio_pci_host_match(&host, &tmp->host)) {
vfio_pci_post_reset(tmp);
break;
@@ -3536,439 +2908,90 @@ out_single:
* _one() will only do a hot reset for the one in-use devices case, calling
* _multi() will do nothing if a _one() would have been sufficient.
*/
-static int vfio_pci_hot_reset_one(VFIODevice *vdev)
+static int vfio_pci_hot_reset_one(VFIOPCIDevice *vdev)
{
return vfio_pci_hot_reset(vdev, true);
}
-static int vfio_pci_hot_reset_multi(VFIODevice *vdev)
+static int vfio_pci_hot_reset_multi(VFIODevice *vbasedev)
{
+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
return vfio_pci_hot_reset(vdev, false);
}
-static void vfio_pci_reset_handler(void *opaque)
-{
- VFIOGroup *group;
- VFIODevice *vdev;
-
- QLIST_FOREACH(group, &group_list, next) {
- QLIST_FOREACH(vdev, &group->device_list, next) {
- if (!vdev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) {
- vdev->needs_reset = true;
- }
- }
- }
-
- QLIST_FOREACH(group, &group_list, next) {
- QLIST_FOREACH(vdev, &group->device_list, next) {
- if (vdev->needs_reset) {
- vfio_pci_hot_reset_multi(vdev);
- }
- }
- }
-}
-
-static void vfio_kvm_device_add_group(VFIOGroup *group)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_GROUP,
- .attr = KVM_DEV_VFIO_GROUP_ADD,
- .addr = (uint64_t)(unsigned long)&group->fd,
- };
-
- if (!kvm_enabled()) {
- return;
- }
-
- if (vfio_kvm_device_fd < 0) {
- struct kvm_create_device cd = {
- .type = KVM_DEV_TYPE_VFIO,
- };
-
- if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
- DPRINTF("KVM_CREATE_DEVICE: %m\n");
- return;
- }
-
- vfio_kvm_device_fd = cd.fd;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_report("Failed to add group %d to KVM VFIO device: %m",
- group->groupid);
- }
-#endif
-}
-
-static void vfio_kvm_device_del_group(VFIOGroup *group)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_GROUP,
- .attr = KVM_DEV_VFIO_GROUP_DEL,
- .addr = (uint64_t)(unsigned long)&group->fd,
- };
-
- if (vfio_kvm_device_fd < 0) {
- return;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_report("Failed to remove group %d from KVM VFIO device: %m",
- group->groupid);
- }
-#endif
-}
-
-static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as)
-{
- VFIOAddressSpace *space;
-
- QLIST_FOREACH(space, &vfio_address_spaces, list) {
- if (space->as == as) {
- return space;
- }
- }
-
- /* No suitable VFIOAddressSpace, create a new one */
- space = g_malloc0(sizeof(*space));
- space->as = as;
- QLIST_INIT(&space->containers);
-
- QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
-
- return space;
-}
-
-static void vfio_put_address_space(VFIOAddressSpace *space)
-{
- if (QLIST_EMPTY(&space->containers)) {
- QLIST_REMOVE(space, list);
- g_free(space);
- }
-}
-
-static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
-{
- VFIOContainer *container;
- int ret, fd;
- VFIOAddressSpace *space;
-
- space = vfio_get_address_space(as);
-
- QLIST_FOREACH(container, &space->containers, next) {
- if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
- return 0;
- }
- }
-
- fd = qemu_open("/dev/vfio/vfio", O_RDWR);
- if (fd < 0) {
- error_report("vfio: failed to open /dev/vfio/vfio: %m");
- ret = -errno;
- goto put_space_exit;
- }
-
- ret = ioctl(fd, VFIO_GET_API_VERSION);
- if (ret != VFIO_API_VERSION) {
- error_report("vfio: supported vfio version: %d, "
- "reported version: %d", VFIO_API_VERSION, ret);
- ret = -EINVAL;
- goto close_fd_exit;
- }
-
- container = g_malloc0(sizeof(*container));
- container->space = space;
- container->fd = fd;
-
- if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
- ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
- if (ret) {
- error_report("vfio: failed to set group container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
- if (ret) {
- error_report("vfio: failed to set iommu for container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- container->iommu_data.type1.listener = vfio_memory_listener;
- container->iommu_data.release = vfio_listener_release;
-
- memory_listener_register(&container->iommu_data.type1.listener,
- &address_space_memory);
-
- if (container->iommu_data.type1.error) {
- ret = container->iommu_data.type1.error;
- error_report("vfio: memory listener initialization failed for container");
- goto listener_release_exit;
- }
-
- container->iommu_data.type1.initialized = true;
-
- } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) {
- ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
- if (ret) {
- error_report("vfio: failed to set group container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU);
- if (ret) {
- error_report("vfio: failed to set iommu for container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- /*
- * The host kernel code implementing VFIO_IOMMU_DISABLE is called
- * when container fd is closed so we do not call it explicitly
- * in this file.
- */
- ret = ioctl(fd, VFIO_IOMMU_ENABLE);
- if (ret) {
- error_report("vfio: failed to enable container: %m");
- ret = -errno;
- goto free_container_exit;
- }
-
- container->iommu_data.type1.listener = vfio_memory_listener;
- container->iommu_data.release = vfio_listener_release;
-
- memory_listener_register(&container->iommu_data.type1.listener,
- container->space->as);
-
- } else {
- error_report("vfio: No available IOMMU models");
- ret = -EINVAL;
- goto free_container_exit;
- }
-
- QLIST_INIT(&container->group_list);
- QLIST_INSERT_HEAD(&space->containers, container, next);
-
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
-
- return 0;
-
-listener_release_exit:
- vfio_listener_release(container);
-
-free_container_exit:
- g_free(container);
-
-close_fd_exit:
- close(fd);
-
-put_space_exit:
- vfio_put_address_space(space);
-
- return ret;
-}
-
-static void vfio_disconnect_container(VFIOGroup *group)
+static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev)
{
- VFIOContainer *container = group->container;
-
- if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
- error_report("vfio: error disconnecting group %d from container",
- group->groupid);
- }
-
- QLIST_REMOVE(group, container_next);
- group->container = NULL;
-
- if (QLIST_EMPTY(&container->group_list)) {
- VFIOAddressSpace *space = container->space;
-
- if (container->iommu_data.release) {
- container->iommu_data.release(container);
- }
- QLIST_REMOVE(container, next);
- DPRINTF("vfio_disconnect_container: close container->fd\n");
- close(container->fd);
- g_free(container);
-
- vfio_put_address_space(space);
+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
+ if (!vbasedev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) {
+ vbasedev->needs_reset = true;
}
}
-static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
-{
- VFIOGroup *group;
- char path[32];
- struct vfio_group_status status = { .argsz = sizeof(status) };
-
- QLIST_FOREACH(group, &group_list, next) {
- if (group->groupid == groupid) {
- /* Found it. Now is it already in the right context? */
- if (group->container->space->as == as) {
- return group;
- } else {
- error_report("vfio: group %d used in multiple address spaces",
- group->groupid);
- return NULL;
- }
- }
- }
-
- group = g_malloc0(sizeof(*group));
-
- snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
- group->fd = qemu_open(path, O_RDWR);
- if (group->fd < 0) {
- error_report("vfio: error opening %s: %m", path);
- goto free_group_exit;
- }
-
- if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
- error_report("vfio: error getting group status: %m");
- goto close_fd_exit;
- }
-
- if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
- error_report("vfio: error, group %d is not viable, please ensure "
- "all devices within the iommu_group are bound to their "
- "vfio bus driver.", groupid);
- goto close_fd_exit;
- }
-
- group->groupid = groupid;
- QLIST_INIT(&group->device_list);
-
- if (vfio_connect_container(group, as)) {
- error_report("vfio: failed to setup container for group %d", groupid);
- goto close_fd_exit;
- }
-
- if (QLIST_EMPTY(&group_list)) {
- qemu_register_reset(vfio_pci_reset_handler, NULL);
- }
-
- QLIST_INSERT_HEAD(&group_list, group, next);
-
- vfio_kvm_device_add_group(group);
-
- return group;
-
-close_fd_exit:
- close(group->fd);
-
-free_group_exit:
- g_free(group);
-
- return NULL;
-}
-
-static void vfio_put_group(VFIOGroup *group)
-{
- if (!QLIST_EMPTY(&group->device_list)) {
- return;
- }
-
- vfio_kvm_device_del_group(group);
- vfio_disconnect_container(group);
- QLIST_REMOVE(group, next);
- DPRINTF("vfio_put_group: close group->fd\n");
- close(group->fd);
- g_free(group);
-
- if (QLIST_EMPTY(&group_list)) {
- qemu_unregister_reset(vfio_pci_reset_handler, NULL);
- }
-}
+static VFIODeviceOps vfio_pci_ops = {
+ .vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
+ .vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
+ .vfio_eoi = vfio_eoi,
+ .vfio_populate_device = vfio_populate_device,
+};
-static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
+static int vfio_populate_device(VFIODevice *vbasedev)
{
- struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
- int ret, i;
-
- ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
- if (ret < 0) {
- error_report("vfio: error getting device %s from group %d: %m",
- name, group->groupid);
- error_printf("Verify all devices in group %d are bound to vfio-pci "
- "or pci-stub and not already in use\n", group->groupid);
- return ret;
- }
-
- vdev->fd = ret;
- vdev->group = group;
- QLIST_INSERT_HEAD(&group->device_list, vdev, next);
+ int i, ret = -1;
/* Sanity check device */
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info);
- if (ret) {
- error_report("vfio: error getting device info: %m");
- goto error;
- }
-
- DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
- dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
-
- if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
+ if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PCI)) {
error_report("vfio: Um, this isn't a PCI device");
goto error;
}
- vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
-
- if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
+ if (vbasedev->num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
error_report("vfio: unexpected number of io regions %u",
- dev_info.num_regions);
+ vbasedev->num_regions);
goto error;
}
- if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
- error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
+ if (vbasedev->num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
+ error_report("vfio: unexpected number of irqs %u", vbasedev->num_irqs);
goto error;
}
for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
reg_info.index = i;
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
if (ret) {
error_report("vfio: Error getting region %d info: %m", i);
goto error;
}
- DPRINTF("Device %s region %d:\n", name, i);
- DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
- (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
- (unsigned long)reg_info.flags);
+ trace_vfio_populate_device_region(vbasedev->name, i,
+ (unsigned long)reg_info.size,
+ (unsigned long)reg_info.offset,
+ (unsigned long)reg_info.flags);
- vdev->bars[i].flags = reg_info.flags;
- vdev->bars[i].size = reg_info.size;
- vdev->bars[i].fd_offset = reg_info.offset;
- vdev->bars[i].fd = vdev->fd;
- vdev->bars[i].nr = i;
+ vdev->bars[i].region.vbasedev = vbasedev;
+ vdev->bars[i].region.flags = reg_info.flags;
+ vdev->bars[i].region.size = reg_info.size;
+ vdev->bars[i].region.fd_offset = reg_info.offset;
+ vdev->bars[i].region.nr = i;
QLIST_INIT(&vdev->bars[i].quirks);
}
reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
if (ret) {
error_report("vfio: Error getting config info: %m");
goto error;
}
- DPRINTF("Device %s config:\n", name);
- DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
- (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
- (unsigned long)reg_info.flags);
+ trace_vfio_populate_device_config(vdev->vbasedev.name,
+ (unsigned long)reg_info.size,
+ (unsigned long)reg_info.offset,
+ (unsigned long)reg_info.flags);
vdev->config_size = reg_info.size;
if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) {
@@ -3977,13 +3000,13 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
vdev->config_offset = reg_info.offset;
if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) &&
- dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) {
+ vbasedev->num_regions > VFIO_PCI_VGA_REGION_INDEX) {
struct vfio_region_info vga_info = {
.argsz = sizeof(vga_info),
.index = VFIO_PCI_VGA_REGION_INDEX,
};
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info);
if (ret) {
error_report(
"vfio: Device does not support requested feature x-vga");
@@ -4000,7 +3023,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
}
vdev->vga.fd_offset = vga_info.offset;
- vdev->vga.fd = vdev->fd;
+ vdev->vga.fd = vdev->vbasedev.fd;
vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE;
vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM;
@@ -4018,44 +3041,36 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
}
irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
- ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
if (ret) {
/* This can fail for an old kernel or legacy PCI dev */
- DPRINTF("VFIO_DEVICE_GET_IRQ_INFO failure: %m\n");
+ trace_vfio_populate_device_get_irq_info_failure();
ret = 0;
} else if (irq_info.count == 1) {
vdev->pci_aer = true;
} else {
- error_report("vfio: %04x:%02x:%02x.%x "
+ error_report("vfio: %s "
"Could not enable error recovery for the device",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
+ vbasedev->name);
}
error:
- if (ret) {
- QLIST_REMOVE(vdev, next);
- vdev->group = NULL;
- close(vdev->fd);
- }
return ret;
}
-static void vfio_put_device(VFIODevice *vdev)
+static void vfio_put_device(VFIOPCIDevice *vdev)
{
- QLIST_REMOVE(vdev, next);
- vdev->group = NULL;
- DPRINTF("vfio_put_device: close vdev->fd\n");
- close(vdev->fd);
+ g_free(vdev->vbasedev.name);
if (vdev->msix) {
g_free(vdev->msix);
vdev->msix = NULL;
}
+ vfio_put_base_device(&vdev->vbasedev);
}
static void vfio_err_notifier_handler(void *opaque)
{
- VFIODevice *vdev = opaque;
+ VFIOPCIDevice *vdev = opaque;
if (!event_notifier_test_and_clear(&vdev->err_notifier)) {
return;
@@ -4084,7 +3099,7 @@ static void vfio_err_notifier_handler(void *opaque)
* and continue after disabling error recovery support for the
* device.
*/
-static void vfio_register_err_notifier(VFIODevice *vdev)
+static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
{
int ret;
int argsz;
@@ -4115,7 +3130,7 @@ static void vfio_register_err_notifier(VFIODevice *vdev)
*pfd = event_notifier_get_fd(&vdev->err_notifier);
qemu_set_fd_handler(*pfd, vfio_err_notifier_handler, NULL, vdev);
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
if (ret) {
error_report("vfio: Failed to set up error notification");
qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
@@ -4125,7 +3140,7 @@ static void vfio_register_err_notifier(VFIODevice *vdev)
g_free(irq_set);
}
-static void vfio_unregister_err_notifier(VFIODevice *vdev)
+static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev)
{
int argsz;
struct vfio_irq_set *irq_set;
@@ -4148,7 +3163,7 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev)
pfd = (int32_t *)&irq_set->data;
*pfd = -1;
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
if (ret) {
error_report("vfio: Failed to de-assign error fd: %m");
}
@@ -4160,7 +3175,8 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev)
static int vfio_initfn(PCIDevice *pdev)
{
- VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIODevice *vbasedev_iter;
VFIOGroup *group;
char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
ssize_t len;
@@ -4178,6 +3194,13 @@ static int vfio_initfn(PCIDevice *pdev)
return -errno;
}
+ vdev->vbasedev.ops = &vfio_pci_ops;
+
+ vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
+ vdev->vbasedev.name = g_strdup_printf("%04x:%02x:%02x.%01x",
+ vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function);
+
strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
len = readlink(path, iommu_group_path, sizeof(path));
@@ -4194,8 +3217,7 @@ static int vfio_initfn(PCIDevice *pdev)
return -errno;
}
- DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
+ trace_vfio_initfn(vdev->vbasedev.name, groupid);
group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev));
if (!group) {
@@ -4207,19 +3229,15 @@ static int vfio_initfn(PCIDevice *pdev)
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function);
- QLIST_FOREACH(pvdev, &group->device_list, next) {
- if (pvdev->host.domain == vdev->host.domain &&
- pvdev->host.bus == vdev->host.bus &&
- pvdev->host.slot == vdev->host.slot &&
- pvdev->host.function == vdev->host.function) {
-
+ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
+ if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) {
error_report("vfio: error: device %s is already attached", path);
vfio_put_group(group);
return -EBUSY;
}
}
- ret = vfio_get_device(group, path, vdev);
+ ret = vfio_get_device(group, path, &vdev->vbasedev);
if (ret) {
error_report("vfio: failed to get device %s", path);
vfio_put_group(group);
@@ -4227,7 +3245,7 @@ static int vfio_initfn(PCIDevice *pdev)
}
/* Get a copy of config space */
- ret = pread(vdev->fd, vdev->pdev.config,
+ ret = pread(vdev->vbasedev.fd, vdev->pdev.config,
MIN(pci_config_size(&vdev->pdev), vdev->config_size),
vdev->config_offset);
if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
@@ -4313,8 +3331,8 @@ out_put:
static void vfio_exitfn(PCIDevice *pdev)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
- VFIOGroup *group = vdev->group;
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOGroup *group = vdev->vbasedev.group;
vfio_unregister_err_notifier(vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
@@ -4333,17 +3351,16 @@ static void vfio_exitfn(PCIDevice *pdev)
static void vfio_pci_reset(DeviceState *dev)
{
PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ trace_vfio_pci_reset(vdev->vbasedev.name);
vfio_pci_pre_reset(vdev);
- if (vdev->reset_works && (vdev->has_flr || !vdev->has_pm_reset) &&
- !ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
- DPRINTF("%04x:%02x:%02x.%x FLR/VFIO_DEVICE_RESET\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ if (vdev->vbasedev.reset_works &&
+ (vdev->has_flr || !vdev->has_pm_reset) &&
+ !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) {
+ trace_vfio_pci_reset_flr(vdev->vbasedev.name);
goto post_reset;
}
@@ -4353,10 +3370,9 @@ static void vfio_pci_reset(DeviceState *dev)
}
/* If nothing else works and the device supports PM reset, use it */
- if (vdev->reset_works && vdev->has_pm_reset &&
- !ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
- DPRINTF("%04x:%02x:%02x.%x PCI PM Reset\n", vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function);
+ if (vdev->vbasedev.reset_works && vdev->has_pm_reset &&
+ !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) {
+ trace_vfio_pci_reset_pm(vdev->vbasedev.name);
goto post_reset;
}
@@ -4367,7 +3383,7 @@ post_reset:
static void vfio_instance_init(Object *obj)
{
PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, PCI_DEVICE(obj));
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj));
device_add_bootindex_property(obj, &vdev->bootindex,
"bootindex", NULL,
@@ -4375,15 +3391,16 @@ static void vfio_instance_init(Object *obj)
}
static Property vfio_pci_dev_properties[] = {
- DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host),
- DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice,
+ DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
+ DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
intx.mmap_timeout, 1100),
- DEFINE_PROP_BIT("x-vga", VFIODevice, features,
+ DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
VFIO_FEATURE_ENABLE_VGA_BIT, false),
+ DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1),
/*
* TODO - support passed fds... is this necessary?
- * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name),
- * DEFINE_PROP_STRING("vfiogroupfd, VFIODevice, vfiogroupfd_name),
+ * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name),
+ * DEFINE_PROP_STRING("vfiogroupfd, VFIOPCIDevice, vfiogroupfd_name),
*/
DEFINE_PROP_END_OF_LIST(),
};
@@ -4413,7 +3430,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
static const TypeInfo vfio_pci_dev_info = {
.name = "vfio-pci",
.parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VFIODevice),
+ .instance_size = sizeof(VFIOPCIDevice),
.class_init = vfio_pci_dev_class_init,
.instance_init = vfio_instance_init,
};
@@ -4424,47 +3441,3 @@ static void register_vfio_pci_dev_type(void)
}
type_init(register_vfio_pci_dev_type)
-
-static int vfio_container_do_ioctl(AddressSpace *as, int32_t groupid,
- int req, void *param)
-{
- VFIOGroup *group;
- VFIOContainer *container;
- int ret = -1;
-
- group = vfio_get_group(groupid, as);
- if (!group) {
- error_report("vfio: group %d not registered", groupid);
- return ret;
- }
-
- container = group->container;
- if (group->container) {
- ret = ioctl(container->fd, req, param);
- if (ret < 0) {
- error_report("vfio: failed to ioctl container: ret=%d, %s",
- ret, strerror(errno));
- }
- }
-
- vfio_put_group(group);
-
- return ret;
-}
-
-int vfio_container_ioctl(AddressSpace *as, int32_t groupid,
- int req, void *param)
-{
- /* We allow only certain ioctls to the container */
- switch (req) {
- case VFIO_CHECK_EXTENSION:
- case VFIO_IOMMU_SPAPR_TCE_GET_INFO:
- break;
- default:
- /* Return an error on unknown requests */
- error_report("vfio: unsupported ioctl %X", req);
- return -1;
- }
-
- return vfio_container_do_ioctl(as, groupid, req, param);
-}
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index cefc9e6988..c4bf56d44f 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -37,6 +37,10 @@ struct arm_boot_info {
hwaddr gic_cpu_if_addr;
int nb_cpus;
int board_id;
+ /* ARM machines that support the ARM Security Extensions use this field to
+ * control whether Linux is booted as secure(true) or non-secure(false).
+ */
+ bool secure_boot;
int (*atag_board)(const struct arm_boot_info *info, void *p);
/* multicore boards that use the default secondary core boot functions
* can ignore these two function calls. If the default functions won't
@@ -66,6 +70,11 @@ struct arm_boot_info {
hwaddr initrd_start;
hwaddr initrd_size;
hwaddr entry;
+
+ /* Boot firmware has been loaded, typically at address 0, with -bios or
+ * -pflash. It also implies that fw_cfg_find() will succeed.
+ */
+ bool firmware_loaded;
};
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index e0a67903ef..3ddc449bb6 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -65,6 +65,8 @@ int qemu_register_machine(QEMUMachine *m);
MachineClass *find_default_machine(void);
extern MachineState *current_machine;
+bool machine_usb(MachineState *machine);
+
/**
* MachineClass:
* @qemu_machine: #QEMUMachine
diff --git a/include/hw/hw.h b/include/hw/hw.h
index 33bdb92712..c78adae06a 100644
--- a/include/hw/hw.h
+++ b/include/hw/hw.h
@@ -41,12 +41,6 @@ typedef void QEMUResetHandler(void *opaque);
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
-/* handler to set the boot_device order for a specific type of QEMUMachine */
-/* return 0 if success */
-typedef int QEMUBootSetHandler(void *opaque, const char *boot_order);
-void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
-int qemu_boot_set(const char *boot_order);
-
#ifdef NEED_CPU_H
#if TARGET_LONG_BITS == 64
#define VMSTATE_UINTTL_V(_f, _s, _v) \
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 64816395dc..899762019f 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -16,6 +16,15 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
ssize_t load_image_size(const char *filename, void *addr, size_t size);
int load_image_targphys(const char *filename, hwaddr,
uint64_t max_sz);
+
+/* This is the limit on the maximum uncompressed image size that
+ * load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents
+ * g_malloc() in those functions from allocating a huge amount of memory.
+ */
+#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
+
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+ uint8_t **buffer);
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
#define ELF_LOAD_FAILED -1
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 56e1ed7122..6d8a8ac564 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -78,8 +78,10 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
void *data, size_t len);
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
size_t len);
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
- hwaddr crl_addr, hwaddr data_addr);
+FWCfgState *fw_cfg_init_io(uint32_t iobase);
+FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
+FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
+ uint32_t data_width);
FWCfgState *fw_cfg_find(void);
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
new file mode 100644
index 0000000000..1d5bfe8fcb
--- /dev/null
+++ b/include/hw/vfio/vfio-common.h
@@ -0,0 +1,151 @@
+/*
+ * common header for vfio based device assignment support
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on qemu-kvm device-assignment:
+ * Adapted for KVM by Qumranet.
+ * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+#ifndef HW_VFIO_VFIO_COMMON_H
+#define HW_VFIO_VFIO_COMMON_H
+
+#include "qemu-common.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "qemu/queue.h"
+#include "qemu/notify.h"
+
+/*#define DEBUG_VFIO*/
+#ifdef DEBUG_VFIO
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+/* Extra debugging, trap acceleration paths for more logging */
+#define VFIO_ALLOW_MMAP 1
+#define VFIO_ALLOW_KVM_INTX 1
+#define VFIO_ALLOW_KVM_MSI 1
+#define VFIO_ALLOW_KVM_MSIX 1
+
+enum {
+ VFIO_DEVICE_TYPE_PCI = 0,
+};
+
+typedef struct VFIORegion {
+ struct VFIODevice *vbasedev;
+ off_t fd_offset; /* offset of region within device fd */
+ MemoryRegion mem; /* slow, read/write access */
+ MemoryRegion mmap_mem; /* direct mapped access */
+ void *mmap;
+ size_t size;
+ uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
+ uint8_t nr; /* cache the region number for debug */
+} VFIORegion;
+
+typedef struct VFIOAddressSpace {
+ AddressSpace *as;
+ QLIST_HEAD(, VFIOContainer) containers;
+ QLIST_ENTRY(VFIOAddressSpace) list;
+} VFIOAddressSpace;
+
+struct VFIOGroup;
+
+typedef struct VFIOType1 {
+ MemoryListener listener;
+ int error;
+ bool initialized;
+} VFIOType1;
+
+typedef struct VFIOContainer {
+ VFIOAddressSpace *space;
+ int fd; /* /dev/vfio/vfio, empowered by the attached groups */
+ struct {
+ /* enable abstraction to support various iommu backends */
+ union {
+ VFIOType1 type1;
+ };
+ void (*release)(struct VFIOContainer *);
+ } iommu_data;
+ QLIST_HEAD(, VFIOGuestIOMMU) giommu_list;
+ QLIST_HEAD(, VFIOGroup) group_list;
+ QLIST_ENTRY(VFIOContainer) next;
+} VFIOContainer;
+
+typedef struct VFIOGuestIOMMU {
+ VFIOContainer *container;
+ MemoryRegion *iommu;
+ Notifier n;
+ QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
+} VFIOGuestIOMMU;
+
+typedef struct VFIODeviceOps VFIODeviceOps;
+
+typedef struct VFIODevice {
+ QLIST_ENTRY(VFIODevice) next;
+ struct VFIOGroup *group;
+ char *name;
+ int fd;
+ int type;
+ bool reset_works;
+ bool needs_reset;
+ VFIODeviceOps *ops;
+ unsigned int num_irqs;
+ unsigned int num_regions;
+ unsigned int flags;
+} VFIODevice;
+
+struct VFIODeviceOps {
+ void (*vfio_compute_needs_reset)(VFIODevice *vdev);
+ int (*vfio_hot_reset_multi)(VFIODevice *vdev);
+ void (*vfio_eoi)(VFIODevice *vdev);
+ int (*vfio_populate_device)(VFIODevice *vdev);
+};
+
+typedef struct VFIOGroup {
+ int fd;
+ int groupid;
+ VFIOContainer *container;
+ QLIST_HEAD(, VFIODevice) device_list;
+ QLIST_ENTRY(VFIOGroup) next;
+ QLIST_ENTRY(VFIOGroup) container_next;
+} VFIOGroup;
+
+void vfio_put_base_device(VFIODevice *vbasedev);
+void vfio_disable_irqindex(VFIODevice *vbasedev, int index);
+void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index);
+void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index);
+void vfio_region_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size);
+uint64_t vfio_region_read(void *opaque,
+ hwaddr addr, unsigned size);
+void vfio_listener_release(VFIOContainer *container);
+int vfio_mmap_region(Object *vdev, VFIORegion *region,
+ MemoryRegion *mem, MemoryRegion *submem,
+ void **map, size_t size, off_t offset,
+ const char *name);
+void vfio_reset_handler(void *opaque);
+VFIOGroup *vfio_get_group(int groupid, AddressSpace *as);
+void vfio_put_group(VFIOGroup *group);
+int vfio_get_device(VFIOGroup *group, const char *name,
+ VFIODevice *vbasedev);
+
+extern const MemoryRegionOps vfio_region_ops;
+extern const MemoryListener vfio_memory_listener;
+extern QLIST_HEAD(vfio_group_head, VFIOGroup) vfio_group_list;
+extern QLIST_HEAD(vfio_as_head, VFIOAddressSpace) vfio_address_spaces;
+
+#endif /* !HW_VFIO_VFIO_COMMON_H */
diff --git a/include/hw/misc/vfio.h b/include/hw/vfio/vfio.h
index 0b26cd8e11..0b26cd8e11 100644
--- a/include/hw/misc/vfio.h
+++ b/include/hw/vfio/vfio.h
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 57ff47f284..f2bbaaf86a 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -22,6 +22,8 @@ typedef struct DisplayState DisplayState;
typedef struct DisplaySurface DisplaySurface;
typedef struct DriveInfo DriveInfo;
typedef struct EventNotifier EventNotifier;
+typedef struct FWCfgIoState FWCfgIoState;
+typedef struct FWCfgMemState FWCfgMemState;
typedef struct FWCfgState FWCfgState;
typedef struct HCIInfo HCIInfo;
typedef struct I2CBus I2CBus;
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 9fea3bc3af..748d0597f0 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -216,10 +216,19 @@ void del_boot_device_path(DeviceState *dev, const char *suffix);
void device_add_bootindex_property(Object *obj, int32_t *bootindex,
const char *name, const char *suffix,
DeviceState *dev, Error **errp);
+void restore_boot_order(void *opaque);
+void validate_bootdevices(const char *devices, Error **errp);
+
+/* handler to set the boot_device order for a specific type of QEMUMachine */
+typedef void QEMUBootSetHandler(void *opaque, const char *boot_order,
+ Error **errp);
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
+void qemu_boot_set(const char *boot_order, Error **errp);
QemuOpts *qemu_get_machine_opts(void);
-bool usb_enabled(bool default_usb);
+bool defaults_enabled(void);
+bool usb_enabled(void);
extern QemuOptsList qemu_legacy_drive_opts;
extern QemuOptsList qemu_common_drive_opts;
diff --git a/monitor.c b/monitor.c
index 503cf515ad..1808e41932 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1494,17 +1494,15 @@ static void do_ioport_write(Monitor *mon, const QDict *qdict)
static void do_boot_set(Monitor *mon, const QDict *qdict)
{
- int res;
+ Error *local_err = NULL;
const char *bootdevice = qdict_get_str(qdict, "bootdevice");
- res = qemu_boot_set(bootdevice);
- if (res == 0) {
- monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
- } else if (res > 0) {
- monitor_printf(mon, "setting boot device list failed\n");
+ qemu_boot_set(bootdevice, &local_err);
+ if (local_err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+ error_free(local_err);
} else {
- monitor_printf(mon, "no function defined to set boot device list for "
- "this architecture\n");
+ monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
}
}
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index dcfda7dfcf..ed5a6441bb 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -100,6 +100,8 @@ typedef struct ARMCPU {
bool start_powered_off;
/* CPU currently in PSCI powered-off state */
bool powered_off;
+ /* CPU has security extension */
+ bool has_el3;
/* PSCI conduit used to invoke PSCI methods
* 0 - disabled, 1 - smc, 2 - hvc
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index d3db279e1b..285947f911 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -327,6 +327,11 @@ static inline void set_feature(CPUARMState *env, int feature)
env->features |= 1ULL << feature;
}
+static inline void unset_feature(CPUARMState *env, int feature)
+{
+ env->features &= ~(1ULL << feature);
+}
+
static void arm_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -383,6 +388,9 @@ static Property arm_cpu_reset_hivecs_property =
static Property arm_cpu_rvbar_property =
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
+static Property arm_cpu_has_el3_property =
+ DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
+
static void arm_cpu_post_init(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -402,6 +410,14 @@ static void arm_cpu_post_init(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property,
&error_abort);
}
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
+ /* Add the has_el3 state CPU property only if EL3 is allowed. This will
+ * prevent "has_el3" from existing on CPUs which cannot support EL3.
+ */
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
+ &error_abort);
+ }
}
static void arm_cpu_finalizefn(Object *obj)
@@ -471,6 +487,18 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
cpu->reset_sctlr |= (1 << 13);
}
+ if (!cpu->has_el3) {
+ /* If the has_el3 CPU property is disabled then we need to disable the
+ * feature.
+ */
+ unset_feature(env, ARM_FEATURE_EL3);
+
+ /* Disable the security extension feature bits in the processor feature
+ * register as well. This is id_pfr1[7:4].
+ */
+ cpu->id_pfr1 &= ~0xf0;
+ }
+
register_cp_regs_for_features(cpu);
arm_cpu_register_gdb_regs_for_features(cpu);
@@ -640,6 +668,7 @@ static void arm1176_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
+ set_feature(&cpu->env, ARM_FEATURE_EL3);
cpu->midr = 0x410fb767;
cpu->reset_fpsid = 0x410120b5;
cpu->mvfr0 = 0x11111111;
@@ -728,6 +757,7 @@ static void cortex_a8_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+ set_feature(&cpu->env, ARM_FEATURE_EL3);
cpu->midr = 0x410fc080;
cpu->reset_fpsid = 0x410330c0;
cpu->mvfr0 = 0x11110222;
@@ -795,6 +825,7 @@ static void cortex_a9_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_EL3);
/* Note that A9 supports the MP extensions even for
* A9UP and single-core A9MP (which are both different
* and valid configurations; we don't model A9UP).
@@ -862,6 +893,7 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
set_feature(&cpu->env, ARM_FEATURE_LPAE);
+ set_feature(&cpu->env, ARM_FEATURE_EL3);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
cpu->midr = 0x412fc0f1;
cpu->reset_fpsid = 0x410430f0;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 96abbed935..3ef0f1f38e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2413,7 +2413,30 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
REGINFO_SENTINEL
};
-static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
+static const ARMCPRegInfo el3_cp_reginfo[] = {
+ { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3),
+ .resetvalue = 0, .writefn = scr_write },
+ { .name = "SCR", .type = ARM_CP_NO_MIGRATE,
+ .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
+ .resetfn = arm_cp_reset_ignore, .writefn = scr_write },
+ { .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.sder) },
+ { .name = "SDER",
+ .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1,
+ .access = PL3_RW, .resetvalue = 0,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.sder) },
+ /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */
+ { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
+ .access = PL3_W | PL1_R, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.nsacr) },
+ { .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1,
+ .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
{ .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL3_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
@@ -2451,33 +2474,6 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
REGINFO_SENTINEL
};
-static const ARMCPRegInfo el3_cp_reginfo[] = {
- { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
- .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
- .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3),
- .resetvalue = 0, .writefn = scr_write },
- { .name = "SCR", .type = ARM_CP_NO_MIGRATE,
- .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
- .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
- .resetfn = arm_cp_reset_ignore, .writefn = scr_write },
- { .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64,
- .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1,
- .access = PL3_RW, .resetvalue = 0,
- .fieldoffset = offsetof(CPUARMState, cp15.sder) },
- { .name = "SDER",
- .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1,
- .access = PL3_RW, .resetvalue = 0,
- .fieldoffset = offsetoflow32(CPUARMState, cp15.sder) },
- /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */
- { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
- .access = PL3_W | PL1_R, .resetvalue = 0,
- .fieldoffset = offsetof(CPUARMState, cp15.nsacr) },
- { .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1,
- .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
- .fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
- REGINFO_SENTINEL
-};
-
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
@@ -3077,9 +3073,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
}
}
if (arm_feature(env, ARM_FEATURE_EL3)) {
- if (arm_feature(env, ARM_FEATURE_V8)) {
- define_arm_cp_regs(cpu, v8_el3_cp_reginfo);
- }
define_arm_cp_regs(cpu, el3_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_MPU)) {
diff --git a/target-tricore/helper.h b/target-tricore/helper.h
index 6c07bd7f28..068dc7b422 100644
--- a/target-tricore/helper.h
+++ b/target-tricore/helper.h
@@ -18,8 +18,12 @@
/* Arithmetic */
DEF_HELPER_3(add_ssov, i32, env, i32, i32)
DEF_HELPER_3(add_suov, i32, env, i32, i32)
+DEF_HELPER_3(add_h_ssov, i32, env, i32, i32)
+DEF_HELPER_3(add_h_suov, i32, env, i32, i32)
DEF_HELPER_3(sub_ssov, i32, env, i32, i32)
DEF_HELPER_3(sub_suov, i32, env, i32, i32)
+DEF_HELPER_3(sub_h_ssov, i32, env, i32, i32)
+DEF_HELPER_3(sub_h_suov, i32, env, i32, i32)
DEF_HELPER_3(mul_ssov, i32, env, i32, i32)
DEF_HELPER_3(mul_suov, i32, env, i32, i32)
DEF_HELPER_3(sha_ssov, i32, env, i32, i32)
@@ -32,6 +36,61 @@ DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_4(msub64_suov, i64, env, i32, i64, i32)
+DEF_HELPER_3(absdif_h_ssov, i32, env, i32, i32)
+DEF_HELPER_2(abs_ssov, i32, env, i32)
+DEF_HELPER_2(abs_h_ssov, i32, env, i32)
+/* hword/byte arithmetic */
+DEF_HELPER_2(abs_b, i32, env, i32)
+DEF_HELPER_2(abs_h, i32, env, i32)
+DEF_HELPER_3(absdif_b, i32, env, i32, i32)
+DEF_HELPER_3(absdif_h, i32, env, i32, i32)
+DEF_HELPER_3(add_b, i32, env, i32, i32)
+DEF_HELPER_3(add_h, i32, env, i32, i32)
+DEF_HELPER_3(sub_b, i32, env, i32, i32)
+DEF_HELPER_3(sub_h, i32, env, i32, i32)
+DEF_HELPER_FLAGS_2(eq_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(eq_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(eqany_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(eqany_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(lt_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(lt_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(lt_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(lt_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+/* count leading ... */
+DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(clz_h, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(cls, TCG_CALL_NO_RWG_SE, i32, i32)
+DEF_HELPER_FLAGS_1(cls_h, TCG_CALL_NO_RWG_SE, i32, i32)
+/* sh */
+DEF_HELPER_FLAGS_2(sh, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(sh_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_3(sha, i32, env, i32, i32)
+DEF_HELPER_2(sha_h, i32, i32, i32)
+/* merge/split/parity */
+DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32)
+DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32)
+/* float */
+DEF_HELPER_1(unpack, i64, i32)
+/* dvinit */
+DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32)
+DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32)
+DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32)
+DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32)
+/* mulh */
+DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32)
/* CSA */
DEF_HELPER_2(call, void, env, i32)
DEF_HELPER_1(ret, void, env)
diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c
index 4da76ff232..13e27291c1 100644
--- a/target-tricore/op_helper.c
+++ b/target-tricore/op_helper.c
@@ -56,118 +56,211 @@ uint32_t helper_circ_update(uint32_t reg, uint32_t off)
return reg - index + new_index;
}
-#define SSOV(env, ret, arg, len) do { \
- int64_t max_pos = INT##len ##_MAX; \
- int64_t max_neg = INT##len ##_MIN; \
- if (arg > max_pos) { \
- env->PSW_USB_V = (1 << 31); \
- env->PSW_USB_SV = (1 << 31); \
- ret = (target_ulong)max_pos; \
- } else { \
- if (arg < max_neg) { \
- env->PSW_USB_V = (1 << 31); \
- env->PSW_USB_SV = (1 << 31); \
- ret = (target_ulong)max_neg; \
- } else { \
- env->PSW_USB_V = 0; \
- ret = (target_ulong)arg; \
- } \
- } \
- env->PSW_USB_AV = arg ^ arg * 2u; \
- env->PSW_USB_SAV |= env->PSW_USB_AV; \
-} while (0)
-
-#define SUOV(env, ret, arg, len) do { \
- int64_t max_pos = UINT##len ##_MAX; \
- if (arg > max_pos) { \
- env->PSW_USB_V = (1 << 31); \
- env->PSW_USB_SV = (1 << 31); \
- ret = (target_ulong)max_pos; \
- } else { \
- if (arg < 0) { \
- env->PSW_USB_V = (1 << 31); \
- env->PSW_USB_SV = (1 << 31); \
- ret = 0; \
- } else { \
- env->PSW_USB_V = 0; \
- ret = (target_ulong)arg; \
- } \
- } \
- env->PSW_USB_AV = arg ^ arg * 2u; \
- env->PSW_USB_SAV |= env->PSW_USB_AV; \
-} while (0)
+static uint32_t ssov32(CPUTriCoreState *env, int64_t arg)
+{
+ uint32_t ret;
+ int64_t max_pos = INT32_MAX;
+ int64_t max_neg = INT32_MIN;
+ if (arg > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ env->PSW_USB_SV = (1 << 31);
+ ret = (target_ulong)max_pos;
+ } else {
+ if (arg < max_neg) {
+ env->PSW_USB_V = (1 << 31);
+ env->PSW_USB_SV = (1 << 31);
+ ret = (target_ulong)max_neg;
+ } else {
+ env->PSW_USB_V = 0;
+ ret = (target_ulong)arg;
+ }
+ }
+ env->PSW_USB_AV = arg ^ arg * 2u;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return ret;
+}
+
+static uint32_t suov32(CPUTriCoreState *env, int64_t arg)
+{
+ uint32_t ret;
+ int64_t max_pos = UINT32_MAX;
+ if (arg > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ env->PSW_USB_SV = (1 << 31);
+ ret = (target_ulong)max_pos;
+ } else {
+ if (arg < 0) {
+ env->PSW_USB_V = (1 << 31);
+ env->PSW_USB_SV = (1 << 31);
+ ret = 0;
+ } else {
+ env->PSW_USB_V = 0;
+ ret = (target_ulong)arg;
+ }
+ }
+ env->PSW_USB_AV = arg ^ arg * 2u;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return ret;
+}
+static uint32_t ssov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1)
+{
+ int32_t max_pos = INT16_MAX;
+ int32_t max_neg = INT16_MIN;
+ int32_t av0, av1;
+
+ env->PSW_USB_V = 0;
+ av0 = hw0 ^ hw0 * 2u;
+ if (hw0 > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ hw0 = max_pos;
+ } else if (hw0 < max_neg) {
+ env->PSW_USB_V = (1 << 31);
+ hw0 = max_neg;
+ }
+
+ av1 = hw1 ^ hw1 * 2u;
+ if (hw1 > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ hw1 = max_pos;
+ } else if (hw1 < max_neg) {
+ env->PSW_USB_V = (1 << 31);
+ hw1 = max_neg;
+ }
+
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = (av0 | av1) << 16;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return (hw0 & 0xffff) | (hw1 << 16);
+}
+
+static uint32_t suov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1)
+{
+ int32_t max_pos = UINT16_MAX;
+ int32_t av0, av1;
+
+ env->PSW_USB_V = 0;
+ av0 = hw0 ^ hw0 * 2u;
+ if (hw0 > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ hw0 = max_pos;
+ } else if (hw0 < 0) {
+ env->PSW_USB_V = (1 << 31);
+ hw0 = 0;
+ }
+
+ av1 = hw1 ^ hw1 * 2u;
+ if (hw1 > max_pos) {
+ env->PSW_USB_V = (1 << 31);
+ hw1 = max_pos;
+ } else if (hw1 < 0) {
+ env->PSW_USB_V = (1 << 31);
+ hw1 = 0;
+ }
+
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = (av0 | av1) << 16;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return (hw0 & 0xffff) | (hw1 << 16);
+}
target_ulong helper_add_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t result = t1 + t2;
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
+}
+
+target_ulong helper_add_h_ssov(CPUTriCoreState *env, target_ulong r1,
+ target_ulong r2)
+{
+ int32_t ret_hw0, ret_hw1;
+
+ ret_hw0 = sextract32(r1, 0, 16) + sextract32(r2, 0, 16);
+ ret_hw1 = sextract32(r1, 16, 16) + sextract32(r2, 16, 16);
+ return ssov16(env, ret_hw0, ret_hw1);
}
target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 + t2;
- SUOV(env, ret, result, 32);
- return ret;
+ return suov32(env, result);
+}
+
+target_ulong helper_add_h_suov(CPUTriCoreState *env, target_ulong r1,
+ target_ulong r2)
+{
+ int32_t ret_hw0, ret_hw1;
+
+ ret_hw0 = extract32(r1, 0, 16) + extract32(r2, 0, 16);
+ ret_hw1 = extract32(r1, 16, 16) + extract32(r2, 16, 16);
+ return suov16(env, ret_hw0, ret_hw1);
}
target_ulong helper_sub_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t result = t1 - t2;
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
+}
+
+target_ulong helper_sub_h_ssov(CPUTriCoreState *env, target_ulong r1,
+ target_ulong r2)
+{
+ int32_t ret_hw0, ret_hw1;
+
+ ret_hw0 = sextract32(r1, 0, 16) - sextract32(r2, 0, 16);
+ ret_hw1 = sextract32(r1, 16, 16) - sextract32(r2, 16, 16);
+ return ssov16(env, ret_hw0, ret_hw1);
}
target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 - t2;
- SUOV(env, ret, result, 32);
- return ret;
+ return suov32(env, result);
+}
+
+target_ulong helper_sub_h_suov(CPUTriCoreState *env, target_ulong r1,
+ target_ulong r2)
+{
+ int32_t ret_hw0, ret_hw1;
+
+ ret_hw0 = extract32(r1, 0, 16) - extract32(r2, 0, 16);
+ ret_hw1 = extract32(r1, 16, 16) - extract32(r2, 16, 16);
+ return suov16(env, ret_hw0, ret_hw1);
}
target_ulong helper_mul_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t result = t1 * t2;
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
}
target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t result = t1 * t2;
- SUOV(env, ret, result, 32);
- return ret;
+ return suov32(env, result);
}
target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int32_t t2 = sextract64(r2, 0, 6);
int64_t result;
@@ -178,14 +271,32 @@ target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1,
} else {
result = t1 >> -t2;
}
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
+}
+
+uint32_t helper_abs_ssov(CPUTriCoreState *env, target_ulong r1)
+{
+ target_ulong result;
+ result = ((int32_t)r1 >= 0) ? r1 : (0 - r1);
+ return ssov32(env, result);
+}
+
+uint32_t helper_abs_h_ssov(CPUTriCoreState *env, target_ulong r1)
+{
+ int32_t ret_h0, ret_h1;
+
+ ret_h0 = sextract32(r1, 0, 16);
+ ret_h0 = (ret_h0 >= 0) ? ret_h0 : (0 - ret_h0);
+
+ ret_h1 = sextract32(r1, 16, 16);
+ ret_h1 = (ret_h1 >= 0) ? ret_h1 : (0 - ret_h1);
+
+ return ssov16(env, ret_h0, ret_h1);
}
target_ulong helper_absdif_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t result;
@@ -195,36 +306,56 @@ target_ulong helper_absdif_ssov(CPUTriCoreState *env, target_ulong r1,
} else {
result = t2 - t1;
}
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
+}
+
+uint32_t helper_absdif_h_ssov(CPUTriCoreState *env, target_ulong r1,
+ target_ulong r2)
+{
+ int32_t t1, t2;
+ int32_t ret_h0, ret_h1;
+
+ t1 = sextract32(r1, 0, 16);
+ t2 = sextract32(r2, 0, 16);
+ if (t1 > t2) {
+ ret_h0 = t1 - t2;
+ } else {
+ ret_h0 = t2 - t1;
+ }
+
+ t1 = sextract32(r1, 16, 16);
+ t2 = sextract32(r2, 16, 16);
+ if (t1 > t2) {
+ ret_h1 = t1 - t2;
+ } else {
+ ret_h1 = t2 - t1;
+ }
+
+ return ssov16(env, ret_h0, ret_h1);
}
target_ulong helper_madd32_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2, target_ulong r3)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t t3 = sextract64(r3, 0, 32);
int64_t result;
result = t2 + (t1 * t3);
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
}
target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2, target_ulong r3)
{
- target_ulong ret;
uint64_t t1 = extract64(r1, 0, 32);
uint64_t t2 = extract64(r2, 0, 32);
uint64_t t3 = extract64(r3, 0, 32);
int64_t result;
result = t2 + (t1 * t3);
- SUOV(env, ret, result, 32);
- return ret;
+ return suov32(env, result);
}
uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1,
@@ -286,29 +417,25 @@ uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong helper_msub32_ssov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2, target_ulong r3)
{
- target_ulong ret;
int64_t t1 = sextract64(r1, 0, 32);
int64_t t2 = sextract64(r2, 0, 32);
int64_t t3 = sextract64(r3, 0, 32);
int64_t result;
result = t2 - (t1 * t3);
- SSOV(env, ret, result, 32);
- return ret;
+ return ssov32(env, result);
}
target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1,
target_ulong r2, target_ulong r3)
{
- target_ulong ret;
int64_t t1 = extract64(r1, 0, 32);
int64_t t2 = extract64(r2, 0, 32);
int64_t t3 = extract64(r3, 0, 32);
int64_t result;
result = t2 - (t1 * t3);
- SUOV(env, ret, result, 32);
- return ret;
+ return suov32(env, result);
}
uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1,
@@ -366,6 +493,813 @@ uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1,
return ret;
}
+uint32_t helper_abs_b(CPUTriCoreState *env, target_ulong arg)
+{
+ int32_t b, i;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ b = sextract32(arg, i * 8, 8);
+ b = (b >= 0) ? b : (0 - b);
+ ovf |= (b > 0x7F) || (b < -0x80);
+ avf |= b ^ b * 2u;
+ ret |= (b & 0xff) << (i * 8);
+ }
+
+ env->PSW_USB_V = ovf << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 24;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_abs_h(CPUTriCoreState *env, target_ulong arg)
+{
+ int32_t h, i;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 2; i++) {
+ h = sextract32(arg, i * 16, 16);
+ h = (h >= 0) ? h : (0 - h);
+ ovf |= (h > 0x7FFF) || (h < -0x8000);
+ avf |= h ^ h * 2u;
+ ret |= (h & 0xffff) << (i * 16);
+ }
+
+ env->PSW_USB_V = ovf << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 16;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_absdif_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t b, i;
+ int32_t extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ extr_r2 = sextract32(r2, i * 8, 8);
+ b = sextract32(r1, i * 8, 8);
+ b = (b > extr_r2) ? (b - extr_r2) : (extr_r2 - b);
+ ovf |= (b > 0x7F) || (b < -0x80);
+ avf |= b ^ b * 2u;
+ ret |= (b & 0xff) << (i * 8);
+ }
+
+ env->PSW_USB_V = ovf << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 24;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+ return ret;
+}
+
+uint32_t helper_absdif_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t h, i;
+ int32_t extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 2; i++) {
+ extr_r2 = sextract32(r2, i * 16, 16);
+ h = sextract32(r1, i * 16, 16);
+ h = (h > extr_r2) ? (h - extr_r2) : (extr_r2 - h);
+ ovf |= (h > 0x7FFF) || (h < -0x8000);
+ avf |= h ^ h * 2u;
+ ret |= (h & 0xffff) << (i * 16);
+ }
+
+ env->PSW_USB_V = ovf << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 16;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_add_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t b, i;
+ int32_t extr_r1, extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ uint32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ extr_r1 = sextract32(r1, i * 8, 8);
+ extr_r2 = sextract32(r2, i * 8, 8);
+
+ b = extr_r1 + extr_r2;
+ ovf |= ((b > 0x7f) || (b < -0x80));
+ avf |= b ^ b * 2u;
+ ret |= ((b & 0xff) << (i*8));
+ }
+
+ env->PSW_USB_V = (ovf << 31);
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 24;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_add_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t h, i;
+ int32_t extr_r1, extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 2; i++) {
+ extr_r1 = sextract32(r1, i * 16, 16);
+ extr_r2 = sextract32(r2, i * 16, 16);
+ h = extr_r1 + extr_r2;
+ ovf |= ((h > 0x7fff) || (h < -0x8000));
+ avf |= h ^ h * 2u;
+ ret |= (h & 0xffff) << (i * 16);
+ }
+
+ env->PSW_USB_V = (ovf << 31);
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = (avf << 16);
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_sub_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t b, i;
+ int32_t extr_r1, extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ uint32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ extr_r1 = sextract32(r1, i * 8, 8);
+ extr_r2 = sextract32(r2, i * 8, 8);
+
+ b = extr_r1 - extr_r2;
+ ovf |= ((b > 0x7f) || (b < -0x80));
+ avf |= b ^ b * 2u;
+ ret |= ((b & 0xff) << (i*8));
+ }
+
+ env->PSW_USB_V = (ovf << 31);
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 24;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_sub_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t h, i;
+ int32_t extr_r1, extr_r2;
+ int32_t ovf = 0;
+ int32_t avf = 0;
+ int32_t ret = 0;
+
+ for (i = 0; i < 2; i++) {
+ extr_r1 = sextract32(r1, i * 16, 16);
+ extr_r2 = sextract32(r2, i * 16, 16);
+ h = extr_r1 - extr_r2;
+ ovf |= ((h > 0x7fff) || (h < -0x8000));
+ avf |= h ^ h * 2u;
+ ret |= (h & 0xffff) << (i * 16);
+ }
+
+ env->PSW_USB_V = (ovf << 31);
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = avf << 16;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_eq_b(target_ulong r1, target_ulong r2)
+{
+ int32_t ret;
+ int32_t i, msk;
+
+ ret = 0;
+ msk = 0xff;
+ for (i = 0; i < 4; i++) {
+ if ((r1 & msk) == (r2 & msk)) {
+ ret |= msk;
+ }
+ msk = msk << 8;
+ }
+
+ return ret;
+}
+
+uint32_t helper_eq_h(target_ulong r1, target_ulong r2)
+{
+ int32_t ret = 0;
+
+ if ((r1 & 0xffff) == (r2 & 0xffff)) {
+ ret = 0xffff;
+ }
+
+ if ((r1 & 0xffff0000) == (r2 & 0xffff0000)) {
+ ret |= 0xffff0000;
+ }
+
+ return ret;
+}
+
+uint32_t helper_eqany_b(target_ulong r1, target_ulong r2)
+{
+ int32_t i;
+ uint32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ ret |= (sextract32(r1, i * 8, 8) == sextract32(r2, i * 8, 8));
+ }
+
+ return ret;
+}
+
+uint32_t helper_eqany_h(target_ulong r1, target_ulong r2)
+{
+ uint32_t ret;
+
+ ret = (sextract32(r1, 0, 16) == sextract32(r2, 0, 16));
+ ret |= (sextract32(r1, 16, 16) == sextract32(r2, 16, 16));
+
+ return ret;
+}
+
+uint32_t helper_lt_b(target_ulong r1, target_ulong r2)
+{
+ int32_t i;
+ uint32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (sextract32(r1, i * 8, 8) < sextract32(r2, i * 8, 8)) {
+ ret |= (0xff << (i * 8));
+ }
+ }
+
+ return ret;
+}
+
+uint32_t helper_lt_bu(target_ulong r1, target_ulong r2)
+{
+ int32_t i;
+ uint32_t ret = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (extract32(r1, i * 8, 8) < extract32(r2, i * 8, 8)) {
+ ret |= (0xff << (i * 8));
+ }
+ }
+
+ return ret;
+}
+
+uint32_t helper_lt_h(target_ulong r1, target_ulong r2)
+{
+ uint32_t ret = 0;
+
+ if (sextract32(r1, 0, 16) < sextract32(r2, 0, 16)) {
+ ret |= 0xffff;
+ }
+
+ if (sextract32(r1, 16, 16) < sextract32(r2, 16, 16)) {
+ ret |= 0xffff0000;
+ }
+
+ return ret;
+}
+
+uint32_t helper_lt_hu(target_ulong r1, target_ulong r2)
+{
+ uint32_t ret = 0;
+
+ if (extract32(r1, 0, 16) < extract32(r2, 0, 16)) {
+ ret |= 0xffff;
+ }
+
+ if (extract32(r1, 16, 16) < extract32(r2, 16, 16)) {
+ ret |= 0xffff0000;
+ }
+
+ return ret;
+}
+
+#define EXTREMA_H_B(name, op) \
+uint32_t helper_##name ##_b(target_ulong r1, target_ulong r2) \
+{ \
+ int32_t i, extr_r1, extr_r2; \
+ uint32_t ret = 0; \
+ \
+ for (i = 0; i < 4; i++) { \
+ extr_r1 = sextract32(r1, i * 8, 8); \
+ extr_r2 = sextract32(r2, i * 8, 8); \
+ extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret |= (extr_r1 & 0xff) << (i * 8); \
+ } \
+ return ret; \
+} \
+ \
+uint32_t helper_##name ##_bu(target_ulong r1, target_ulong r2)\
+{ \
+ int32_t i; \
+ uint32_t extr_r1, extr_r2; \
+ uint32_t ret = 0; \
+ \
+ for (i = 0; i < 4; i++) { \
+ extr_r1 = extract32(r1, i * 8, 8); \
+ extr_r2 = extract32(r2, i * 8, 8); \
+ extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret |= (extr_r1 & 0xff) << (i * 8); \
+ } \
+ return ret; \
+} \
+ \
+uint32_t helper_##name ##_h(target_ulong r1, target_ulong r2) \
+{ \
+ int32_t extr_r1, extr_r2; \
+ uint32_t ret = 0; \
+ \
+ extr_r1 = sextract32(r1, 0, 16); \
+ extr_r2 = sextract32(r2, 0, 16); \
+ ret = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret = ret & 0xffff; \
+ \
+ extr_r1 = sextract32(r1, 16, 16); \
+ extr_r2 = sextract32(r2, 16, 16); \
+ extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret |= extr_r1 << 16; \
+ \
+ return ret; \
+} \
+ \
+uint32_t helper_##name ##_hu(target_ulong r1, target_ulong r2)\
+{ \
+ uint32_t extr_r1, extr_r2; \
+ uint32_t ret = 0; \
+ \
+ extr_r1 = extract32(r1, 0, 16); \
+ extr_r2 = extract32(r2, 0, 16); \
+ ret = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret = ret & 0xffff; \
+ \
+ extr_r1 = extract32(r1, 16, 16); \
+ extr_r2 = extract32(r2, 16, 16); \
+ extr_r1 = (extr_r1 op extr_r2) ? extr_r1 : extr_r2; \
+ ret |= extr_r1 << (16); \
+ \
+ return ret; \
+} \
+
+EXTREMA_H_B(max, >)
+EXTREMA_H_B(min, <)
+
+#undef EXTREMA_H_B
+
+uint32_t helper_clo(target_ulong r1)
+{
+ return clo32(r1);
+}
+
+uint32_t helper_clo_h(target_ulong r1)
+{
+ uint32_t ret_hw0 = extract32(r1, 0, 16);
+ uint32_t ret_hw1 = extract32(r1, 16, 16);
+
+ ret_hw0 = clo32(ret_hw0 << 16);
+ ret_hw1 = clo32(ret_hw1 << 16);
+
+ if (ret_hw0 > 16) {
+ ret_hw0 = 16;
+ }
+ if (ret_hw1 > 16) {
+ ret_hw1 = 16;
+ }
+
+ return ret_hw0 | (ret_hw1 << 16);
+}
+
+uint32_t helper_clz(target_ulong r1)
+{
+ return clz32(r1);
+}
+
+uint32_t helper_clz_h(target_ulong r1)
+{
+ uint32_t ret_hw0 = extract32(r1, 0, 16);
+ uint32_t ret_hw1 = extract32(r1, 16, 16);
+
+ ret_hw0 = clz32(ret_hw0 << 16);
+ ret_hw1 = clz32(ret_hw1 << 16);
+
+ if (ret_hw0 > 16) {
+ ret_hw0 = 16;
+ }
+ if (ret_hw1 > 16) {
+ ret_hw1 = 16;
+ }
+
+ return ret_hw0 | (ret_hw1 << 16);
+}
+
+uint32_t helper_cls(target_ulong r1)
+{
+ return clrsb32(r1);
+}
+
+uint32_t helper_cls_h(target_ulong r1)
+{
+ uint32_t ret_hw0 = extract32(r1, 0, 16);
+ uint32_t ret_hw1 = extract32(r1, 16, 16);
+
+ ret_hw0 = clrsb32(ret_hw0 << 16);
+ ret_hw1 = clrsb32(ret_hw1 << 16);
+
+ if (ret_hw0 > 15) {
+ ret_hw0 = 15;
+ }
+ if (ret_hw1 > 15) {
+ ret_hw1 = 15;
+ }
+
+ return ret_hw0 | (ret_hw1 << 16);
+}
+
+uint32_t helper_sh(target_ulong r1, target_ulong r2)
+{
+ int32_t shift_count = sextract32(r2, 0, 6);
+
+ if (shift_count == -32) {
+ return 0;
+ } else if (shift_count < 0) {
+ return r1 >> -shift_count;
+ } else {
+ return r1 << shift_count;
+ }
+}
+
+uint32_t helper_sh_h(target_ulong r1, target_ulong r2)
+{
+ int32_t ret_hw0, ret_hw1;
+ int32_t shift_count;
+
+ shift_count = sextract32(r2, 0, 5);
+
+ if (shift_count == -16) {
+ return 0;
+ } else if (shift_count < 0) {
+ ret_hw0 = extract32(r1, 0, 16) >> -shift_count;
+ ret_hw1 = extract32(r1, 16, 16) >> -shift_count;
+ return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
+ } else {
+ ret_hw0 = extract32(r1, 0, 16) << shift_count;
+ ret_hw1 = extract32(r1, 16, 16) << shift_count;
+ return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
+ }
+}
+
+uint32_t helper_sha(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
+{
+ int32_t shift_count;
+ int64_t result, t1;
+ uint32_t ret;
+
+ shift_count = sextract32(r2, 0, 6);
+ t1 = sextract32(r1, 0, 32);
+
+ if (shift_count == 0) {
+ env->PSW_USB_C = env->PSW_USB_V = 0;
+ ret = r1;
+ } else if (shift_count == -32) {
+ env->PSW_USB_C = r1;
+ env->PSW_USB_V = 0;
+ ret = t1 >> 31;
+ } else if (shift_count > 0) {
+ result = t1 << shift_count;
+ /* calc carry */
+ env->PSW_USB_C = ((result & 0xffffffff00000000) != 0);
+ /* calc v */
+ env->PSW_USB_V = (((result > 0x7fffffffLL) ||
+ (result < -0x80000000LL)) << 31);
+ /* calc sv */
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ ret = (uint32_t)result;
+ } else {
+ env->PSW_USB_V = 0;
+ env->PSW_USB_C = (r1 & ((1 << -shift_count) - 1));
+ ret = t1 >> -shift_count;
+ }
+
+ env->PSW_USB_AV = ret ^ ret * 2u;
+ env->PSW_USB_SAV |= env->PSW_USB_AV;
+
+ return ret;
+}
+
+uint32_t helper_sha_h(target_ulong r1, target_ulong r2)
+{
+ int32_t shift_count;
+ int32_t ret_hw0, ret_hw1;
+
+ shift_count = sextract32(r2, 0, 5);
+
+ if (shift_count == 0) {
+ return r1;
+ } else if (shift_count < 0) {
+ ret_hw0 = sextract32(r1, 0, 16) >> -shift_count;
+ ret_hw1 = sextract32(r1, 16, 16) >> -shift_count;
+ return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
+ } else {
+ ret_hw0 = sextract32(r1, 0, 16) << shift_count;
+ ret_hw1 = sextract32(r1, 16, 16) << shift_count;
+ return (ret_hw0 & 0xffff) | (ret_hw1 << 16);
+ }
+}
+
+uint32_t helper_bmerge(target_ulong r1, target_ulong r2)
+{
+ uint32_t i, ret;
+
+ ret = 0;
+ for (i = 0; i < 16; i++) {
+ ret |= (r1 & 1) << (2 * i + 1);
+ ret |= (r2 & 1) << (2 * i);
+ r1 = r1 >> 1;
+ r2 = r2 >> 1;
+ }
+ return ret;
+}
+
+uint64_t helper_bsplit(uint32_t r1)
+{
+ int32_t i;
+ uint64_t ret;
+
+ ret = 0;
+ for (i = 0; i < 32; i = i + 2) {
+ /* even */
+ ret |= (r1 & 1) << (i/2);
+ r1 = r1 >> 1;
+ /* odd */
+ ret |= (uint64_t)(r1 & 1) << (i/2 + 32);
+ r1 = r1 >> 1;
+ }
+ return ret;
+}
+
+uint32_t helper_parity(target_ulong r1)
+{
+ uint32_t ret;
+ uint32_t nOnes, i;
+
+ ret = 0;
+ nOnes = 0;
+ for (i = 0; i < 8; i++) {
+ ret ^= (r1 & 1);
+ r1 = r1 >> 1;
+ }
+ /* second byte */
+ nOnes = 0;
+ for (i = 0; i < 8; i++) {
+ nOnes ^= (r1 & 1);
+ r1 = r1 >> 1;
+ }
+ ret |= nOnes << 8;
+ /* third byte */
+ nOnes = 0;
+ for (i = 0; i < 8; i++) {
+ nOnes ^= (r1 & 1);
+ r1 = r1 >> 1;
+ }
+ ret |= nOnes << 16;
+ /* fourth byte */
+ nOnes = 0;
+ for (i = 0; i < 8; i++) {
+ nOnes ^= (r1 & 1);
+ r1 = r1 >> 1;
+ }
+ ret |= nOnes << 24;
+
+ return ret;
+}
+
+uint64_t helper_unpack(target_ulong arg1)
+{
+ int32_t fp_exp = extract32(arg1, 23, 8);
+ int32_t fp_frac = extract32(arg1, 0, 23);
+ uint64_t ret;
+ int32_t int_exp, int_mant;
+
+ if (fp_exp == 255) {
+ int_exp = 255;
+ int_mant = (fp_frac << 7);
+ } else if ((fp_exp == 0) && (fp_frac == 0)) {
+ int_exp = -127;
+ int_mant = 0;
+ } else if ((fp_exp == 0) && (fp_frac != 0)) {
+ int_exp = -126;
+ int_mant = (fp_frac << 7);
+ } else {
+ int_exp = fp_exp - 127;
+ int_mant = (fp_frac << 7);
+ int_mant |= (1 << 30);
+ }
+ ret = int_exp;
+ ret = ret << 32;
+ ret |= int_mant;
+
+ return ret;
+}
+
+uint64_t helper_dvinit_b_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t ret;
+ int32_t abs_sig_dividend, abs_base_dividend, abs_divisor;
+ int32_t quotient_sign;
+
+ ret = sextract32(r1, 0, 32);
+ ret = ret << 24;
+ quotient_sign = 0;
+ if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
+ ret |= 0xffffff;
+ quotient_sign = 1;
+ }
+
+ abs_sig_dividend = abs(r1) >> 7;
+ abs_base_dividend = abs(r1) & 0x7f;
+ abs_divisor = abs(r1);
+ /* calc overflow */
+ env->PSW_USB_V = 0;
+ if ((quotient_sign) && (abs_divisor)) {
+ env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) &&
+ (abs_base_dividend >= abs_divisor)) ||
+ (abs_sig_dividend > abs_divisor));
+ } else {
+ env->PSW_USB_V = (abs_sig_dividend >= abs_divisor);
+ }
+ env->PSW_USB_V = env->PSW_USB_V << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = 0;
+
+ return ret;
+}
+
+uint64_t helper_dvinit_b_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t ret = sextract32(r1, 0, 32);
+
+ ret = ret << 24;
+ if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
+ ret |= 0xffffff;
+ }
+ /* calc overflow */
+ env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffffff80)));
+ env->PSW_USB_V = env->PSW_USB_V << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = 0;
+
+ return ret;
+}
+
+uint64_t helper_dvinit_h_13(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t ret;
+ int32_t abs_sig_dividend, abs_base_dividend, abs_divisor;
+ int32_t quotient_sign;
+
+ ret = sextract32(r1, 0, 32);
+ ret = ret << 16;
+ quotient_sign = 0;
+ if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
+ ret |= 0xffff;
+ quotient_sign = 1;
+ }
+
+ abs_sig_dividend = abs(r1) >> 7;
+ abs_base_dividend = abs(r1) & 0x7f;
+ abs_divisor = abs(r1);
+ /* calc overflow */
+ env->PSW_USB_V = 0;
+ if ((quotient_sign) && (abs_divisor)) {
+ env->PSW_USB_V = (((abs_sig_dividend == abs_divisor) &&
+ (abs_base_dividend >= abs_divisor)) ||
+ (abs_sig_dividend > abs_divisor));
+ } else {
+ env->PSW_USB_V = (abs_sig_dividend >= abs_divisor);
+ }
+ env->PSW_USB_V = env->PSW_USB_V << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = 0;
+
+ return ret;
+}
+
+uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+ uint64_t ret = sextract32(r1, 0, 32);
+
+ ret = ret << 16;
+ if (!((r1 & 0x80000000) == (r2 & 0x80000000))) {
+ ret |= 0xffff;
+ }
+ /* calc overflow */
+ env->PSW_USB_V = ((r2 == 0) || ((r2 == 0xffffffff) && (r1 == 0xffff8000)));
+ env->PSW_USB_V = env->PSW_USB_V << 31;
+ env->PSW_USB_SV |= env->PSW_USB_V;
+ env->PSW_USB_AV = 0;
+
+ return ret;
+}
+
+uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01,
+ uint32_t arg10, uint32_t arg11, uint32_t n)
+{
+ uint64_t ret;
+ uint32_t result0, result1;
+
+ int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
+ ((arg10 & 0xffff) == 0x8000) && (n == 1);
+ int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
+ ((arg11 & 0xffff) == 0x8000) && (n == 1);
+ if (sc1) {
+ result1 = 0x7fffffff;
+ } else {
+ result1 = (((uint32_t)(arg00 * arg10)) << n);
+ }
+ if (sc0) {
+ result0 = 0x7fffffff;
+ } else {
+ result0 = (((uint32_t)(arg01 * arg11)) << n);
+ }
+ ret = (((uint64_t)result1 << 32)) | result0;
+ return ret;
+}
+
+uint64_t helper_mulm_h(uint32_t arg00, uint32_t arg01,
+ uint32_t arg10, uint32_t arg11, uint32_t n)
+{
+ uint64_t ret;
+ int64_t result0, result1;
+
+ int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
+ ((arg10 & 0xffff) == 0x8000) && (n == 1);
+ int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
+ ((arg11 & 0xffff) == 0x8000) && (n == 1);
+
+ if (sc1) {
+ result1 = 0x7fffffff;
+ } else {
+ result1 = (((int32_t)arg00 * (int32_t)arg10) << n);
+ }
+ if (sc0) {
+ result0 = 0x7fffffff;
+ } else {
+ result0 = (((int32_t)arg01 * (int32_t)arg11) << n);
+ }
+ ret = (result1 + result0);
+ ret = ret << 16;
+ return ret;
+}
+uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01,
+ uint32_t arg10, uint32_t arg11, uint32_t n)
+{
+ uint32_t result0, result1;
+
+ int32_t sc1 = ((arg00 & 0xffff) == 0x8000) &&
+ ((arg10 & 0xffff) == 0x8000) && (n == 1);
+ int32_t sc0 = ((arg01 & 0xffff) == 0x8000) &&
+ ((arg11 & 0xffff) == 0x8000) && (n == 1);
+
+ if (sc1) {
+ result1 = 0x7fffffff;
+ } else {
+ result1 = ((arg00 * arg10) << n) + 0x8000;
+ }
+ if (sc0) {
+ result0 = 0x7fffffff;
+ } else {
+ result0 = ((arg01 * arg11) << n) + 0x8000;
+ }
+ return (result1 & 0xffff0000) | (result0 >> 16);
+}
+
/* context save area (CSA) related helpers */
static int cdc_increment(target_ulong *psw)
diff --git a/target-tricore/translate.c b/target-tricore/translate.c
index f57eb7e9c1..3b83782be2 100644
--- a/target-tricore/translate.c
+++ b/target-tricore/translate.c
@@ -85,22 +85,31 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f,
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
+ uint32_t psw;
int i;
- cpu_fprintf(f, "PC=%08x\n", env->PC);
+ psw = psw_read(env);
+
+ cpu_fprintf(f, "PC: " TARGET_FMT_lx, env->PC);
+ cpu_fprintf(f, " PSW: " TARGET_FMT_lx, psw);
+ cpu_fprintf(f, " ICR: " TARGET_FMT_lx, env->ICR);
+ cpu_fprintf(f, "\nPCXI: " TARGET_FMT_lx, env->PCXI);
+ cpu_fprintf(f, " FCX: " TARGET_FMT_lx, env->FCX);
+ cpu_fprintf(f, " LCX: " TARGET_FMT_lx, env->LCX);
+
for (i = 0; i < 16; ++i) {
if ((i & 3) == 0) {
- cpu_fprintf(f, "GPR A%02d:", i);
+ cpu_fprintf(f, "\nGPR A%02d:", i);
}
- cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames_a[i], env->gpr_a[i]);
+ cpu_fprintf(f, " " TARGET_FMT_lx, env->gpr_a[i]);
}
for (i = 0; i < 16; ++i) {
if ((i & 3) == 0) {
- cpu_fprintf(f, "GPR D%02d:", i);
+ cpu_fprintf(f, "\nGPR D%02d:", i);
}
- cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames_d[i], env->gpr_d[i]);
+ cpu_fprintf(f, " " TARGET_FMT_lx, env->gpr_d[i]);
}
-
+ cpu_fprintf(f, "\n");
}
/*
@@ -115,6 +124,64 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f,
tcg_temp_free_i32(helper_tmp); \
} while (0)
+#define GEN_HELPER_LL(name, ret, arg0, arg1, n) do { \
+ TCGv arg00 = tcg_temp_new(); \
+ TCGv arg01 = tcg_temp_new(); \
+ TCGv arg11 = tcg_temp_new(); \
+ tcg_gen_sari_tl(arg00, arg0, 16); \
+ tcg_gen_ext16s_tl(arg01, arg0); \
+ tcg_gen_ext16s_tl(arg11, arg1); \
+ gen_helper_##name(ret, arg00, arg01, arg11, arg11, n); \
+ tcg_temp_free(arg00); \
+ tcg_temp_free(arg01); \
+ tcg_temp_free(arg11); \
+} while (0)
+
+#define GEN_HELPER_LU(name, ret, arg0, arg1, n) do { \
+ TCGv arg00 = tcg_temp_new(); \
+ TCGv arg01 = tcg_temp_new(); \
+ TCGv arg10 = tcg_temp_new(); \
+ TCGv arg11 = tcg_temp_new(); \
+ tcg_gen_sari_tl(arg00, arg0, 16); \
+ tcg_gen_ext16s_tl(arg01, arg0); \
+ tcg_gen_sari_tl(arg11, arg1, 16); \
+ tcg_gen_ext16s_tl(arg10, arg1); \
+ gen_helper_##name(ret, arg00, arg01, arg10, arg11, n); \
+ tcg_temp_free(arg00); \
+ tcg_temp_free(arg01); \
+ tcg_temp_free(arg10); \
+ tcg_temp_free(arg11); \
+} while (0)
+
+#define GEN_HELPER_UL(name, ret, arg0, arg1, n) do { \
+ TCGv arg00 = tcg_temp_new(); \
+ TCGv arg01 = tcg_temp_new(); \
+ TCGv arg10 = tcg_temp_new(); \
+ TCGv arg11 = tcg_temp_new(); \
+ tcg_gen_sari_tl(arg00, arg0, 16); \
+ tcg_gen_ext16s_tl(arg01, arg0); \
+ tcg_gen_sari_tl(arg10, arg1, 16); \
+ tcg_gen_ext16s_tl(arg11, arg1); \
+ gen_helper_##name(ret, arg00, arg01, arg10, arg11, n); \
+ tcg_temp_free(arg00); \
+ tcg_temp_free(arg01); \
+ tcg_temp_free(arg10); \
+ tcg_temp_free(arg11); \
+} while (0)
+
+#define GEN_HELPER_UU(name, ret, arg0, arg1, n) do { \
+ TCGv arg00 = tcg_temp_new(); \
+ TCGv arg01 = tcg_temp_new(); \
+ TCGv arg11 = tcg_temp_new(); \
+ tcg_gen_sari_tl(arg01, arg0, 16); \
+ tcg_gen_ext16s_tl(arg00, arg0); \
+ tcg_gen_sari_tl(arg11, arg1, 16); \
+ gen_helper_##name(ret, arg00, arg01, arg11, arg11, n); \
+ tcg_temp_free(arg00); \
+ tcg_temp_free(arg01); \
+ tcg_temp_free(arg11); \
+} while (0)
+
#define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF))
#define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \
((offset & 0x0fffff) << 1))
@@ -719,6 +786,62 @@ static inline void gen_sub_d(TCGv ret, TCGv r1, TCGv r2)
tcg_temp_free(result);
}
+static inline void gen_sub_CC(TCGv ret, TCGv r1, TCGv r2)
+{
+ TCGv result = tcg_temp_new();
+ TCGv temp = tcg_temp_new();
+
+ tcg_gen_sub_tl(result, r1, r2);
+ /* calc C bit */
+ tcg_gen_setcond_tl(TCG_COND_GEU, cpu_PSW_C, r1, r2);
+ /* calc V bit */
+ tcg_gen_xor_tl(cpu_PSW_V, result, r1);
+ tcg_gen_xor_tl(temp, r1, r2);
+ tcg_gen_and_tl(cpu_PSW_V, cpu_PSW_V, temp);
+ /* calc SV bit */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* Calc AV bit */
+ tcg_gen_add_tl(cpu_PSW_AV, result, result);
+ tcg_gen_xor_tl(cpu_PSW_AV, result, cpu_PSW_AV);
+ /* calc SAV bit */
+ tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV);
+ /* write back result */
+ tcg_gen_mov_tl(ret, result);
+
+ tcg_temp_free(result);
+ tcg_temp_free(temp);
+}
+
+static inline void gen_subc_CC(TCGv ret, TCGv r1, TCGv r2)
+{
+ TCGv temp = tcg_temp_new();
+ tcg_gen_not_tl(temp, r2);
+ gen_addc_CC(ret, r1, temp);
+ tcg_temp_free(temp);
+}
+
+static inline void gen_abs(TCGv ret, TCGv r1)
+{
+ TCGv temp = tcg_temp_new();
+ TCGv t0 = tcg_const_i32(0);
+
+ tcg_gen_neg_tl(temp, r1);
+ tcg_gen_movcond_tl(TCG_COND_GE, ret, r1, t0, r1, temp);
+ /* overflow can only happen, if r1 = 0x80000000 */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, r1, 0x80000000);
+ tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
+ /* calc SV bit */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* Calc AV bit */
+ tcg_gen_add_tl(cpu_PSW_AV, ret, ret);
+ tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV);
+ /* calc SAV bit */
+ tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV);
+
+ tcg_temp_free(temp);
+ tcg_temp_free(t0);
+}
+
static inline void gen_absdif(TCGv ret, TCGv r1, TCGv r2)
{
TCGv temp = tcg_temp_new_i32();
@@ -1208,6 +1331,13 @@ gen_accumulating_condi(int cond, TCGv ret, TCGv r1, int32_t con,
tcg_temp_free(temp);
}
+/* ret = (r1 cond r2) ? 0xFFFFFFFF ? 0x00000000;*/
+static inline void gen_cond_w(TCGCond cond, TCGv ret, TCGv r1, TCGv r2)
+{
+ tcg_gen_setcond_tl(cond, ret, r1, r2);
+ tcg_gen_neg_tl(ret, ret);
+}
+
static inline void gen_eqany_bi(TCGv ret, TCGv r1, int32_t con)
{
TCGv b0 = tcg_temp_new();
@@ -1284,6 +1414,86 @@ static inline void gen_insert(TCGv ret, TCGv r1, TCGv r2, TCGv width, TCGv pos)
tcg_temp_free(temp2);
}
+static inline void gen_bsplit(TCGv rl, TCGv rh, TCGv r1)
+{
+ TCGv_i64 temp = tcg_temp_new_i64();
+
+ gen_helper_bsplit(temp, r1);
+ tcg_gen_extr_i64_i32(rl, rh, temp);
+
+ tcg_temp_free_i64(temp);
+}
+
+static inline void gen_unpack(TCGv rl, TCGv rh, TCGv r1)
+{
+ TCGv_i64 temp = tcg_temp_new_i64();
+
+ gen_helper_unpack(temp, r1);
+ tcg_gen_extr_i64_i32(rl, rh, temp);
+
+ tcg_temp_free_i64(temp);
+}
+
+static inline void
+gen_dvinit_b(CPUTriCoreState *env, TCGv rl, TCGv rh, TCGv r1, TCGv r2)
+{
+ TCGv_i64 ret = tcg_temp_new_i64();
+
+ if (!tricore_feature(env, TRICORE_FEATURE_131)) {
+ gen_helper_dvinit_b_13(ret, cpu_env, r1, r2);
+ } else {
+ gen_helper_dvinit_b_131(ret, cpu_env, r1, r2);
+ }
+ tcg_gen_extr_i64_i32(rl, rh, ret);
+
+ tcg_temp_free_i64(ret);
+}
+
+static inline void
+gen_dvinit_h(CPUTriCoreState *env, TCGv rl, TCGv rh, TCGv r1, TCGv r2)
+{
+ TCGv_i64 ret = tcg_temp_new_i64();
+
+ if (!tricore_feature(env, TRICORE_FEATURE_131)) {
+ gen_helper_dvinit_h_13(ret, cpu_env, r1, r2);
+ } else {
+ gen_helper_dvinit_h_131(ret, cpu_env, r1, r2);
+ }
+ tcg_gen_extr_i64_i32(rl, rh, ret);
+
+ tcg_temp_free_i64(ret);
+}
+
+static void gen_calc_usb_mul_h(TCGv arg_low, TCGv arg_high)
+{
+ TCGv temp = tcg_temp_new();
+ /* calc AV bit */
+ tcg_gen_add_tl(temp, arg_low, arg_low);
+ tcg_gen_xor_tl(temp, temp, arg_low);
+ tcg_gen_add_tl(cpu_PSW_AV, arg_high, arg_high);
+ tcg_gen_xor_tl(cpu_PSW_AV, cpu_PSW_AV, arg_high);
+ tcg_gen_or_tl(cpu_PSW_AV, cpu_PSW_AV, temp);
+ /* calc SAV bit */
+ tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV);
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ tcg_temp_free(temp);
+}
+
+static void gen_calc_usb_mulr_h(TCGv arg)
+{
+ TCGv temp = tcg_temp_new();
+ /* calc AV bit */
+ tcg_gen_add_tl(temp, arg, arg);
+ tcg_gen_xor_tl(temp, temp, arg);
+ tcg_gen_shli_tl(cpu_PSW_AV, temp, 16);
+ tcg_gen_or_tl(cpu_PSW_AV, cpu_PSW_AV, temp);
+ /* calc SAV bit */
+ tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV);
+ /* clear V bit */
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ tcg_temp_free(temp);
+}
+
/* helpers for generating program flow micro-ops */
static inline void gen_save_pc(target_ulong pc)
@@ -3203,7 +3413,7 @@ static void decode_bol_opc(CPUTriCoreState *env, DisasContext *ctx, int32_t op1)
tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LEUL);
tcg_temp_free(temp);
break;
- case OPC1_32_BOL_LD_W_LONFOFF:
+ case OPC1_32_BOL_LD_W_LONGOFF:
temp = tcg_temp_new();
tcg_gen_addi_tl(temp, cpu_gpr_a[r2], address);
tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUL);
@@ -3222,8 +3432,49 @@ static void decode_bol_opc(CPUTriCoreState *env, DisasContext *ctx, int32_t op1)
case OPC1_32_BOL_ST_W_LONGOFF:
gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUL);
break;
+ case OPC1_32_BOL_LD_B_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
+ case OPC1_32_BOL_LD_BU_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_UB);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
+ case OPC1_32_BOL_LD_H_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
+ case OPC1_32_BOL_LD_HU_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUW);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
+ case OPC1_32_BOL_ST_B_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
+ case OPC1_32_BOL_ST_H_LONGOFF:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW);
+ } else {
+ /* raise illegal opcode trap */
+ }
+ break;
}
-
}
/* RC format */
@@ -3776,11 +4027,23 @@ static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx,
tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r1], const16 << 16);
break;
case OPC1_32_RLC_MFCR:
+ const16 = MASK_OP_RLC_CONST16(ctx->opcode);
gen_mfcr(env, cpu_gpr_d[r2], const16);
break;
case OPC1_32_RLC_MOV:
tcg_gen_movi_tl(cpu_gpr_d[r2], const16);
break;
+ case OPC1_32_RLC_MOV_64:
+ if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ if ((r2 & 0x1) != 0) {
+ /* TODO: raise OPD trap */
+ }
+ tcg_gen_movi_tl(cpu_gpr_d[r2], const16);
+ tcg_gen_movi_tl(cpu_gpr_d[r2+1], const16 >> 15);
+ } else {
+ /* TODO: raise illegal opcode trap */
+ }
+ break;
case OPC1_32_RLC_MOV_U:
const16 = MASK_OP_RLC_CONST16(ctx->opcode);
tcg_gen_movi_tl(cpu_gpr_d[r2], const16);
@@ -3792,11 +4055,729 @@ static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx,
tcg_gen_movi_tl(cpu_gpr_a[r2], const16 << 16);
break;
case OPC1_32_RLC_MTCR:
- gen_mtcr(env, ctx, cpu_gpr_d[r2], const16);
+ const16 = MASK_OP_RLC_CONST16(ctx->opcode);
+ gen_mtcr(env, ctx, cpu_gpr_d[r1], const16);
break;
}
}
+/* RR format */
+static void decode_rr_accumulator(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2;
+ int r3, r2, r1;
+
+ r3 = MASK_OP_RR_D(ctx->opcode);
+ r2 = MASK_OP_RR_S2(ctx->opcode);
+ r1 = MASK_OP_RR_S1(ctx->opcode);
+ op2 = MASK_OP_RR_OP2(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR_ABS:
+ gen_abs(cpu_gpr_d[r3], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABS_B:
+ gen_helper_abs_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABS_H:
+ gen_helper_abs_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSDIF:
+ gen_absdif(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSDIF_B:
+ gen_helper_absdif_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSDIF_H:
+ gen_helper_absdif_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSDIFS:
+ gen_helper_absdif_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSDIFS_H:
+ gen_helper_absdif_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSS:
+ gen_helper_abs_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ABSS_H:
+ gen_helper_abs_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADD:
+ gen_add_d(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADD_B:
+ gen_helper_add_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADD_H:
+ gen_helper_add_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDC:
+ gen_addc_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDS:
+ gen_adds(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDS_H:
+ gen_helper_add_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDS_HU:
+ gen_helper_add_h_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDS_U:
+ gen_helper_add_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ADDX:
+ gen_add_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_AND_EQ:
+ gen_accumulating_cond(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_AND_GE:
+ gen_accumulating_cond(TCG_COND_GE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_AND_GE_U:
+ gen_accumulating_cond(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_AND_LT:
+ gen_accumulating_cond(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_AND_LT_U:
+ gen_accumulating_cond(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_AND_NE:
+ gen_accumulating_cond(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_and_tl);
+ break;
+ case OPC2_32_RR_EQ:
+ tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_EQ_B:
+ gen_helper_eq_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_EQ_H:
+ gen_helper_eq_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_EQ_W:
+ gen_cond_w(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_EQANY_B:
+ gen_helper_eqany_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_EQANY_H:
+ gen_helper_eqany_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_GE:
+ tcg_gen_setcond_tl(TCG_COND_GE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_GE_U:
+ tcg_gen_setcond_tl(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT:
+ tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_U:
+ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_B:
+ gen_helper_lt_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_BU:
+ gen_helper_lt_bu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_H:
+ gen_helper_lt_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_HU:
+ gen_helper_lt_hu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_W:
+ gen_cond_w(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_LT_WU:
+ gen_cond_w(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX:
+ tcg_gen_movcond_tl(TCG_COND_GT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX_U:
+ tcg_gen_movcond_tl(TCG_COND_GTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX_B:
+ gen_helper_max_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX_BU:
+ gen_helper_max_bu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX_H:
+ gen_helper_max_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MAX_HU:
+ gen_helper_max_hu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN:
+ tcg_gen_movcond_tl(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN_U:
+ tcg_gen_movcond_tl(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN_B:
+ gen_helper_min_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN_BU:
+ gen_helper_min_bu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN_H:
+ gen_helper_min_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MIN_HU:
+ gen_helper_min_hu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MOV:
+ tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_NE:
+ tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_OR_EQ:
+ gen_accumulating_cond(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_OR_GE:
+ gen_accumulating_cond(TCG_COND_GE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_OR_GE_U:
+ gen_accumulating_cond(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_OR_LT:
+ gen_accumulating_cond(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_OR_LT_U:
+ gen_accumulating_cond(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_OR_NE:
+ gen_accumulating_cond(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_or_tl);
+ break;
+ case OPC2_32_RR_SAT_B:
+ gen_saturate(cpu_gpr_d[r3], cpu_gpr_d[r1], 0x7f, -0x80);
+ break;
+ case OPC2_32_RR_SAT_BU:
+ gen_saturate_u(cpu_gpr_d[r3], cpu_gpr_d[r1], 0xff);
+ break;
+ case OPC2_32_RR_SAT_H:
+ gen_saturate(cpu_gpr_d[r3], cpu_gpr_d[r1], 0x7fff, -0x8000);
+ break;
+ case OPC2_32_RR_SAT_HU:
+ gen_saturate_u(cpu_gpr_d[r3], cpu_gpr_d[r1], 0xffff);
+ break;
+ case OPC2_32_RR_SH_EQ:
+ gen_sh_cond(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_GE:
+ gen_sh_cond(TCG_COND_GE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_GE_U:
+ gen_sh_cond(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_LT:
+ gen_sh_cond(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_LT_U:
+ gen_sh_cond(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_NE:
+ gen_sh_cond(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUB:
+ gen_sub_d(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUB_B:
+ gen_helper_sub_b(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUB_H:
+ gen_helper_sub_h(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBC:
+ gen_subc_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBS:
+ gen_subs(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBS_U:
+ gen_subsu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBS_H:
+ gen_helper_sub_h_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBS_HU:
+ gen_helper_sub_h_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SUBX:
+ gen_sub_CC(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_XOR_EQ:
+ gen_accumulating_cond(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ case OPC2_32_RR_XOR_GE:
+ gen_accumulating_cond(TCG_COND_GE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ case OPC2_32_RR_XOR_GE_U:
+ gen_accumulating_cond(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ case OPC2_32_RR_XOR_LT:
+ gen_accumulating_cond(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ case OPC2_32_RR_XOR_LT_U:
+ gen_accumulating_cond(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ case OPC2_32_RR_XOR_NE:
+ gen_accumulating_cond(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1],
+ cpu_gpr_d[r2], &tcg_gen_xor_tl);
+ break;
+ }
+}
+
+static void decode_rr_logical_shift(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2;
+ int r3, r2, r1;
+ TCGv temp;
+
+ r3 = MASK_OP_RR_D(ctx->opcode);
+ r2 = MASK_OP_RR_S2(ctx->opcode);
+ r1 = MASK_OP_RR_S1(ctx->opcode);
+
+ temp = tcg_temp_new();
+ op2 = MASK_OP_RR_OP2(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR_AND:
+ tcg_gen_and_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ANDN:
+ tcg_gen_andc_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_CLO:
+ gen_helper_clo(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_CLO_H:
+ gen_helper_clo_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_CLS:
+ gen_helper_cls(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_CLS_H:
+ gen_helper_cls_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_CLZ:
+ gen_helper_clz(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_CLZ_H:
+ gen_helper_clz_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_NAND:
+ tcg_gen_nand_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_NOR:
+ tcg_gen_nor_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_OR:
+ tcg_gen_or_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_ORN:
+ tcg_gen_orc_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH:
+ gen_helper_sh(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SH_H:
+ gen_helper_sh_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SHA:
+ gen_helper_sha(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SHA_H:
+ gen_helper_sha_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_SHAS:
+ gen_shas(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_XNOR:
+ tcg_gen_eqv_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_XOR:
+ tcg_gen_xor_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ }
+ tcg_temp_free(temp);
+}
+
+static void decode_rr_address(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2, n;
+ int r1, r2, r3;
+ TCGv temp;
+
+ op2 = MASK_OP_RR_OP2(ctx->opcode);
+ r3 = MASK_OP_RR_D(ctx->opcode);
+ r2 = MASK_OP_RR_S2(ctx->opcode);
+ r1 = MASK_OP_RR_S1(ctx->opcode);
+ n = MASK_OP_RR_N(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR_ADD_A:
+ tcg_gen_add_tl(cpu_gpr_a[r3], cpu_gpr_a[r1], cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_ADDSC_A:
+ temp = tcg_temp_new();
+ tcg_gen_shli_tl(temp, cpu_gpr_d[r1], n);
+ tcg_gen_add_tl(cpu_gpr_a[r3], cpu_gpr_a[r2], temp);
+ tcg_temp_free(temp);
+ break;
+ case OPC2_32_RR_ADDSC_AT:
+ temp = tcg_temp_new();
+ tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 3);
+ tcg_gen_add_tl(temp, cpu_gpr_a[r2], temp);
+ tcg_gen_andi_tl(cpu_gpr_a[r3], temp, 0xFFFFFFFC);
+ tcg_temp_free(temp);
+ break;
+ case OPC2_32_RR_EQ_A:
+ tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_a[r1],
+ cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_EQZ:
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_a[r1], 0);
+ break;
+ case OPC2_32_RR_GE_A:
+ tcg_gen_setcond_tl(TCG_COND_GEU, cpu_gpr_d[r3], cpu_gpr_a[r1],
+ cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_LT_A:
+ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_a[r1],
+ cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_MOV_A:
+ tcg_gen_mov_tl(cpu_gpr_a[r3], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_MOV_AA:
+ tcg_gen_mov_tl(cpu_gpr_a[r3], cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_MOV_D:
+ tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_NE_A:
+ tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_a[r1],
+ cpu_gpr_a[r2]);
+ break;
+ case OPC2_32_RR_NEZ_A:
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_a[r1], 0);
+ break;
+ case OPC2_32_RR_SUB_A:
+ tcg_gen_sub_tl(cpu_gpr_a[r3], cpu_gpr_a[r1], cpu_gpr_a[r2]);
+ break;
+ }
+}
+
+static void decode_rr_idirect(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2;
+ int r1;
+
+ op2 = MASK_OP_RR_OP2(ctx->opcode);
+ r1 = MASK_OP_RR_S1(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR_JI:
+ tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
+ break;
+ case OPC2_32_RR_JLI:
+ tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc);
+ tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
+ break;
+ case OPC2_32_RR_CALLI:
+ gen_helper_1arg(call, ctx->next_pc);
+ tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
+ break;
+ }
+ tcg_gen_exit_tb(0);
+ ctx->bstate = BS_BRANCH;
+}
+
+static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2;
+ int r1, r2, r3;
+
+ TCGv temp, temp2;
+
+ op2 = MASK_OP_RR_OP2(ctx->opcode);
+ r3 = MASK_OP_RR_D(ctx->opcode);
+ r2 = MASK_OP_RR_S2(ctx->opcode);
+ r1 = MASK_OP_RR_S1(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR_BMERGE:
+ gen_helper_bmerge(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_BSPLIT:
+ gen_bsplit(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_DVINIT_B:
+ gen_dvinit_b(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_DVINIT_BU:
+ temp = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ /* reset av */
+ tcg_gen_movi_tl(cpu_PSW_AV, 0);
+ if (!tricore_feature(env, TRICORE_FEATURE_131)) {
+ /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */
+ tcg_gen_neg_tl(temp, cpu_gpr_d[r3+1]);
+ /* use cpu_PSW_AV to compare against 0 */
+ tcg_gen_movcond_tl(TCG_COND_LT, temp, cpu_gpr_d[r3+1], cpu_PSW_AV,
+ temp, cpu_gpr_d[r3+1]);
+ tcg_gen_neg_tl(temp2, cpu_gpr_d[r2]);
+ tcg_gen_movcond_tl(TCG_COND_LT, temp2, cpu_gpr_d[r2], cpu_PSW_AV,
+ temp2, cpu_gpr_d[r2]);
+ tcg_gen_setcond_tl(TCG_COND_GE, cpu_PSW_V, temp, temp2);
+ } else {
+ /* overflow = (D[b] == 0) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0);
+ }
+ tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
+ /* sv */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* write result */
+ tcg_gen_shri_tl(temp, cpu_gpr_d[r1], 8);
+ tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], 24);
+ tcg_gen_mov_tl(cpu_gpr_d[r3+1], temp);
+
+ tcg_temp_free(temp);
+ tcg_temp_free(temp2);
+ break;
+ case OPC2_32_RR_DVINIT_H:
+ gen_dvinit_h(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1],
+ cpu_gpr_d[r2]);
+ break;
+ case OPC2_32_RR_DVINIT_HU:
+ temp = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ /* reset av */
+ tcg_gen_movi_tl(cpu_PSW_AV, 0);
+ if (!tricore_feature(env, TRICORE_FEATURE_131)) {
+ /* overflow = (abs(D[r3+1]) >= abs(D[r2])) */
+ tcg_gen_neg_tl(temp, cpu_gpr_d[r3+1]);
+ /* use cpu_PSW_AV to compare against 0 */
+ tcg_gen_movcond_tl(TCG_COND_LT, temp, cpu_gpr_d[r3+1], cpu_PSW_AV,
+ temp, cpu_gpr_d[r3+1]);
+ tcg_gen_neg_tl(temp2, cpu_gpr_d[r2]);
+ tcg_gen_movcond_tl(TCG_COND_LT, temp2, cpu_gpr_d[r2], cpu_PSW_AV,
+ temp2, cpu_gpr_d[r2]);
+ tcg_gen_setcond_tl(TCG_COND_GE, cpu_PSW_V, temp, temp2);
+ } else {
+ /* overflow = (D[b] == 0) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0);
+ }
+ tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
+ /* sv */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* write result */
+ tcg_gen_mov_tl(temp, cpu_gpr_d[r1]);
+ tcg_gen_shri_tl(cpu_gpr_d[r3+1], temp, 16);
+ tcg_gen_shli_tl(cpu_gpr_d[r3], temp, 16);
+ tcg_temp_free(temp);
+ tcg_temp_free(temp2);
+ break;
+ case OPC2_32_RR_DVINIT:
+ temp = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ /* overflow = ((D[b] == 0) ||
+ ((D[b] == 0xFFFFFFFF) && (D[a] == 0x80000000))) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, temp, cpu_gpr_d[r2], 0xffffffff);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, cpu_gpr_d[r1], 0x80000000);
+ tcg_gen_and_tl(temp, temp, temp2);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, cpu_gpr_d[r2], 0);
+ tcg_gen_or_tl(cpu_PSW_V, temp, temp2);
+ tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
+ /* sv */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* reset av */
+ tcg_gen_movi_tl(cpu_PSW_AV, 0);
+ /* write result */
+ tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ /* sign extend to high reg */
+ tcg_gen_sari_tl(cpu_gpr_d[r3+1], cpu_gpr_d[r1], 31);
+ tcg_temp_free(temp);
+ tcg_temp_free(temp2);
+ break;
+ case OPC2_32_RR_DVINIT_U:
+ /* overflow = (D[b] == 0) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0);
+ tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31);
+ /* sv */
+ tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V);
+ /* reset av */
+ tcg_gen_movi_tl(cpu_PSW_AV, 0);
+ /* write result */
+ tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ /* zero extend to high reg*/
+ tcg_gen_movi_tl(cpu_gpr_d[r3+1], 0);
+ break;
+ case OPC2_32_RR_PARITY:
+ gen_helper_parity(cpu_gpr_d[r3], cpu_gpr_d[r1]);
+ break;
+ case OPC2_32_RR_UNPACK:
+ gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
+ break;
+ }
+}
+
+/* RR1 Format */
+static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx)
+{
+ uint32_t op2;
+
+ int r1, r2, r3;
+ TCGv n;
+ TCGv_i64 temp64;
+
+ r1 = MASK_OP_RR1_S1(ctx->opcode);
+ r2 = MASK_OP_RR1_S2(ctx->opcode);
+ r3 = MASK_OP_RR1_D(ctx->opcode);
+ n = tcg_const_i32(MASK_OP_RR1_N(ctx->opcode));
+ op2 = MASK_OP_RR1_OP2(ctx->opcode);
+
+ switch (op2) {
+ case OPC2_32_RR1_MUL_H_32_LL:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_LL(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MUL_H_32_LU:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_LU(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MUL_H_32_UL:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_UL(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MUL_H_32_UU:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_UU(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MULM_H_64_LL:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_LL(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ /* reset V bit */
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ /* reset AV bit */
+ tcg_gen_mov_tl(cpu_PSW_AV, cpu_PSW_V);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MULM_H_64_LU:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_LU(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ /* reset V bit */
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ /* reset AV bit */
+ tcg_gen_mov_tl(cpu_PSW_AV, cpu_PSW_V);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MULM_H_64_UL:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_UL(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ /* reset V bit */
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ /* reset AV bit */
+ tcg_gen_mov_tl(cpu_PSW_AV, cpu_PSW_V);
+ tcg_temp_free_i64(temp64);
+ break;
+ case OPC2_32_RR1_MULM_H_64_UU:
+ temp64 = tcg_temp_new_i64();
+ GEN_HELPER_UU(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64);
+ /* reset V bit */
+ tcg_gen_movi_tl(cpu_PSW_V, 0);
+ /* reset AV bit */
+ tcg_gen_mov_tl(cpu_PSW_AV, cpu_PSW_V);
+ tcg_temp_free_i64(temp64);
+
+ break;
+ case OPC2_32_RR1_MULR_H_16_LL:
+ GEN_HELPER_LL(mulr_h, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ gen_calc_usb_mulr_h(cpu_gpr_d[r3]);
+ break;
+ case OPC2_32_RR1_MULR_H_16_LU:
+ GEN_HELPER_LU(mulr_h, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ gen_calc_usb_mulr_h(cpu_gpr_d[r3]);
+ break;
+ case OPC2_32_RR1_MULR_H_16_UL:
+ GEN_HELPER_UL(mulr_h, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ gen_calc_usb_mulr_h(cpu_gpr_d[r3]);
+ break;
+ case OPC2_32_RR1_MULR_H_16_UU:
+ GEN_HELPER_UU(mulr_h, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n);
+ gen_calc_usb_mulr_h(cpu_gpr_d[r3]);
+ break;
+ }
+ tcg_temp_free(n);
+}
+
static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
{
int op1;
@@ -3808,8 +4789,8 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
op1 = MASK_OP_MAJOR(ctx->opcode);
- /* handle JNZ.T opcode only being 6 bit long */
- if (unlikely((op1 & 0x3f) == OPCM_32_BRN_JTT)) {
+ /* handle JNZ.T opcode only being 7 bit long */
+ if (unlikely((op1 & 0x7f) == OPCM_32_BRN_JTT)) {
op1 = OPCM_32_BRN_JTT;
}
@@ -3884,7 +4865,7 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
case OPC1_32_B_JA:
case OPC1_32_B_JL:
case OPC1_32_B_JLA:
- address = MASK_OP_B_DISP24(ctx->opcode);
+ address = MASK_OP_B_DISP24_SEXT(ctx->opcode);
gen_compute_branch(ctx, op1, 0, 0, 0, address);
break;
/* Bit-format */
@@ -3930,10 +4911,16 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
break;
/* BOL-format */
case OPC1_32_BOL_LD_A_LONGOFF:
- case OPC1_32_BOL_LD_W_LONFOFF:
+ case OPC1_32_BOL_LD_W_LONGOFF:
case OPC1_32_BOL_LEA_LONGOFF:
case OPC1_32_BOL_ST_W_LONGOFF:
case OPC1_32_BOL_ST_A_LONGOFF:
+ case OPC1_32_BOL_LD_B_LONGOFF:
+ case OPC1_32_BOL_LD_BU_LONGOFF:
+ case OPC1_32_BOL_LD_H_LONGOFF:
+ case OPC1_32_BOL_LD_HU_LONGOFF:
+ case OPC1_32_BOL_ST_B_LONGOFF:
+ case OPC1_32_BOL_ST_H_LONGOFF:
decode_bol_opc(env, ctx, op1);
break;
/* BRC Format */
@@ -4021,12 +5008,33 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
case OPC1_32_RLC_ADDIH_A:
case OPC1_32_RLC_MFCR:
case OPC1_32_RLC_MOV:
+ case OPC1_32_RLC_MOV_64:
case OPC1_32_RLC_MOV_U:
case OPC1_32_RLC_MOV_H:
case OPC1_32_RLC_MOVH_A:
case OPC1_32_RLC_MTCR:
decode_rlc_opc(env, ctx, op1);
break;
+/* RR Format */
+ case OPCM_32_RR_ACCUMULATOR:
+ decode_rr_accumulator(env, ctx);
+ break;
+ case OPCM_32_RR_LOGICAL_SHIFT:
+ decode_rr_logical_shift(env, ctx);
+ break;
+ case OPCM_32_RR_ADRESS:
+ decode_rr_address(env, ctx);
+ break;
+ case OPCM_32_RR_IDIRECT:
+ decode_rr_idirect(env, ctx);
+ break;
+ case OPCM_32_RR_DIVIDE:
+ decode_rr_divide(env, ctx);
+ break;
+/* RR1 Format */
+ case OPCM_32_RR1_MUL:
+ decode_rr1_mul(env, ctx);
+ break;
}
}
diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h
index 0a9122cfb9..919063e422 100644
--- a/target-tricore/tricore-opcodes.h
+++ b/target-tricore/tricore-opcodes.h
@@ -94,6 +94,8 @@
/* B Format */
#define MASK_OP_B_DISP24(op) (MASK_BITS_SHIFT(op, 16, 31) + \
(MASK_BITS_SHIFT(op, 8, 15) << 16))
+#define MASK_OP_B_DISP24_SEXT(op) (MASK_BITS_SHIFT(op, 16, 31) + \
+ (MASK_BITS_SHIFT_SEXT(op, 8, 15) << 16))
/* BIT Format */
#define MASK_OP_BIT_D(op) MASK_BITS_SHIFT(op, 28, 31)
#define MASK_OP_BIT_POS2(op) MASK_BITS_SHIFT(op, 23, 27)
@@ -114,7 +116,7 @@
/* BOL Format */
#define MASK_OP_BOL_OFF16(op) ((MASK_BITS_SHIFT(op, 16, 21) + \
(MASK_BITS_SHIFT(op, 28, 31) << 6)) + \
- (MASK_BITS_SHIFT(op, 22, 27) >> 10))
+ (MASK_BITS_SHIFT(op, 22, 27) << 10))
#define MASK_OP_BOL_OFF16_SEXT(op) ((MASK_BITS_SHIFT(op, 16, 21) + \
(MASK_BITS_SHIFT(op, 28, 31) << 6)) + \
(MASK_BITS_SHIFT_SEXT(op, 22, 27) << 10))
@@ -447,10 +449,16 @@ enum {
OPCM_32_BO_ADDRMODE_LDMST_BITREVERSE_CIRCULAR = 0x69,
/* BOL Format */
OPC1_32_BOL_LD_A_LONGOFF = 0x99,
- OPC1_32_BOL_LD_W_LONFOFF = 0x19,
+ OPC1_32_BOL_LD_W_LONGOFF = 0x19,
OPC1_32_BOL_LEA_LONGOFF = 0xd9,
OPC1_32_BOL_ST_W_LONGOFF = 0x59,
OPC1_32_BOL_ST_A_LONGOFF = 0xb5, /* 1.6 only */
+ OPC1_32_BOL_LD_B_LONGOFF = 0x79, /* 1.6 only */
+ OPC1_32_BOL_LD_BU_LONGOFF = 0x39, /* 1.6 only */
+ OPC1_32_BOL_LD_H_LONGOFF = 0xc9, /* 1.6 only */
+ OPC1_32_BOL_LD_HU_LONGOFF = 0xb9, /* 1.6 only */
+ OPC1_32_BOL_ST_B_LONGOFF = 0xe9, /* 1.6 only */
+ OPC1_32_BOL_ST_H_LONGOFF = 0xf9, /* 1.6 only */
/* BRC Format */
OPCM_32_BRC_EQ_NEQ = 0xdf,
OPCM_32_BRC_GE = 0xff,
@@ -487,6 +495,7 @@ enum {
OPC1_32_RLC_ADDIH_A = 0x11,
OPC1_32_RLC_MFCR = 0x4d,
OPC1_32_RLC_MOV = 0x3b,
+ OPC1_32_RLC_MOV_64 = 0xfb, /* 1.6 only */
OPC1_32_RLC_MOV_U = 0xbb,
OPC1_32_RLC_MOV_H = 0x7b,
OPC1_32_RLC_MOVH_A = 0x91,
@@ -495,7 +504,7 @@ enum {
OPCM_32_RR_LOGICAL_SHIFT = 0x0f,
OPCM_32_RR_ACCUMULATOR = 0x0b,
OPCM_32_RR_ADRESS = 0x01,
- OPCM_32_RR_FLOAT = 0x4b,
+ OPCM_32_RR_DIVIDE = 0x4b,
OPCM_32_RR_IDIRECT = 0x2d,
/* RR1 Format */
OPCM_32_RR1_MUL = 0xb3,
@@ -1033,8 +1042,8 @@ enum {
OPC2_32_RR_MAX_BU = 0x5b,
OPC2_32_RR_MAX_H = 0x7a,
OPC2_32_RR_MAX_HU = 0x7b,
- OPC2_32_RR_MIN = 0x19,
- OPC2_32_RR_MIN_U = 0x18,
+ OPC2_32_RR_MIN = 0x18,
+ OPC2_32_RR_MIN_U = 0x19,
OPC2_32_RR_MIN_B = 0x58,
OPC2_32_RR_MIN_BU = 0x59,
OPC2_32_RR_MIN_H = 0x78,
diff --git a/trace-events b/trace-events
index b5722ea8ae..8acbcce0f0 100644
--- a/trace-events
+++ b/trace-events
@@ -1351,7 +1351,86 @@ xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (ad
pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x"
pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x"
-# hw/acpi/memory_hotplug.c
+# hw/vfio/vfio-pci.c
+vfio_intx_interrupt(const char *name, char line) " (%s) Pin %c"
+vfio_eoi(const char *name) " (%s) EOI"
+vfio_enable_intx_kvm(const char *name) " (%s) KVM INTx accel enabled"
+vfio_disable_intx_kvm(const char *name) " (%s) KVM INTx accel disabled"
+vfio_update_irq(const char *name, int new_irq, int target_irq) " (%s) IRQ moved %d -> %d"
+vfio_enable_intx(const char *name) " (%s)"
+vfio_disable_intx(const char *name) " (%s)"
+vfio_msi_interrupt(const char *name, int index, uint64_t addr, int data) " (%s) vector %d 0x%"PRIx64"/0x%x"
+vfio_msix_vector_do_use(const char *name, int index) " (%s) vector %d used"
+vfio_msix_vector_release(const char *name, int index) " (%s) vector %d released"
+vfio_enable_msix(const char *name) " (%s)"
+vfio_enable_msi(const char *name, int nr_vectors) " (%s) Enabled %d MSI vectors"
+vfio_disable_msix(const char *name) " (%s)"
+vfio_disable_msi(const char *name) " (%s)"
+vfio_pci_load_rom(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s ROM:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
+vfio_rom_read(const char *name, uint64_t addr, int size, uint64_t data) " (%s, 0x%"PRIx64", 0x%x) = 0x%"PRIx64
+vfio_pci_size_rom(const char *name, int size) "%s ROM size 0x%x"
+vfio_vga_write(uint64_t addr, uint64_t data, int size) " (0x%"PRIx64", 0x%"PRIx64", %d)"
+vfio_vga_read(uint64_t addr, int size, uint64_t data) " (0x%"PRIx64", %d) = 0x%"PRIx64
+# remove ) =
+vfio_generic_window_quirk_read(const char * region_name, const char *name, int index, uint64_t addr, int size, uint64_t data) "%s read(%s:BAR%d+0x%"PRIx64", %d = 0x%"PRIx64
+## remove )
+vfio_generic_window_quirk_write(const char * region_name, const char *name, int index, uint64_t addr, uint64_t data, int size) "%s write(%s:BAR%d+0x%"PRIx64", 0x%"PRIx64", %d"
+# remove ) =
+vfio_generic_quirk_read(const char * region_name, const char *name, int index, uint64_t addr, int size, uint64_t data) "%s read(%s:BAR%d+0x%"PRIx64", %d = 0x%"PRIx64
+# remove )
+vfio_generic_quirk_write(const char * region_name, const char *name, int index, uint64_t addr, uint64_t data, int size) "%s write(%s:BAR%d+0x%"PRIx64", 0x%"PRIx64", %d"
+vfio_ati_3c3_quirk_read(uint64_t data) " (0x3c3, 1) = 0x%"PRIx64
+vfio_vga_probe_ati_3c3_quirk(const char *name) "Enabled ATI/AMD quirk 0x3c3 BAR4for device %s"
+vfio_probe_ati_bar4_window_quirk(const char *name) "Enabled ATI/AMD BAR4 window quirk for device %s"
+#issue with )
+vfio_rtl8168_window_quirk_read_fake(const char *region_name, const char *name) "%s fake read(%s"
+vfio_rtl8168_window_quirk_read_table(const char *region_name, const char *name) "%s MSI-X table read(%s"
+vfio_rtl8168_window_quirk_read_direct(const char *region_name, const char *name) "%s direct read(%s"
+vfio_rtl8168_window_quirk_write_table(const char *region_name, const char *name) "%s MSI-X table write(%s"
+vfio_rtl8168_window_quirk_write_direct(const char *region_name, const char *name) "%s direct write(%s"
+vfio_probe_rtl8168_bar2_window_quirk(const char *name) "Enabled RTL8168 BAR2 window quirk for device %s"
+vfio_probe_ati_bar2_4000_quirk(const char *name) "Enabled ATI/AMD BAR2 0x4000 quirk for device %s"
+vfio_nvidia_3d0_quirk_read(int size, uint64_t data) " (0x3d0, %d) = 0x%"PRIx64
+vfio_nvidia_3d0_quirk_write(uint64_t data, int size) " (0x3d0, 0x%"PRIx64", %d)"
+vfio_vga_probe_nvidia_3d0_quirk(const char *name) "Enabled NVIDIA VGA 0x3d0 quirk for device %s"
+vfio_probe_nvidia_bar5_window_quirk(const char *name) "Enabled NVIDIA BAR5 window quirk for device %s"
+vfio_probe_nvidia_bar0_88000_quirk(const char *name) "Enabled NVIDIA BAR0 0x88000 quirk for device %s"
+vfio_probe_nvidia_bar0_1800_quirk_id(int id) "Nvidia NV%02x"
+vfio_probe_nvidia_bar0_1800_quirk(const char *name) "Enabled NVIDIA BAR0 0x1800 quirk for device %s"
+vfio_pci_read_config(const char *name, int addr, int len, int val) " (%s, @0x%x, len=0x%x) %x"
+vfio_pci_write_config(const char *name, int addr, int val, int len) " (%s, @0x%x, 0x%x, len=0x%x)"
+vfio_setup_msi(const char *name, int pos) "%s PCI MSI CAP @0x%x"
+vfio_early_setup_msix(const char *name, int pos, int table_bar, int offset, int entries) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d"
+vfio_check_pcie_flr(const char *name) "%s Supports FLR via PCIe cap"
+vfio_check_pm_reset(const char *name) "%s Supports PM reset"
+vfio_check_af_flr(const char *name) "%s Supports FLR via AF cap"
+vfio_pci_hot_reset(const char *name, const char *type) " (%s) %s"
+vfio_pci_hot_reset_has_dep_devices(const char *name) "%s: hot reset dependent devices:"
+vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int group_id) "\t%04x:%02x:%02x.%x group %d"
+vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s"
+vfio_populate_device_region(const char *region_name, int index, unsigned long size, unsigned long offset, unsigned long flags) "Device %s region %d:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
+vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
+vfio_populate_device_get_irq_info_failure(void) "VFIO_DEVICE_GET_IRQ_INFO failure: %m"
+vfio_initfn(const char *name, int group_id) " (%s) group %d"
+vfio_pci_reset(const char *name) " (%s)"
+vfio_pci_reset_flr(const char *name) "%s FLR/VFIO_DEVICE_RESET"
+vfio_pci_reset_pm(const char *name) "%s PCI PM Reset"
+
+# hw/vfio/vfio-common.c
+vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
+vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64
+vfio_iommu_map_notify(uint64_t iova_start, uint64_t iova_end) "iommu map @ %"PRIx64" - %"PRIx64
+vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add %"PRIx64" - %"PRIx64
+vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] %"PRIx64" - %"PRIx64
+vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] %"PRIx64" - %"PRIx64" [%p]"
+vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del %"PRIx64" - %"PRIx64
+vfio_listener_region_del(uint64_t start, uint64_t end) "region_del %"PRIx64" - %"PRIx64
+vfio_disconnect_container(int fd) "close container->fd=%d"
+vfio_put_group(int fd) "close group->fd=%d"
+vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
+vfio_put_base_device(int fd) "close vdev->fd=%d"
+
+#hw/acpi/memory_hotplug.c
mhp_acpi_invalid_slot_selected(uint32_t slot) "0x%"PRIx32
mhp_acpi_read_addr_lo(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr lo: 0x%"PRIx32
mhp_acpi_read_addr_hi(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr hi: 0x%"PRIx32
diff --git a/vl.c b/vl.c
index 113e98e56b..7786b2f921 100644
--- a/vl.c
+++ b/vl.c
@@ -196,9 +196,6 @@ NodeInfo numa_info[MAX_NODES];
uint8_t qemu_uuid[16];
bool qemu_uuid_set;
-static QEMUBootSetHandler *boot_set_handler;
-static void *boot_set_opaque;
-
static NotifierList exit_notifiers =
NOTIFIER_LIST_INITIALIZER(exit_notifiers);
@@ -311,84 +308,12 @@ static QemuOptsList qemu_machine_opts = {
.merge_lists = true,
.head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
.desc = {
- {
- .name = "type",
- .type = QEMU_OPT_STRING,
- .help = "emulated machine"
- }, {
- .name = "accel",
- .type = QEMU_OPT_STRING,
- .help = "accelerator list",
- }, {
- .name = "kernel_irqchip",
- .type = QEMU_OPT_BOOL,
- .help = "use KVM in-kernel irqchip",
- }, {
- .name = "kvm_shadow_mem",
- .type = QEMU_OPT_SIZE,
- .help = "KVM shadow MMU size",
- }, {
- .name = "kernel",
- .type = QEMU_OPT_STRING,
- .help = "Linux kernel image file",
- }, {
- .name = "initrd",
- .type = QEMU_OPT_STRING,
- .help = "Linux initial ramdisk file",
- }, {
- .name = "append",
- .type = QEMU_OPT_STRING,
- .help = "Linux kernel command line",
- }, {
- .name = "dtb",
- .type = QEMU_OPT_STRING,
- .help = "Linux kernel device tree file",
- }, {
- .name = "dumpdtb",
- .type = QEMU_OPT_STRING,
- .help = "Dump current dtb to a file and quit",
- }, {
- .name = "phandle_start",
- .type = QEMU_OPT_NUMBER,
- .help = "The first phandle ID we may generate dynamically",
- }, {
- .name = "dt_compatible",
- .type = QEMU_OPT_STRING,
- .help = "Overrides the \"compatible\" property of the dt root node",
- }, {
- .name = "dump-guest-core",
- .type = QEMU_OPT_BOOL,
- .help = "Include guest memory in a core dump",
- }, {
- .name = "mem-merge",
- .type = QEMU_OPT_BOOL,
- .help = "enable/disable memory merge support",
- },{
- .name = "usb",
- .type = QEMU_OPT_BOOL,
- .help = "Set on/off to enable/disable usb",
- },{
- .name = "firmware",
- .type = QEMU_OPT_STRING,
- .help = "firmware image",
- },{
- .name = "kvm-type",
- .type = QEMU_OPT_STRING,
- .help = "Specifies the KVM virtualization mode (HV, PR)",
- },{
- .name = PC_MACHINE_MAX_RAM_BELOW_4G,
- .type = QEMU_OPT_SIZE,
- .help = "maximum ram below the 4G boundary (32bit boundary)",
- }, {
- .name = PC_MACHINE_VMPORT,
- .type = QEMU_OPT_STRING,
- .help = "Enable vmport (pc & q35)",
- },{
- .name = "iommu",
- .type = QEMU_OPT_BOOL,
- .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
- },
- { /* End of list */ }
+ /*
+ * no elements => accept any
+ * sanity checking will happen later
+ * when setting machine properties
+ */
+ { }
},
};
@@ -1072,10 +997,14 @@ static int parse_name(QemuOpts *opts, void *opaque)
return 0;
}
-bool usb_enabled(bool default_usb)
+bool defaults_enabled(void)
{
- return qemu_opt_get_bool(qemu_get_machine_opts(), "usb",
- has_defaults && default_usb);
+ return has_defaults;
+}
+
+bool usb_enabled(void)
+{
+ return machine_usb(current_machine);
}
#ifndef _WIN32
@@ -1198,65 +1127,6 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type,
}
-void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
-{
- boot_set_handler = func;
- boot_set_opaque = opaque;
-}
-
-int qemu_boot_set(const char *boot_order)
-{
- if (!boot_set_handler) {
- return -EINVAL;
- }
- return boot_set_handler(boot_set_opaque, boot_order);
-}
-
-static void validate_bootdevices(const char *devices)
-{
- /* We just do some generic consistency checks */
- const char *p;
- int bitmap = 0;
-
- for (p = devices; *p != '\0'; p++) {
- /* Allowed boot devices are:
- * a-b: floppy disk drives
- * c-f: IDE disk drives
- * g-m: machine implementation dependent drives
- * n-p: network devices
- * It's up to each machine implementation to check if the given boot
- * devices match the actual hardware implementation and firmware
- * features.
- */
- if (*p < 'a' || *p > 'p') {
- fprintf(stderr, "Invalid boot device '%c'\n", *p);
- exit(1);
- }
- if (bitmap & (1 << (*p - 'a'))) {
- fprintf(stderr, "Boot device '%c' was given twice\n", *p);
- exit(1);
- }
- bitmap |= 1 << (*p - 'a');
- }
-}
-
-static void restore_boot_order(void *opaque)
-{
- char *normal_boot_order = opaque;
- static int first = 1;
-
- /* Restore boot order and remove ourselves after the first boot */
- if (first) {
- first = 0;
- return;
- }
-
- qemu_boot_set(normal_boot_order);
-
- qemu_unregister_reset(restore_boot_order, normal_boot_order);
- g_free(normal_boot_order);
-}
-
static QemuOptsList qemu_smp_opts = {
.name = "smp-opts",
.implied_opt_name = "cpus",
@@ -1358,7 +1228,7 @@ static int usb_device_add(const char *devname)
const char *p;
#endif
- if (!usb_enabled(false)) {
+ if (!usb_enabled()) {
return -1;
}
@@ -1390,7 +1260,7 @@ static int usb_device_del(const char *devname)
return -1;
}
- if (!usb_enabled(false)) {
+ if (!usb_enabled()) {
return -1;
}
@@ -1557,6 +1427,31 @@ MachineInfoList *qmp_query_machines(Error **errp)
return mach_list;
}
+static int machine_help_func(QemuOpts *opts, MachineState *machine)
+{
+ ObjectProperty *prop;
+
+ if (!qemu_opt_has_help_opt(opts)) {
+ return 0;
+ }
+
+ QTAILQ_FOREACH(prop, &OBJECT(machine)->properties, node) {
+ if (!prop->set) {
+ continue;
+ }
+
+ error_printf("%s.%s=%s", MACHINE_GET_CLASS(machine)->name,
+ prop->name, prop->type);
+ if (prop->description) {
+ error_printf(" (%s)\n", prop->description);
+ } else {
+ error_printf("\n");
+ }
+ }
+
+ return 1;
+}
+
/***********************************************************/
/* main execution loop */
@@ -2669,7 +2564,6 @@ static int machine_set_property(const char *name, const char *value,
void *opaque)
{
Object *obj = OBJECT(opaque);
- StringInputVisitor *siv;
Error *local_err = NULL;
char *c, *qom_name;
@@ -2685,9 +2579,7 @@ static int machine_set_property(const char *name, const char *value,
}
}
- siv = string_input_visitor_new(value);
- object_property_set(obj, string_input_get_visitor(siv), qom_name, &local_err);
- string_input_visitor_cleanup(siv);
+ object_property_parse(obj, value, qom_name, &local_err);
g_free(qom_name);
if (local_err) {
@@ -3895,6 +3787,9 @@ int main(int argc, char **argv, char **envp)
current_machine = MACHINE(object_new(object_class_get_name(
OBJECT_CLASS(machine_class))));
+ if (machine_help_func(qemu_get_machine_opts(), current_machine)) {
+ exit(0);
+ }
object_property_add_child(object_get_root(), "machine",
OBJECT(current_machine), &error_abort);
cpu_exec_init_all();
@@ -4149,16 +4044,25 @@ int main(int argc, char **argv, char **envp)
if (opts) {
char *normal_boot_order;
const char *order, *once;
+ Error *local_err = NULL;
order = qemu_opt_get(opts, "order");
if (order) {
- validate_bootdevices(order);
+ validate_bootdevices(order, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
boot_order = order;
}
once = qemu_opt_get(opts, "once");
if (once) {
- validate_bootdevices(once);
+ validate_bootdevices(once, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
normal_boot_order = g_strdup(boot_order);
boot_order = once;
qemu_register_reset(restore_boot_order, normal_boot_order);
@@ -4325,7 +4229,7 @@ int main(int argc, char **argv, char **envp)
set_numa_modes();
/* init USB devices */
- if (usb_enabled(false)) {
+ if (usb_enabled()) {
if (foreach_device_config(DEV_USB, usb_parse) < 0)
exit(1);
}