aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/Makefile.objs4
-rw-r--r--hw/arm/boot.c34
-rw-r--r--hw/arm/fsl-imx25.c302
-rw-r--r--hw/arm/fsl-imx31.c276
-rw-r--r--hw/arm/imx25_pdk.c159
-rw-r--r--hw/arm/kzm.c205
-rw-r--r--hw/arm/omap1.c30
-rw-r--r--hw/arm/omap2.c15
-rw-r--r--hw/arm/pxa2xx.c11
-rw-r--r--hw/arm/spitz.c5
-rw-r--r--hw/arm/stellaris.c2
-rw-r--r--hw/arm/strongarm.c2
-rw-r--r--hw/arm/vexpress.c4
-rw-r--r--hw/arm/virt-acpi-build.c17
-rw-r--r--hw/arm/virt.c140
-rw-r--r--hw/arm/xlnx-zynqmp.c42
-rw-r--r--hw/audio/fmopl.c2
-rw-r--r--hw/block/nvme.c2
-rw-r--r--hw/block/virtio-blk.c7
-rw-r--r--hw/block/xen_disk.c1
-rw-r--r--hw/bt/hci.c9
-rw-r--r--hw/char/exynos4210_uart.c6
-rw-r--r--hw/char/imx_serial.c35
-rw-r--r--hw/char/omap_uart.c3
-rw-r--r--hw/char/virtio-serial-bus.c2
-rw-r--r--hw/core/loader.c3
-rw-r--r--hw/core/machine.c20
-rw-r--r--hw/core/qdev-properties.c4
-rw-r--r--hw/core/qdev.c2
-rw-r--r--hw/cpu/a15mpcore.c13
-rw-r--r--hw/cpu/a9mpcore.c11
-rw-r--r--hw/cris/axis_dev88.c2
-rw-r--r--hw/display/exynos4210_fimd.c4
-rw-r--r--hw/display/omap_dss.c3
-rw-r--r--hw/display/omap_lcdc.c3
-rw-r--r--hw/display/qxl-render.c2
-rw-r--r--hw/dma/omap_dma.c6
-rw-r--r--hw/dma/xilinx_axidma.c2
-rw-r--r--hw/gpio/Makefile.objs1
-rw-r--r--hw/gpio/imx_gpio.c340
-rw-r--r--hw/gpio/omap_gpio.c4
-rw-r--r--hw/gpio/zaurus.c5
-rw-r--r--hw/i2c/Makefile.objs1
-rw-r--r--hw/i2c/imx_i2c.c334
-rw-r--r--hw/i386/Makefile.objs1
-rw-r--r--hw/i386/kvm/pci-assign.c82
-rw-r--r--hw/i386/pc.c8
-rw-r--r--hw/i386/pc_piix.c148
-rw-r--r--hw/i386/pc_q35.c9
-rw-r--r--hw/i386/pci-assign-load-rom.c91
-rw-r--r--hw/i386/xen/xen_platform.c2
-rw-r--r--hw/ide/ahci.c28
-rw-r--r--hw/ide/ahci.h16
-rw-r--r--hw/input/stellaris_input.c6
-rw-r--r--hw/intc/arm_gic.c247
-rw-r--r--hw/intc/arm_gic_common.c59
-rw-r--r--hw/intc/armv7m_nvic.c13
-rw-r--r--hw/intc/s390_flic_kvm.c2
-rw-r--r--hw/intc/xics.c2
-rw-r--r--hw/mips/mips_r4k.c4
-rw-r--r--hw/misc/omap_clk.c2
-rw-r--r--hw/misc/omap_gpmc.c3
-rw-r--r--hw/misc/omap_sdrc.c3
-rw-r--r--hw/net/Makefile.objs1
-rw-r--r--hw/net/cadence_gem.c2
-rw-r--r--hw/net/fsl_etsec/etsec.c2
-rw-r--r--hw/net/fsl_etsec/rings.c4
-rw-r--r--hw/net/imx_fec.c709
-rw-r--r--hw/net/ne2000-isa.c1
-rw-r--r--hw/net/ne2000.c10
-rw-r--r--hw/net/ne2000.h1
-rw-r--r--hw/net/rocker/rocker.c4
-rw-r--r--hw/net/rocker/rocker_desc.c8
-rw-r--r--hw/net/rtl8139.c119
-rw-r--r--hw/net/vhost_net.c2
-rw-r--r--hw/net/virtio-net.c31
-rw-r--r--hw/net/vmxnet3.c1
-rw-r--r--hw/net/xen_nic.c1
-rw-r--r--hw/nvram/fw_cfg.c4
-rw-r--r--hw/pci-host/piix.c94
-rw-r--r--hw/pci-host/prep.c4
-rw-r--r--hw/pci/msix.c4
-rw-r--r--hw/pci/pci.c21
-rw-r--r--hw/pci/shpc.c1
-rw-r--r--hw/ppc/spapr_pci.c12
-rw-r--r--hw/s390x/Makefile.objs2
-rw-r--r--hw/s390x/css.c9
-rw-r--r--hw/s390x/event-facility.c55
-rw-r--r--hw/s390x/s390-skeys-kvm.c75
-rw-r--r--hw/s390x/s390-skeys.c415
-rw-r--r--hw/s390x/s390-virtio-bus.c5
-rw-r--r--hw/s390x/s390-virtio-ccw.c110
-rw-r--r--hw/s390x/s390-virtio.c37
-rw-r--r--hw/s390x/s390-virtio.h3
-rw-r--r--hw/s390x/sclp.c267
-rw-r--r--hw/s390x/sclpcpu.c28
-rw-r--r--hw/s390x/sclpquiesce.c4
-rw-r--r--hw/scsi/virtio-scsi.c8
-rw-r--r--hw/sd/omap_mmc.c6
-rw-r--r--hw/sd/pl181.c2
-rw-r--r--hw/sd/sd.c3
-rw-r--r--hw/sd/sdhci.c6
-rw-r--r--hw/sh4/r2d.c6
-rw-r--r--hw/smbios/smbios.c84
-rw-r--r--hw/ssi/omap_spi.c3
-rw-r--r--hw/timer/imx_epit.c11
-rw-r--r--hw/timer/imx_gpt.c11
-rw-r--r--hw/timer/omap_gptimer.c3
-rw-r--r--hw/tpm/tpm_passthrough.c2
-rw-r--r--hw/usb/hcd-ehci-pci.c6
-rw-r--r--hw/usb/hcd-xhci.c4
-rw-r--r--hw/usb/host-libusb.c2
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/vfio/common.c2
-rw-r--r--hw/vfio/pci.c3
-rw-r--r--hw/vfio/platform.c2
-rw-r--r--hw/virtio/dataplane/vring.c10
-rw-r--r--hw/virtio/vhost.c4
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/virtio/virtio-pci.c9
-rw-r--r--hw/virtio/virtio.c14
-rw-r--r--hw/watchdog/wdt_i6300esb.c2
-rw-r--r--hw/xen/Makefile.objs1
-rw-r--r--hw/xen/xen-host-pci-device.c12
-rw-r--r--hw/xen/xen-host-pci-device.h2
-rw-r--r--hw/xen/xen_pt.c192
-rw-r--r--hw/xen/xen_pt.h30
-rw-r--r--hw/xen/xen_pt_config_init.c285
-rw-r--r--hw/xen/xen_pt_graphics.c272
-rw-r--r--hw/xen/xen_pt_msi.c20
130 files changed, 4826 insertions, 1042 deletions
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index cf346c1d0a..2195b60fac 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,6 +1,6 @@
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
obj-$(CONFIG_DIGIC) += digic_boards.o
-obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
+obj-y += integratorcp.o mainstone.o musicpal.o nseries.o
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-$(CONFIG_ACPI) += virt-acpi-build.o
@@ -13,3 +13,5 @@ obj-y += omap1.o omap2.o strongarm.o
obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
+obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
+obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 5b969cda1c..bef451b3b2 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -10,6 +10,7 @@
#include "config.h"
#include "hw/hw.h"
#include "hw/arm/arm.h"
+#include "hw/arm/linux-boot-if.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/loader.h"
@@ -555,6 +556,20 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
+static int do_arm_linux_init(Object *obj, void *opaque)
+{
+ if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) {
+ ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj);
+ ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj);
+ struct arm_boot_info *info = opaque;
+
+ if (albifc->arm_linux_init) {
+ albifc->arm_linux_init(albif, info->secure_boot);
+ }
+ }
+ return 0;
+}
+
static void arm_load_kernel_notify(Notifier *notifier, void *data)
{
CPUState *cs;
@@ -778,6 +793,12 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
if (info->nb_cpus > 1) {
info->write_secondary_boot(cpu, info);
}
+
+ /* Notify devices which need to fake up firmware initialization
+ * that we're doing a direct kernel boot.
+ */
+ object_child_foreach_recursive(object_get_root(),
+ do_arm_linux_init, info);
}
info->is_linux = is_linux;
@@ -803,3 +824,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
}
}
+
+static const TypeInfo arm_linux_boot_if_info = {
+ .name = TYPE_ARM_LINUX_BOOT_IF,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(ARMLinuxBootIfClass),
+};
+
+static void arm_linux_boot_register_types(void)
+{
+ type_register_static(&arm_linux_boot_if_info);
+}
+
+type_init(arm_linux_boot_register_types)
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
new file mode 100644
index 0000000000..86fde42e34
--- /dev/null
+++ b/hw/arm/fsl-imx25.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * i.MX25 SOC emulation.
+ *
+ * Based on hw/arm/xlnx-zynqmp.c
+ *
+ * Copyright (C) 2015 Xilinx Inc
+ * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/arm/fsl-imx25.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+#include "hw/boards.h"
+#include "sysemu/char.h"
+
+static void fsl_imx25_init(Object *obj)
+{
+ FslIMX25State *s = FSL_IMX25(obj);
+ int i;
+
+ object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU);
+
+ object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
+ qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
+
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+ qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
+
+ for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
+ object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
+ qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
+ object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT);
+ qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
+ object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
+ qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
+ }
+
+ object_initialize(&s->fec, sizeof(s->fec), TYPE_IMX_FEC);
+ qdev_set_parent_bus(DEVICE(&s->fec), sysbus_get_default());
+
+ for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
+ object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
+ qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
+ object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
+ qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
+ }
+}
+
+static void fsl_imx25_realize(DeviceState *dev, Error **errp)
+{
+ FslIMX25State *s = FSL_IMX25(dev);
+ uint8_t i;
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
+
+ object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR);
+
+ /* Initialize all UARTs */
+ for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[FSL_IMX25_NUM_UARTS] = {
+ { FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ },
+ { FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ },
+ { FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ },
+ { FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ },
+ { FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ }
+ };
+
+ if (i < MAX_SERIAL_PORTS) {
+ CharDriverState *chr;
+
+ chr = serial_hds[i];
+
+ if (!chr) {
+ char label[20];
+ snprintf(label, sizeof(label), "imx31.uart%d", i);
+ chr = qemu_chr_new(label, "null", NULL);
+ }
+
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
+ }
+
+ object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ serial_table[i].irq));
+ }
+
+ /* Initialize all GPT timers */
+ for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } gpt_table[FSL_IMX25_NUM_GPTS] = {
+ { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ },
+ { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ },
+ { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ },
+ { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
+ };
+
+ s->gpt[i].ccm = DEVICE(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ gpt_table[i].irq));
+ }
+
+ /* Initialize all EPIT timers */
+ for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } epit_table[FSL_IMX25_NUM_EPITS] = {
+ { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ },
+ { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
+ };
+
+ s->epit[i].ccm = DEVICE(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ epit_table[i].irq));
+ }
+
+ qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
+ object_property_set_bool(OBJECT(&s->fec), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
+
+
+ /* Initialize all I2C */
+ for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } i2c_table[FSL_IMX25_NUM_I2CS] = {
+ { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ },
+ { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ },
+ { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ }
+ };
+
+ object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ i2c_table[i].irq));
+ }
+
+ /* Initialize all GPIOs */
+ for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } gpio_table[FSL_IMX25_NUM_GPIOS] = {
+ { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ },
+ { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ },
+ { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ },
+ { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ }
+ };
+
+ object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ /* Connect GPIO IRQ to PIC */
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ gpio_table[i].irq));
+ }
+
+ /* initialize 2 x 16 KB ROM */
+ memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
+ "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
+ &s->rom[0]);
+ memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL,
+ "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR,
+ &s->rom[1]);
+
+ /* initialize internal RAM (128 KB) */
+ memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE,
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
+ &s->iram);
+ vmstate_register_ram_global(&s->iram);
+
+ /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
+ memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias",
+ &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR,
+ &s->iram_alias);
+}
+
+static void fsl_imx25_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = fsl_imx25_realize;
+}
+
+static const TypeInfo fsl_imx25_type_info = {
+ .name = TYPE_FSL_IMX25,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(FslIMX25State),
+ .instance_init = fsl_imx25_init,
+ .class_init = fsl_imx25_class_init,
+};
+
+static void fsl_imx25_register_types(void)
+{
+ type_register_static(&fsl_imx25_type_info);
+}
+
+type_init(fsl_imx25_register_types)
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
new file mode 100644
index 0000000000..8e1ed4811b
--- /dev/null
+++ b/hw/arm/fsl-imx31.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * i.MX31 SOC emulation.
+ *
+ * Based on hw/arm/fsl-imx31.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/arm/fsl-imx31.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+#include "hw/boards.h"
+#include "sysemu/char.h"
+
+static void fsl_imx31_init(Object *obj)
+{
+ FslIMX31State *s = FSL_IMX31(obj);
+ int i;
+
+ object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU);
+
+ object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
+ qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
+
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+ qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
+
+ for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
+ object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
+ qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
+ }
+
+ object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
+ qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
+
+ for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
+ object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
+ qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) {
+ object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
+ qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
+ object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
+ qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
+ }
+}
+
+static void fsl_imx31_realize(DeviceState *dev, Error **errp)
+{
+ FslIMX31State *s = FSL_IMX31(dev);
+ uint16_t i;
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
+
+ object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR);
+
+ /* Initialize all UARTS */
+ for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[FSL_IMX31_NUM_UARTS] = {
+ { FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ },
+ { FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ },
+ };
+
+ if (i < MAX_SERIAL_PORTS) {
+ CharDriverState *chr;
+
+ chr = serial_hds[i];
+
+ if (!chr) {
+ char label[20];
+ snprintf(label, sizeof(label), "imx31.uart%d", i);
+ chr = qemu_chr_new(label, "null", NULL);
+ }
+
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
+ }
+
+ object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ serial_table[i].irq));
+ }
+
+ s->gpt.ccm = DEVICE(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX31_GPT_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ));
+
+ /* Initialize all EPIT timers */
+ for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } epit_table[FSL_IMX31_NUM_EPITS] = {
+ { FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ },
+ { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ },
+ };
+
+ s->epit[i].ccm = DEVICE(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ epit_table[i].irq));
+ }
+
+ /* Initialize all I2C */
+ for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } i2c_table[FSL_IMX31_NUM_I2CS] = {
+ { FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ },
+ { FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ },
+ { FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ }
+ };
+
+ /* Initialize the I2C */
+ object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ /* Map I2C memory */
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
+ /* Connect I2C IRQ to PIC */
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ i2c_table[i].irq));
+ }
+
+ /* Initialize all GPIOs */
+ for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } gpio_table[FSL_IMX31_NUM_GPIOS] = {
+ { FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ },
+ { FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ },
+ { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ }
+ };
+
+ object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ /* Connect GPIO IRQ to PIC */
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic),
+ gpio_table[i].irq));
+ }
+
+ /* On a real system, the first 16k is a `secure boot rom' */
+ memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL,
+ "imx31.secure_rom",
+ FSL_IMX31_SECURE_ROM_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR,
+ &s->secure_rom);
+
+ /* There is also a 16k ROM */
+ memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom",
+ FSL_IMX31_ROM_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR,
+ &s->rom);
+
+ /* initialize internal RAM (16 KB) */
+ memory_region_init_ram(&s->iram, NULL, "imx31.iram", FSL_IMX31_IRAM_SIZE,
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR,
+ &s->iram);
+ vmstate_register_ram_global(&s->iram);
+
+ /* internal RAM (16 KB) is aliased over 256 MB - 16 KB */
+ memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias",
+ &s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR,
+ &s->iram_alias);
+}
+
+static void fsl_imx31_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = fsl_imx31_realize;
+}
+
+static const TypeInfo fsl_imx31_type_info = {
+ .name = TYPE_FSL_IMX31,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(FslIMX31State),
+ .instance_init = fsl_imx31_init,
+ .class_init = fsl_imx31_class_init,
+};
+
+static void fsl_imx31_register_types(void)
+{
+ type_register_static(&fsl_imx31_type_info);
+}
+
+type_init(fsl_imx31_register_types)
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
new file mode 100644
index 0000000000..c34667f068
--- /dev/null
+++ b/hw/arm/imx25_pdk.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * PDK Board System emulation.
+ *
+ * Based on hw/arm/kzm.c
+ *
+ * Copyright (c) 2008 OKL and 2011 NICTA
+ * Written by Hans at OK-Labs
+ * Updated by Peter Chubb.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/arm/fsl-imx25.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "sysemu/qtest.h"
+#include "hw/i2c/i2c.h"
+
+/* Memory map for PDK Emulation Baseboard:
+ * 0x00000000-0x7fffffff See i.MX25 SOC fr support
+ * 0x80000000-0x87ffffff RAM + Alias EMULATED
+ * 0x90000000-0x9fffffff RAM + Alias EMULATED
+ * 0xa0000000-0xa7ffffff Flash IGNORED
+ * 0xa8000000-0xafffffff Flash IGNORED
+ * 0xb0000000-0xb1ffffff SRAM IGNORED
+ * 0xb2000000-0xb3ffffff SRAM IGNORED
+ * 0xb4000000-0xb5ffffff CS4 IGNORED
+ * 0xb6000000-0xb8000fff Reserved IGNORED
+ * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED
+ * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED
+ * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED
+ * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED
+ * 0xb8005000-0xbaffffff Reserved IGNORED
+ * 0xbb000000-0xbb000fff NAND flash area buf IGNORED
+ * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED
+ * 0xbb001200-0xbb001dff Reserved IGNORED
+ * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED
+ * 0xbb012000-0xbfffffff Reserved IGNORED
+ * 0xc0000000-0xffffffff Reserved IGNORED
+ */
+
+typedef struct IMX25PDK {
+ FslIMX25State soc;
+ MemoryRegion ram;
+ MemoryRegion ram_alias;
+} IMX25PDK;
+
+static struct arm_boot_info imx25_pdk_binfo;
+
+static void imx25_pdk_init(MachineState *machine)
+{
+ IMX25PDK *s = g_new0(IMX25PDK, 1);
+ Error *err = NULL;
+ unsigned int ram_size;
+ unsigned int alias_offset;
+ int i;
+
+ object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25);
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
+ &error_abort);
+
+ object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ /* We need to initialize our memory */
+ if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
+ error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
+ "reduced to %x", machine->ram_size,
+ FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
+ machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE;
+ }
+
+ memory_region_allocate_system_memory(&s->ram, NULL, "imx25.ram",
+ machine->ram_size);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX25_SDRAM0_ADDR,
+ &s->ram);
+
+ /* initialize the alias memory if any */
+ for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
+ (i < 2) && ram_size; i++) {
+ unsigned int size;
+ static const struct {
+ hwaddr addr;
+ unsigned int size;
+ } ram[2] = {
+ { FSL_IMX25_SDRAM0_ADDR, FSL_IMX25_SDRAM0_SIZE },
+ { FSL_IMX25_SDRAM1_ADDR, FSL_IMX25_SDRAM1_SIZE },
+ };
+
+ size = MIN(ram_size, ram[i].size);
+
+ ram_size -= size;
+
+ if (size < ram[i].size) {
+ memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
+ &s->ram, alias_offset, ram[i].size - size);
+ memory_region_add_subregion(get_system_memory(),
+ ram[i].addr + size, &s->ram_alias);
+ }
+
+ alias_offset += ram[i].size;
+ }
+
+ imx25_pdk_binfo.ram_size = machine->ram_size;
+ imx25_pdk_binfo.kernel_filename = machine->kernel_filename;
+ imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline;
+ imx25_pdk_binfo.initrd_filename = machine->initrd_filename;
+ imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
+ imx25_pdk_binfo.board_id = 1771,
+ imx25_pdk_binfo.nb_cpus = 1;
+
+ /*
+ * We test explicitly for qtest here as it is not done (yet?) in
+ * arm_load_kernel(). Without this the "make check" command would
+ * fail.
+ */
+ if (!qtest_enabled()) {
+ arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo);
+ } else {
+ /*
+ * This I2C device doesn't exist on the real board.
+ * We add it here (only on qtest usage) to be able to do a bit
+ * of simple qtest. See "make check" for details.
+ */
+ i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]),
+ "i2c"),
+ "ds1338", 0x68);
+ }
+}
+
+static QEMUMachine imx25_pdk_machine = {
+ .name = "imx25_pdk",
+ .desc = "ARM i.MX25 PDK board (ARM926)",
+ .init = imx25_pdk_init,
+};
+
+static void imx25_pdk_machine_init(void)
+{
+ qemu_register_machine(&imx25_pdk_machine);
+}
+
+machine_init(imx25_pdk_machine_init)
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index d7af230925..241b1d7819 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -13,131 +13,130 @@
* i.MX31 SoC
*/
-#include "hw/sysbus.h"
+#include "hw/arm/fsl-imx31.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
#include "exec/address-spaces.h"
-#include "hw/hw.h"
-#include "hw/arm/arm.h"
-#include "hw/devices.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
+#include "hw/devices.h"
#include "hw/char/serial.h"
-#include "hw/intc/imx_avic.h"
-#include "hw/arm/imx.h"
-
- /* Memory map for Kzm Emulation Baseboard:
- * 0x00000000-0x00003fff 16k secure ROM IGNORED
- * 0x00004000-0x00407fff Reserved IGNORED
- * 0x00404000-0x00407fff ROM IGNORED
- * 0x00408000-0x0fffffff Reserved IGNORED
- * 0x10000000-0x1fffbfff RAM aliasing IGNORED
- * 0x1fffc000-0x1fffffff RAM EMULATED
- * 0x20000000-0x2fffffff Reserved IGNORED
- * 0x30000000-0x7fffffff I.MX31 Internal Register Space
- * 0x43f00000 IO_AREA0
- * 0x43f90000 UART1 EMULATED
- * 0x43f94000 UART2 EMULATED
- * 0x68000000 AVIC EMULATED
- * 0x53f80000 CCM EMULATED
- * 0x53f94000 PIT 1 EMULATED
- * 0x53f98000 PIT 2 EMULATED
- * 0x53f90000 GPT EMULATED
- * 0x80000000-0x87ffffff RAM EMULATED
- * 0x88000000-0x8fffffff RAM Aliasing EMULATED
- * 0xa0000000-0xafffffff NAND Flash IGNORED
- * 0xb0000000-0xb3ffffff Unavailable IGNORED
- * 0xb4000000-0xb4000fff 8-bit free space IGNORED
- * 0xb4001000-0xb400100f Board control IGNORED
- * 0xb4001003 DIP switch
- * 0xb4001010-0xb400101f 7-segment LED IGNORED
- * 0xb4001020-0xb400102f LED IGNORED
- * 0xb4001030-0xb400103f LED IGNORED
- * 0xb4001040-0xb400104f FPGA, UART EMULATED
- * 0xb4001050-0xb400105f FPGA, UART EMULATED
- * 0xb4001060-0xb40fffff FPGA IGNORED
- * 0xb6000000-0xb61fffff LAN controller EMULATED
- * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
- * 0xb6300000-0xb7ffffff Free IGNORED
- * 0xb8000000-0xb8004fff Memory control registers IGNORED
- * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
- * 0xc4000000-0xffffffff Reserved IGNORED
- */
-
-#define KZM_RAMADDRESS (0x80000000)
-#define KZM_FPGA (0xb4001040)
+#include "sysemu/qtest.h"
+
+/* Memory map for Kzm Emulation Baseboard:
+ * 0x00000000-0x7fffffff See i.MX31 SOC for support
+ * 0x80000000-0x8fffffff RAM EMULATED
+ * 0x90000000-0x9fffffff RAM EMULATED
+ * 0xa0000000-0xafffffff Flash IGNORED
+ * 0xb0000000-0xb3ffffff Unavailable IGNORED
+ * 0xb4000000-0xb4000fff 8-bit free space IGNORED
+ * 0xb4001000-0xb400100f Board control IGNORED
+ * 0xb4001003 DIP switch
+ * 0xb4001010-0xb400101f 7-segment LED IGNORED
+ * 0xb4001020-0xb400102f LED IGNORED
+ * 0xb4001030-0xb400103f LED IGNORED
+ * 0xb4001040-0xb400104f FPGA, UART EMULATED
+ * 0xb4001050-0xb400105f FPGA, UART EMULATED
+ * 0xb4001060-0xb40fffff FPGA IGNORED
+ * 0xb6000000-0xb61fffff LAN controller EMULATED
+ * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
+ * 0xb6300000-0xb7ffffff Free IGNORED
+ * 0xb8000000-0xb8004fff Memory control registers IGNORED
+ * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
+ * 0xc4000000-0xffffffff Reserved IGNORED
+ */
+
+typedef struct IMX31KZM {
+ FslIMX31State soc;
+ MemoryRegion ram;
+ MemoryRegion ram_alias;
+} IMX31KZM;
+
+#define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR)
+#define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040)
+#define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR)
static struct arm_boot_info kzm_binfo = {
- .loader_start = KZM_RAMADDRESS,
+ .loader_start = KZM_RAM_ADDR,
.board_id = 1722,
};
static void kzm_init(MachineState *machine)
{
- ram_addr_t ram_size = machine->ram_size;
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- ARMCPU *cpu;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
- DeviceState *dev;
- DeviceState *ccm;
-
- if (!cpu_model) {
- cpu_model = "arm1136";
- }
-
- cpu = cpu_arm_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find CPU definition\n");
+ IMX31KZM *s = g_new0(IMX31KZM, 1);
+ Error *err = NULL;
+ unsigned int ram_size;
+ unsigned int alias_offset;
+ unsigned int i;
+
+ object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31);
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
+ &error_abort);
+
+ object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
exit(1);
}
- /* On a real system, the first 16k is a `secure boot rom' */
-
- memory_region_allocate_system_memory(ram, NULL, "kzm.ram", ram_size);
- memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
-
- memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
- memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
-
- memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort);
- memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
-
- dev = sysbus_create_varargs(TYPE_IMX_AVIC, 0x68000000,
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
- NULL);
-
- imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
- imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
-
- ccm = sysbus_create_simple(TYPE_IMX_CCM, 0x53f80000, NULL);
+ /* Check the amount of memory is compatible with the SOC */
+ if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) {
+ error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
+ "reduced to %x", machine->ram_size,
+ FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE);
+ machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE;
+ }
- imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
- imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);
- imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm);
+ memory_region_allocate_system_memory(&s->ram, NULL, "kzm.ram",
+ machine->ram_size);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX31_SDRAM0_ADDR,
+ &s->ram);
+
+ /* initialize the alias memory if any */
+ for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
+ (i < 2) && ram_size; i++) {
+ unsigned int size;
+ static const struct {
+ hwaddr addr;
+ unsigned int size;
+ } ram[2] = {
+ { FSL_IMX31_SDRAM0_ADDR, FSL_IMX31_SDRAM0_SIZE },
+ { FSL_IMX31_SDRAM1_ADDR, FSL_IMX31_SDRAM1_SIZE },
+ };
+
+ size = MIN(ram_size, ram[i].size);
+
+ ram_size -= size;
+
+ if (size < ram[i].size) {
+ memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
+ &s->ram, alias_offset, ram[i].size - size);
+ memory_region_add_subregion(get_system_memory(),
+ ram[i].addr + size, &s->ram_alias);
+ }
+
+ alias_offset += ram[i].size;
+ }
if (nd_table[0].used) {
- lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52));
+ lan9118_init(&nd_table[0], KZM_LAN9118_ADDR,
+ qdev_get_gpio_in(DEVICE(&s->soc.avic), 52));
}
if (serial_hds[2]) { /* touchscreen */
- serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0,
- qdev_get_gpio_in(dev, 52),
- 14745600, serial_hds[2],
- DEVICE_NATIVE_ENDIAN);
+ serial_mm_init(get_system_memory(), KZM_FPGA_ADDR+0x10, 0,
+ qdev_get_gpio_in(DEVICE(&s->soc.avic), 52),
+ 14745600, serial_hds[2], DEVICE_NATIVE_ENDIAN);
}
- kzm_binfo.ram_size = ram_size;
- kzm_binfo.kernel_filename = kernel_filename;
- kzm_binfo.kernel_cmdline = kernel_cmdline;
- kzm_binfo.initrd_filename = initrd_filename;
+ kzm_binfo.ram_size = machine->ram_size;
+ kzm_binfo.kernel_filename = machine->kernel_filename;
+ kzm_binfo.kernel_cmdline = machine->kernel_cmdline;
+ kzm_binfo.initrd_filename = machine->initrd_filename;
kzm_binfo.nb_cpus = 1;
- arm_load_kernel(cpu, &kzm_binfo);
+
+ if (!qtest_enabled()) {
+ arm_load_kernel(&s->soc.cpu, &kzm_binfo);
+ }
}
static QEMUMachine kzm_machine = {
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index de2b289257..8873f9427c 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -258,8 +258,7 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
hwaddr base,
qemu_irq irq, omap_clk clk)
{
- struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
- g_malloc0(sizeof(struct omap_mpu_timer_s));
+ struct omap_mpu_timer_s *s = g_new0(struct omap_mpu_timer_s, 1);
s->irq = irq;
s->clk = clk;
@@ -388,8 +387,7 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
hwaddr base,
qemu_irq irq, omap_clk clk)
{
- struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
- g_malloc0(sizeof(struct omap_watchdog_timer_s));
+ struct omap_watchdog_timer_s *s = g_new0(struct omap_watchdog_timer_s, 1);
s->timer.irq = irq;
s->timer.clk = clk;
@@ -495,8 +493,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
hwaddr base,
qemu_irq irq, omap_clk clk)
{
- struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
- g_malloc0(sizeof(struct omap_32khz_timer_s));
+ struct omap_32khz_timer_s *s = g_new0(struct omap_32khz_timer_s, 1);
s->timer.irq = irq;
s->timer.clk = clk;
@@ -1236,8 +1233,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
MemoryRegion *memory, hwaddr base,
qemu_irq abort_irq, omap_clk clk)
{
- struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
- g_malloc0(sizeof(struct omap_tipb_bridge_s));
+ struct omap_tipb_bridge_s *s = g_new0(struct omap_tipb_bridge_s, 1);
s->abort = abort_irq;
omap_tipb_bridge_reset(s);
@@ -2099,8 +2095,7 @@ static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
omap_clk clk)
{
- struct omap_mpuio_s *s = (struct omap_mpuio_s *)
- g_malloc0(sizeof(struct omap_mpuio_s));
+ struct omap_mpuio_s *s = g_new0(struct omap_mpuio_s, 1);
s->irq = gpio_int;
s->kbd_irq = kbd_int;
@@ -2292,8 +2287,7 @@ static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
qemu_irq dma,
omap_clk clk)
{
- struct omap_uwire_s *s = (struct omap_uwire_s *)
- g_malloc0(sizeof(struct omap_uwire_s));
+ struct omap_uwire_s *s = g_new0(struct omap_uwire_s, 1);
s->txirq = txirq;
s->rxirq = rxirq;
@@ -2932,8 +2926,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
qemu_irq timerirq, qemu_irq alarmirq,
omap_clk clk)
{
- struct omap_rtc_s *s = (struct omap_rtc_s *)
- g_malloc0(sizeof(struct omap_rtc_s));
+ struct omap_rtc_s *s = g_new0(struct omap_rtc_s, 1);
s->irq = timerirq;
s->alarm = alarmirq;
@@ -3468,8 +3461,7 @@ static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
qemu_irq txirq, qemu_irq rxirq,
qemu_irq *dma, omap_clk clk)
{
- struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
- g_malloc0(sizeof(struct omap_mcbsp_s));
+ struct omap_mcbsp_s *s = g_new0(struct omap_mcbsp_s, 1);
s->txirq = txirq;
s->rxirq = rxirq;
@@ -3648,8 +3640,7 @@ static void omap_lpg_clk_update(void *opaque, int line, int on)
static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
hwaddr base, omap_clk clk)
{
- struct omap_lpg_s *s = (struct omap_lpg_s *)
- g_malloc0(sizeof(struct omap_lpg_s));
+ struct omap_lpg_s *s = g_new0(struct omap_lpg_s, 1);
s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s);
@@ -3853,8 +3844,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
const char *core)
{
int i;
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
- g_malloc0(sizeof(struct omap_mpu_state_s));
+ struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
qemu_irq dma_irqs[6];
DriveInfo *dinfo;
SysBusDevice *busdev;
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index e39b317290..1ee2d610f7 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -596,8 +596,7 @@ static const MemoryRegionOps omap_eac_ops = {
static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
{
- struct omap_eac_s *s = (struct omap_eac_s *)
- g_malloc0(sizeof(struct omap_eac_s));
+ struct omap_eac_s *s = g_new0(struct omap_eac_s, 1);
s->irq = irq;
s->codec.rxdrq = *drq ++;
@@ -788,8 +787,7 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
hwaddr channel_base, qemu_irq irq, omap_clk clk,
CharDriverState *chr)
{
- struct omap_sti_s *s = (struct omap_sti_s *)
- g_malloc0(sizeof(struct omap_sti_s));
+ struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
s->irq = irq;
omap_sti_reset(s);
@@ -1806,8 +1804,7 @@ static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
struct omap_mpu_state_s *mpu)
{
- struct omap_prcm_s *s = (struct omap_prcm_s *)
- g_malloc0(sizeof(struct omap_prcm_s));
+ struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1);
s->irq[0] = mpu_int;
s->irq[1] = dsp_int;
@@ -2185,8 +2182,7 @@ static void omap_sysctl_reset(struct omap_sysctl_s *s)
static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
omap_clk iclk, struct omap_mpu_state_s *mpu)
{
- struct omap_sysctl_s *s = (struct omap_sysctl_s *)
- g_malloc0(sizeof(struct omap_sysctl_s));
+ struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1);
s->mpu = mpu;
omap_sysctl_reset(s);
@@ -2248,8 +2244,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
unsigned long sdram_size,
const char *core)
{
- struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
- g_malloc0(sizeof(struct omap_mpu_state_s));
+ struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
qemu_irq dma_irqs[4];
DriveInfo *dinfo;
int i;
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index ec353f79c4..ec56b6172e 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1731,8 +1731,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
hwaddr base,
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
{
- PXA2xxI2SState *s = (PXA2xxI2SState *)
- g_malloc0(sizeof(PXA2xxI2SState));
+ PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
s->irq = irq;
s->rx_dma = rx_dma;
@@ -2061,7 +2060,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
PXA2xxState *s;
int i;
DriveInfo *dinfo;
- s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
+ s = g_new0(PXA2xxState, 1);
if (revision && strncmp(revision, "pxa27", 5)) {
fprintf(stderr, "Machine requires a PXA27x processor.\n");
@@ -2157,7 +2156,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
for (i = 0; pxa27x_ssp[i].io_base; i ++);
- s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
+ s->ssp = g_new0(SSIBus *, i);
for (i = 0; pxa27x_ssp[i].io_base; i ++) {
DeviceState *dev;
dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
@@ -2202,7 +2201,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
int i;
DriveInfo *dinfo;
- s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
+ s = g_new0(PXA2xxState, 1);
s->cpu = cpu_arm_init("pxa255");
if (s->cpu == NULL) {
@@ -2290,7 +2289,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
for (i = 0; pxa255_ssp[i].io_base; i ++);
- s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
+ s->ssp = g_new0(SSIBus *, i);
for (i = 0; pxa255_ssp[i].io_base; i ++) {
DeviceState *dev;
dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index 5bf032a637..fdb1010386 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -1060,10 +1060,6 @@ static VMStateDescription vmstate_spitz_kbd = {
},
};
-static Property spitz_keyboard_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1071,7 +1067,6 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
k->init = spitz_keyboard_init;
dc->vmsd = &vmstate_spitz_kbd;
- dc->props = spitz_keyboard_properties;
}
static const TypeInfo spitz_keyboard_info = {
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index cb515ec765..ca4628b0fc 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -675,7 +675,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
{
ssys_state *s;
- s = (ssys_state *)g_malloc0(sizeof(ssys_state));
+ s = g_new0(ssys_state, 1);
s->irq = irq;
s->board = board;
/* Most devices come preprogrammed with a MAC address in the user data. */
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index da9fc1d51b..9624ecb586 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1588,7 +1588,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
StrongARMState *s;
int i;
- s = g_malloc0(sizeof(StrongARMState));
+ s = g_new0(StrongARMState, 1);
if (!rev) {
rev = "sa1110-b5";
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index da217884e6..0f8bf1ca5c 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -541,7 +541,7 @@ static void vexpress_common_init(MachineState *machine)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
- VEDBoardInfo *daughterboard = vmc->daughterboard;;
+ VEDBoardInfo *daughterboard = vmc->daughterboard;
DeviceState *dev, *sysctl, *pl041;
qemu_irq pic[64];
uint32_t sys_id;
@@ -762,7 +762,7 @@ static void vexpress_a9_class_init(ObjectClass *oc, void *data)
mc->name = TYPE_VEXPRESS_A9_MACHINE;
mc->desc = "ARM Versatile Express for Cortex-A9";
- vmc->daughterboard = &a9_daughterboard;;
+ vmc->daughterboard = &a9_daughterboard;
}
static void vexpress_a15_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f365140319..9088248c3a 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -159,7 +159,8 @@ static void acpi_dsdt_add_virtio(Aml *scope,
}
}
-static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
+static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
+ bool use_highmem)
{
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
int i, bus_no;
@@ -234,6 +235,17 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio,
size_pio));
+ if (use_highmem) {
+ hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base;
+ hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size;
+
+ aml_append(rbuf,
+ aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000,
+ base_mmio_high, base_mmio_high, 0x0000,
+ size_mmio_high));
+ }
+
aml_append(method, aml_name_decl("RBUF", rbuf));
aml_append(method, aml_return(rbuf));
aml_append(dev, method);
@@ -510,7 +522,8 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
- acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE));
+ acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
+ guest_info->use_highmem);
aml_append(dsdt, scope);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d5a84175c9..e9324f56bd 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -50,6 +50,7 @@
#include "hw/arm/fdt.h"
#include "hw/intc/arm_gic_common.h"
#include "kvm_arm.h"
+#include "hw/smbios/smbios.h"
/* Number of external interrupt lines to configure the GIC with */
#define NUM_IRQS 256
@@ -79,6 +80,7 @@ typedef struct {
typedef struct {
MachineState parent;
bool secure;
+ bool highmem;
} VirtMachineState;
#define TYPE_VIRT_MACHINE "virt"
@@ -119,6 +121,8 @@ static const MemMapEntry a15memmap[] = {
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
+ /* Second PCIe window, 512GB wide at the 512GB boundary */
+ [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL },
};
static const int a15irqmap[] = {
@@ -284,9 +288,32 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
{
int cpu;
+ int addr_cells = 1;
+
+ /*
+ * From Documentation/devicetree/bindings/arm/cpus.txt
+ * On ARM v8 64-bit systems value should be set to 2,
+ * that corresponds to the MPIDR_EL1 register size.
+ * If MPIDR_EL1[63:32] value is equal to 0 on all CPUs
+ * in the system, #address-cells can be set to 1, since
+ * MPIDR_EL1[63:32] bits are not used for CPUs
+ * identification.
+ *
+ * Here we actually don't know whether our system is 32- or 64-bit one.
+ * The simplest way to go is to examine affinity IDs of all our CPUs. If
+ * at least one of them has Aff3 populated, we set #address-cells to 2.
+ */
+ for (cpu = 0; cpu < vbi->smp_cpus; cpu++) {
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
+
+ if (armcpu->mp_affinity & ARM_AFF3_MASK) {
+ addr_cells = 2;
+ break;
+ }
+ }
qemu_fdt_add_subnode(vbi->fdt, "/cpus");
- qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1);
+ qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells);
qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) {
@@ -303,7 +330,14 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
"enable-method", "psci");
}
- qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity);
+ if (addr_cells == 2) {
+ qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg",
+ armcpu->mp_affinity);
+ } else {
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg",
+ armcpu->mp_affinity);
+ }
+
g_free(nodename);
}
}
@@ -362,7 +396,7 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
fdt_add_v2m_gic_node(vbi);
}
-static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure)
{
/* We create a standalone GIC v2 */
DeviceState *gicdev;
@@ -379,6 +413,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
+ if (!kvm_irqchip_in_kernel()) {
+ qdev_prop_set_bit(gicdev, "has-security-extensions", secure);
+ }
qdev_init_nofail(gicdev);
gicbusdev = SYS_BUS_DEVICE(gicdev);
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
@@ -666,10 +703,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
0x7 /* PCI irq */);
}
-static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
+ bool use_highmem)
{
hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
+ hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base;
+ hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size;
hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base;
hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size;
hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base;
@@ -706,6 +746,16 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
mmio_reg, base_mmio, size_mmio);
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
+ if (use_highmem) {
+ /* Map high MMIO space */
+ MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1);
+
+ memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
+ mmio_reg, base_mmio_high, size_mmio_high);
+ memory_region_add_subregion(get_system_memory(), base_mmio_high,
+ high_mmio_alias);
+ }
+
/* Map IO port space */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
@@ -727,11 +777,23 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
2, base_ecam, 2, size_ecam);
- qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
- 1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, base_pio, 2, size_pio,
- 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
- 2, base_mmio, 2, size_mmio);
+
+ if (use_highmem) {
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, 0,
+ 2, base_pio, 2, size_pio,
+ 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
+ 2, base_mmio, 2, size_mmio,
+ 1, FDT_PCI_RANGE_MMIO_64BIT,
+ 2, base_mmio_high,
+ 2, base_mmio_high, 2, size_mmio_high);
+ } else {
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, 0,
+ 2, base_pio, 2, size_pio,
+ 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
+ 2, base_mmio, 2, size_mmio);
+ }
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
@@ -788,12 +850,37 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
return board->fdt;
}
+static void virt_build_smbios(VirtGuestInfo *guest_info)
+{
+ FWCfgState *fw_cfg = guest_info->fw_cfg;
+ uint8_t *smbios_tables, *smbios_anchor;
+ size_t smbios_tables_len, smbios_anchor_len;
+
+ if (!fw_cfg) {
+ return;
+ }
+
+ smbios_set_defaults("QEMU", "QEMU Virtual Machine",
+ "1.0", false, true, SMBIOS_ENTRY_POINT_30);
+
+ smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len,
+ &smbios_anchor, &smbios_anchor_len);
+
+ if (smbios_anchor) {
+ fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
+ smbios_tables, smbios_tables_len);
+ fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
+ smbios_anchor, smbios_anchor_len);
+ }
+}
+
static
void virt_guest_info_machine_done(Notifier *notifier, void *data)
{
VirtGuestInfoState *guest_info_state = container_of(notifier,
VirtGuestInfoState, machine_done);
virt_acpi_setup(&guest_info_state->info);
+ virt_build_smbios(&guest_info_state->info);
}
static void machvirt_init(MachineState *machine)
@@ -883,13 +970,13 @@ static void machvirt_init(MachineState *machine)
create_flash(vbi);
- create_gic(vbi, pic);
+ create_gic(vbi, pic, vms->secure);
create_uart(vbi, pic);
create_rtc(vbi, pic);
- create_pcie(vbi, pic);
+ create_pcie(vbi, pic, vms->highmem);
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
@@ -904,6 +991,7 @@ static void machvirt_init(MachineState *machine)
guest_info->fw_cfg = fw_cfg_find();
guest_info->memmap = vbi->memmap;
guest_info->irqmap = vbi->irqmap;
+ guest_info->use_highmem = vms->highmem;
guest_info_state->machine_done.notify = virt_guest_info_machine_done;
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
@@ -941,18 +1029,44 @@ static void virt_set_secure(Object *obj, bool value, Error **errp)
vms->secure = value;
}
+static bool virt_get_highmem(Object *obj, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ return vms->highmem;
+}
+
+static void virt_set_highmem(Object *obj, bool value, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ vms->highmem = value;
+}
+
static void virt_instance_init(Object *obj)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- /* EL3 is enabled by default on virt */
- vms->secure = true;
+ /* EL3 is disabled by default on virt: this makes us consistent
+ * between KVM and TCG for this board, and it also allows us to
+ * boot UEFI blobs which assume no TrustZone support.
+ */
+ vms->secure = false;
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);
+
+ /* High memory is enabled by default */
+ vms->highmem = true;
+ object_property_add_bool(obj, "highmem", virt_get_highmem,
+ virt_set_highmem, NULL);
+ object_property_set_description(obj, "highmem",
+ "Set on/off to enable/disable using "
+ "physical address space above 32 bits",
+ NULL);
}
static void virt_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 388baef76e..21855420dd 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -28,6 +28,10 @@
#define GIC_DIST_ADDR 0xf9010000
#define GIC_CPU_ADDR 0xf9020000
+#define SATA_INTR 133
+#define SATA_ADDR 0xFD0C0000
+#define SATA_NUM_PORTS 2
+
static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
};
@@ -90,6 +94,9 @@ static void xlnx_zynqmp_init(Object *obj)
object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART);
qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
}
+
+ object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI);
+ qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
}
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -121,7 +128,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS);
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
if (err) {
- error_propagate((errp), (err));
+ error_propagate(errp, err);
return;
}
assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
@@ -162,16 +169,11 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
g_free(name);
object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
- "reset-cbar", &err);
- if (err) {
- error_propagate((errp), (err));
- return;
- }
-
+ "reset-cbar", &error_abort);
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
&err);
if (err) {
- error_propagate((errp), (err));
+ error_propagate(errp, err);
return;
}
@@ -200,16 +202,11 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
g_free(name);
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs",
- &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
-
+ &error_abort);
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
&err);
if (err) {
- error_propagate((errp), (err));
+ error_propagate(errp, err);
return;
}
}
@@ -232,7 +229,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
if (err) {
- error_propagate((errp), (err));
+ error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
@@ -243,13 +240,24 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
if (err) {
- error_propagate((errp), (err));
+ error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
gic_spi[uart_intr[i]]);
}
+
+ object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
}
static Property xlnx_zynqmp_props[] = {
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index adcef2d3b9..81c0c1be20 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -1177,7 +1177,7 @@ void OPLResetChip(FM_OPL *OPL)
OPLWriteReg(OPL,0x03,0); /* Timer2 */
OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
- /* reset OPerator paramater */
+ /* reset operator parameter */
for( c = 0 ; c < OPL->max_ch ; c++ )
{
OPL_CH *CH = &OPL->P_CH[c];
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 40d4880326..5da41b23cf 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -805,7 +805,7 @@ static int nvme_init(PCIDevice *pci_dev)
n->num_namespaces = 1;
n->num_queues = 64;
- n->reg_size = 1 << qemu_fls(0x1004 + 2 * (n->num_queues + 1) * 4);
+ n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4);
n->ns_size = bs_size / (uint64_t)n->num_namespaces;
n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 1556c9cf5a..f9301ae541 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -731,7 +731,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
- if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
+ if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
if (s->conf.scsi) {
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
return 0;
@@ -782,10 +782,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
*
* s->blk would erroneously be placed in writethrough mode.
*/
- if (!virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
aio_context_acquire(blk_get_aio_context(s->blk));
blk_set_enable_write_cache(s->blk,
- virtio_has_feature(vdev, VIRTIO_BLK_F_WCE));
+ virtio_vdev_has_feature(vdev,
+ VIRTIO_BLK_F_WCE));
aio_context_release(blk_get_aio_context(s->blk));
}
}
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 267d8a8c70..36d7398f4f 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -24,7 +24,6 @@
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
-#include <signal.h>
#include <inttypes.h>
#include <time.h>
#include <fcntl.h>
diff --git a/hw/bt/hci.c b/hw/bt/hci.c
index 7ea3dc6b70..3fec435378 100644
--- a/hw/bt/hci.c
+++ b/hw/bt/hci.c
@@ -1151,8 +1151,7 @@ static void bt_hci_reset(struct bt_hci_s *hci)
hci->event_mask[7] = 0x00;
hci->device.inquiry_scan = 0;
hci->device.page_scan = 0;
- if (hci->device.lmp_name)
- g_free((void *) hci->device.lmp_name);
+ g_free((void *) hci->device.lmp_name);
hci->device.lmp_name = NULL;
hci->device.class[0] = 0x00;
hci->device.class[1] = 0x00;
@@ -1829,8 +1828,7 @@ static void bt_submit_hci(struct HCIInfo *info,
case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
LENGTH_CHECK(change_local_name);
- if (hci->device.lmp_name)
- g_free((void *) hci->device.lmp_name);
+ g_free((void *) hci->device.lmp_name);
hci->device.lmp_name = g_strndup(PARAM(change_local_name, name),
sizeof(PARAM(change_local_name, name)));
bt_hci_event_complete_status(hci, HCI_SUCCESS);
@@ -2231,8 +2229,7 @@ static void bt_hci_done(struct HCIInfo *info)
bt_device_done(&hci->device);
- if (hci->device.lmp_name)
- g_free((void *) hci->device.lmp_name);
+ g_free((void *) hci->device.lmp_name);
/* Be gentle and send DISCONNECT to all connected peers and those
* currently waiting for us to accept or reject a connection request.
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 7614e5860f..215f9622c9 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -234,10 +234,8 @@ static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
static void fifo_reset(Exynos4210UartFIFO *q)
{
- if (q->data != NULL) {
- g_free(q->data);
- q->data = NULL;
- }
+ g_free(q->data);
+ q->data = NULL;
q->data = (uint8_t *)g_malloc0(q->size);
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 801156db2d..e8f32c46c2 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -21,7 +21,6 @@
#include "hw/char/imx_serial.h"
#include "sysemu/sysemu.h"
#include "sysemu/char.h"
-#include "hw/arm/imx.h"
//#define DEBUG_SERIAL 1
#ifdef DEBUG_SERIAL
@@ -334,40 +333,6 @@ static void imx_serial_init(Object *obj)
sysbus_init_irq(sbd, &s->irq);
}
-void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *bus;
- CharDriverState *chr;
- const char chr_name[] = "serial";
- char label[ARRAY_SIZE(chr_name) + 1];
-
- dev = qdev_create(NULL, TYPE_IMX_SERIAL);
-
- if (uart >= MAX_SERIAL_PORTS) {
- hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
- uart, MAX_SERIAL_PORTS);
- }
- chr = serial_hds[uart];
- if (!chr) {
- snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
- chr = qemu_chr_new(label, "null", NULL);
- if (!(chr)) {
- hw_error("Can't assign serial port to imx-uart%d.\n", uart);
- }
- }
-
- qdev_prop_set_chr(dev, "chardev", chr);
- bus = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
- sysbus_connect_irq(bus, 0, irq);
-
-}
-
-
static Property imx_serial_properties[] = {
DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index 88f20943e4..278ce36cb0 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -55,8 +55,7 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
qemu_irq txdma, qemu_irq rxdma,
const char *label, CharDriverState *chr)
{
- struct omap_uart_s *s = (struct omap_uart_s *)
- g_malloc0(sizeof(struct omap_uart_s));
+ struct omap_uart_s *s = g_new0(struct omap_uart_s, 1);
s->base = base;
s->fclk = fclk;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index bc56f5d520..be97058712 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -76,7 +76,7 @@ static VirtIOSerialPort *find_port_by_name(char *name)
static bool use_multiport(VirtIOSerial *vser)
{
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
- return virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT);
+ return virtio_vdev_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT);
}
static size_t write_to_port(VirtIOSerialPort *port,
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 216eeeb917..a96a74e579 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -594,8 +594,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
ret = hdr->ih_size;
out:
- if (data)
- g_free(data);
+ g_free(data);
close(fd);
return ret;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index ac4654e9dd..51ed6b2e05 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -226,6 +226,20 @@ static void machine_set_usb(Object *obj, bool value, Error **errp)
ms->usb_disabled = !value;
}
+static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->igd_gfx_passthru;
+}
+
+static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->igd_gfx_passthru = value;
+}
+
static char *machine_get_firmware(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -388,6 +402,12 @@ static void machine_initfn(Object *obj)
object_property_set_description(obj, "usb",
"Set on/off to enable/disable usb",
NULL);
+ object_property_add_bool(obj, "igd-passthru",
+ machine_get_igd_gfx_passthru,
+ machine_set_igd_gfx_passthru, NULL);
+ object_property_set_description(obj, "igd-passthru",
+ "Set on/off to enable/disable igd passthrou",
+ NULL);
object_property_add_str(obj, "firmware",
machine_get_firmware,
machine_set_firmware, NULL);
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 04fd80a4de..33e245e12f 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -422,9 +422,7 @@ static void set_string(Object *obj, Visitor *v, void *opaque,
error_propagate(errp, local_err);
return;
}
- if (*ptr) {
- g_free(*ptr);
- }
+ g_free(*ptr);
*ptr = str;
}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index b2f404a765..a24493a48d 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -506,7 +506,7 @@ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
return ret;
}
-/* disconnect a GPIO ouput, returning the disconnected input (if any) */
+/* disconnect a GPIO output, returning the disconnected input (if any) */
static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
const char *name, int n)
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 58ac02e610..94e8cc1a66 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -52,10 +52,23 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
SysBusDevice *busdev;
int i;
Error *err = NULL;
+ bool has_el3;
+ Object *cpuobj;
gicdev = DEVICE(&s->gic);
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
+
+ if (!kvm_irqchip_in_kernel()) {
+ /* Make the GIC's TZ support match the CPUs. We assume that
+ * either all the CPUs have TZ, or none do.
+ */
+ cpuobj = OBJECT(qemu_get_cpu(0));
+ has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
+ object_property_get_bool(cpuobj, "has_el3", &error_abort);
+ qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
+ }
+
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c
index c09358c6e7..869818cd8a 100644
--- a/hw/cpu/a9mpcore.c
+++ b/hw/cpu/a9mpcore.c
@@ -49,6 +49,8 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
*wdtbusdev;
Error *err = NULL;
int i;
+ bool has_el3;
+ Object *cpuobj;
scudev = DEVICE(&s->scu);
qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
@@ -62,6 +64,15 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
gicdev = DEVICE(&s->gic);
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
+
+ /* Make the GIC's TZ support match the CPUs. We assume that
+ * either all the CPUs have TZ, or none do.
+ */
+ cpuobj = OBJECT(qemu_get_cpu(0));
+ has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
+ object_property_get_bool(cpuobj, "has_el3", &error_abort);
+ qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
+
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 3cae480fa2..2e8c2c74fb 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -138,7 +138,7 @@ static void tempsensor_clkedge(struct tempsensor_t *s,
s->count = 16;
if ((s->regs[0] & 0xff) == 0) {
- /* 25 degrees celcius. */
+ /* 25 degrees celsius. */
s->shiftreg = 0x0b9f;
} else if ((s->regs[0] & 0xff) == 0xff) {
/* Sensor ID, 0x8100 LM70. */
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 603ef50568..45239e836a 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1354,9 +1354,7 @@ static void exynos4210_fimd_reset(DeviceState *d)
fimd_update_get_alpha(s, w);
}
- if (s->ifb != NULL) {
- g_free(s->ifb);
- }
+ g_free(s->ifb);
s->ifb = NULL;
exynos4210_fimd_invalidate(s);
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
index f1fef2767e..b1c7af5819 100644
--- a/hw/display/omap_dss.c
+++ b/hw/display/omap_dss.c
@@ -1051,8 +1051,7 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
omap_clk fck1, omap_clk fck2, omap_clk ck54m,
omap_clk ick1, omap_clk ick2)
{
- struct omap_dss_s *s = (struct omap_dss_s *)
- g_malloc0(sizeof(struct omap_dss_s));
+ struct omap_dss_s *s = g_new0(struct omap_dss_s, 1);
s->irq = irq;
s->drq = drq;
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index a7c6cd79b9..678f9a1b42 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -403,8 +403,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
struct omap_dma_lcd_channel_s *dma,
omap_clk clk)
{
- struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
- g_malloc0(sizeof(struct omap_lcd_panel_s));
+ struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1);
s->irq = irq;
s->dma = dma;
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index a542087fcc..7e4ef1ed04 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -159,7 +159,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
/*
* use ssd.lock to protect render_update_cookie_num.
* qxl_render_update is called by io thread or vcpu thread, and the completion
- * callbacks are called by spice_server thread, defering to bh called from the
+ * callbacks are called by spice_server thread, deferring to bh called from the
* io thread.
*/
void qxl_render_update(PCIQXLDevice *qxl)
diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index 97c57a03c0..db68730990 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -1626,8 +1626,7 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
enum omap_dma_model model)
{
int num_irqs, memsize, i;
- struct omap_dma_s *s = (struct omap_dma_s *)
- g_malloc0(sizeof(struct omap_dma_s));
+ struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
if (model <= omap_dma_3_1) {
num_irqs = 6;
@@ -2061,8 +2060,7 @@ struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
int chans, omap_clk iclk, omap_clk fclk)
{
int i;
- struct omap_dma_s *s = (struct omap_dma_s *)
- g_malloc0(sizeof(struct omap_dma_s));
+ struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
s->model = omap_dma_4;
s->chans = chans;
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index cf842a3cc7..b1cfa11356 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -133,7 +133,7 @@ struct XilinxAXIDMA {
};
/*
- * Helper calls to extract info from desriptors and other trivial
+ * Helper calls to extract info from descriptors and other trivial
* state from regs.
*/
static inline int stream_desc_sof(struct SDesc *d)
diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index 1abcf17988..52233f7e2f 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
common-obj-$(CONFIG_E500) += mpc8xxx.o
obj-$(CONFIG_OMAP) += omap_gpio.o
+obj-$(CONFIG_IMX) += imx_gpio.o
diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
new file mode 100644
index 0000000000..d56ffcd8d7
--- /dev/null
+++ b/hw/gpio/imx_gpio.c
@@ -0,0 +1,340 @@
+/*
+ * i.MX processors GPIO emulation.
+ *
+ * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/gpio/imx_gpio.h"
+
+#ifndef DEBUG_IMX_GPIO
+#define DEBUG_IMX_GPIO 0
+#endif
+
+typedef enum IMXGPIOLevel {
+ IMX_GPIO_LEVEL_LOW = 0,
+ IMX_GPIO_LEVEL_HIGH = 1,
+} IMXGPIOLevel;
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX_GPIO) { \
+ fprintf(stderr, "%s: " fmt , __func__, ##args); \
+ } \
+ } while (0)
+
+static const char *imx_gpio_reg_name(uint32_t reg)
+{
+ switch (reg) {
+ case DR_ADDR:
+ return "DR";
+ case GDIR_ADDR:
+ return "GDIR";
+ case PSR_ADDR:
+ return "PSR";
+ case ICR1_ADDR:
+ return "ICR1";
+ case ICR2_ADDR:
+ return "ICR2";
+ case IMR_ADDR:
+ return "IMR";
+ case ISR_ADDR:
+ return "ISR";
+ case EDGE_SEL_ADDR:
+ return "EDGE_SEL";
+ default:
+ return "[?]";
+ }
+}
+
+static void imx_gpio_update_int(IMXGPIOState *s)
+{
+ qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
+}
+
+static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
+{
+ /* if this signal isn't configured as an input signal, nothing to do */
+ if (!extract32(s->gdir, line, 1)) {
+ return;
+ }
+
+ /* When set, EDGE_SEL overrides the ICR config */
+ if (extract32(s->edge_sel, line, 1)) {
+ /* we detect interrupt on rising and falling edge */
+ if (extract32(s->psr, line, 1) != level) {
+ /* level changed */
+ s->isr = deposit32(s->isr, line, 1, 1);
+ }
+ } else if (extract64(s->icr, 2*line + 1, 1)) {
+ /* interrupt is edge sensitive */
+ if (extract32(s->psr, line, 1) != level) {
+ /* level changed */
+ if (extract64(s->icr, 2*line, 1) != level) {
+ s->isr = deposit32(s->isr, line, 1, 1);
+ }
+ }
+ } else {
+ /* interrupt is level sensitive */
+ if (extract64(s->icr, 2*line, 1) == level) {
+ s->isr = deposit32(s->isr, line, 1, 1);
+ }
+ }
+}
+
+static void imx_gpio_set(void *opaque, int line, int level)
+{
+ IMXGPIOState *s = IMX_GPIO(opaque);
+ IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
+
+ imx_gpio_set_int_line(s, line, imx_level);
+
+ /* this is an input signal, so set PSR */
+ s->psr = deposit32(s->psr, line, 1, imx_level);
+
+ imx_gpio_update_int(s);
+}
+
+static void imx_gpio_set_all_int_lines(IMXGPIOState *s)
+{
+ int i;
+
+ for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
+ IMXGPIOLevel imx_level = extract32(s->psr, i, 1);
+ imx_gpio_set_int_line(s, i, imx_level);
+ }
+
+ imx_gpio_update_int(s);
+}
+
+static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s)
+{
+ int i;
+
+ for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
+ /*
+ * if the line is set as output, then forward the line
+ * level to its user.
+ */
+ if (extract32(s->gdir, i, 1) && s->output[i]) {
+ qemu_set_irq(s->output[i], extract32(s->dr, i, 1));
+ }
+ }
+}
+
+static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
+{
+ IMXGPIOState *s = IMX_GPIO(opaque);
+ uint32_t reg_value = 0;
+
+ switch (offset) {
+ case DR_ADDR:
+ /*
+ * depending on the "line" configuration, the bit values
+ * are coming either from DR or PSR
+ */
+ reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir);
+ break;
+
+ case GDIR_ADDR:
+ reg_value = s->gdir;
+ break;
+
+ case PSR_ADDR:
+ reg_value = s->psr & ~s->gdir;
+ break;
+
+ case ICR1_ADDR:
+ reg_value = extract64(s->icr, 0, 32);
+ break;
+
+ case ICR2_ADDR:
+ reg_value = extract64(s->icr, 32, 32);
+ break;
+
+ case IMR_ADDR:
+ reg_value = s->imr;
+ break;
+
+ case ISR_ADDR:
+ reg_value = s->isr;
+ break;
+
+ case EDGE_SEL_ADDR:
+ if (s->has_edge_sel) {
+ reg_value = s->edge_sel;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not "
+ "present on this version of GPIO device\n",
+ TYPE_IMX_GPIO, __func__);
+ }
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n",
+ TYPE_IMX_GPIO, __func__, (int)offset);
+ break;
+ }
+
+ DPRINTF("(%s) = 0x%"PRIx32"\n", imx_gpio_reg_name(offset), reg_value);
+
+ return reg_value;
+}
+
+static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMXGPIOState *s = IMX_GPIO(opaque);
+
+ DPRINTF("(%s, value = 0x%"PRIx32")\n", imx_gpio_reg_name(offset),
+ (uint32_t)value);
+
+ switch (offset) {
+ case DR_ADDR:
+ s->dr = value;
+ imx_gpio_set_all_output_lines(s);
+ break;
+
+ case GDIR_ADDR:
+ s->gdir = value;
+ imx_gpio_set_all_output_lines(s);
+ imx_gpio_set_all_int_lines(s);
+ break;
+
+ case ICR1_ADDR:
+ s->icr = deposit64(s->icr, 0, 32, value);
+ imx_gpio_set_all_int_lines(s);
+ break;
+
+ case ICR2_ADDR:
+ s->icr = deposit64(s->icr, 32, 32, value);
+ imx_gpio_set_all_int_lines(s);
+ break;
+
+ case IMR_ADDR:
+ s->imr = value;
+ imx_gpio_update_int(s);
+ break;
+
+ case ISR_ADDR:
+ s->isr |= ~value;
+ imx_gpio_set_all_int_lines(s);
+ break;
+
+ case EDGE_SEL_ADDR:
+ if (s->has_edge_sel) {
+ s->edge_sel = value;
+ imx_gpio_set_all_int_lines(s);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not "
+ "present on this version of GPIO device\n",
+ TYPE_IMX_GPIO, __func__);
+ }
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n",
+ TYPE_IMX_GPIO, __func__, (int)offset);
+ break;
+ }
+
+ return;
+}
+
+static const MemoryRegionOps imx_gpio_ops = {
+ .read = imx_gpio_read,
+ .write = imx_gpio_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_imx_gpio = {
+ .name = TYPE_IMX_GPIO,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(dr, IMXGPIOState),
+ VMSTATE_UINT32(gdir, IMXGPIOState),
+ VMSTATE_UINT32(psr, IMXGPIOState),
+ VMSTATE_UINT64(icr, IMXGPIOState),
+ VMSTATE_UINT32(imr, IMXGPIOState),
+ VMSTATE_UINT32(isr, IMXGPIOState),
+ VMSTATE_BOOL(has_edge_sel, IMXGPIOState),
+ VMSTATE_UINT32(edge_sel, IMXGPIOState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property imx_gpio_properties[] = {
+ DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_gpio_reset(DeviceState *dev)
+{
+ IMXGPIOState *s = IMX_GPIO(dev);
+
+ s->dr = 0;
+ s->gdir = 0;
+ s->psr = 0;
+ s->icr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->edge_sel = 0;
+
+ imx_gpio_set_all_output_lines(s);
+ imx_gpio_update_int(s);
+}
+
+static void imx_gpio_realize(DeviceState *dev, Error **errp)
+{
+ IMXGPIOState *s = IMX_GPIO(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s,
+ TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE);
+
+ qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
+ qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+}
+
+static void imx_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = imx_gpio_realize;
+ dc->reset = imx_gpio_reset;
+ dc->props = imx_gpio_properties;
+ dc->vmsd = &vmstate_imx_gpio;
+ dc->desc = "i.MX GPIO controller";
+}
+
+static const TypeInfo imx_gpio_info = {
+ .name = TYPE_IMX_GPIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXGPIOState),
+ .class_init = imx_gpio_class_init,
+};
+
+static void imx_gpio_register_types(void)
+{
+ type_register_static(&imx_gpio_info);
+}
+
+type_init(imx_gpio_register_types)
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
index d92f8cfbae..3c538985ee 100644
--- a/hw/gpio/omap_gpio.c
+++ b/hw/gpio/omap_gpio.c
@@ -710,8 +710,8 @@ static int omap2_gpio_init(SysBusDevice *sbd)
} else {
s->modulecount = 6;
}
- s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s));
- s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq));
+ s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
+ s->handler = g_new0(qemu_irq, s->modulecount * 32);
qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
for (i = 0; i < s->modulecount; i++) {
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
index 24a77272d7..aa8ee5fa0e 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -235,10 +235,6 @@ static const VMStateDescription vmstate_scoop_regs = {
},
};
-static Property scoop_sysbus_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -247,7 +243,6 @@ static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
k->init = scoop_init;
dc->desc = "Scoop2 Sharp custom ASIC";
dc->vmsd = &vmstate_scoop_regs;
- dc->props = scoop_sysbus_properties;
}
static const TypeInfo scoop_sysbus_info = {
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0f130608c1..aeb8f38d70 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
common-obj-$(CONFIG_APM) += pm_smbus.o
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
+common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
obj-$(CONFIG_OMAP) += omap_i2c.o
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
new file mode 100644
index 0000000000..8474872e07
--- /dev/null
+++ b/hw/i2c/imx_i2c.c
@@ -0,0 +1,334 @@
+/*
+ * i.MX I2C Bus Serial Interface Emulation
+ *
+ * Copyright (C) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/i2c/imx_i2c.h"
+#include "hw/i2c/i2c.h"
+
+#ifndef IMX_I2C_DEBUG
+#define IMX_I2C_DEBUG 0
+#endif
+
+#if IMX_I2C_DEBUG
+#define DPRINT(fmt, args...) \
+ do { fprintf(stderr, "%s: "fmt, __func__, ## args); } while (0)
+
+static const char *imx_i2c_get_regname(unsigned offset)
+{
+ switch (offset) {
+ case IADR_ADDR:
+ return "IADR";
+ case IFDR_ADDR:
+ return "IFDR";
+ case I2CR_ADDR:
+ return "I2CR";
+ case I2SR_ADDR:
+ return "I2SR";
+ case I2DR_ADDR:
+ return "I2DR";
+ default:
+ return "[?]";
+ }
+}
+#else
+#define DPRINT(fmt, args...) do { } while (0)
+#endif
+
+static inline bool imx_i2c_is_enabled(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_IEN;
+}
+
+static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_IIEN;
+}
+
+static inline bool imx_i2c_is_master(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_MSTA;
+}
+
+static void imx_i2c_reset(DeviceState *dev)
+{
+ IMXI2CState *s = IMX_I2C(dev);
+
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ }
+
+ s->address = ADDR_RESET;
+ s->iadr = IADR_RESET;
+ s->ifdr = IFDR_RESET;
+ s->i2cr = I2CR_RESET;
+ s->i2sr = I2SR_RESET;
+ s->i2dr_read = I2DR_RESET;
+ s->i2dr_write = I2DR_RESET;
+}
+
+static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
+{
+ /*
+ * raise an interrupt if the device is enabled and it is configured
+ * to generate some interrupts.
+ */
+ if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
+ s->i2sr |= I2SR_IIF;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint16_t value;
+ IMXI2CState *s = IMX_I2C(opaque);
+
+ switch (offset) {
+ case IADR_ADDR:
+ value = s->iadr;
+ break;
+ case IFDR_ADDR:
+ value = s->ifdr;
+ break;
+ case I2CR_ADDR:
+ value = s->i2cr;
+ break;
+ case I2SR_ADDR:
+ value = s->i2sr;
+ break;
+ case I2DR_ADDR:
+ value = s->i2dr_read;
+
+ if (imx_i2c_is_master(s)) {
+ int ret = 0xff;
+
+ if (s->address == ADDR_RESET) {
+ /* something is wrong as the address is not set */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+ "without specifying the slave address\n",
+ TYPE_IMX_I2C, __func__);
+ } else if (s->i2cr & I2CR_MTX) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+ "but MTX is set\n", TYPE_IMX_I2C, __func__);
+ } else {
+ /* get the next byte */
+ ret = i2c_recv(s->bus);
+
+ if (ret >= 0) {
+ imx_i2c_raise_interrupt(s);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: read failed "
+ "for device 0x%02x\n", TYPE_IMX_I2C,
+ __func__, s->address);
+ ret = 0xff;
+ }
+ }
+
+ s->i2dr_read = ret;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+ TYPE_IMX_I2C, __func__);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_I2C, __func__, s->address);
+ value = 0;
+ break;
+ }
+
+ DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
+ (unsigned int)offset, value);
+
+ return (uint64_t)value;
+}
+
+static void imx_i2c_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMXI2CState *s = IMX_I2C(opaque);
+
+ DPRINT("write %s [0x%02x] <- 0x%02x\n", imx_i2c_get_regname(offset),
+ (unsigned int)offset, (int)value);
+
+ value &= 0xff;
+
+ switch (offset) {
+ case IADR_ADDR:
+ s->iadr = value & IADR_MASK;
+ /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */
+ break;
+ case IFDR_ADDR:
+ s->ifdr = value & IFDR_MASK;
+ break;
+ case I2CR_ADDR:
+ if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) {
+ /* This is a soft reset. IADR is preserved during soft resets */
+ uint16_t iadr = s->iadr;
+ imx_i2c_reset(DEVICE(s));
+ s->iadr = iadr;
+ } else { /* normal write */
+ s->i2cr = value & I2CR_MASK;
+
+ if (imx_i2c_is_master(s)) {
+ /* set the bus to busy */
+ s->i2sr |= I2SR_IBB;
+ } else { /* slave mode */
+ /* bus is not busy anymore */
+ s->i2sr &= ~I2SR_IBB;
+
+ /*
+ * if we unset the master mode then it ends the ongoing
+ * transfer if any
+ */
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = ADDR_RESET;
+ }
+ }
+
+ if (s->i2cr & I2CR_RSTA) { /* Restart */
+ /* if this is a restart then it ends the ongoing transfer */
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = ADDR_RESET;
+ s->i2cr &= ~I2CR_RSTA;
+ }
+ }
+ }
+ break;
+ case I2SR_ADDR:
+ /*
+ * if the user writes 0 to IIF then lower the interrupt and
+ * reset the bit
+ */
+ if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) {
+ s->i2sr &= ~I2SR_IIF;
+ qemu_irq_lower(s->irq);
+ }
+
+ /*
+ * if the user writes 0 to IAL, reset the bit
+ */
+ if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) {
+ s->i2sr &= ~I2SR_IAL;
+ }
+
+ break;
+ case I2DR_ADDR:
+ /* if the device is not enabled, nothing to do */
+ if (!imx_i2c_is_enabled(s)) {
+ break;
+ }
+
+ s->i2dr_write = value & I2DR_MASK;
+
+ if (imx_i2c_is_master(s)) {
+ /* If this is the first write cycle then it is the slave addr */
+ if (s->address == ADDR_RESET) {
+ if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7),
+ extract32(s->i2dr_write, 0, 1))) {
+ /* if non zero is returned, the adress is not valid */
+ s->i2sr |= I2SR_RXAK;
+ } else {
+ s->address = s->i2dr_write;
+ s->i2sr &= ~I2SR_RXAK;
+ imx_i2c_raise_interrupt(s);
+ }
+ } else { /* This is a normal data write */
+ if (i2c_send(s->bus, s->i2dr_write)) {
+ /* if the target return non zero then end the transfer */
+ s->i2sr |= I2SR_RXAK;
+ s->address = ADDR_RESET;
+ i2c_end_transfer(s->bus);
+ } else {
+ s->i2sr &= ~I2SR_RXAK;
+ imx_i2c_raise_interrupt(s);
+ }
+ }
+ } else {
+ qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+ TYPE_IMX_I2C, __func__);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_I2C, __func__, s->address);
+ break;
+ }
+}
+
+static const MemoryRegionOps imx_i2c_ops = {
+ .read = imx_i2c_read,
+ .write = imx_i2c_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 2,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription imx_i2c_vmstate = {
+ .name = TYPE_IMX_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(address, IMXI2CState),
+ VMSTATE_UINT16(iadr, IMXI2CState),
+ VMSTATE_UINT16(ifdr, IMXI2CState),
+ VMSTATE_UINT16(i2cr, IMXI2CState),
+ VMSTATE_UINT16(i2sr, IMXI2CState),
+ VMSTATE_UINT16(i2dr_read, IMXI2CState),
+ VMSTATE_UINT16(i2dr_write, IMXI2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void imx_i2c_realize(DeviceState *dev, Error **errp)
+{
+ IMXI2CState *s = IMX_I2C(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C,
+ IMX_I2C_MEM_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+ s->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void imx_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &imx_i2c_vmstate;
+ dc->reset = imx_i2c_reset;
+ dc->realize = imx_i2c_realize;
+}
+
+static const TypeInfo imx_i2c_type_info = {
+ .name = TYPE_IMX_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXI2CState),
+ .class_init = imx_i2c_class_init,
+};
+
+static void imx_i2c_register_types(void)
+{
+ type_register_static(&imx_i2c_type_info);
+}
+
+type_init(imx_i2c_register_types)
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index ebd1015a08..c250deb848 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -7,6 +7,7 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-y += kvmvapic.o
obj-y += acpi-build.o
+obj-y += pci-assign-load-rom.o
gen-hex-y += hw/i386/acpi-dsdt.hex
gen-hex-y += hw/i386/q35-acpi-dsdt.hex
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 74d22f4fd2..b1beaa66b2 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -37,6 +37,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
#include "kvm_i386.h"
+#include "hw/pci/pci-assign.h"
#define MSIX_PAGE_SIZE 0x1000
@@ -48,17 +49,6 @@
#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
#define IORESOURCE_MEM_64 0x00100000
-//#define DEVICE_ASSIGNMENT_DEBUG
-
-#ifdef DEVICE_ASSIGNMENT_DEBUG
-#define DEBUG(fmt, ...) \
- do { \
- fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \
- } while (0)
-#else
-#define DEBUG(fmt, ...)
-#endif
-
typedef struct PCIRegion {
int type; /* Memory or port I/O */
int valid;
@@ -1896,73 +1886,15 @@ static void assign_register_types(void)
type_init(assign_register_types)
-/*
- * Scan the assigned devices for the devices that have an option ROM, and then
- * load the corresponding ROM data to RAM. If an error occurs while loading an
- * option ROM, we just ignore that option ROM and continue with the next one.
- */
static void assigned_dev_load_option_rom(AssignedDevice *dev)
{
- char name[32], rom_file[64];
- FILE *fp;
- uint8_t val;
- struct stat st;
- void *ptr;
-
- /* If loading ROM from file, pci handles it */
- if (dev->dev.romfile || !dev->dev.rom_bar) {
- return;
- }
+ int size = 0;
- snprintf(rom_file, sizeof(rom_file),
- "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
- dev->host.domain, dev->host.bus, dev->host.slot,
- dev->host.function);
+ pci_assign_dev_load_option_rom(&dev->dev, OBJECT(dev), &size,
+ dev->host.domain, dev->host.bus,
+ dev->host.slot, dev->host.function);
- if (stat(rom_file, &st)) {
- return;
- }
-
- if (access(rom_file, F_OK)) {
- error_report("pci-assign: Insufficient privileges for %s", rom_file);
- return;
- }
-
- /* Write "1" to the ROM file to enable it */
- fp = fopen(rom_file, "r+");
- if (fp == NULL) {
- return;
+ if (!size) {
+ error_report("pci-assign: Invalid ROM.");
}
- val = 1;
- if (fwrite(&val, 1, 1, fp) != 1) {
- goto close_rom;
- }
- fseek(fp, 0, SEEK_SET);
-
- snprintf(name, sizeof(name), "%s.rom",
- object_get_typename(OBJECT(dev)));
- memory_region_init_ram(&dev->dev.rom, OBJECT(dev), name, st.st_size,
- &error_abort);
- vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev);
- ptr = memory_region_get_ram_ptr(&dev->dev.rom);
- memset(ptr, 0xff, st.st_size);
-
- if (!fread(ptr, 1, st.st_size, fp)) {
- error_report("pci-assign: Cannot read from host %s", rom_file);
- 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");
- goto close_rom;
- }
-
- pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom);
- dev->dev.has_rom = true;
-close_rom:
- /* Write "0" to disable ROM */
- fseek(fp, 0, SEEK_SET);
- val = 0;
- if (!fwrite(&val, 1, 1, fp)) {
- DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
- }
- fclose(fp);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 16d06c6bf8..56aecced7b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1412,7 +1412,13 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) {
uint64_t *val = g_malloc(sizeof(*val));
- *val = cpu_to_le64(ROUND_UP(pcms->hotplug_memory.base, 0x1ULL << 30));
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+ uint64_t res_mem_end = pcms->hotplug_memory.base;
+
+ if (!pcmc->broken_reserved_end) {
+ res_mem_end += memory_region_size(&pcms->hotplug_memory.mr);
+ }
+ *val = cpu_to_le64(ROUND_UP(res_mem_end, 0x1ULL << 30));
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
}
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 95584676e2..3f925b26db 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -50,7 +50,8 @@
#include "cpu.h"
#include "qemu/error-report.h"
#ifdef CONFIG_XEN
-# include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_info_table.h>
+#include "hw/xen/xen_pt.h"
#endif
#include "migration/migration.h"
@@ -76,7 +77,8 @@ static bool has_reserved_memory = true;
static bool kvmclock_enabled = true;
/* PC hardware initialisation */
-static void pc_init1(MachineState *machine)
+static void pc_init1(MachineState *machine,
+ const char *host_type, const char *pci_type)
{
PCMachineState *pcms = PC_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
@@ -134,9 +136,7 @@ static void pc_init1(MachineState *machine)
pcms->below_4g_mem_size = machine->ram_size;
}
- if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size,
- &pcms->above_4g_mem_size,
- &ram_memory) != 0) {
+ if (xen_enabled() && xen_hvm_init(pcms, &ram_memory) != 0) {
fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
exit(1);
}
@@ -173,7 +173,8 @@ static void pc_init1(MachineState *machine)
MachineClass *mc = MACHINE_GET_CLASS(machine);
/* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
- mc->name, smbios_legacy_mode, smbios_uuid_encoded);
+ mc->name, smbios_legacy_mode, smbios_uuid_encoded,
+ SMBIOS_ENTRY_POINT_21);
}
/* allocate ram and load rom/bios */
@@ -195,7 +196,9 @@ static void pc_init1(MachineState *machine)
}
if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
+ pci_bus = i440fx_init(host_type,
+ pci_type,
+ &i440fx_state, &piix3_devfn, &isa_bus, gsi,
system_memory, system_io, machine->ram_size,
pcms->below_4g_mem_size,
pcms->above_4g_mem_size,
@@ -413,15 +416,25 @@ static void pc_init_isa(MachineState *machine)
}
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode();
- pc_init1(machine);
+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
#ifdef CONFIG_XEN
+static void pc_xen_hvm_init_pci(MachineState *machine)
+{
+ const char *pci_type = has_igd_gfx_passthru ?
+ TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE : TYPE_I440FX_PCI_DEVICE;
+
+ pc_init1(machine,
+ TYPE_I440FX_PCI_HOST_BRIDGE,
+ pci_type);
+}
+
static void pc_xen_hvm_init(MachineState *machine)
{
PCIBus *bus;
- pc_init1(machine);
+ pc_xen_hvm_init_pci(machine);
bus = pci_find_primary_bus();
if (bus != NULL) {
@@ -437,7 +450,8 @@ static void pc_xen_hvm_init(MachineState *machine)
if (compat) { \
compat(machine); \
} \
- pc_init1(machine); \
+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
+ TYPE_I440FX_PCI_DEVICE); \
} \
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
@@ -450,7 +464,9 @@ static void pc_i440fx_machine_options(MachineClass *m)
static void pc_i440fx_2_4_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_options(m);
+ pcmc->broken_reserved_end = true;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
m->alias = "pc";
@@ -877,6 +893,118 @@ static void pc_i440fx_0_10_machine_options(MachineClass *m)
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
pc_i440fx_0_10_machine_options);
+typedef struct {
+ uint16_t gpu_device_id;
+ uint16_t pch_device_id;
+ uint8_t pch_revision_id;
+} IGDDeviceIDInfo;
+
+/* In real world different GPU should have different PCH. But actually
+ * the different PCH DIDs likely map to different PCH SKUs. We do the
+ * same thing for the GPU. For PCH, the different SKUs are going to be
+ * all the same silicon design and implementation, just different
+ * features turn on and off with fuses. The SW interfaces should be
+ * consistent across all SKUs in a given family (eg LPT). But just same
+ * features may not be supported.
+ *
+ * Most of these different PCH features probably don't matter to the
+ * Gfx driver, but obviously any difference in display port connections
+ * will so it should be fine with any PCH in case of passthrough.
+ *
+ * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
+ * scenarios, 0x9cc3 for BDW(Broadwell).
+ */
+static const IGDDeviceIDInfo igd_combo_id_infos[] = {
+ /* HSW Classic */
+ {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
+ {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
+ {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
+ {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
+ {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
+ /* HSW ULT */
+ {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
+ {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
+ {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
+ {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
+ {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
+ {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
+ /* HSW CRW */
+ {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
+ {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
+ /* HSW Server */
+ {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
+ /* HSW SRVR */
+ {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
+ /* BSW */
+ {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
+ {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
+ {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
+ {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
+ {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
+ {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
+ {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
+ {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
+ {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
+ {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
+ {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
+};
+
+static void isa_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge faked to support IGD PT";
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+};
+
+static TypeInfo isa_bridge_info = {
+ .name = "igd-passthrough-isa-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = isa_bridge_class_init,
+};
+
+static void pt_graphics_register_types(void)
+{
+ type_register_static(&isa_bridge_info);
+}
+type_init(pt_graphics_register_types)
+
+void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
+{
+ struct PCIDevice *bridge_dev;
+ int i, num;
+ uint16_t pch_dev_id = 0xffff;
+ uint8_t pch_rev_id;
+
+ num = ARRAY_SIZE(igd_combo_id_infos);
+ for (i = 0; i < num; i++) {
+ if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
+ pch_dev_id = igd_combo_id_infos[i].pch_device_id;
+ pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
+ }
+ }
+
+ if (pch_dev_id == 0xffff) {
+ return;
+ }
+
+ /* Currently IGD drivers always need to access PCH by 1f.0. */
+ bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
+ "igd-passthrough-isa-bridge");
+
+ /*
+ * Note that vendor id is always PCI_VENDOR_ID_INTEL.
+ */
+ if (!bridge_dev) {
+ fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
+ return;
+ }
+ pci_config_set_device_id(bridge_dev->config, pch_dev_id);
+ pci_config_set_revision(bridge_dev->config, pch_rev_id);
+}
static void isapc_machine_options(MachineClass *m)
{
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index c07d65bc46..11601ab005 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -125,9 +125,7 @@ static void pc_q35_init(MachineState *machine)
pcms->below_4g_mem_size = machine->ram_size;
}
- if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size,
- &pcms->above_4g_mem_size,
- &ram_memory) != 0) {
+ if (xen_enabled() && xen_hvm_init(pcms, &ram_memory) != 0) {
fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
exit(1);
}
@@ -165,7 +163,8 @@ static void pc_q35_init(MachineState *machine)
if (smbios_defaults) {
/* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
- mc->name, smbios_legacy_mode, smbios_uuid_encoded);
+ mc->name, smbios_legacy_mode, smbios_uuid_encoded,
+ SMBIOS_ENTRY_POINT_21);
}
/* allocate ram and load rom/bios */
@@ -369,7 +368,9 @@ static void pc_q35_machine_options(MachineClass *m)
static void pc_q35_2_4_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_options(m);
+ pcmc->broken_reserved_end = true;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
m->no_floppy = 1;
diff --git a/hw/i386/pci-assign-load-rom.c b/hw/i386/pci-assign-load-rom.c
new file mode 100644
index 0000000000..34a3a7ed7f
--- /dev/null
+++ b/hw/i386/pci-assign-load-rom.c
@@ -0,0 +1,91 @@
+/*
+ * This is splited from hw/i386/kvm/pci-assign.c
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/loader.h"
+#include "monitor/monitor.h"
+#include "qemu/range.h"
+#include "sysemu/sysemu.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci-assign.h"
+
+/*
+ * Scan the assigned devices for the devices that have an option ROM, and then
+ * load the corresponding ROM data to RAM. If an error occurs while loading an
+ * option ROM, we just ignore that option ROM and continue with the next one.
+ */
+void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
+ int *size, unsigned int domain,
+ unsigned int bus, unsigned int slot,
+ unsigned int function)
+{
+ char name[32], rom_file[64];
+ FILE *fp;
+ uint8_t val;
+ struct stat st;
+ void *ptr = NULL;
+
+ /* If loading ROM from file, pci handles it */
+ if (dev->romfile || !dev->rom_bar) {
+ return NULL;
+ }
+
+ snprintf(rom_file, sizeof(rom_file),
+ "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
+ domain, bus, slot, function);
+
+ if (stat(rom_file, &st)) {
+ return NULL;
+ }
+
+ if (access(rom_file, F_OK)) {
+ error_report("pci-assign: Insufficient privileges for %s", rom_file);
+ return NULL;
+ }
+
+ /* Write "1" to the ROM file to enable it */
+ fp = fopen(rom_file, "r+");
+ if (fp == NULL) {
+ return NULL;
+ }
+ val = 1;
+ if (fwrite(&val, 1, 1, fp) != 1) {
+ goto close_rom;
+ }
+ fseek(fp, 0, SEEK_SET);
+
+ snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner));
+ memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort);
+ vmstate_register_ram(&dev->rom, &dev->qdev);
+ ptr = memory_region_get_ram_ptr(&dev->rom);
+ memset(ptr, 0xff, st.st_size);
+
+ if (!fread(ptr, 1, st.st_size, fp)) {
+ error_report("pci-assign: Cannot read from host %s", rom_file);
+ 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");
+ goto close_rom;
+ }
+
+ pci_register_bar(dev, PCI_ROM_SLOT, 0, &dev->rom);
+ dev->has_rom = true;
+ *size = st.st_size;
+close_rom:
+ /* Write "0" to disable ROM */
+ fseek(fp, 0, SEEK_SET);
+ val = 0;
+ if (!fwrite(&val, 1, 1, fp)) {
+ DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
+ }
+ fclose(fp);
+
+ return ptr;
+}
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 28b324a6f4..ee45f038b8 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -23,8 +23,6 @@
* THE SOFTWARE.
*/
-#include <assert.h>
-
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/ide.h"
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 48749c1dc1..44f6e27398 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -25,7 +25,6 @@
#include <hw/pci/msi.h>
#include <hw/i386/pc.h>
#include <hw/pci/pci.h>
-#include <hw/sysbus.h>
#include "qemu/error-report.h"
#include "sysemu/block-backend.h"
@@ -122,9 +121,9 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
{
- AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
- PCIDevice *pci_dev =
- (PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
+ DeviceState *dev_state = s->container;
+ PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
+ TYPE_PCI_DEVICE);
DPRINTF(0, "raise irq\n");
@@ -137,9 +136,9 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
{
- AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
- PCIDevice *pci_dev =
- (PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
+ DeviceState *dev_state = s->container;
+ PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
+ TYPE_PCI_DEVICE);
DPRINTF(0, "lower irq\n");
@@ -877,7 +876,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
limit - sglist->size));
if (sglist->size > INT32_MAX) {
error_report("AHCI Physical Region Descriptor Table describes "
- "more than 2 GiB.\n");
+ "more than 2 GiB.");
qemu_sglist_destroy(sglist);
r = -1;
goto out;
@@ -1437,6 +1436,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
s->as = as;
s->ports = ports;
s->dev = g_new0(AHCIDevice, ports);
+ s->container = qdev;
ahci_reg_init(s);
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
@@ -1625,18 +1625,6 @@ const VMStateDescription vmstate_ahci = {
},
};
-#define TYPE_SYSBUS_AHCI "sysbus-ahci"
-#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
-
-typedef struct SysbusAHCIState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- AHCIState ahci;
- uint32_t num_ports;
-} SysbusAHCIState;
-
static const VMStateDescription vmstate_sysbus_ahci = {
.name = "sysbus-ahci",
.fields = (VMStateField[]) {
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 79a463d93c..c9b3805415 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -24,6 +24,8 @@
#ifndef HW_IDE_AHCI_H
#define HW_IDE_AHCI_H
+#include <hw/sysbus.h>
+
#define AHCI_MEM_BAR_SIZE 0x1000
#define AHCI_MAX_PORTS 32
#define AHCI_MAX_SG 168 /* hardware max is 64K */
@@ -285,6 +287,8 @@ struct AHCIDevice {
};
typedef struct AHCIState {
+ DeviceState *container;
+
AHCIDevice *dev;
AHCIControlRegs control_regs;
MemoryRegion mem;
@@ -369,4 +373,16 @@ void ahci_reset(AHCIState *s);
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd);
+#define TYPE_SYSBUS_AHCI "sysbus-ahci"
+#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
+
+typedef struct SysbusAHCIState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ AHCIState ahci;
+ uint32_t num_ports;
+} SysbusAHCIState;
+
#endif /* HW_IDE_AHCI_H */
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
index 0609e80868..4d86c04e51 100644
--- a/hw/input/stellaris_input.c
+++ b/hw/input/stellaris_input.c
@@ -69,14 +69,14 @@ static const VMStateDescription vmstate_stellaris_gamepad = {
}
};
-/* Returns an array 5 ouput slots. */
+/* Returns an array of 5 output slots. */
void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
{
gamepad_state *s;
int i;
- s = (gamepad_state *)g_malloc0(sizeof (gamepad_state));
- s->buttons = (gamepad_button *)g_malloc0(n * sizeof (gamepad_button));
+ s = g_new0(gamepad_state, 1);
+ s->buttons = g_new0(gamepad_button, n);
for (i = 0; i < n; i++) {
s->buttons[i].irq = irq[i];
s->buttons[i].keycode = keycode[i];
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index a8c5d19448..8bad132d5a 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -219,15 +219,99 @@ static uint16_t gic_get_current_pending_irq(GICState *s, int cpu,
return pending_irq;
}
-static void gic_set_running_irq(GICState *s, int cpu, int irq)
+static int gic_get_group_priority(GICState *s, int cpu, int irq)
{
- s->running_irq[cpu] = irq;
- if (irq == 1023) {
- s->running_priority[cpu] = 0x100;
+ /* Return the group priority of the specified interrupt
+ * (which is the top bits of its priority, with the number
+ * of bits masked determined by the applicable binary point register).
+ */
+ int bpr;
+ uint32_t mask;
+
+ if (gic_has_groups(s) &&
+ !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) &&
+ GIC_TEST_GROUP(irq, (1 << cpu))) {
+ bpr = s->abpr[cpu];
} else {
- s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
+ bpr = s->bpr[cpu];
}
- gic_update(s);
+
+ /* a BPR of 0 means the group priority bits are [7:1];
+ * a BPR of 1 means they are [7:2], and so on down to
+ * a BPR of 7 meaning no group priority bits at all.
+ */
+ mask = ~0U << ((bpr & 7) + 1);
+
+ return GIC_GET_PRIORITY(irq, cpu) & mask;
+}
+
+static void gic_activate_irq(GICState *s, int cpu, int irq)
+{
+ /* Set the appropriate Active Priority Register bit for this IRQ,
+ * and update the running priority.
+ */
+ int prio = gic_get_group_priority(s, cpu, irq);
+ int preemption_level = prio >> (GIC_MIN_BPR + 1);
+ int regno = preemption_level / 32;
+ int bitno = preemption_level % 32;
+
+ if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) {
+ s->nsapr[regno][cpu] &= (1 << bitno);
+ } else {
+ s->apr[regno][cpu] &= (1 << bitno);
+ }
+
+ s->running_priority[cpu] = prio;
+ GIC_SET_ACTIVE(irq, 1 << cpu);
+}
+
+static int gic_get_prio_from_apr_bits(GICState *s, int cpu)
+{
+ /* Recalculate the current running priority for this CPU based
+ * on the set bits in the Active Priority Registers.
+ */
+ int i;
+ for (i = 0; i < GIC_NR_APRS; i++) {
+ uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu];
+ if (!apr) {
+ continue;
+ }
+ return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
+ }
+ return 0x100;
+}
+
+static void gic_drop_prio(GICState *s, int cpu, int group)
+{
+ /* Drop the priority of the currently active interrupt in the
+ * specified group.
+ *
+ * Note that we can guarantee (because of the requirement to nest
+ * GICC_IAR reads [which activate an interrupt and raise priority]
+ * with GICC_EOIR writes [which drop the priority for the interrupt])
+ * that the interrupt we're being called for is the highest priority
+ * active interrupt, meaning that it has the lowest set bit in the
+ * APR registers.
+ *
+ * If the guest does not honour the ordering constraints then the
+ * behaviour of the GIC is UNPREDICTABLE, which for us means that
+ * the values of the APR registers might become incorrect and the
+ * running priority will be wrong, so interrupts that should preempt
+ * might not do so, and interrupts that should not preempt might do so.
+ */
+ int i;
+
+ for (i = 0; i < GIC_NR_APRS; i++) {
+ uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu];
+ if (!*papr) {
+ continue;
+ }
+ /* Clear lowest set bit */
+ *papr &= *papr - 1;
+ break;
+ }
+
+ s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
}
uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
@@ -239,7 +323,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
* for the case where this GIC supports grouping and the pending interrupt
* is in the wrong group.
*/
- irq = gic_get_current_pending_irq(s, cpu, attrs);;
+ irq = gic_get_current_pending_irq(s, cpu, attrs);
if (irq >= GIC_MAXIRQ) {
DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq);
@@ -250,7 +334,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq);
return 1023;
}
- s->last_active[irq][cpu] = s->running_irq[cpu];
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
/* Clear pending flags for both level and edge triggered interrupts.
@@ -281,7 +364,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
}
}
- gic_set_running_irq(s, cpu, irq);
+ gic_activate_irq(s, cpu, irq);
+ gic_update(s);
DPRINTF("ACK %d\n", irq);
return ret;
}
@@ -411,8 +495,9 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
{
- int update = 0;
int cm = 1 << cpu;
+ int group;
+
DPRINTF("EOI %d\n", irq);
if (irq >= s->num_irq) {
/* This handles two cases:
@@ -425,8 +510,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
*/
return;
}
- if (s->running_irq[cpu] == 1023)
+ if (s->running_priority[cpu] == 0x100) {
return; /* No active IRQ. */
+ }
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
/* Mark level triggered interrupts as pending if they are still
@@ -435,11 +521,12 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
&& GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
DPRINTF("Set %d pending mask %x\n", irq, cm);
GIC_SET_PENDING(irq, cm);
- update = 1;
}
}
- if (s->security_extn && !attrs.secure && !GIC_TEST_GROUP(irq, cm)) {
+ group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
+
+ if (s->security_extn && !attrs.secure && !group) {
DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq);
return;
}
@@ -449,23 +536,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
* i.e. go ahead and complete the irq anyway.
*/
- if (irq != s->running_irq[cpu]) {
- /* Complete an IRQ that is not currently running. */
- int tmp = s->running_irq[cpu];
- while (s->last_active[tmp][cpu] != 1023) {
- if (s->last_active[tmp][cpu] == irq) {
- s->last_active[tmp][cpu] = s->last_active[irq][cpu];
- break;
- }
- tmp = s->last_active[tmp][cpu];
- }
- if (update) {
- gic_update(s);
- }
- } else {
- /* Complete the current running IRQ. */
- gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
- }
+ gic_drop_prio(s, cpu, group);
+ GIC_CLEAR_ACTIVE(irq, cm);
+ gic_update(s);
}
static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
@@ -922,6 +995,68 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
}
}
+static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno)
+{
+ /* Return the Nonsecure view of GICC_APR<regno>. This is the
+ * second half of GICC_NSAPR.
+ */
+ switch (GIC_MIN_BPR) {
+ case 0:
+ if (regno < 2) {
+ return s->nsapr[regno + 2][cpu];
+ }
+ break;
+ case 1:
+ if (regno == 0) {
+ return s->nsapr[regno + 1][cpu];
+ }
+ break;
+ case 2:
+ if (regno == 0) {
+ return extract32(s->nsapr[0][cpu], 16, 16);
+ }
+ break;
+ case 3:
+ if (regno == 0) {
+ return extract32(s->nsapr[0][cpu], 8, 8);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return 0;
+}
+
+static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno,
+ uint32_t value)
+{
+ /* Write the Nonsecure view of GICC_APR<regno>. */
+ switch (GIC_MIN_BPR) {
+ case 0:
+ if (regno < 2) {
+ s->nsapr[regno + 2][cpu] = value;
+ }
+ break;
+ case 1:
+ if (regno == 0) {
+ s->nsapr[regno + 1][cpu] = value;
+ }
+ break;
+ case 2:
+ if (regno == 0) {
+ s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value);
+ }
+ break;
+ case 3:
+ if (regno == 0) {
+ s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
uint64_t *data, MemTxAttrs attrs)
{
@@ -962,8 +1097,31 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
}
break;
case 0xd0: case 0xd4: case 0xd8: case 0xdc:
- *data = s->apr[(offset - 0xd0) / 4][cpu];
+ {
+ int regno = (offset - 0xd0) / 4;
+
+ if (regno >= GIC_NR_APRS || s->revision != 2) {
+ *data = 0;
+ } else if (s->security_extn && !attrs.secure) {
+ /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
+ *data = gic_apr_ns_view(s, regno, cpu);
+ } else {
+ *data = s->apr[regno][cpu];
+ }
break;
+ }
+ case 0xe0: case 0xe4: case 0xe8: case 0xec:
+ {
+ int regno = (offset - 0xe0) / 4;
+
+ if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) ||
+ (s->security_extn && !attrs.secure)) {
+ *data = 0;
+ } else {
+ *data = s->nsapr[regno][cpu];
+ }
+ break;
+ }
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_read: Bad offset %x\n", (int)offset);
@@ -1001,8 +1159,33 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
}
break;
case 0xd0: case 0xd4: case 0xd8: case 0xdc:
- qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
+ {
+ int regno = (offset - 0xd0) / 4;
+
+ if (regno >= GIC_NR_APRS || s->revision != 2) {
+ return MEMTX_OK;
+ }
+ if (s->security_extn && !attrs.secure) {
+ /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
+ gic_apr_write_ns_view(s, regno, cpu, value);
+ } else {
+ s->apr[regno][cpu] = value;
+ }
break;
+ }
+ case 0xe0: case 0xe4: case 0xe8: case 0xec:
+ {
+ int regno = (offset - 0xe0) / 4;
+
+ if (regno >= GIC_NR_APRS || s->revision != 2) {
+ return MEMTX_OK;
+ }
+ if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) {
+ return MEMTX_OK;
+ }
+ s->nsapr[regno][cpu] = value;
+ break;
+ }
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_write: Bad offset %x\n", (int)offset);
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
index fe64b51cff..9c82b97293 100644
--- a/hw/intc/arm_gic_common.c
+++ b/hw/intc/arm_gic_common.c
@@ -19,6 +19,7 @@
*/
#include "gic_internal.h"
+#include "hw/arm/linux-boot-if.h"
static void gic_pre_save(void *opaque)
{
@@ -59,8 +60,8 @@ static const VMStateDescription vmstate_gic_irq_state = {
static const VMStateDescription vmstate_gic = {
.name = "arm_gic",
- .version_id = 10,
- .minimum_version_id = 10,
+ .version_id = 12,
+ .minimum_version_id = 12,
.pre_save = gic_pre_save,
.post_load = gic_post_load,
.fields = (VMStateField[]) {
@@ -71,15 +72,14 @@ static const VMStateDescription vmstate_gic = {
VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
- VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
- VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
+ VMSTATE_UINT32_2DARRAY(nsapr, GICState, GIC_NR_APRS, GIC_NCPU),
VMSTATE_END_OF_LIST()
}
};
@@ -165,21 +165,35 @@ static void arm_gic_common_reset(DeviceState *dev)
{
GICState *s = ARM_GIC_COMMON(dev);
int i, j;
+ int resetprio;
+
+ /* If we're resetting a TZ-aware GIC as if secure firmware
+ * had set it up ready to start a kernel in non-secure,
+ * we need to set interrupt priorities to a "zero for the
+ * NS view" value. This is particularly critical for the
+ * priority_mask[] values, because if they are zero then NS
+ * code cannot ever rewrite the priority to anything else.
+ */
+ if (s->security_extn && s->irq_reset_nonsecure) {
+ resetprio = 0x80;
+ } else {
+ resetprio = 0;
+ }
+
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < s->num_cpu; i++) {
if (s->revision == REV_11MPCORE) {
s->priority_mask[i] = 0xf0;
} else {
- s->priority_mask[i] = 0;
+ s->priority_mask[i] = resetprio;
}
s->current_pending[i] = 1023;
- s->running_irq[i] = 1023;
s->running_priority[i] = 0x100;
s->cpu_ctlr[i] = 0;
s->bpr[i] = GIC_MIN_BPR;
s->abpr[i] = GIC_MIN_ABPR;
for (j = 0; j < GIC_INTERNAL; j++) {
- s->priority1[j][i] = 0;
+ s->priority1[j][i] = resetprio;
}
for (j = 0; j < GIC_NR_SGIS; j++) {
s->sgi_pending[j][i] = 0;
@@ -191,7 +205,7 @@ static void arm_gic_common_reset(DeviceState *dev)
}
for (i = 0; i < ARRAY_SIZE(s->priority2); i++) {
- s->priority2[i] = 0;
+ s->priority2[i] = resetprio;
}
for (i = 0; i < GIC_MAXIRQ; i++) {
@@ -202,9 +216,32 @@ static void arm_gic_common_reset(DeviceState *dev)
s->irq_target[i] = 0;
}
}
+ if (s->security_extn && s->irq_reset_nonsecure) {
+ for (i = 0; i < GIC_MAXIRQ; i++) {
+ GIC_SET_GROUP(i, ALL_CPU_MASK);
+ }
+ }
+
s->ctlr = 0;
}
+static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
+ bool secure_boot)
+{
+ GICState *s = ARM_GIC_COMMON(obj);
+
+ if (s->security_extn && !secure_boot) {
+ /* We're directly booting a kernel into NonSecure. If this GIC
+ * implements the security extensions then we must configure it
+ * to have all the interrupts be NonSecure (this is a job that
+ * is done by the Secure boot firmware in real hardware, and in
+ * this mode QEMU is acting as a minimalist firmware-and-bootloader
+ * equivalent).
+ */
+ s->irq_reset_nonsecure = true;
+ }
+}
+
static Property arm_gic_common_properties[] = {
DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
@@ -221,11 +258,13 @@ static Property arm_gic_common_properties[] = {
static void arm_gic_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
dc->reset = arm_gic_common_reset;
dc->realize = arm_gic_common_realize;
dc->props = arm_gic_common_properties;
dc->vmsd = &vmstate_gic;
+ albifc->arm_linux_init = arm_gic_common_linux_init;
}
static const TypeInfo arm_gic_common_type = {
@@ -235,6 +274,10 @@ static const TypeInfo arm_gic_common_type = {
.class_size = sizeof(ARMGICCommonClass),
.class_init = arm_gic_common_class_init,
.abstract = true,
+ .interfaces = (InterfaceInfo []) {
+ { TYPE_ARM_LINUX_BOOT_IF },
+ { },
+ },
};
static void register_types(void)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index e13b729e1d..3ec8408618 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -185,26 +185,25 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */
- val = s->gic.running_irq[0];
+ cpu = ARM_CPU(current_cpu);
+ val = cpu->env.v7m.exception;
if (val == 1023) {
val = 0;
} else if (val >= 32) {
val -= 16;
}
- /* RETTOBASE */
- if (s->gic.running_irq[0] == 1023
- || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
- val |= (1 << 11);
- }
/* VECTPENDING */
if (s->gic.current_pending[0] != 1023)
val |= (s->gic.current_pending[0] << 12);
- /* ISRPENDING */
+ /* ISRPENDING and RETTOBASE */
for (irq = 32; irq < s->num_irq; irq++) {
if (s->gic.irq_state[irq].pending) {
val |= (1 << 22);
break;
}
+ if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) {
+ val |= (1 << 11);
+ }
}
/* PENDSTSET */
if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index b471e7a41e..48714f96a3 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -228,6 +228,8 @@ static int kvm_s390_add_adapter_routes(S390FLICState *fs,
routes->gsi[i] = ret;
routes->adapter.ind_offset++;
}
+ kvm_irqchip_commit_routes(kvm_state);
+
/* Restore passed-in structure to original state. */
routes->adapter.ind_offset = ind_offset;
return 0;
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 924b1ae3c9..67881c7109 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -739,7 +739,7 @@ int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi)
}
/*
- * Allocate block of consequtive IRQs, returns a number of the first.
+ * Allocate block of consecutive IRQs, and return the number of the first IRQ in the block.
* If align==true, aligns the first IRQ number to num.
*/
int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align)
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index f4dcacd862..86b2c0bcb7 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -252,9 +252,7 @@ void mips_r4k_init(MachineState *machine)
fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
bios_name);
}
- if (filename) {
- g_free(filename);
- }
+ g_free(filename);
if (kernel_filename) {
loaderparams.ram_size = ram_size;
diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c
index 80a3c50e1e..73d4f8becd 100644
--- a/hw/misc/omap_clk.c
+++ b/hw/misc/omap_clk.c
@@ -1239,7 +1239,7 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
for (i = onchip_clks, count = 0; *i; i ++)
if ((*i)->flags & flag)
count ++;
- mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1));
+ mpu->clks = g_new0(struct clk, count + 1);
for (i = onchip_clks, j = mpu->clks; *i; i ++)
if ((*i)->flags & flag) {
memcpy(j, *i, sizeof(struct clk));
diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c
index 74fc91c8e9..8960f1bf16 100644
--- a/hw/misc/omap_gpmc.c
+++ b/hw/misc/omap_gpmc.c
@@ -826,8 +826,7 @@ struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
qemu_irq irq, qemu_irq drq)
{
int cs;
- struct omap_gpmc_s *s = (struct omap_gpmc_s *)
- g_malloc0(sizeof(struct omap_gpmc_s));
+ struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
memory_region_add_subregion(get_system_memory(), base, &s->iomem);
diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c
index 3de0c0e9d0..bca25307b5 100644
--- a/hw/misc/omap_sdrc.c
+++ b/hw/misc/omap_sdrc.c
@@ -157,8 +157,7 @@ static const MemoryRegionOps omap_sdrc_ops = {
struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
hwaddr base)
{
- struct omap_sdrc_s *s = (struct omap_sdrc_s *)
- g_malloc0(sizeof(struct omap_sdrc_s));
+ struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
omap_sdrc_reset(s);
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 98801739ef..64d044923c 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -19,6 +19,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
common-obj-$(CONFIG_MIPSNET) += mipsnet.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 494a346cf6..1127223cfd 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -951,7 +951,7 @@ static void gem_phy_reset(CadenceGEMState *s)
s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
- s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00;
+ s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0x7C00;
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
s->phy_regs[PHY_REG_LED] = 0x4100;
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 0f5cf4477b..04bb41da64 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -353,7 +353,7 @@ static ssize_t etsec_receive(NetClientState *nc,
etsec->need_flush = false;
ret = etsec_rx_ring_write(etsec, buf, size);
if (ret == 0) {
- /* The packet will be queued, let's flush it when buffer is avilable
+ /* The packet will be queued, let's flush it when buffer is available
* again. */
etsec->need_flush = true;
}
diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c
index 68e7b6d16b..0a5c6cfe3f 100644
--- a/hw/net/fsl_etsec/rings.c
+++ b/hw/net/fsl_etsec/rings.c
@@ -464,9 +464,7 @@ static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
etsec->rx_fcb_size = 0;
}
- if (etsec->rx_buffer != NULL) {
- g_free(etsec->rx_buffer);
- }
+ g_free(etsec->rx_buffer);
/* Do not copy the frame for now */
etsec->rx_buffer = (uint8_t *)buf;
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
new file mode 100644
index 0000000000..725f3fa335
--- /dev/null
+++ b/hw/net/imx_fec.c
@@ -0,0 +1,709 @@
+/*
+ * i.MX Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
+ *
+ * Based on Coldfire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/net/imx_fec.h"
+#include "sysemu/dma.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+#ifndef IMX_FEC_DEBUG
+#define IMX_FEC_DEBUG 0
+#endif
+
+#ifndef IMX_PHY_DEBUG
+#define IMX_PHY_DEBUG 0
+#endif
+
+#if IMX_FEC_DEBUG
+#define FEC_PRINTF(fmt, ...) \
+ do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+ ## __VA_ARGS__); \
+ } while (0)
+#else
+#define FEC_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if IMX_PHY_DEBUG
+#define PHY_PRINTF(fmt, ...) \
+ do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+ ## __VA_ARGS__); \
+ } while (0)
+#else
+#define PHY_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+static const VMStateDescription vmstate_imx_fec = {
+ .name = TYPE_IMX_FEC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_state, IMXFECState),
+ VMSTATE_UINT32(eir, IMXFECState),
+ VMSTATE_UINT32(eimr, IMXFECState),
+ VMSTATE_UINT32(rx_enabled, IMXFECState),
+ VMSTATE_UINT32(rx_descriptor, IMXFECState),
+ VMSTATE_UINT32(tx_descriptor, IMXFECState),
+ VMSTATE_UINT32(ecr, IMXFECState),
+ VMSTATE_UINT32(mmfr, IMXFECState),
+ VMSTATE_UINT32(mscr, IMXFECState),
+ VMSTATE_UINT32(mibc, IMXFECState),
+ VMSTATE_UINT32(rcr, IMXFECState),
+ VMSTATE_UINT32(tcr, IMXFECState),
+ VMSTATE_UINT32(tfwr, IMXFECState),
+ VMSTATE_UINT32(frsr, IMXFECState),
+ VMSTATE_UINT32(erdsr, IMXFECState),
+ VMSTATE_UINT32(etdsr, IMXFECState),
+ VMSTATE_UINT32(emrbr, IMXFECState),
+ VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
+ VMSTATE_UINT32(miigsk_enr, IMXFECState),
+
+ VMSTATE_UINT32(phy_status, IMXFECState),
+ VMSTATE_UINT32(phy_control, IMXFECState),
+ VMSTATE_UINT32(phy_advertise, IMXFECState),
+ VMSTATE_UINT32(phy_int, IMXFECState),
+ VMSTATE_UINT32(phy_int_mask, IMXFECState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define PHY_INT_ENERGYON (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
+#define PHY_INT_FAULT (1 << 5)
+#define PHY_INT_DOWN (1 << 4)
+#define PHY_INT_AUTONEG_LP (1 << 3)
+#define PHY_INT_PARFAULT (1 << 2)
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
+
+static void imx_fec_update(IMXFECState *s);
+
+/*
+ * The MII phy could raise a GPIO to the processor which in turn
+ * could be handled as an interrpt by the OS.
+ * For now we don't handle any GPIO/interrupt line, so the OS will
+ * have to poll for the PHY status.
+ */
+static void phy_update_irq(IMXFECState *s)
+{
+ imx_fec_update(s);
+}
+
+static void phy_update_link(IMXFECState *s)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (qemu_get_queue(s->nic)->link_down) {
+ PHY_PRINTF("link is down\n");
+ s->phy_status &= ~0x0024;
+ s->phy_int |= PHY_INT_DOWN;
+ } else {
+ PHY_PRINTF("link is up\n");
+ s->phy_status |= 0x0024;
+ s->phy_int |= PHY_INT_ENERGYON;
+ s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ phy_update_irq(s);
+}
+
+static void imx_fec_set_link(NetClientState *nc)
+{
+ phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
+}
+
+static void phy_reset(IMXFECState *s)
+{
+ s->phy_status = 0x7809;
+ s->phy_control = 0x3000;
+ s->phy_advertise = 0x01e1;
+ s->phy_int_mask = 0;
+ s->phy_int = 0;
+ phy_update_link(s);
+}
+
+static uint32_t do_phy_read(IMXFECState *s, int reg)
+{
+ uint32_t val;
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return 0;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ val = s->phy_control;
+ break;
+ case 1: /* Basic Status */
+ val = s->phy_status;
+ break;
+ case 2: /* ID1 */
+ val = 0x0007;
+ break;
+ case 3: /* ID2 */
+ val = 0xc0d1;
+ break;
+ case 4: /* Auto-neg advertisement */
+ val = s->phy_advertise;
+ break;
+ case 5: /* Auto-neg Link Partner Ability */
+ val = 0x0f71;
+ break;
+ case 6: /* Auto-neg Expansion */
+ val = 1;
+ break;
+ case 29: /* Interrupt source. */
+ val = s->phy_int;
+ s->phy_int = 0;
+ phy_update_irq(s);
+ break;
+ case 30: /* Interrupt mask */
+ val = s->phy_int_mask;
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ }
+
+ PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
+
+ return val;
+}
+
+static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
+{
+ PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ if (val & 0x8000) {
+ phy_reset(s);
+ } else {
+ s->phy_control = val & 0x7980;
+ /* Complete autonegotiation immediately. */
+ if (val & 0x1000) {
+ s->phy_status |= 0x0020;
+ }
+ }
+ break;
+ case 4: /* Auto-neg advertisement */
+ s->phy_advertise = (val & 0x2d7f) | 0x80;
+ break;
+ case 30: /* Interrupt mask */
+ s->phy_int_mask = val & 0xff;
+ phy_update_irq(s);
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s.phy[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ }
+}
+
+static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_update(IMXFECState *s)
+{
+ uint32_t active;
+ uint32_t changed;
+
+ active = s->eir & s->eimr;
+ changed = active ^ s->irq_state;
+ if (changed) {
+ qemu_set_irq(s->irq, active);
+ }
+ s->irq_state = active;
+}
+
+static void imx_fec_do_tx(IMXFECState *s)
+{
+ int frame_size = 0;
+ uint8_t frame[FEC_MAX_FRAME_SIZE];
+ uint8_t *ptr = frame;
+ uint32_t addr = s->tx_descriptor;
+
+ while (1) {
+ IMXFECBufDesc bd;
+ int len;
+
+ imx_fec_read_bd(&bd, addr);
+ FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
+ addr, bd.flags, bd.length, bd.data);
+ if ((bd.flags & FEC_BD_R) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = bd.length;
+ if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+ len = FEC_MAX_FRAME_SIZE - frame_size;
+ s->eir |= FEC_INT_BABT;
+ }
+ dma_memory_read(&address_space_memory, bd.data, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.flags & FEC_BD_L) {
+ /* Last buffer in frame. */
+ qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->eir |= FEC_INT_TXF;
+ }
+ s->eir |= FEC_INT_TXB;
+ bd.flags &= ~FEC_BD_R;
+ /* Write back the modified descriptor. */
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->etdsr;
+ } else {
+ addr += 8;
+ }
+ }
+
+ s->tx_descriptor = addr;
+
+ imx_fec_update(s);
+}
+
+static void imx_fec_enable_rx(IMXFECState *s)
+{
+ IMXFECBufDesc bd;
+ uint32_t tmp;
+
+ imx_fec_read_bd(&bd, s->rx_descriptor);
+
+ tmp = ((bd.flags & FEC_BD_E) != 0);
+
+ if (!tmp) {
+ FEC_PRINTF("RX buffer full\n");
+ } else if (!s->rx_enabled) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+
+ s->rx_enabled = tmp;
+}
+
+static void imx_fec_reset(DeviceState *d)
+{
+ IMXFECState *s = IMX_FEC(d);
+
+ /* Reset the FEC */
+ s->eir = 0;
+ s->eimr = 0;
+ s->rx_enabled = 0;
+ s->ecr = 0;
+ s->mscr = 0;
+ s->mibc = 0xc0000000;
+ s->rcr = 0x05ee0001;
+ s->tcr = 0;
+ s->tfwr = 0;
+ s->frsr = 0x500;
+ s->miigsk_cfgr = 0;
+ s->miigsk_enr = 0x6;
+
+ /* We also reset the PHY */
+ phy_reset(s);
+}
+
+static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("reading from @ 0x%03x\n", (int)addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004:
+ return s->eir;
+ case 0x008:
+ return s->eimr;
+ case 0x010:
+ return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+ case 0x014:
+ return 0; /* TDAR */
+ case 0x024:
+ return s->ecr;
+ case 0x040:
+ return s->mmfr;
+ case 0x044:
+ return s->mscr;
+ case 0x064:
+ return s->mibc; /* MIBC */
+ case 0x084:
+ return s->rcr;
+ case 0x0c4:
+ return s->tcr;
+ case 0x0e4: /* PALR */
+ return (s->conf.macaddr.a[0] << 24)
+ | (s->conf.macaddr.a[1] << 16)
+ | (s->conf.macaddr.a[2] << 8)
+ | s->conf.macaddr.a[3];
+ break;
+ case 0x0e8: /* PAUR */
+ return (s->conf.macaddr.a[4] << 24)
+ | (s->conf.macaddr.a[5] << 16)
+ | 0x8808;
+ case 0x0ec:
+ return 0x10000; /* OPD */
+ case 0x118:
+ return 0;
+ case 0x11c:
+ return 0;
+ case 0x120:
+ return 0;
+ case 0x124:
+ return 0;
+ case 0x144:
+ return s->tfwr;
+ case 0x14c:
+ return 0x600;
+ case 0x150:
+ return s->frsr;
+ case 0x180:
+ return s->erdsr;
+ case 0x184:
+ return s->etdsr;
+ case 0x188:
+ return s->emrbr;
+ case 0x300:
+ return s->miigsk_cfgr;
+ case 0x308:
+ return s->miigsk_enr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, (int)addr);
+ return 0;
+ }
+}
+
+static void imx_fec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("writing 0x%08x @ 0x%03x\n", (int)value, (int)addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004: /* EIR */
+ s->eir &= ~value;
+ break;
+ case 0x008: /* EIMR */
+ s->eimr = value;
+ break;
+ case 0x010: /* RDAR */
+ if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+ imx_fec_enable_rx(s);
+ }
+ break;
+ case 0x014: /* TDAR */
+ if (s->ecr & FEC_EN) {
+ imx_fec_do_tx(s);
+ }
+ break;
+ case 0x024: /* ECR */
+ s->ecr = value;
+ if (value & FEC_RESET) {
+ imx_fec_reset(DEVICE(s));
+ }
+ if ((s->ecr & FEC_EN) == 0) {
+ s->rx_enabled = 0;
+ }
+ break;
+ case 0x040: /* MMFR */
+ /* store the value */
+ s->mmfr = value;
+ if (extract32(value, 28, 1)) {
+ do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
+ } else {
+ s->mmfr = do_phy_read(s, extract32(value, 18, 9));
+ }
+ /* raise the interrupt as the PHY operation is done */
+ s->eir |= FEC_INT_MII;
+ break;
+ case 0x044: /* MSCR */
+ s->mscr = value & 0xfe;
+ break;
+ case 0x064: /* MIBC */
+ /* TODO: Implement MIB. */
+ s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
+ break;
+ case 0x084: /* RCR */
+ s->rcr = value & 0x07ff003f;
+ /* TODO: Implement LOOP mode. */
+ break;
+ case 0x0c4: /* TCR */
+ /* We transmit immediately, so raise GRA immediately. */
+ s->tcr = value;
+ if (value & 1) {
+ s->eir |= FEC_INT_GRA;
+ }
+ break;
+ case 0x0e4: /* PALR */
+ s->conf.macaddr.a[0] = value >> 24;
+ s->conf.macaddr.a[1] = value >> 16;
+ s->conf.macaddr.a[2] = value >> 8;
+ s->conf.macaddr.a[3] = value;
+ break;
+ case 0x0e8: /* PAUR */
+ s->conf.macaddr.a[4] = value >> 24;
+ s->conf.macaddr.a[5] = value >> 16;
+ break;
+ case 0x0ec: /* OPDR */
+ break;
+ case 0x118: /* IAUR */
+ case 0x11c: /* IALR */
+ case 0x120: /* GAUR */
+ case 0x124: /* GALR */
+ /* TODO: implement MAC hash filtering. */
+ break;
+ case 0x144: /* TFWR */
+ s->tfwr = value & 3;
+ break;
+ case 0x14c: /* FRBR */
+ /* FRBR writes ignored. */
+ break;
+ case 0x150: /* FRSR */
+ s->frsr = (value & 0x3fc) | 0x400;
+ break;
+ case 0x180: /* ERDSR */
+ s->erdsr = value & ~3;
+ s->rx_descriptor = s->erdsr;
+ break;
+ case 0x184: /* ETDSR */
+ s->etdsr = value & ~3;
+ s->tx_descriptor = s->etdsr;
+ break;
+ case 0x188: /* EMRBR */
+ s->emrbr = value & 0x7f0;
+ break;
+ case 0x300: /* MIIGSK_CFGR */
+ s->miigsk_cfgr = value & 0x53;
+ break;
+ case 0x308: /* MIIGSK_ENR */
+ s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, (int)addr);
+ break;
+ }
+
+ imx_fec_update(s);
+}
+
+static int imx_fec_can_receive(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ return s->rx_enabled;
+}
+
+static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
+ size_t len)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+ IMXFECBufDesc bd;
+ uint32_t flags = 0;
+ uint32_t addr;
+ uint32_t crc;
+ uint32_t buf_addr;
+ uint8_t *crc_ptr;
+ unsigned int buf_len;
+ size_t size = len;
+
+ FEC_PRINTF("len %d\n", (int)size);
+
+ if (!s->rx_enabled) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n",
+ TYPE_IMX_FEC, __func__);
+ return 0;
+ }
+
+ /* 4 bytes for the CRC. */
+ size += 4;
+ crc = cpu_to_be32(crc32(~0, buf, size));
+ crc_ptr = (uint8_t *) &crc;
+
+ /* Huge frames are truncted. */
+ if (size > FEC_MAX_FRAME_SIZE) {
+ size = FEC_MAX_FRAME_SIZE;
+ flags |= FEC_BD_TR | FEC_BD_LG;
+ }
+
+ /* Frames larger than the user limit just set error flags. */
+ if (size > (s->rcr >> 16)) {
+ flags |= FEC_BD_LG;
+ }
+
+ addr = s->rx_descriptor;
+ while (size > 0) {
+ imx_fec_read_bd(&bd, addr);
+ if ((bd.flags & FEC_BD_E) == 0) {
+ /* No descriptors available. Bail out. */
+ /*
+ * FIXME: This is wrong. We should probably either
+ * save the remainder for when more RX buffers are
+ * available, or flag an error.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n",
+ TYPE_IMX_FEC, __func__);
+ break;
+ }
+ buf_len = (size <= s->emrbr) ? size : s->emrbr;
+ bd.length = buf_len;
+ size -= buf_len;
+ FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length);
+ /* The last 4 bytes are the CRC. */
+ if (size < 4) {
+ buf_len += size - 4;
+ }
+ buf_addr = bd.data;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ buf += buf_len;
+ if (size < 4) {
+ dma_memory_write(&address_space_memory, buf_addr + buf_len,
+ crc_ptr, 4 - size);
+ crc_ptr += 4 - size;
+ }
+ bd.flags &= ~FEC_BD_E;
+ if (size == 0) {
+ /* Last buffer in frame. */
+ bd.flags |= flags | FEC_BD_L;
+ FEC_PRINTF("rx frame flags %04x\n", bd.flags);
+ s->eir |= FEC_INT_RXF;
+ } else {
+ s->eir |= FEC_INT_RXB;
+ }
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->erdsr;
+ } else {
+ addr += 8;
+ }
+ }
+ s->rx_descriptor = addr;
+ imx_fec_enable_rx(s);
+ imx_fec_update(s);
+ return len;
+}
+
+static const MemoryRegionOps imx_fec_ops = {
+ .read = imx_fec_read,
+ .write = imx_fec_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_fec_cleanup(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ s->nic = NULL;
+}
+
+static NetClientInfo net_imx_fec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = imx_fec_can_receive,
+ .receive = imx_fec_receive,
+ .cleanup = imx_fec_cleanup,
+ .link_status_changed = imx_fec_set_link,
+};
+
+
+static void imx_fec_realize(DeviceState *dev, Error **errp)
+{
+ IMXFECState *s = IMX_FEC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
+ TYPE_IMX_FEC, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+ s->conf.peers.ncs[0] = nd_table[0].netdev;
+
+ s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
+ object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
+ s);
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static Property imx_fec_properties[] = {
+ DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_fec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_imx_fec;
+ dc->reset = imx_fec_reset;
+ dc->props = imx_fec_properties;
+ dc->realize = imx_fec_realize;
+}
+
+static const TypeInfo imx_fec_info = {
+ .name = TYPE_IMX_FEC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXFECState),
+ .class_init = imx_fec_class_init,
+};
+
+static void imx_fec_register_types(void)
+{
+ type_register_static(&imx_fec_info);
+}
+
+type_init(imx_fec_register_types)
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
index 17e7199f70..18b064463a 100644
--- a/hw/net/ne2000-isa.c
+++ b/hw/net/ne2000-isa.c
@@ -44,7 +44,6 @@ typedef struct ISANE2000State {
static NetClientInfo net_ne2000_isa_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = ne2000_can_receive,
.receive = ne2000_receive,
};
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 3492db3663..53c704ad41 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -165,15 +165,6 @@ static int ne2000_buffer_full(NE2000State *s)
return 0;
}
-int ne2000_can_receive(NetClientState *nc)
-{
- NE2000State *s = qemu_get_nic_opaque(nc);
-
- if (s->cmd & E8390_STOP)
- return 1;
- return !ne2000_buffer_full(s);
-}
-
#define MIN_BUF_SIZE 60
ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
@@ -705,7 +696,6 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
static NetClientInfo net_ne2000_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = ne2000_can_receive,
.receive = ne2000_receive,
};
diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h
index e500306aac..d022b28fc2 100644
--- a/hw/net/ne2000.h
+++ b/hw/net/ne2000.h
@@ -34,7 +34,6 @@ typedef struct NE2000State {
void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size);
extern const VMStateDescription vmstate_ne2000;
void ne2000_reset(NE2000State *s);
-int ne2000_can_receive(NetClientState *nc);
ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
#endif
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index 47d080fd33..7e7bda4987 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -265,9 +265,7 @@ err_bad_io:
err_no_mem:
err_bad_attr:
for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
- if (iov[i].iov_base) {
- g_free(iov[i].iov_base);
- }
+ g_free(iov[i].iov_base);
}
return err;
diff --git a/hw/net/rocker/rocker_desc.c b/hw/net/rocker/rocker_desc.c
index 9d896fe470..b5c0b4a241 100644
--- a/hw/net/rocker/rocker_desc.c
+++ b/hw/net/rocker/rocker_desc.c
@@ -136,9 +136,7 @@ bool desc_ring_set_size(DescRing *ring, uint32_t size)
}
for (i = 0; i < ring->size; i++) {
- if (ring->info[i].buf) {
- g_free(ring->info[i].buf);
- }
+ g_free(ring->info[i].buf);
}
ring->size = size;
@@ -360,9 +358,7 @@ DescRing *desc_ring_alloc(Rocker *r, int index)
void desc_ring_free(DescRing *ring)
{
- if (ring->info) {
- g_free(ring->info);
- }
+ g_free(ring->info);
g_free(ring);
}
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index edbb61ccf3..b0d6c40f58 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -43,7 +43,7 @@
* Added rx/tx buffer reset when enabling rx/tx operation
*
* 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only
- * when strictly needed (required for for
+ * when strictly needed (required for
* Darwin)
* 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
*/
@@ -56,6 +56,7 @@
#include "sysemu/dma.h"
#include "qemu/timer.h"
#include "net/net.h"
+#include "net/eth.h"
#include "hw/loader.h"
#include "sysemu/sysemu.h"
#include "qemu/iov.h"
@@ -72,11 +73,8 @@
#define MOD2(input, size) \
( ( input ) & ( size - 1 ) )
-#define ETHER_ADDR_LEN 6
#define ETHER_TYPE_LEN 2
-#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+#define ETH_HLEN (ETH_ALEN * 2 + ETHER_TYPE_LEN)
#define ETH_MTU 1500
#define VLAN_TCI_LEN 2
@@ -1016,8 +1014,8 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* write VLAN info to descriptor variables. */
if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
- &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
- dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
+ &buf[ETH_ALEN * 2]) == ETH_P_VLAN) {
+ dot1q_buf = &buf[ETH_ALEN * 2];
size -= VLAN_HLEN;
/* if too small buffer, use the tailroom added duing expansion */
if (size < MIN_BUF_SIZE) {
@@ -1058,10 +1056,10 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* receive/copy to target memory */
if (dot1q_buf) {
- pci_dma_write(d, rx_addr, buf, 2 * ETHER_ADDR_LEN);
- pci_dma_write(d, rx_addr + 2 * ETHER_ADDR_LEN,
- buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
- size - 2 * ETHER_ADDR_LEN);
+ pci_dma_write(d, rx_addr, buf, 2 * ETH_ALEN);
+ pci_dma_write(d, rx_addr + 2 * ETH_ALEN,
+ buf + 2 * ETH_ALEN + VLAN_HLEN,
+ size - 2 * ETH_ALEN);
} else {
pci_dma_write(d, rx_addr, buf, size);
}
@@ -1148,7 +1146,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* if receiver buffer is empty then avail == 0 */
- if (avail != 0 && size + 8 >= avail)
+#define RX_ALIGN(x) (((x) + 3) & ~0x3)
+
+ if (avail != 0 && RX_ALIGN(size + 8) >= avail)
{
DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
"read 0x%04x === available 0x%04x need 0x%04x\n",
@@ -1157,7 +1157,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
s->IntrStatus |= RxOverflow;
++s->RxMissed;
rtl8139_update_irq(s);
- return size_;
+ return 0;
}
packet_header |= RxStatusOK;
@@ -1176,7 +1176,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
rtl8139_write_buffer(s, (uint8_t *)&val, 4);
/* correct buffer write pointer */
- s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
+ s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize);
/* now we can signal we have received something */
@@ -1783,12 +1783,12 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
return;
}
- if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
+ if (dot1q_buf && size >= ETH_ALEN * 2) {
iov = (struct iovec[3]) {
- { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+ { .iov_base = buf, .iov_len = ETH_ALEN * 2 },
{ .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
- { .iov_base = buf + ETHER_ADDR_LEN * 2,
- .iov_len = size - ETHER_ADDR_LEN * 2 },
+ { .iov_base = buf + ETH_ALEN * 2,
+ .iov_len = size - ETH_ALEN * 2 },
};
memcpy(vlan_iov, iov, sizeof(vlan_iov));
@@ -1868,64 +1868,12 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
}
/* structures and macros for task offloading */
-typedef struct ip_header
-{
- uint8_t ip_ver_len; /* version and header length */
- uint8_t ip_tos; /* type of service */
- uint16_t ip_len; /* total length */
- uint16_t ip_id; /* identification */
- uint16_t ip_off; /* fragment offset field */
- uint8_t ip_ttl; /* time to live */
- uint8_t ip_p; /* protocol */
- uint16_t ip_sum; /* checksum */
- uint32_t ip_src,ip_dst; /* source and dest address */
-} ip_header;
-
-#define IP_HEADER_VERSION_4 4
-#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
-#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
-
-typedef struct tcp_header
-{
- uint16_t th_sport; /* source port */
- uint16_t th_dport; /* destination port */
- uint32_t th_seq; /* sequence number */
- uint32_t th_ack; /* acknowledgement number */
- uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
- uint16_t th_win; /* window */
- uint16_t th_sum; /* checksum */
- uint16_t th_urp; /* urgent pointer */
-} tcp_header;
-
-typedef struct udp_header
-{
- uint16_t uh_sport; /* source port */
- uint16_t uh_dport; /* destination port */
- uint16_t uh_ulen; /* udp length */
- uint16_t uh_sum; /* udp checksum */
-} udp_header;
-
-typedef struct ip_pseudo_header
-{
- uint32_t ip_src;
- uint32_t ip_dst;
- uint8_t zeros;
- uint8_t ip_proto;
- uint16_t ip_payload;
-} ip_pseudo_header;
-
-#define IP_PROTO_TCP 6
-#define IP_PROTO_UDP 17
-
#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
-#define TCP_FLAG_FIN 0x01
-#define TCP_FLAG_PUSH 0x08
-
/* produces ones' complement sum of data */
static uint16_t ones_complement_sum(uint8_t *data, size_t len)
{
@@ -2134,7 +2082,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
dot1q_buffer = (uint16_t *) dot1q_buffer_space;
- dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
+ dot1q_buffer[0] = cpu_to_be16(ETH_P_VLAN);
/* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
} else {
@@ -2151,12 +2099,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DPRINTF("+++ C+ mode offloaded task checksum\n");
/* Large enough for Ethernet and IP headers? */
- if (saved_size < ETH_HLEN + sizeof(ip_header)) {
+ if (saved_size < ETH_HLEN + sizeof(struct ip_header)) {
goto skip_offload;
}
/* ip packet header */
- ip_header *ip = NULL;
+ struct ip_header *ip = NULL;
int hlen = 0;
uint8_t ip_protocol = 0;
uint16_t ip_data_len = 0;
@@ -2172,11 +2120,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DPRINTF("+++ C+ mode has IP packet\n");
- /* not aligned */
+ /* Note on memory alignment: eth_payload_data is 16-bit aligned
+ * since saved_buffer is allocated with g_malloc() and ETH_HLEN is
+ * even. 32-bit accesses must use ldl/stl wrappers to avoid
+ * unaligned accesses.
+ */
eth_payload_data = saved_buffer + ETH_HLEN;
eth_payload_len = saved_size - ETH_HLEN;
- ip = (ip_header*)eth_payload_data;
+ ip = (struct ip_header*)eth_payload_data;
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
DPRINTF("+++ C+ mode packet has bad IP version %d "
@@ -2185,8 +2137,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
goto skip_offload;
}
- hlen = IP_HEADER_LENGTH(ip);
- if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
+ hlen = IP_HDR_GET_LEN(ip);
+ if (hlen < sizeof(struct ip_header) || hlen > eth_payload_len) {
goto skip_offload;
}
@@ -2269,7 +2221,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
}
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
- be32_to_cpu(p_tcp_hdr->th_seq));
+ ldl_be_p(&p_tcp_hdr->th_seq));
/* add 4 TCP pseudoheader fields */
/* copy IP source and destination fields */
@@ -2287,7 +2239,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
/* keep PUSH and FIN flags only for the last frame */
if (!is_last_frame)
{
- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
+ TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TH_PUSH | TH_FIN);
}
/* recalculate TCP checksum */
@@ -2325,7 +2277,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
0, (uint8_t *) dot1q_buffer);
/* add transferred count to TCP sequence number */
- p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
+ stl_be_p(&p_tcp_hdr->th_seq,
+ chunk_size + ldl_be_p(&p_tcp_hdr->th_seq));
++send_count;
}
@@ -3438,10 +3391,8 @@ static void pci_rtl8139_uninit(PCIDevice *dev)
{
RTL8139State *s = RTL8139(dev);
- if (s->cplus_txbuffer) {
- g_free(s->cplus_txbuffer);
- s->cplus_txbuffer = NULL;
- }
+ g_free(s->cplus_txbuffer);
+ s->cplus_txbuffer = NULL;
timer_del(s->timer);
timer_free(s->timer);
qemu_del_nic(s->nic);
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 5c1d11f517..1d76b94c84 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -197,7 +197,7 @@ static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
{
int r = 0;
- if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) ||
+ if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) ||
(virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
r = qemu_set_vnet_le(peer, set);
if (r) {
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 8d28e45afc..f72eebff2b 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -86,8 +86,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
memcpy(&netcfg, config, n->config_size);
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
- !virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
+ !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
memcpy(n->mac, netcfg.mac, ETH_ALEN);
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
@@ -304,7 +304,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
info->multicast_table = str_list;
info->vlan_table = get_vlan_table(n);
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
info->vlan = RX_STATE_ALL;
} else if (!info->vlan_table) {
info->vlan = RX_STATE_NONE;
@@ -529,13 +529,13 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
int i;
virtio_net_set_multiqueue(n,
- __virtio_has_feature(features, VIRTIO_NET_F_MQ));
+ virtio_has_feature(features, VIRTIO_NET_F_MQ));
virtio_net_set_mrg_rx_bufs(n,
- __virtio_has_feature(features,
- VIRTIO_NET_F_MRG_RXBUF),
- __virtio_has_feature(features,
- VIRTIO_F_VERSION_1));
+ virtio_has_feature(features,
+ VIRTIO_NET_F_MRG_RXBUF),
+ virtio_has_feature(features,
+ VIRTIO_F_VERSION_1));
if (n->has_vnet_hdr) {
n->curr_guest_offloads =
@@ -552,7 +552,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
vhost_net_ack_features(get_vhost_net(nc->peer), features);
}
- if (__virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
+ if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
memset(n->vlans, 0, MAX_VLAN >> 3);
} else {
memset(n->vlans, 0xff, MAX_VLAN >> 3);
@@ -599,7 +599,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
uint64_t offloads;
size_t s;
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
return VIRTIO_NET_ERR;
}
@@ -1449,7 +1449,7 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
}
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
qemu_put_be64(f, n->curr_guest_offloads);
}
}
@@ -1475,7 +1475,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
n->vqs[0].tx_waiting = qemu_get_be32(f);
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
- virtio_has_feature(vdev, VIRTIO_F_VERSION_1));
+ virtio_vdev_has_feature(vdev,
+ VIRTIO_F_VERSION_1));
if (version_id >= 3)
n->status = qemu_get_be16(f);
@@ -1558,7 +1559,7 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
}
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
n->curr_guest_offloads = qemu_get_be64(f);
} else {
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
@@ -1585,8 +1586,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_subqueue(n->nic, i)->link_down = link_down;
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
- virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
+ virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
n->announce_counter = SELF_ANNOUNCE_ROUNDS;
timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
}
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 071feebf15..04159c8222 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -1988,7 +1988,6 @@ static void vmxnet3_set_link_status(NetClientState *nc)
static NetClientInfo net_vmxnet3_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = vmxnet3_can_receive,
.receive = vmxnet3_receive,
.link_status_changed = vmxnet3_set_link_status,
};
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index d7cbfc1033..0da16b44f4 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -24,7 +24,6 @@
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
-#include <signal.h>
#include <inttypes.h>
#include <fcntl.h>
#include <errno.h>
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 88481b78c4..658f8c4ff1 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -187,9 +187,7 @@ static void fw_cfg_bootsplash(FWCfgState *s)
g_free(filename);
return;
}
- if (boot_splash_filedata != NULL) {
- g_free(boot_splash_filedata);
- }
+ g_free(boot_splash_filedata);
boot_splash_filedata = (uint8_t *)file_data;
boot_splash_filedata_size = file_size;
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 1cb25f3fa6..1fb71c8081 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -40,7 +40,6 @@
* http://download.intel.com/design/chipsets/datashts/29054901.pdf
*/
-#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
#define I440FX_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX_PCI_HOST_BRIDGE)
@@ -95,7 +94,6 @@ typedef struct PIIX3State {
#define PIIX3_PCI_DEVICE(obj) \
OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
-#define TYPE_I440FX_PCI_DEVICE "i440FX"
#define I440FX_PCI_DEVICE(obj) \
OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
@@ -305,7 +303,8 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
dev->config[I440FX_SMRAM] = 0x02;
}
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
+PCIBus *i440fx_init(const char *host_type, const char *pci_type,
+ PCII440FXState **pi440fx_state,
int *piix3_devfn,
ISABus **isa_bus, qemu_irq *pic,
MemoryRegion *address_space_mem,
@@ -325,7 +324,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
unsigned i;
I440FXState *i440fx;
- dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
+ dev = qdev_create(NULL, host_type);
s = PCI_HOST_BRIDGE(dev);
b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0, TYPE_PCI_BUS);
@@ -333,7 +332,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
qdev_init_nofail(dev);
- d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE);
+ d = pci_create_simple(b, 0, pci_type);
*pi440fx_state = I440FX_PCI_DEVICE(d);
f = *pi440fx_state;
f->system_memory = address_space_mem;
@@ -740,6 +739,90 @@ static const TypeInfo i440fx_info = {
.class_init = i440fx_class_init,
};
+/* IGD Passthrough Host Bridge. */
+typedef struct {
+ uint8_t offset;
+ uint8_t len;
+} IGDHostInfo;
+
+/* Here we just expose minimal host bridge offset subset. */
+static const IGDHostInfo igd_host_bridge_infos[] = {
+ {0x08, 2}, /* revision id */
+ {0x2c, 2}, /* sybsystem vendor id */
+ {0x2e, 2}, /* sybsystem id */
+ {0x50, 2}, /* SNB: processor graphics control register */
+ {0x52, 2}, /* processor graphics control register */
+ {0xa4, 4}, /* SNB: graphics base of stolen memory */
+ {0xa8, 4}, /* SNB: base of GTT stolen memory */
+};
+
+static int host_pci_config_read(int pos, int len, uint32_t val)
+{
+ char path[PATH_MAX];
+ int config_fd;
+ ssize_t size = sizeof(path);
+ /* Access real host bridge. */
+ int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
+ 0, 0, 0, 0, "config");
+
+ if (rc >= size || rc < 0) {
+ return -ENODEV;
+ }
+
+ config_fd = open(path, O_RDWR);
+ if (config_fd < 0) {
+ return -ENODEV;
+ }
+
+ if (lseek(config_fd, pos, SEEK_SET) != pos) {
+ return -errno;
+ }
+ do {
+ rc = read(config_fd, (uint8_t *)&val, len);
+ } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
+ if (rc != len) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int igd_pt_i440fx_initfn(struct PCIDevice *pci_dev)
+{
+ uint32_t val = 0;
+ int rc, i, num;
+ int pos, len;
+
+ num = ARRAY_SIZE(igd_host_bridge_infos);
+ for (i = 0; i < num; i++) {
+ pos = igd_host_bridge_infos[i].offset;
+ len = igd_host_bridge_infos[i].len;
+ rc = host_pci_config_read(pos, len, val);
+ if (rc) {
+ return -ENODEV;
+ }
+ pci_default_write_config(pci_dev, pos, val, len);
+ }
+
+ return 0;
+}
+
+static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = igd_pt_i440fx_initfn;
+ dc->desc = "IGD Passthrough Host bridge";
+}
+
+static const TypeInfo igd_passthrough_i440fx_info = {
+ .name = TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE,
+ .parent = TYPE_I440FX_PCI_DEVICE,
+ .instance_size = sizeof(PCII440FXState),
+ .class_init = igd_passthrough_i440fx_class_init,
+};
+
static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
@@ -781,6 +864,7 @@ static const TypeInfo i440fx_pcihost_info = {
static void i440fx_register_types(void)
{
type_register_static(&i440fx_info);
+ type_register_static(&igd_passthrough_i440fx_info);
type_register_static(&piix3_pci_type_info);
type_register_static(&piix3_info);
type_register_static(&piix3_xen_info);
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
index c63f45d217..988907bfa0 100644
--- a/hw/pci-host/prep.c
+++ b/hw/pci-host/prep.c
@@ -328,9 +328,7 @@ static void raven_realize(PCIDevice *d, Error **errp)
if (bios_size < 0 || bios_size > BIOS_SIZE) {
hw_error("qemu: could not load bios image '%s'\n", s->bios_name);
}
- if (filename) {
- g_free(filename);
- }
+ g_free(filename);
}
}
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 7716bf3649..2fdada4e8f 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -314,9 +314,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
bar_size = bar_pba_offset + bar_pba_size;
}
- if (bar_size & (bar_size - 1)) {
- bar_size = 1 << qemu_fls(bar_size);
- }
+ bar_size = pow2ceil(bar_size);
name = g_strdup_printf("%s-msix", dev->name);
memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, bar_size);
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 9f57aeaeba..ccea628209 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1154,16 +1154,16 @@ static void pci_update_mappings(PCIDevice *d)
/* now do the real mapping */
if (r->addr != PCI_BAR_UNMAPPED) {
trace_pci_update_mappings_del(d, pci_bus_num(d->bus),
- PCI_FUNC(d->devfn),
PCI_SLOT(d->devfn),
+ PCI_FUNC(d->devfn),
i, r->addr, r->size);
memory_region_del_subregion(r->address_space, r->memory);
}
r->addr = new_addr;
if (r->addr != PCI_BAR_UNMAPPED) {
trace_pci_update_mappings_add(d, pci_bus_num(d->bus),
- PCI_FUNC(d->devfn),
PCI_SLOT(d->devfn),
+ PCI_FUNC(d->devfn),
i, r->addr, r->size);
memory_region_add_subregion_overlap(r->address_space,
r->addr, r->memory, 1);
@@ -2071,9 +2071,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
g_free(path);
return;
}
- if (size & (size - 1)) {
- size = 1 << qemu_fls(size);
- }
+ size = pow2ceil(size);
vmsd = qdev_get_vmsd(DEVICE(pdev));
@@ -2385,17 +2383,14 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
{
PCIBus *bus = PCI_BUS(dev->bus);
+ PCIBus *iommu_bus = bus;
- if (bus->iommu_fn) {
- return bus->iommu_fn(bus, bus->iommu_opaque, dev->devfn);
+ while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
+ iommu_bus = PCI_BUS(iommu_bus->parent_dev->bus);
}
-
- if (bus->parent_dev) {
- /** We are ignoring the bus master DMA bit of the bridge
- * as it would complicate things such as VFIO for no good reason */
- return pci_device_iommu_address_space(bus->parent_dev);
+ if (iommu_bus && iommu_bus->iommu_fn) {
+ return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
}
-
return &address_space_memory;
}
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index bfb4d31b62..d34fdf3ecb 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -1,5 +1,4 @@
#include "qemu-common.h"
-#include <strings.h>
#include <stdint.h>
#include "qemu/range.h"
#include "qemu/error-report.h"
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index a8f79d8003..a2feb4c985 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1460,10 +1460,8 @@ static void spapr_pci_pre_save(void *opaque)
gpointer key, value;
int i;
- if (sphb->msi_devs) {
- g_free(sphb->msi_devs);
- sphb->msi_devs = NULL;
- }
+ g_free(sphb->msi_devs);
+ sphb->msi_devs = NULL;
sphb->msi_devs_num = g_hash_table_size(sphb->msi);
if (!sphb->msi_devs_num) {
return;
@@ -1490,10 +1488,8 @@ static int spapr_pci_post_load(void *opaque, int version_id)
sizeof(sphb->msi_devs[i].value));
g_hash_table_insert(sphb->msi, key, value);
}
- if (sphb->msi_devs) {
- g_free(sphb->msi_devs);
- sphb->msi_devs = NULL;
- }
+ g_free(sphb->msi_devs);
+ sphb->msi_devs = NULL;
sphb->msi_devs_num = 0;
return 0;
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 27cd75a932..527d75400a 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -9,3 +9,5 @@ obj-y += css.o
obj-y += s390-virtio-ccw.o
obj-y += virtio-ccw.o
obj-y += s390-pci-bus.o s390-pci-inst.o
+obj-y += s390-skeys.o
+obj-$(CONFIG_KVM) += s390-skeys-kvm.o
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 5df450e00b..c033612889 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -261,6 +261,9 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
ret.flags = tmp0.flags;
ret.count = be16_to_cpu(tmp0.count);
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
+ if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) {
+ ret.cmd_code &= 0x0f;
+ }
}
return ret;
}
@@ -287,6 +290,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
((ccw.cmd_code & 0xf0) != 0)) {
return -EINVAL;
}
+ if (!sch->ccw_fmt_1 && (ccw.count == 0) &&
+ (ccw.cmd_code != CCW_CMD_TIC)) {
+ return -EINVAL;
+ }
if (ccw.flags & CCW_FLAG_SUSPEND) {
return -EINPROGRESS;
@@ -392,6 +399,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
path = 0x80;
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
+ s->cstat = 0;
+ s->dstat = 0;
/* Look at the orb and try to execute the channel program. */
assert(orb != NULL); /* resume does not pass an orb */
p->intparm = orb->intparm;
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 0c700effb1..ef2a05160a 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -27,12 +27,12 @@ typedef struct SCLPEventsBus {
struct SCLPEventFacility {
SysBusDevice parent_obj;
SCLPEventsBus sbus;
+ SCLPEvent quiesce_event;
+ SCLPEvent cpu_hotplug_event;
/* guest' receive mask */
unsigned int receive_mask;
};
-static SCLPEvent cpu_hotplug;
-
/* return true if any child has event pending set */
static bool event_pending(SCLPEventFacility *ef)
{
@@ -240,12 +240,13 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
sclp_active_selection_mask = sclp_cp_receive_mask;
break;
case SCLP_SELECTIVE_READ:
- if (!(sclp_cp_receive_mask & be32_to_cpu(red->mask))) {
+ sclp_active_selection_mask = be32_to_cpu(red->mask);
+ if (!sclp_cp_receive_mask ||
+ (sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
sccb->h.response_code =
cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
goto out;
}
- sclp_active_selection_mask = be32_to_cpu(red->mask);
break;
default:
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
@@ -286,8 +287,26 @@ out:
#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus"
+static void sclp_events_bus_realize(BusState *bus, Error **errp)
+{
+ BusChild *kid;
+
+ /* TODO: recursive realization has to be done in common code */
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
+
+ object_property_set_bool(OBJECT(dev), true, "realized", errp);
+ if (*errp) {
+ return;
+ }
+ }
+}
+
static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
{
+ BusClass *bc = BUS_CLASS(klass);
+
+ bc->realize = sclp_events_bus_realize;
}
static const TypeInfo sclp_events_bus_info = {
@@ -324,26 +343,24 @@ static const VMStateDescription vmstate_event_facility = {
}
};
-static int init_event_facility(SCLPEventFacility *event_facility)
+static void init_event_facility(Object *obj)
{
- DeviceState *sdev = DEVICE(event_facility);
- DeviceState *quiesce;
+ SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
+ DeviceState *sdev = DEVICE(obj);
/* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
- quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
- if (!quiesce) {
- return -1;
- }
- qdev_init_nofail(quiesce);
-
- object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG);
- qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus));
- object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL);
-
- return 0;
+ object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent),
+ TYPE_SCLP_QUIESCE);
+ qdev_set_parent_bus(DEVICE(&event_facility->quiesce_event),
+ &event_facility->sbus.qbus);
+ object_initialize(&event_facility->cpu_hotplug_event, sizeof(SCLPEvent),
+ TYPE_SCLP_CPU_HOTPLUG);
+ qdev_set_parent_bus(DEVICE(&event_facility->cpu_hotplug_event),
+ &event_facility->sbus.qbus);
+ /* the facility will automatically realize the devices via the bus */
}
static void reset_event_facility(DeviceState *dev)
@@ -362,7 +379,6 @@ static void init_event_facility_class(ObjectClass *klass, void *data)
dc->reset = reset_event_facility;
dc->vmsd = &vmstate_event_facility;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- k->init = init_event_facility;
k->command_handler = command_handler;
k->event_pending = event_pending;
}
@@ -370,6 +386,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data)
static const TypeInfo sclp_event_facility_info = {
.name = TYPE_SCLP_EVENT_FACILITY,
.parent = TYPE_SYS_BUS_DEVICE,
+ .instance_init = init_event_facility,
.instance_size = sizeof(SCLPEventFacility),
.class_init = init_event_facility_class,
.class_size = sizeof(SCLPEventFacilityClass),
diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c
new file mode 100644
index 0000000000..682949afb2
--- /dev/null
+++ b/hw/s390x/s390-skeys-kvm.c
@@ -0,0 +1,75 @@
+/*
+ * s390 storage key device
+ *
+ * Copyright 2015 IBM Corp.
+ * Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "hw/s390x/storage-keys.h"
+#include "sysemu/kvm.h"
+#include "qemu/error-report.h"
+
+static int kvm_s390_skeys_enabled(S390SKeysState *ss)
+{
+ S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
+ uint8_t single_key;
+ int r;
+
+ r = skeyclass->get_skeys(ss, 0, 1, &single_key);
+ if (r != 0 && r != KVM_S390_GET_SKEYS_NONE) {
+ error_report("S390_GET_KEYS error %d\n", r);
+ }
+ return (r == 0);
+}
+
+static int kvm_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
+ uint64_t count, uint8_t *keys)
+{
+ struct kvm_s390_skeys args = {
+ .start_gfn = start_gfn,
+ .count = count,
+ .skeydata_addr = (__u64)keys
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_S390_GET_SKEYS, &args);
+}
+
+static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
+ uint64_t count, uint8_t *keys)
+{
+ struct kvm_s390_skeys args = {
+ .start_gfn = start_gfn,
+ .count = count,
+ .skeydata_addr = (__u64)keys
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_S390_SET_SKEYS, &args);
+}
+
+static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data)
+{
+ S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
+
+ skeyclass->skeys_enabled = kvm_s390_skeys_enabled;
+ skeyclass->get_skeys = kvm_s390_skeys_get;
+ skeyclass->set_skeys = kvm_s390_skeys_set;
+}
+
+static const TypeInfo kvm_s390_skeys_info = {
+ .name = TYPE_KVM_S390_SKEYS,
+ .parent = TYPE_S390_SKEYS,
+ .instance_size = sizeof(S390SKeysState),
+ .class_init = kvm_s390_skeys_class_init,
+ .class_size = sizeof(S390SKeysClass),
+};
+
+static void kvm_s390_skeys_register_types(void)
+{
+ type_register_static(&kvm_s390_skeys_info);
+}
+
+type_init(kvm_s390_skeys_register_types)
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
new file mode 100644
index 0000000000..539ef6d3a4
--- /dev/null
+++ b/hw/s390x/s390-skeys.c
@@ -0,0 +1,415 @@
+/*
+ * s390 storage key device
+ *
+ * Copyright 2015 IBM Corp.
+ * Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "hw/boards.h"
+#include "qmp-commands.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/storage-keys.h"
+#include "qemu/error-report.h"
+
+#define S390_SKEYS_BUFFER_SIZE 131072 /* Room for 128k storage keys */
+#define S390_SKEYS_SAVE_FLAG_EOS 0x01
+#define S390_SKEYS_SAVE_FLAG_SKEYS 0x02
+#define S390_SKEYS_SAVE_FLAG_ERROR 0x04
+
+S390SKeysState *s390_get_skeys_device(void)
+{
+ S390SKeysState *ss;
+
+ ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL));
+ assert(ss);
+ return ss;
+}
+
+void s390_skeys_init(void)
+{
+ Object *obj;
+
+ if (kvm_enabled()) {
+ obj = object_new(TYPE_KVM_S390_SKEYS);
+ } else {
+ obj = object_new(TYPE_QEMU_S390_SKEYS);
+ }
+ object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS,
+ obj, NULL);
+ object_unref(obj);
+
+ qdev_init_nofail(DEVICE(obj));
+}
+
+static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
+ uint64_t count, Error **errp)
+{
+ uint64_t curpage = startgfn;
+ uint64_t maxpage = curpage + count - 1;
+ const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
+ " ch=%d, reserved=%d\n";
+ char buf[128];
+ int len;
+
+ for (; curpage <= maxpage; curpage++) {
+ uint8_t acc = (*keys & 0xF0) >> 4;
+ int fp = (*keys & 0x08);
+ int ref = (*keys & 0x04);
+ int ch = (*keys & 0x02);
+ int res = (*keys & 0x01);
+
+ len = snprintf(buf, sizeof(buf), fmt, curpage,
+ *keys, acc, fp, ref, ch, res);
+ assert(len < sizeof(buf));
+ qemu_put_buffer(f, (uint8_t *)buf, len);
+ keys++;
+ }
+}
+
+void hmp_info_skeys(Monitor *mon, const QDict *qdict)
+{
+ S390SKeysState *ss = s390_get_skeys_device();
+ S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
+ uint64_t addr = qdict_get_int(qdict, "addr");
+ uint8_t key;
+ int r;
+
+ /* Quick check to see if guest is using storage keys*/
+ if (!skeyclass->skeys_enabled(ss)) {
+ monitor_printf(mon, "Error: This guest is not using storage keys\n");
+ return;
+ }
+
+ r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ if (r < 0) {
+ monitor_printf(mon, "Error: %s\n", strerror(-r));
+ return;
+ }
+
+ monitor_printf(mon, " key: 0x%X\n", key);
+}
+
+void hmp_dump_skeys(Monitor *mon, const QDict *qdict)
+{
+ const char *filename = qdict_get_str(qdict, "filename");
+ Error *err = NULL;
+
+ qmp_dump_skeys(filename, &err);
+ if (err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(err));
+ error_free(err);
+ }
+}
+
+void qmp_dump_skeys(const char *filename, Error **errp)
+{
+ S390SKeysState *ss = s390_get_skeys_device();
+ S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
+ const uint64_t total_count = ram_size / TARGET_PAGE_SIZE;
+ uint64_t handled_count = 0, cur_count;
+ Error *lerr = NULL;
+ vaddr cur_gfn = 0;
+ uint8_t *buf;
+ int ret;
+ QEMUFile *f;
+
+ /* Quick check to see if guest is using storage keys*/
+ if (!skeyclass->skeys_enabled(ss)) {
+ error_setg(errp, "This guest is not using storage keys - "
+ "nothing to dump");
+ return;
+ }
+
+ f = qemu_fopen(filename, "wb");
+ if (!f) {
+ error_setg_file_open(errp, errno, filename);
+ return;
+ }
+
+ buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
+ if (!buf) {
+ error_setg(errp, "Could not allocate memory");
+ goto out;
+ }
+
+ /* we'll only dump initial memory for now */
+ while (handled_count < total_count) {
+ /* Calculate how many keys to ask for & handle overflow case */
+ cur_count = MIN(total_count - handled_count, S390_SKEYS_BUFFER_SIZE);
+
+ ret = skeyclass->get_skeys(ss, cur_gfn, cur_count, buf);
+ if (ret < 0) {
+ error_setg(errp, "get_keys error %d", ret);
+ goto out_free;
+ }
+
+ /* write keys to stream */
+ write_keys(f, buf, cur_gfn, cur_count, &lerr);
+ if (lerr) {
+ goto out_free;
+ }
+
+ cur_gfn += cur_count;
+ handled_count += cur_count;
+ }
+
+out_free:
+ error_propagate(errp, lerr);
+ g_free(buf);
+out:
+ qemu_fclose(f);
+}
+
+static void qemu_s390_skeys_init(Object *obj)
+{
+ QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
+ MachineState *machine = MACHINE(qdev_get_machine());
+
+ skeys->key_count = machine->maxram_size / TARGET_PAGE_SIZE;
+ skeys->keydata = g_malloc0(skeys->key_count);
+}
+
+static int qemu_s390_skeys_enabled(S390SKeysState *ss)
+{
+ return 1;
+}
+
+/*
+ * TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get
+ * will have to make sure that the given gfn belongs to a memory region and not
+ * a memory hole.
+ */
+static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
+ uint64_t count, uint8_t *keys)
+{
+ QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
+ int i;
+
+ /* Check for uint64 overflow and access beyond end of key data */
+ if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
+ error_report("Error: Setting storage keys for page beyond the end "
+ "of memory: gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn,
+ count);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < count; i++) {
+ skeydev->keydata[start_gfn + i] = keys[i];
+ }
+ return 0;
+}
+
+static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
+ uint64_t count, uint8_t *keys)
+{
+ QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
+ int i;
+
+ /* Check for uint64 overflow and access beyond end of key data */
+ if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
+ error_report("Error: Getting storage keys for page beyond the end "
+ "of memory: gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn,
+ count);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < count; i++) {
+ keys[i] = skeydev->keydata[start_gfn + i];
+ }
+ return 0;
+}
+
+static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
+{
+ S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
+
+ skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
+ skeyclass->get_skeys = qemu_s390_skeys_get;
+ skeyclass->set_skeys = qemu_s390_skeys_set;
+}
+
+static const TypeInfo qemu_s390_skeys_info = {
+ .name = TYPE_QEMU_S390_SKEYS,
+ .parent = TYPE_S390_SKEYS,
+ .instance_init = qemu_s390_skeys_init,
+ .instance_size = sizeof(QEMUS390SKeysState),
+ .class_init = qemu_s390_skeys_class_init,
+ .instance_size = sizeof(S390SKeysClass),
+};
+
+static void s390_storage_keys_save(QEMUFile *f, void *opaque)
+{
+ S390SKeysState *ss = S390_SKEYS(opaque);
+ S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
+ uint64_t pages_left = ram_size / TARGET_PAGE_SIZE;
+ uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS;
+ vaddr cur_gfn = 0;
+ int error = 0;
+ uint8_t *buf;
+
+ if (!skeyclass->skeys_enabled(ss)) {
+ goto end_stream;
+ }
+
+ buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
+ if (!buf) {
+ error_report("storage key save could not allocate memory\n");
+ goto end_stream;
+ }
+
+ /* We only support initial memory. Standby memory is not handled yet. */
+ qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS);
+ qemu_put_be64(f, pages_left);
+
+ while (pages_left) {
+ read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE);
+
+ if (!error) {
+ error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf);
+ if (error) {
+ /*
+ * If error: we want to fill the stream with valid data instead
+ * of stopping early so we pad the stream with 0x00 values and
+ * use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
+ * reading side.
+ */
+ error_report("S390_GET_KEYS error %d\n", error);
+ memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
+ eos = S390_SKEYS_SAVE_FLAG_ERROR;
+ }
+ }
+
+ qemu_put_buffer(f, buf, read_count);
+ cur_gfn += read_count;
+ pages_left -= read_count;
+ }
+
+ g_free(buf);
+end_stream:
+ qemu_put_be64(f, eos);
+}
+
+static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
+{
+ S390SKeysState *ss = S390_SKEYS(opaque);
+ S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
+ int ret = 0;
+
+ while (!ret) {
+ ram_addr_t addr;
+ int flags;
+
+ addr = qemu_get_be64(f);
+ flags = addr & ~TARGET_PAGE_MASK;
+ addr &= TARGET_PAGE_MASK;
+
+ switch (flags) {
+ case S390_SKEYS_SAVE_FLAG_SKEYS: {
+ const uint64_t total_count = qemu_get_be64(f);
+ uint64_t handled_count = 0, cur_count;
+ uint64_t cur_gfn = addr / TARGET_PAGE_SIZE;
+ uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
+
+ if (!buf) {
+ error_report("storage key load could not allocate memory\n");
+ ret = -ENOMEM;
+ break;
+ }
+
+ while (handled_count < total_count) {
+ cur_count = MIN(total_count - handled_count,
+ S390_SKEYS_BUFFER_SIZE);
+ qemu_get_buffer(f, buf, cur_count);
+
+ ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf);
+ if (ret < 0) {
+ error_report("S390_SET_KEYS error %d\n", ret);
+ break;
+ }
+ handled_count += cur_count;
+ cur_gfn += cur_count;
+ }
+ g_free(buf);
+ break;
+ }
+ case S390_SKEYS_SAVE_FLAG_ERROR: {
+ error_report("Storage key data is incomplete");
+ ret = -EINVAL;
+ break;
+ }
+ case S390_SKEYS_SAVE_FLAG_EOS:
+ /* normal exit */
+ return 0;
+ default:
+ error_report("Unexpected storage key flag data: %#x", flags);
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp)
+{
+ S390SKeysState *ss = S390_SKEYS(obj);
+
+ return ss->migration_enabled;
+}
+
+static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
+ Error **errp)
+{
+ S390SKeysState *ss = S390_SKEYS(obj);
+
+ /* Prevent double registration of savevm handler */
+ if (ss->migration_enabled == value) {
+ return;
+ }
+
+ ss->migration_enabled = value;
+
+ if (ss->migration_enabled) {
+ register_savevm(NULL, TYPE_S390_SKEYS, 0, 1, s390_storage_keys_save,
+ s390_storage_keys_load, ss);
+ } else {
+ unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss);
+ }
+}
+
+static void s390_skeys_instance_init(Object *obj)
+{
+ object_property_add_bool(obj, "migration-enabled",
+ s390_skeys_get_migration_enabled,
+ s390_skeys_set_migration_enabled, NULL);
+ object_property_set_bool(obj, true, "migration-enabled", NULL);
+}
+
+static void s390_skeys_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->hotpluggable = false;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo s390_skeys_info = {
+ .name = TYPE_S390_SKEYS,
+ .parent = TYPE_DEVICE,
+ .instance_init = s390_skeys_instance_init,
+ .instance_size = sizeof(S390SKeysState),
+ .class_init = s390_skeys_class_init,
+ .class_size = sizeof(S390SKeysClass),
+ .abstract = true,
+};
+
+static void qemu_s390_skeys_register_types(void)
+{
+ type_register_static(&s390_skeys_info);
+ type_register_static(&qemu_s390_skeys_info);
+}
+
+type_init(qemu_s390_skeys_register_types)
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 77aec8a5bd..98cb1293c2 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -577,17 +577,12 @@ static const TypeInfo s390_virtio_blk = {
.class_init = s390_virtio_blk_class_init,
};
-static Property s390_virtio_serial_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
k->realize = s390_virtio_serial_realize;
- dc->props = s390_virtio_serial_properties;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 4c51d1a5bd..27a8360207 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -19,6 +19,7 @@
#include "virtio-ccw.h"
#include "qemu/config-file.h"
#include "s390-pci-bus.h"
+#include "hw/s390x/storage-keys.h"
#define TYPE_S390_CCW_MACHINE "s390-ccw-machine"
@@ -99,58 +100,31 @@ static void virtio_ccw_register_hcalls(void)
virtio_ccw_hcall_early_printk);
}
-static void ccw_init(MachineState *machine)
+void s390_memory_init(ram_addr_t mem_size)
{
- ram_addr_t my_ram_size = machine->ram_size;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
- sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev();
- uint8_t *storage_keys;
+
+ /* allocate RAM for core */
+ memory_region_init_ram(ram, NULL, "s390.ram", mem_size, &error_abort);
+ vmstate_register_ram_global(ram);
+ memory_region_add_subregion(sysmem, 0, ram);
+
+ /* Initialize storage key device */
+ s390_skeys_init();
+}
+
+static void ccw_init(MachineState *machine)
+{
int ret;
VirtualCssBus *css_bus;
DeviceState *dev;
- QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL);
- ram_addr_t pad_size = 0;
- ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size);
- ram_addr_t standby_mem_size = maxmem - my_ram_size;
- uint64_t kvm_limit;
-
- /* The storage increment size is a multiple of 1M and is a power of 2.
- * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
- * The variable 'mhd->increment_size' is an exponent of 2 that can be
- * used to calculate the size (in bytes) of an increment. */
- mhd->increment_size = 20;
- while ((my_ram_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) {
- mhd->increment_size++;
- }
- while ((standby_mem_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) {
- mhd->increment_size++;
- }
- /* The core and standby memory areas need to be aligned with
- * the increment size. In effect, this can cause the
- * user-specified memory size to be rounded down to align
- * with the nearest increment boundary. */
- standby_mem_size = standby_mem_size >> mhd->increment_size
- << mhd->increment_size;
- my_ram_size = my_ram_size >> mhd->increment_size
- << mhd->increment_size;
-
- /* let's propagate the changed ram size into the global variable. */
- ram_size = my_ram_size;
- machine->maxram_size = my_ram_size + standby_mem_size;
-
- ret = s390_set_memory_limit(machine->maxram_size, &kvm_limit);
- if (ret == -E2BIG) {
- hw_error("qemu: host supports a maximum of %" PRIu64 " GB",
- kvm_limit >> 30);
- } else if (ret) {
- hw_error("qemu: setting the guest size failed");
- }
+ s390_sclp_init();
+ s390_memory_init(machine->ram_size);
/* get a BUS */
css_bus = virtual_css_bus_init();
- s390_sclp_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename, "s390-ccw.img", true);
s390_flic_init();
@@ -163,27 +137,8 @@ static void ccw_init(MachineState *machine)
/* register hypercalls */
virtio_ccw_register_hcalls();
- /* allocate RAM for core */
- memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(sysmem, 0, ram);
-
- /* If the size of ram is not on a MEM_SECTION_SIZE boundary,
- calculate the pad size necessary to force this boundary. */
- if (standby_mem_size) {
- if (my_ram_size % MEM_SECTION_SIZE) {
- pad_size = MEM_SECTION_SIZE - my_ram_size % MEM_SECTION_SIZE;
- }
- my_ram_size += standby_mem_size + pad_size;
- mhd->pad_size = pad_size;
- mhd->standby_mem_size = standby_mem_size;
- }
-
- /* allocate storage keys */
- storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
-
/* init CPUs */
- s390_init_cpus(machine->cpu_model, storage_keys);
+ s390_init_cpus(machine->cpu_model);
if (kvm_enabled()) {
kvm_s390_enable_css_support(s390_cpu_addr2state(0));
@@ -282,14 +237,24 @@ static const TypeInfo ccw_machine_info = {
},
};
+#define CCW_COMPAT_2_4 \
+ {\
+ .driver = TYPE_S390_SKEYS,\
+ .property = "migration-enabled",\
+ .value = "off",\
+ },
+
static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ static GlobalProperty compat_props[] = {
+ CCW_COMPAT_2_4
+ { /* end of list */ }
+ };
mc->name = "s390-ccw-virtio-2.4";
- mc->alias = "s390-ccw-virtio";
mc->desc = "VirtIO-ccw based S390 machine v2.4";
- mc->is_default = 1;
+ mc->compat_props = compat_props;
}
static const TypeInfo ccw_machine_2_4_info = {
@@ -298,10 +263,27 @@ static const TypeInfo ccw_machine_2_4_info = {
.class_init = ccw_machine_2_4_class_init,
};
+static void ccw_machine_2_5_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = "s390-ccw-virtio-2.5";
+ mc->alias = "s390-ccw-virtio";
+ mc->desc = "VirtIO-ccw based S390 machine v2.5";
+ mc->is_default = 1;
+}
+
+static const TypeInfo ccw_machine_2_5_info = {
+ .name = TYPE_S390_CCW_MACHINE "2.5",
+ .parent = TYPE_S390_CCW_MACHINE,
+ .class_init = ccw_machine_2_5_class_init,
+};
+
static void ccw_machine_register_types(void)
{
type_register_static(&ccw_machine_info);
type_register_static(&ccw_machine_2_4_info);
+ type_register_static(&ccw_machine_2_5_info);
}
type_init(ccw_machine_register_types)
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 1284e77b22..e4000c92e1 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -23,6 +23,7 @@
#include "hw/hw.h"
#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
@@ -38,6 +39,7 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio.h"
+#include "hw/s390x/storage-keys.h"
#include "cpu.h"
//#define DEBUG_S390
@@ -164,7 +166,7 @@ void s390_init_ipl_dev(const char *kernel_filename,
qdev_init_nofail(dev);
}
-void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys)
+void s390_init_cpus(const char *cpu_model)
{
int i;
@@ -184,7 +186,6 @@ void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys)
ipi_states[i] = cpu;
cs->halted = 1;
cs->exception_index = EXCP_HLT;
- cpu->env.storage_keys = storage_keys;
}
}
@@ -260,31 +261,20 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id)
/* PC hardware initialisation */
static void s390_init(MachineState *machine)
{
- ram_addr_t my_ram_size = machine->ram_size;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- int increment_size = 20;
- uint8_t *storage_keys;
+ ram_addr_t my_ram_size;
void *virtio_region;
hwaddr virtio_region_len;
hwaddr virtio_region_start;
- /*
- * The storage increment size is a multiple of 1M and is a power of 2.
- * The number of storage increments must be MAX_STORAGE_INCREMENTS or
- * fewer.
- */
- while ((my_ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) {
- increment_size++;
+ if (machine->ram_slots) {
+ error_report("Memory hotplug not supported by the selected machine.");
+ exit(EXIT_FAILURE);
}
- my_ram_size = my_ram_size >> increment_size << increment_size;
-
- /* let's propagate the changed ram size into the global variable. */
- ram_size = my_ram_size;
+ s390_sclp_init();
+ my_ram_size = machine->ram_size;
/* get a BUS */
s390_bus = s390_virtio_bus_init(&my_ram_size);
- s390_sclp_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename, ZIPL_FILENAME, false);
s390_flic_init();
@@ -293,9 +283,7 @@ static void s390_init(MachineState *machine)
s390_virtio_register_hcalls();
/* allocate RAM */
- memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort);
- vmstate_register_ram_global(ram);
- memory_region_add_subregion(sysmem, 0, ram);
+ s390_memory_init(my_ram_size);
/* clear virtio region */
virtio_region_len = my_ram_size - ram_size;
@@ -306,11 +294,8 @@ static void s390_init(MachineState *machine)
cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
virtio_region_len);
- /* allocate storage keys */
- storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
-
/* init CPUs */
- s390_init_cpus(machine->cpu_model, storage_keys);
+ s390_init_cpus(machine->cpu_model);
/* Create VirtIO network adapters */
s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390");
diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h
index c847853957..f389aa1a67 100644
--- a/hw/s390x/s390-virtio.h
+++ b/hw/s390x/s390-virtio.h
@@ -19,7 +19,7 @@
typedef int (*s390_virtio_fn)(const uint64_t *args);
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
-void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys);
+void s390_init_cpus(const char *cpu_model);
void s390_init_ipl_dev(const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
@@ -27,4 +27,5 @@ void s390_init_ipl_dev(const char *kernel_filename,
bool enforce_bios);
void s390_create_virtio_net(BusState *bus, const char *name);
void s390_nmi(NMIState *n, int cpu_index, Error **errp);
+void s390_memory_init(ram_addr_t mem_size);
#endif
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index b3a6c5e5a4..fd277e1bf0 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -17,37 +17,27 @@
#include "exec/memory.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
-#include "qemu/config-file.h"
+#include "hw/boards.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
-static inline SCLPEventFacility *get_event_facility(void)
+static inline SCLPDevice *get_sclp_device(void)
{
- ObjectProperty *op = object_property_find(qdev_get_machine(),
- TYPE_SCLP_EVENT_FACILITY,
- NULL);
- assert(op);
- return op->opaque;
+ return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL));
}
/* Provide information about the configuration, CPUs and storage */
-static void read_SCP_info(SCCB *sccb)
+static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
{
ReadInfo *read_info = (ReadInfo *) sccb;
+ MachineState *machine = MACHINE(qdev_get_machine());
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
CPUState *cpu;
int cpu_count = 0;
int i = 0;
- int increment_size = 20;
int rnsize, rnmax;
- QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL);
- int slots = qemu_opt_get_number(opts, "slots", 0);
- int max_avail_slots = s390_get_memslot_count(kvm_state);
-
- if (slots > max_avail_slots) {
- slots = max_avail_slots;
- }
+ int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
CPU_FOREACH(cpu) {
cpu_count++;
@@ -66,23 +56,8 @@ static void read_SCP_info(SCCB *sccb)
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
SCLP_HAS_PCI_RECONFIG);
- /*
- * The storage increment size is a multiple of 1M and is a power of 2.
- * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
- */
- while ((ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) {
- increment_size++;
- }
- rnmax = ram_size >> increment_size;
-
/* Memory Hotplug is only supported for the ccw machine type */
if (mhd) {
- while ((mhd->standby_mem_size >> increment_size) >
- MAX_STORAGE_INCREMENTS) {
- increment_size++;
- }
- assert(increment_size == mhd->increment_size);
-
mhd->standby_subregion_size = MEM_SECTION_SIZE;
/* Deduct the memory slot already used for core */
if (slots > 0) {
@@ -108,13 +83,11 @@ static void read_SCP_info(SCCB *sccb)
}
mhd->padded_ram_size = ram_size + mhd->pad_size;
mhd->rzm = 1 << mhd->increment_size;
- rnmax = ((ram_size + mhd->standby_mem_size + mhd->pad_size)
- >> mhd->increment_size);
read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR);
}
- rnsize = 1 << (increment_size - 20);
+ rnsize = 1 << (sclp->increment_size - 20);
if (rnsize <= 128) {
read_info->rnsize = rnsize;
} else {
@@ -122,6 +95,7 @@ static void read_SCP_info(SCCB *sccb)
read_info->rnsize2 = cpu_to_be32(rnsize);
}
+ rnmax = machine->maxram_size >> sclp->increment_size;
if (rnmax < 0x10000) {
read_info->rnmax = cpu_to_be16(rnmax);
} else {
@@ -132,14 +106,17 @@ static void read_SCP_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void read_storage_element0_info(SCCB *sccb)
+static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb)
{
int i, assigned;
int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- assert(mhd);
+ if (!mhd) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ return;
+ }
if ((ram_size >> mhd->increment_size) >= 0x10000) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
@@ -158,12 +135,15 @@ static void read_storage_element0_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void read_storage_element1_info(SCCB *sccb)
+static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb)
{
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- assert(mhd);
+ if (!mhd) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ return;
+ }
if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
@@ -179,13 +159,17 @@ static void read_storage_element1_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION);
}
-static void attach_storage_element(SCCB *sccb, uint16_t element)
+static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb,
+ uint16_t element)
{
int i, assigned, subincrement_id;
AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- assert(mhd);
+ if (!mhd) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ return;
+ }
if (element != 1) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
@@ -203,20 +187,26 @@ static void attach_storage_element(SCCB *sccb, uint16_t element)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
}
-static void assign_storage(SCCB *sccb)
+static void assign_storage(SCLPDevice *sclp, SCCB *sccb)
{
MemoryRegion *mr = NULL;
uint64_t this_subregion_size;
AssignStorage *assign_info = (AssignStorage *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- assert(mhd);
- ram_addr_t assign_addr = (assign_info->rn - 1) * mhd->rzm;
+ ram_addr_t assign_addr;
MemoryRegion *sysmem = get_system_memory();
+ if (!mhd) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ return;
+ }
+ assign_addr = (assign_info->rn - 1) * mhd->rzm;
+
if ((assign_addr % MEM_SECTION_SIZE == 0) &&
(assign_addr >= mhd->padded_ram_size)) {
/* Re-use existing memory region if found */
mr = memory_region_find(sysmem, assign_addr, 1).mr;
+ memory_region_unref(mr);
if (!mr) {
MemoryRegion *standby_ram = g_new(MemoryRegion, 1);
@@ -242,6 +232,11 @@ static void assign_storage(SCCB *sccb)
}
memory_region_init_ram(standby_ram, NULL, id, this_subregion_size, &error_abort);
+ /* This is a hack to make memory hotunplug work again. Once we have
+ * subdevices, we have to unparent them when unassigning memory,
+ * instead of doing it via the ref count of the MemoryRegion. */
+ object_ref(OBJECT(standby_ram));
+ object_unparent(OBJECT(standby_ram));
vmstate_register_ram_global(standby_ram);
memory_region_add_subregion(sysmem, offset, standby_ram);
}
@@ -252,15 +247,20 @@ static void assign_storage(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
}
-static void unassign_storage(SCCB *sccb)
+static void unassign_storage(SCLPDevice *sclp, SCCB *sccb)
{
MemoryRegion *mr = NULL;
AssignStorage *assign_info = (AssignStorage *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- assert(mhd);
- ram_addr_t unassign_addr = (assign_info->rn - 1) * mhd->rzm;
+ ram_addr_t unassign_addr;
MemoryRegion *sysmem = get_system_memory();
+ if (!mhd) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ return;
+ }
+ unassign_addr = (assign_info->rn - 1) * mhd->rzm;
+
/* if the addr is a multiple of 256 MB */
if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
(unassign_addr >= mhd->padded_ram_size)) {
@@ -269,6 +269,7 @@ static void unassign_storage(SCCB *sccb)
/* find the specified memory region and destroy it */
mr = memory_region_find(sysmem, unassign_addr, 1).mr;
+ memory_region_unref(mr);
if (mr) {
int i;
int is_removable = 1;
@@ -287,8 +288,7 @@ static void unassign_storage(SCCB *sccb)
}
if (is_removable) {
memory_region_del_subregion(sysmem, mr);
- object_unparent(OBJECT(mr));
- g_free(mr);
+ object_unref(OBJECT(mr));
}
}
}
@@ -296,7 +296,7 @@ static void unassign_storage(SCCB *sccb)
}
/* Provide information about the CPU */
-static void sclp_read_cpu_info(SCCB *sccb)
+static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
{
ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
CPUState *cpu;
@@ -323,34 +323,35 @@ static void sclp_read_cpu_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void sclp_execute(SCCB *sccb, uint32_t code)
+static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
{
- SCLPEventFacility *ef = get_event_facility();
+ SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
+ SCLPEventFacility *ef = sclp->event_facility;
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED:
- read_SCP_info(sccb);
+ sclp_c->read_SCP_info(sclp, sccb);
break;
case SCLP_CMDW_READ_CPU_INFO:
- sclp_read_cpu_info(sccb);
+ sclp_c->read_cpu_info(sclp, sccb);
break;
case SCLP_READ_STORAGE_ELEMENT_INFO:
if (code & 0xff00) {
- read_storage_element1_info(sccb);
+ sclp_c->read_storage_element1_info(sclp, sccb);
} else {
- read_storage_element0_info(sccb);
+ sclp_c->read_storage_element0_info(sclp, sccb);
}
break;
case SCLP_ATTACH_STORAGE_ELEMENT:
- attach_storage_element(sccb, (code & 0xff00) >> 8);
+ sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8);
break;
case SCLP_ASSIGN_STORAGE:
- assign_storage(sccb);
+ sclp_c->assign_storage(sclp, sccb);
break;
case SCLP_UNASSIGN_STORAGE:
- unassign_storage(sccb);
+ sclp_c->unassign_storage(sclp, sccb);
break;
case SCLP_CMDW_CONFIGURE_PCI:
s390_pci_sclp_configure(1, sccb);
@@ -366,6 +367,8 @@ static void sclp_execute(SCCB *sccb, uint32_t code)
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
{
+ SCLPDevice *sclp = get_sclp_device();
+ SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
int r = 0;
SCCB work_sccb;
@@ -400,20 +403,20 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
goto out;
}
- sclp_execute((SCCB *)&work_sccb, code);
+ sclp_c->execute(sclp, (SCCB *)&work_sccb, code);
cpu_physical_memory_write(sccb, &work_sccb,
be16_to_cpu(work_sccb.h.length));
- sclp_service_interrupt(sccb);
+ sclp_c->service_interrupt(sclp, sccb);
out:
return r;
}
-void sclp_service_interrupt(uint32_t sccb)
+static void service_interrupt(SCLPDevice *sclp, uint32_t sccb)
{
- SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacility *ef = sclp->event_facility;
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
uint32_t param = sccb & ~3;
@@ -428,17 +431,148 @@ void sclp_service_interrupt(uint32_t sccb)
s390_sclp_extint(param);
}
+void sclp_service_interrupt(uint32_t sccb)
+{
+ SCLPDevice *sclp = get_sclp_device();
+ SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
+
+ sclp_c->service_interrupt(sclp, sccb);
+}
+
/* qemu object creation and initialization functions */
void s390_sclp_init(void)
{
- DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
+ Object *new = object_new(TYPE_SCLP);
- object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
+ object_property_add_child(qdev_get_machine(), TYPE_SCLP, new,
+ NULL);
+ object_unref(OBJECT(new));
+ qdev_init_nofail(DEVICE(new));
+}
+
+static void sclp_realize(DeviceState *dev, Error **errp)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ SCLPDevice *sclp = SCLP(dev);
+ Error *l_err = NULL;
+ uint64_t hw_limit;
+ int ret;
+
+ object_property_set_bool(OBJECT(sclp->event_facility), true, "realized",
+ &l_err);
+ if (l_err) {
+ goto error;
+ }
+
+ ret = s390_set_memory_limit(machine->maxram_size, &hw_limit);
+ if (ret == -E2BIG) {
+ error_setg(&l_err, "qemu: host supports a maximum of %" PRIu64 " GB",
+ hw_limit >> 30);
+ goto error;
+ } else if (ret) {
+ error_setg(&l_err, "qemu: setting the guest size failed");
+ goto error;
+ }
+ return;
+error:
+ assert(l_err);
+ error_propagate(errp, l_err);
+}
+
+static void sclp_memory_init(SCLPDevice *sclp)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ ram_addr_t initial_mem = machine->ram_size;
+ ram_addr_t max_mem = machine->maxram_size;
+ ram_addr_t standby_mem = max_mem - initial_mem;
+ ram_addr_t pad_mem = 0;
+ int increment_size = 20;
+
+ /* The storage increment size is a multiple of 1M and is a power of 2.
+ * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
+ * The variable 'increment_size' is an exponent of 2 that can be
+ * used to calculate the size (in bytes) of an increment. */
+ while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
+ increment_size++;
+ }
+ if (machine->ram_slots) {
+ while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
+ increment_size++;
+ }
+ }
+ sclp->increment_size = increment_size;
+
+ /* The core and standby memory areas need to be aligned with
+ * the increment size. In effect, this can cause the
+ * user-specified memory size to be rounded down to align
+ * with the nearest increment boundary. */
+ initial_mem = initial_mem >> increment_size << increment_size;
+ standby_mem = standby_mem >> increment_size << increment_size;
+
+ /* If the size of ram is not on a MEM_SECTION_SIZE boundary,
+ calculate the pad size necessary to force this boundary. */
+ if (machine->ram_slots && standby_mem) {
+ sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev();
+
+ if (initial_mem % MEM_SECTION_SIZE) {
+ pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE;
+ }
+ mhd->increment_size = increment_size;
+ mhd->pad_size = pad_mem;
+ mhd->standby_mem_size = standby_mem;
+ }
+ machine->ram_size = initial_mem;
+ machine->maxram_size = initial_mem + pad_mem + standby_mem;
+ /* let's propagate the changed ram size into the global variable. */
+ ram_size = initial_mem;
+}
+
+static void sclp_init(Object *obj)
+{
+ SCLPDevice *sclp = SCLP(obj);
+ Object *new;
+
+ new = object_new(TYPE_SCLP_EVENT_FACILITY);
+ object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL);
+ /* qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS */
+ qdev_set_parent_bus(DEVICE(new), sysbus_get_default());
+ object_unref(new);
+ sclp->event_facility = EVENT_FACILITY(new);
+
+ sclp_memory_init(sclp);
}
+static void sclp_class_init(ObjectClass *oc, void *data)
+{
+ SCLPDeviceClass *sc = SCLP_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->desc = "SCLP (Service-Call Logical Processor)";
+ dc->realize = sclp_realize;
+ dc->hotpluggable = false;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+
+ sc->read_SCP_info = read_SCP_info;
+ sc->read_storage_element0_info = read_storage_element0_info;
+ sc->read_storage_element1_info = read_storage_element1_info;
+ sc->attach_storage_element = attach_storage_element;
+ sc->assign_storage = assign_storage;
+ sc->unassign_storage = unassign_storage;
+ sc->read_cpu_info = sclp_read_cpu_info;
+ sc->execute = sclp_execute;
+ sc->service_interrupt = service_interrupt;
+}
+
+static TypeInfo sclp_info = {
+ .name = TYPE_SCLP,
+ .parent = TYPE_DEVICE,
+ .instance_init = sclp_init,
+ .instance_size = sizeof(SCLPDevice),
+ .class_init = sclp_class_init,
+ .class_size = sizeof(SCLPDeviceClass),
+};
+
sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void)
{
DeviceState *dev;
@@ -475,5 +609,6 @@ static TypeInfo sclp_memory_hotplug_dev_info = {
static void register_types(void)
{
type_register_static(&sclp_memory_hotplug_dev_info);
+ type_register_static(&sclp_info);
}
type_init(register_types);
diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c
index 2fe8b5aa40..322eb31d95 100644
--- a/hw/s390x/sclpcpu.c
+++ b/hw/s390x/sclpcpu.c
@@ -25,13 +25,16 @@ typedef struct ConfigMgtData {
uint8_t event_qualifier;
} QEMU_PACKED ConfigMgtData;
-static qemu_irq *irq_cpu_hotplug; /* Only used in this file */
-
#define EVENT_QUAL_CPU_CHANGE 1
void raise_irq_cpu_hotplug(void)
{
- qemu_irq_raise(*irq_cpu_hotplug);
+ Object *obj = object_resolve_path_type("", TYPE_SCLP_CPU_HOTPLUG, NULL);
+
+ SCLP_EVENT(obj)->event_pending = true;
+
+ /* Trigger SCLP read operation */
+ sclp_service_interrupt(0);
}
static unsigned int send_mask(void)
@@ -70,36 +73,19 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1;
}
-static void trigger_signal(void *opaque, int n, int level)
-{
- SCLPEvent *event = opaque;
- event->event_pending = true;
-
- /* Trigger SCLP read operation */
- sclp_service_interrupt(0);
-}
-
-static int irq_cpu_hotplug_init(SCLPEvent *event)
-{
- irq_cpu_hotplug = qemu_allocate_irqs(trigger_signal, event, 1);
- return 0;
-}
-
static void cpu_class_init(ObjectClass *oc, void *data)
{
SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
- k->init = irq_cpu_hotplug_init;
k->get_send_mask = send_mask;
k->get_receive_mask = receive_mask;
k->read_event_data = read_event_data;
- k->write_event_data = NULL;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo sclp_cpu_info = {
- .name = "sclp-cpu-hotplug",
+ .name = TYPE_SCLP_CPU_HOTPLUG,
.parent = TYPE_SCLP_EVENT,
.instance_size = sizeof(SCLPEvent),
.class_init = cpu_class_init,
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index ffa5553135..15b06e108b 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -66,7 +66,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
}
static const VMStateDescription vmstate_sclpquiesce = {
- .name = "sclpquiesce",
+ .name = TYPE_SCLP_QUIESCE,
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
@@ -127,7 +127,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo sclp_quiesce_info = {
- .name = "sclpquiesce",
+ .name = TYPE_SCLP_QUIESCE,
.parent = TYPE_SCLP_EVENT,
.instance_size = sizeof(SCLPEvent),
.class_init = quiesce_class_init,
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index a8bb1c66f9..1c33f146a7 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -145,7 +145,7 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
*
* TODO: always disable this workaround for virtio 1.0 devices.
*/
- if (!virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
if (req->elem.out_num) {
req_size = req->elem.out_sg[0].iov_len;
}
@@ -759,7 +759,7 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
VirtIODevice *vdev = VIRTIO_DEVICE(s);
- if (virtio_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
+ if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
dev->type != TYPE_ROM) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
sense.asc | (sense.ascq << 8));
@@ -783,7 +783,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
aio_context_release(s->ctx);
}
- if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN);
@@ -797,7 +797,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
SCSIDevice *sd = SCSI_DEVICE(dev);
- if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_REMOVED);
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index d072deca11..35d8033402 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -578,8 +578,7 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
BlockBackend *blk,
qemu_irq irq, qemu_irq dma[], omap_clk clk)
{
- struct omap_mmc_s *s = (struct omap_mmc_s *)
- g_malloc0(sizeof(struct omap_mmc_s));
+ struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
s->irq = irq;
s->dma = dma;
@@ -605,8 +604,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
omap_clk fclk, omap_clk iclk)
{
- struct omap_mmc_s *s = (struct omap_mmc_s *)
- g_malloc0(sizeof(struct omap_mmc_s));
+ struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
s->irq = irq;
s->dma = dma;
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index 11fcd479df..5242176a33 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -46,7 +46,7 @@ typedef struct PL181State {
int32_t fifo_pos;
int32_t fifo_len;
/* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
- while it is reading the FIFO. We hack around this be defering
+ while it is reading the FIFO. We hack around this by deferring
subsequent transfers until after the driver polls the status word.
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
*/
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index a1ff465a67..3e2a451154 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -412,8 +412,7 @@ static void sd_reset(SDState *sd)
sd_set_cardstatus(sd);
sd_set_sdstatus(sd);
- if (sd->wp_groups)
- g_free(sd->wp_groups);
+ g_free(sd->wp_groups);
sd->wp_switch = sd->blk ? blk_is_read_only(sd->blk) : false;
sd->wpgrps_size = sect;
sd->wp_groups = bitmap_new(sd->wpgrps_size);
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index e63367ba56..65304cff5e 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1169,10 +1169,8 @@ static void sdhci_uninitfn(SDHCIState *s)
qemu_free_irq(s->eject_cb);
qemu_free_irq(s->ro_cb);
- if (s->fifo_buffer) {
- g_free(s->fifo_buffer);
- s->fifo_buffer = NULL;
- }
+ g_free(s->fifo_buffer);
+ s->fifo_buffer = NULL;
}
const VMStateDescription sdhci_vmstate = {
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 5e22ed79b2..3b0b2ecfa4 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -338,9 +338,9 @@ static void r2d_init(MachineState *machine)
}
/* initialization which should be done by firmware */
- boot_params.loader_type = 1;
- boot_params.initrd_start = INITRD_LOAD_OFFSET;
- boot_params.initrd_size = initrd_size;
+ boot_params.loader_type = tswap32(1);
+ boot_params.initrd_start = tswap32(INITRD_LOAD_OFFSET);
+ boot_params.initrd_size = tswap32(initrd_size);
}
if (kernel_cmdline) {
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index efdbb5de6f..b81a1d349d 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -55,7 +55,9 @@ static uint8_t *smbios_tables;
static size_t smbios_tables_len;
static unsigned smbios_table_max;
static unsigned smbios_table_cnt;
-static struct smbios_entry_point ep;
+static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_21;
+
+static SmbiosEntryPoint ep;
static int smbios_type4_count = 0;
static bool smbios_immutable;
@@ -771,11 +773,12 @@ void smbios_set_cpuid(uint32_t version, uint32_t features)
void smbios_set_defaults(const char *manufacturer, const char *product,
const char *version, bool legacy_mode,
- bool uuid_encoded)
+ bool uuid_encoded, SmbiosEntryPointType ep_type)
{
smbios_have_defaults = true;
smbios_legacy = legacy_mode;
smbios_uuid_encoded = uuid_encoded;
+ smbios_ep_type = ep_type;
/* drop unwanted version of command-line file blob(s) */
if (smbios_legacy) {
@@ -808,26 +811,53 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
static void smbios_entry_point_setup(void)
{
- memcpy(ep.anchor_string, "_SM_", 4);
- memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
- ep.length = sizeof(struct smbios_entry_point);
- ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
- memset(ep.formatted_area, 0, 5);
-
- /* compliant with smbios spec v2.8 */
- ep.smbios_major_version = 2;
- ep.smbios_minor_version = 8;
- ep.smbios_bcd_revision = 0x28;
-
- /* set during table construction, but BIOS may override: */
- ep.structure_table_length = cpu_to_le16(smbios_tables_len);
- ep.max_structure_size = cpu_to_le16(smbios_table_max);
- ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
-
- /* BIOS must recalculate: */
- ep.checksum = 0;
- ep.intermediate_checksum = 0;
- ep.structure_table_address = cpu_to_le32(0);
+ switch (smbios_ep_type) {
+ case SMBIOS_ENTRY_POINT_21:
+ memcpy(ep.ep21.anchor_string, "_SM_", 4);
+ memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
+ ep.ep21.length = sizeof(struct smbios_21_entry_point);
+ ep.ep21.entry_point_revision = 0; /* formatted_area reserved */
+ memset(ep.ep21.formatted_area, 0, 5);
+
+ /* compliant with smbios spec v2.8 */
+ ep.ep21.smbios_major_version = 2;
+ ep.ep21.smbios_minor_version = 8;
+ ep.ep21.smbios_bcd_revision = 0x28;
+
+ /* set during table construction, but BIOS may override: */
+ ep.ep21.structure_table_length = cpu_to_le16(smbios_tables_len);
+ ep.ep21.max_structure_size = cpu_to_le16(smbios_table_max);
+ ep.ep21.number_of_structures = cpu_to_le16(smbios_table_cnt);
+
+ /* BIOS must recalculate */
+ ep.ep21.checksum = 0;
+ ep.ep21.intermediate_checksum = 0;
+ ep.ep21.structure_table_address = cpu_to_le32(0);
+
+ break;
+ case SMBIOS_ENTRY_POINT_30:
+ memcpy(ep.ep30.anchor_string, "_SM3_", 5);
+ ep.ep30.length = sizeof(struct smbios_30_entry_point);
+ ep.ep30.entry_point_revision = 1;
+ ep.ep30.reserved = 0;
+
+ /* compliant with smbios spec 3.0 */
+ ep.ep30.smbios_major_version = 3;
+ ep.ep30.smbios_minor_version = 0;
+ ep.ep30.smbios_doc_rev = 0;
+
+ /* set during table construct, but BIOS might override */
+ ep.ep30.structure_table_max_size = cpu_to_le32(smbios_tables_len);
+
+ /* BIOS must recalculate */
+ ep.ep30.checksum = 0;
+ ep.ep30.structure_table_address = cpu_to_le64(0);
+
+ break;
+ default:
+ abort();
+ break;
+ }
}
void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
@@ -885,7 +915,15 @@ void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
*tables = smbios_tables;
*tables_len = smbios_tables_len;
*anchor = (uint8_t *)&ep;
- *anchor_len = sizeof(struct smbios_entry_point);
+
+ /* calculate length based on anchor string */
+ if (!strncmp((char *)&ep, "_SM_", 4)) {
+ *anchor_len = sizeof(struct smbios_21_entry_point);
+ } else if (!strncmp((char *)&ep, "_SM3_", 5)) {
+ *anchor_len = sizeof(struct smbios_30_entry_point);
+ } else {
+ abort();
+ }
}
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
index 119e325a64..27263299be 100644
--- a/hw/ssi/omap_spi.c
+++ b/hw/ssi/omap_spi.c
@@ -342,8 +342,7 @@ static const MemoryRegionOps omap_mcspi_ops = {
struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
{
- struct omap_mcspi_s *s = (struct omap_mcspi_s *)
- g_malloc0(sizeof(struct omap_mcspi_s));
+ struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
struct omap_mcspi_ch_s *ch = s->ch;
s->irq = irq;
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index 10c5d2b91e..9649851526 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -12,7 +12,6 @@
*
*/
-#include "hw/arm/imx.h"
#include "hw/timer/imx_epit.h"
#include "hw/misc/imx_ccm.h"
#include "qemu/main-loop.h"
@@ -287,16 +286,6 @@ static void imx_epit_cmp(void *opaque)
imx_epit_update_int(s);
}
-void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
-{
- IMXEPITState *pp;
- DeviceState *dev;
-
- dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
- pp = IMX_EPIT(dev);
- pp->ccm = ccm;
-}
-
static const MemoryRegionOps imx_epit_ops = {
.read = imx_epit_read,
.write = imx_epit_write,
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 01f802e8f1..4bac67d333 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -12,7 +12,6 @@
*
*/
-#include "hw/arm/imx.h"
#include "hw/timer/imx_gpt.h"
#include "hw/misc/imx_ccm.h"
#include "qemu/main-loop.h"
@@ -449,16 +448,6 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp)
s->timer = ptimer_init(bh);
}
-void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
-{
- IMXGPTState *pp;
- DeviceState *dev;
-
- dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq);
- pp = IMX_GPT(dev);
- pp->ccm = ccm;
-}
-
static void imx_gpt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c
index b8c8c0137d..dcf706c46e 100644
--- a/hw/timer/omap_gptimer.c
+++ b/hw/timer/omap_gptimer.c
@@ -468,8 +468,7 @@ static const MemoryRegionOps omap_gp_timer_ops = {
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
qemu_irq irq, omap_clk fclk, omap_clk iclk)
{
- struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
- g_malloc0(sizeof(struct omap_gp_timer_s));
+ struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
s->ta = ta;
s->irq = irq;
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 79a8f98af0..be160c19b3 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -22,8 +22,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
-#include <dirent.h>
-
#include "qemu-common.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 7afa5f9d67..16fb845d07 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -95,10 +95,8 @@ static void usb_ehci_pci_exit(PCIDevice *dev)
usb_ehci_unrealize(s, DEVICE(dev), NULL);
- if (s->irq) {
- g_free(s->irq);
- s->irq = NULL;
- }
+ g_free(s->irq);
+ s->irq = NULL;
}
static void usb_ehci_pci_reset(DeviceState *dev)
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index c673bed4c4..1c57e20e70 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1453,9 +1453,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report)
t->running_retry = 0;
killed = 1;
}
- if (t->trbs) {
- g_free(t->trbs);
- }
+ g_free(t->trbs);
t->trbs = NULL;
t->trb_count = t->trb_alloced = 0;
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 11429f5e73..5e492fda0f 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1429,7 +1429,7 @@ static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
* still present in the first place. Attemping to contine where we
* left off is impossible.
*
- * What we are going to to to here is emulate a surprise removal of
+ * What we are going to do here is emulate a surprise removal of
* the usb device passed through, then kick host scan so the device
* will get re-attached (and re-initialized by the guest) in case it
* is still present.
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 25df25fd0f..38086cd0f2 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -33,9 +33,7 @@
#include "qemu/iov.h"
#include "sysemu/char.h"
-#include <dirent.h>
#include <sys/ioctl.h>
-#include <signal.h>
#include <usbredirparser.h>
#include <usbredirfilter.h>
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 85ee9b005e..6d21311575 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -226,7 +226,7 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
/*
* 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.
+ * the VGA ROM space.
*/
if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
(errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 4023d8e823..73d34b9b2e 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -18,7 +18,6 @@
* Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
*/
-#include <dirent.h>
#include <linux/vfio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -3378,7 +3377,7 @@ static bool vfio_radeon_smc_is_running(VFIOPCIDevice *vdev)
uint32_t clk, pc_c;
/*
- * Registers 200h and 204h are index and data registers for acessing
+ * Registers 200h and 204h are index and data registers for accessing
* indirect configuration registers within the device.
*/
vfio_region_write(&vdev->bars[5].region, 0x200, 0x80000004, 4);
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 60365d1279..de4ec52a07 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -234,7 +234,7 @@ static void vfio_intp_interrupt(VFIOINTp *intp)
ret = event_notifier_test_and_clear(&intp->interrupt);
if (!ret) {
- error_report("Error when clearing fd=%d (ret = %d)\n",
+ error_report("Error when clearing fd=%d (ret = %d)",
event_notifier_get_fd(&intp->interrupt), ret);
}
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index 07fd69c69e..fece83a829 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -105,7 +105,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
/* Disable guest->host notifies */
void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
{
- if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
}
}
@@ -116,7 +116,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
*/
bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
{
- if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_avail_event(&vring->vr) = vring->vr.avail->idx;
} else {
vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
@@ -135,12 +135,12 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
* interrupts. */
smp_mb();
- if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
unlikely(!vring_more_avail(vdev, vring))) {
return true;
}
- if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
return !(vring_get_avail_flags(vdev, vring) &
VRING_AVAIL_F_NO_INTERRUPT);
}
@@ -402,7 +402,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
/* On success, increment avail index. */
vring->last_avail_idx++;
- if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_avail_event(&vring->vr) =
virtio_tswap16(vdev, vring->last_avail_idx);
}
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 2712c6fc0a..a08c36bb45 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -742,7 +742,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
return -errno;
}
- if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
virtio_legacy_is_cross_endian(vdev)) {
r = vhost_virtqueue_set_vring_endian_legacy(dev,
virtio_is_big_endian(vdev),
@@ -839,7 +839,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
/* In the cross-endian case, we need to reset the vring endianness to
* native as legacy devices expect so by default.
*/
- if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
virtio_legacy_is_cross_endian(vdev)) {
r = vhost_virtqueue_set_vring_endian_legacy(dev,
!virtio_is_big_endian(vdev),
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 3577b7af91..c419b17143 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -70,7 +70,7 @@ static inline void reset_stats(VirtIOBalloon *dev)
static bool balloon_stats_supported(const VirtIOBalloon *s)
{
VirtIODevice *vdev = VIRTIO_DEVICE(s);
- return virtio_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ);
+ return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ);
}
static bool balloon_stats_enabled(const VirtIOBalloon *s)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index c024161f59..eda8205d58 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1505,9 +1505,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (legacy) {
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
+ virtio_bus_get_vdev_config_len(bus);
- if (size & (size - 1)) {
- size = 1 << qemu_fls(size);
- }
+ size = pow2ceil(size);
memory_region_init_io(&proxy->bar, OBJECT(proxy),
&virtio_pci_config_ops,
@@ -2009,10 +2007,6 @@ static const TypeInfo virtio_net_pci_info = {
/* virtio-rng-pci */
-static Property virtio_rng_pci_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
@@ -2039,7 +2033,6 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_rng_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = virtio_rng_pci_properties;
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 788b556a74..0832db9935 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -220,7 +220,7 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val)
void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
vq->notification = enable;
- if (virtio_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_set_avail_event(vq, vring_avail_idx(vq));
} else if (enable) {
vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
@@ -471,7 +471,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
max = vq->vring.num;
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
- if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
vring_set_avail_event(vq, vq->last_avail_idx);
}
@@ -560,7 +560,7 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
trace_virtio_set_status(vdev, val);
- if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) &&
val & VIRTIO_CONFIG_S_FEATURES_OK) {
int ret = virtio_validate_features(vdev);
@@ -898,7 +898,7 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
/* virtio-1 compliant devices cannot change the alignment */
- if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
error_report("tried to modify queue alignment for virtio-1 device");
return;
}
@@ -993,12 +993,12 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
/* We need to expose used array entries before checking used event. */
smp_mb();
/* Always notify when queue is empty (when feature acknowledge) */
- if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
!vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx) {
return true;
}
- if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
}
@@ -1035,7 +1035,7 @@ static bool virtio_device_endian_needed(void *opaque)
VirtIODevice *vdev = opaque;
assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
- if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
return vdev->device_endian != virtio_default_endian();
}
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index cfa2b1be13..3e07d44878 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -136,7 +136,7 @@ static void i6300esb_restart_timer(I6300State *d, int stage)
* multiply here can exceed 64-bits, before we divide by 33MHz, so
* we use a higher-precision intermediate result.
*/
- timeout = muldiv64(get_ticks_per_sec(), timeout, 33000000);
+ timeout = muldiv64(timeout, get_ticks_per_sec(), 33000000);
i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index a0ca0aa3df..a9ad7e70f7 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -3,3 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_pt_graphics.o
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 743b37b991..7d8a0237cf 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -40,7 +40,7 @@ static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
d->domain, d->bus, d->dev, d->func, name);
if (rc >= size || rc < 0) {
- /* The ouput is truncated or an other error is encountered */
+ /* The output is truncated, or some other error was encountered */
return -ENODEV;
}
return 0;
@@ -376,6 +376,11 @@ int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
goto error;
}
d->irq = v;
+ rc = xen_host_pci_get_hex_value(d, "class", &v);
+ if (rc) {
+ goto error;
+ }
+ d->class_code = v;
d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
return 0;
@@ -387,6 +392,11 @@ error:
return rc;
}
+bool xen_host_pci_device_closed(XenHostPCIDevice *d)
+{
+ return d->config_fd == -1;
+}
+
void xen_host_pci_device_put(XenHostPCIDevice *d)
{
if (d->config_fd >= 0) {
diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
index c2486f0c19..3d44e044ff 100644
--- a/hw/xen/xen-host-pci-device.h
+++ b/hw/xen/xen-host-pci-device.h
@@ -25,6 +25,7 @@ typedef struct XenHostPCIDevice {
uint16_t vendor_id;
uint16_t device_id;
+ uint32_t class_code;
int irq;
XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
@@ -38,6 +39,7 @@ typedef struct XenHostPCIDevice {
int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
uint8_t bus, uint8_t dev, uint8_t func);
void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
+bool xen_host_pci_device_closed(XenHostPCIDevice *d);
int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index ed5fcaec0d..2b54f52707 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -56,6 +56,7 @@
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
+#include "hw/i386/pc.h"
#include "hw/xen/xen_backend.h"
#include "xen_pt.h"
#include "qemu/range.h"
@@ -378,7 +379,7 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
}
}
- /* need to shift back before passing them to xen_host_pci_device */
+ /* need to shift back before passing them to xen_host_pci_set_block. */
val >>= (addr & 3) << 3;
memory_region_transaction_commit();
@@ -406,7 +407,7 @@ out:
(uint8_t *)&val + index, len);
if (rc < 0) {
- XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
+ XEN_PT_ERR(d, "xen_host_pci_set_block failed. return value: %d.\n", rc);
}
}
}
@@ -502,6 +503,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
d->rom.size, d->rom.base_addr);
}
+ xen_pt_register_vga_regions(d);
return 0;
}
@@ -683,13 +685,86 @@ static const MemoryListener xen_pt_io_listener = {
.priority = 10,
};
+static void
+xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
+ XenHostPCIDevice *dev)
+{
+ uint16_t gpu_dev_id;
+ PCIDevice *d = &s->dev;
+
+ gpu_dev_id = dev->device_id;
+ igd_passthrough_isa_bridge_create(d->bus, gpu_dev_id);
+}
+
+/* destroy. */
+static void xen_pt_destroy(PCIDevice *d) {
+
+ XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
+ XenHostPCIDevice *host_dev = &s->real_device;
+ uint8_t machine_irq = s->machine_irq;
+ uint8_t intx;
+ int rc;
+
+ if (machine_irq && !xen_host_pci_device_closed(&s->real_device)) {
+ intx = xen_pt_pci_intx(s);
+ rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
+ PT_IRQ_TYPE_PCI,
+ pci_bus_num(d->bus),
+ PCI_SLOT(s->dev.devfn),
+ intx,
+ 0 /* isa_irq */);
+ if (rc < 0) {
+ XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
+ " (machine irq: %i, err: %d)"
+ " But bravely continuing on..\n",
+ 'a' + intx, machine_irq, errno);
+ }
+ }
+
+ /* N.B. xen_pt_config_delete takes care of freeing them. */
+ if (s->msi) {
+ xen_pt_msi_disable(s);
+ }
+ if (s->msix) {
+ xen_pt_msix_disable(s);
+ }
+
+ if (machine_irq) {
+ xen_pt_mapped_machine_irq[machine_irq]--;
+
+ if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
+ rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
+
+ if (rc < 0) {
+ XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
+ " But bravely continuing on..\n",
+ machine_irq, errno);
+ }
+ }
+ s->machine_irq = 0;
+ }
+
+ /* delete all emulated config registers */
+ xen_pt_config_delete(s);
+
+ xen_pt_unregister_vga_regions(host_dev);
+
+ if (s->listener_set) {
+ memory_listener_unregister(&s->memory_listener);
+ memory_listener_unregister(&s->io_listener);
+ s->listener_set = false;
+ }
+ if (!xen_host_pci_device_closed(&s->real_device)) {
+ xen_host_pci_device_put(&s->real_device);
+ }
+}
/* init */
static int xen_pt_initfn(PCIDevice *d)
{
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
int rc = 0;
- uint8_t machine_irq = 0;
+ uint8_t machine_irq = 0, scratch;
uint16_t cmd = 0;
int pirq = XEN_PT_UNASSIGNED_PIRQ;
@@ -715,27 +790,48 @@ static int xen_pt_initfn(PCIDevice *d)
}
/* Initialize virtualized PCI configuration (Extended 256 Bytes) */
- if (xen_host_pci_get_block(&s->real_device, 0, d->config,
- PCI_CONFIG_SPACE_SIZE) == -1) {
- xen_host_pci_device_put(&s->real_device);
- return -1;
- }
+ memset(d->config, 0, PCI_CONFIG_SPACE_SIZE);
s->memory_listener = xen_pt_memory_listener;
s->io_listener = xen_pt_io_listener;
+ /* Setup VGA bios for passthrough GFX */
+ if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
+ (s->real_device.dev == 2) && (s->real_device.func == 0)) {
+ if (!is_igd_vga_passthrough(&s->real_device)) {
+ XEN_PT_ERR(d, "Need to enable igd-passthru if you're trying"
+ " to passthrough IGD GFX.\n");
+ xen_host_pci_device_put(&s->real_device);
+ return -1;
+ }
+
+ if (xen_pt_setup_vga(s, &s->real_device) < 0) {
+ XEN_PT_ERR(d, "Setup VGA BIOS of passthrough GFX failed!\n");
+ xen_host_pci_device_put(&s->real_device);
+ return -1;
+ }
+
+ /* Register ISA bridge for passthrough GFX. */
+ xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
+ }
+
/* Handle real device's MMIO/PIO BARs */
xen_pt_register_regions(s, &cmd);
/* reinitialize each config register to be emulated */
- if (xen_pt_config_init(s)) {
+ rc = xen_pt_config_init(s);
+ if (rc) {
XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
- xen_host_pci_device_put(&s->real_device);
- return -1;
+ goto err_out;
}
/* Bind interrupt */
- if (!s->dev.config[PCI_INTERRUPT_PIN]) {
+ rc = xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &scratch);
+ if (rc) {
+ XEN_PT_ERR(d, "Failed to read PCI_INTERRUPT_PIN! (rc:%d)\n", rc);
+ goto err_out;
+ }
+ if (!scratch) {
XEN_PT_LOG(d, "no pin interrupt\n");
goto out;
}
@@ -785,69 +881,41 @@ static int xen_pt_initfn(PCIDevice *d)
out:
if (cmd) {
- xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
- pci_get_word(d->config + PCI_COMMAND) | cmd);
+ uint16_t val;
+
+ rc = xen_host_pci_get_word(&s->real_device, PCI_COMMAND, &val);
+ if (rc) {
+ XEN_PT_ERR(d, "Failed to read PCI_COMMAND! (rc: %d)\n", rc);
+ goto err_out;
+ } else {
+ val |= cmd;
+ rc = xen_host_pci_set_word(&s->real_device, PCI_COMMAND, val);
+ if (rc) {
+ XEN_PT_ERR(d, "Failed to write PCI_COMMAND val=0x%x!(rc: %d)\n",
+ val, rc);
+ goto err_out;
+ }
+ }
}
memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
memory_listener_register(&s->io_listener, &address_space_io);
+ s->listener_set = true;
XEN_PT_LOG(d,
"Real physical device %02x:%02x.%d registered successfully!\n",
s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
return 0;
+
+err_out:
+ xen_pt_destroy(d);
+ assert(rc);
+ return rc;
}
static void xen_pt_unregister_device(PCIDevice *d)
{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- uint8_t machine_irq = s->machine_irq;
- uint8_t intx = xen_pt_pci_intx(s);
- int rc;
-
- if (machine_irq) {
- rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
- PT_IRQ_TYPE_PCI,
- pci_bus_num(d->bus),
- PCI_SLOT(s->dev.devfn),
- intx,
- 0 /* isa_irq */);
- if (rc < 0) {
- XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
- " (machine irq: %i, err: %d)"
- " But bravely continuing on..\n",
- 'a' + intx, machine_irq, errno);
- }
- }
-
- if (s->msi) {
- xen_pt_msi_disable(s);
- }
- if (s->msix) {
- xen_pt_msix_disable(s);
- }
-
- if (machine_irq) {
- xen_pt_mapped_machine_irq[machine_irq]--;
-
- if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
- rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
-
- if (rc < 0) {
- XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
- " But bravely continuing on..\n",
- machine_irq, errno);
- }
- }
- }
-
- /* delete all emulated config registers */
- xen_pt_config_delete(s);
-
- memory_listener_unregister(&s->memory_listener);
- memory_listener_unregister(&s->io_listener);
-
- xen_host_pci_device_put(&s->real_device);
+ xen_pt_destroy(d);
}
static Property xen_pci_passthrough_properties[] = {
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 393f36ccbf..3bc22eb1d1 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -40,6 +40,9 @@ typedef struct XenPCIPassthroughState XenPCIPassthroughState;
#define XEN_PT_DEVICE(obj) \
OBJECT_CHECK(XenPCIPassthroughState, (obj), TYPE_XEN_PT_DEVICE)
+uint32_t igd_read_opregion(XenPCIPassthroughState *s);
+void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
+
/* function type for config reg */
typedef int (*xen_pt_conf_reg_init)
(XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
@@ -66,8 +69,9 @@ typedef int (*xen_pt_conf_byte_read)
#define XEN_PT_BAR_ALLF 0xFFFFFFFF
#define XEN_PT_BAR_UNMAPPED (-1)
-#define PCI_CAP_MAX 48
+#define XEN_PCI_CAP_MAX 48
+#define XEN_PCI_INTEL_OPREGION 0xfc
typedef enum {
XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
@@ -134,7 +138,11 @@ struct XenPTRegInfo {
struct XenPTReg {
QLIST_ENTRY(XenPTReg) entries;
XenPTRegInfo *reg;
- uint32_t data; /* emulated value */
+ union {
+ uint8_t *byte;
+ uint16_t *half_word;
+ uint32_t *word;
+ } ptr; /* pointer to dev.config. */
};
typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo;
@@ -217,6 +225,7 @@ struct XenPCIPassthroughState {
MemoryListener memory_listener;
MemoryListener io_listener;
+ bool listener_set;
};
int xen_pt_config_init(XenPCIPassthroughState *s);
@@ -282,6 +291,7 @@ static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
" value=%i, acceptable range is 1 - 4\n", r_val);
r_val = 0;
} else {
+ /* Note that if s.real_device.config_fd is closed we make 0xff. */
r_val -= 1;
}
@@ -289,7 +299,6 @@ static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
}
/* MSI/MSI-X */
-int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
int xen_pt_msi_setup(XenPCIPassthroughState *s);
int xen_pt_msi_update(XenPCIPassthroughState *d);
void xen_pt_msi_disable(XenPCIPassthroughState *s);
@@ -305,5 +314,18 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
return s->msix && s->msix->bar_index == bar;
}
-
+extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
+ struct Object *owner, int *size,
+ unsigned int domain,
+ unsigned int bus, unsigned int slot,
+ unsigned int function);
+extern bool has_igd_gfx_passthru;
+static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
+{
+ return (has_igd_gfx_passthru
+ && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
+}
+int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
+int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev);
#endif /* !XEN_PT_H */
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index dd37be38a4..4a5bc11f30 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -128,10 +128,11 @@ static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
{
XenPTRegInfo *reg = cfg_entry->reg;
uint8_t valid_emu_mask = 0;
+ uint8_t *data = cfg_entry->ptr.byte;
/* emulate byte register */
valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+ *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
return 0;
}
@@ -140,10 +141,11 @@ static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
{
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t valid_emu_mask = 0;
+ uint16_t *data = cfg_entry->ptr.half_word;
/* emulate word register */
valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+ *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
return 0;
}
@@ -152,10 +154,11 @@ static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t valid_emu_mask = 0;
+ uint32_t *data = cfg_entry->ptr.word;
/* emulate long register */
valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+ *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
return 0;
}
@@ -169,10 +172,11 @@ static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
XenPTRegInfo *reg = cfg_entry->reg;
uint8_t writable_mask = 0;
uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint8_t *data = cfg_entry->ptr.byte;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -186,10 +190,11 @@ static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint16_t *data = cfg_entry->ptr.half_word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -203,10 +208,11 @@ static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint32_t *data = cfg_entry->ptr.word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -255,7 +261,7 @@ static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
if (reg_entry) {
/* check Capabilities Pointer register */
- if (reg_entry->data) {
+ if (*reg_entry->ptr.half_word) {
reg_field |= PCI_STATUS_CAP_LIST;
} else {
reg_field &= ~PCI_STATUS_CAP_LIST;
@@ -301,10 +307,11 @@ static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint16_t *data = cfg_entry->ptr.half_word;
/* modify emulate register */
writable_mask = ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
if (*val & PCI_COMMAND_INTX_DISABLE) {
@@ -447,7 +454,7 @@ static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
/* emulate BAR */
valid_emu_mask = bar_emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+ *value = XEN_PT_MERGE_VALUE(*value, *cfg_entry->ptr.word, ~valid_emu_mask);
return 0;
}
@@ -464,6 +471,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
uint32_t bar_ro_mask = 0;
uint32_t r_size = 0;
int index = 0;
+ uint32_t *data = cfg_entry->ptr.word;
index = xen_pt_bar_offset_to_index(reg->offset);
if (index < 0 || index >= PCI_NUM_REGIONS) {
@@ -500,7 +508,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
/* modify emulate register */
writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* check whether we need to update the virtual region address or not */
switch (s->bases[index].bar_flag) {
@@ -533,6 +541,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
pcibus_t r_size = 0;
uint32_t bar_ro_mask = 0;
+ uint32_t *data = cfg_entry->ptr.word;
r_size = d->io_regions[PCI_ROM_SLOT].size;
base = &s->bases[PCI_ROM_SLOT];
@@ -544,7 +553,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
/* modify emulate register */
writable_mask = ~bar_ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -552,6 +561,22 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
return 0;
}
+static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
+ XenPTReg *cfg_entry,
+ uint32_t *value, uint32_t valid_mask)
+{
+ *value = igd_read_opregion(s);
+ return 0;
+}
+
+static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
+ XenPTReg *cfg_entry, uint32_t *value,
+ uint32_t dev_value, uint32_t valid_mask)
+{
+ igd_write_opregion(s, *value);
+ return 0;
+}
+
/* Header Type0 reg static information table */
static XenPTRegInfo xen_pt_emu_reg_header0[] = {
/* Vendor ID reg */
@@ -800,15 +825,21 @@ static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
uint32_t offset)
{
- uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
- return flags & PCI_EXP_FLAGS_VERS;
+ uint8_t flag;
+ if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
+ return 0;
+ }
+ return flag & PCI_EXP_FLAGS_VERS;
}
static inline uint8_t get_device_type(XenPCIPassthroughState *s,
uint32_t offset)
{
- uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
- return (flags & PCI_EXP_FLAGS_TYPE) >> 4;
+ uint8_t flag;
+ if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
+ return 0;
+ }
+ return (flag & PCI_EXP_FLAGS_TYPE) >> 4;
}
/* initialize Link Control register */
@@ -857,8 +888,14 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
reg_field = XEN_PT_INVALID_REG;
} else {
/* set Supported Link Speed */
- uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset
- + PCI_EXP_LNKCAP);
+ uint8_t lnkcap;
+ int rc;
+ rc = xen_host_pci_get_byte(&s->real_device,
+ real_offset - reg->offset + PCI_EXP_LNKCAP,
+ &lnkcap);
+ if (rc) {
+ return rc;
+ }
reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
}
@@ -971,10 +1008,11 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint16_t *data = cfg_entry->ptr.half_word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
@@ -1039,13 +1077,15 @@ static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
XenPTRegInfo *reg, uint32_t real_offset,
uint32_t *data)
{
- PCIDevice *d = &s->dev;
XenPTMSI *msi = s->msi;
- uint16_t reg_field = 0;
+ uint16_t reg_field;
+ int rc;
/* use I/O device register's value as initial value */
- reg_field = pci_get_word(d->config + real_offset);
-
+ rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
+ if (rc) {
+ return rc;
+ }
if (reg_field & PCI_MSI_FLAGS_ENABLE) {
XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
xen_host_pci_set_word(&s->real_device, real_offset,
@@ -1067,6 +1107,7 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
XenPTMSI *msi = s->msi;
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+ uint16_t *data = cfg_entry->ptr.half_word;
/* Currently no support for multi-vector */
if (*val & PCI_MSI_FLAGS_QSIZE) {
@@ -1075,8 +1116,8 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
- msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
+ msi->flags |= *data & ~PCI_MSI_FLAGS_ENABLE;
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -1086,7 +1127,7 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
/* setup MSI pirq for the first time */
if (!msi->initialized) {
/* Init physical one */
- XEN_PT_LOG(&s->dev, "setup MSI\n");
+ XEN_PT_LOG(&s->dev, "setup MSI (register: %x).\n", *val);
if (xen_pt_msi_setup(s)) {
/* We do not broadcast the error to the framework code, so
* that MSI errors are contained in MSI emulation code and
@@ -1094,12 +1135,12 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
* Guest MSI would be actually not working.
*/
*val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not map MSI.\n");
+ XEN_PT_WARN(&s->dev, "Can not map MSI (register: %x)!\n", *val);
return 0;
}
if (xen_pt_msi_update(s)) {
*val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not bind MSI\n");
+ XEN_PT_WARN(&s->dev, "Can not bind MSI (register: %x)!\n", *val);
return 0;
}
msi->initialized = true;
@@ -1190,18 +1231,19 @@ static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t old_addr = cfg_entry->data;
+ uint32_t old_addr = *cfg_entry->ptr.word;
+ uint32_t *data = cfg_entry->ptr.word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
- s->msi->addr_lo = cfg_entry->data;
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
+ s->msi->addr_lo = *data;
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
- if (cfg_entry->data != old_addr) {
+ if (*data != old_addr) {
if (s->msi->mapped) {
xen_pt_msi_update(s);
}
@@ -1216,7 +1258,8 @@ static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t old_addr = cfg_entry->data;
+ uint32_t old_addr = *cfg_entry->ptr.word;
+ uint32_t *data = cfg_entry->ptr.word;
/* check whether the type is 64 bit or not */
if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
@@ -1227,15 +1270,15 @@ static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* update the msi_info too */
- s->msi->addr_hi = cfg_entry->data;
+ s->msi->addr_hi = *data;
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
- if (cfg_entry->data != old_addr) {
+ if (*data != old_addr) {
if (s->msi->mapped) {
xen_pt_msi_update(s);
}
@@ -1254,8 +1297,9 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
XenPTRegInfo *reg = cfg_entry->reg;
XenPTMSI *msi = s->msi;
uint16_t writable_mask = 0;
- uint16_t old_data = cfg_entry->data;
+ uint16_t old_data = *cfg_entry->ptr.half_word;
uint32_t offset = reg->offset;
+ uint16_t *data = cfg_entry->ptr.half_word;
/* check the offset whether matches the type or not */
if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
@@ -1266,15 +1310,15 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* update the msi_info too */
- msi->data = cfg_entry->data;
+ msi->data = *data;
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
- if (cfg_entry->data != old_data) {
+ if (*data != old_data) {
if (msi->mapped) {
xen_pt_msi_update(s);
}
@@ -1411,14 +1455,16 @@ static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
XenPTRegInfo *reg, uint32_t real_offset,
uint32_t *data)
{
- PCIDevice *d = &s->dev;
- uint16_t reg_field = 0;
+ uint16_t reg_field;
+ int rc;
/* use I/O device register's value as initial value */
- reg_field = pci_get_word(d->config + real_offset);
-
+ rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
+ if (rc) {
+ return rc;
+ }
if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
- XEN_PT_LOG(d, "MSIX already enabled, disabling it first\n");
+ XEN_PT_LOG(&s->dev, "MSIX already enabled, disabling it first\n");
xen_host_pci_set_word(&s->real_device, real_offset,
reg_field & ~PCI_MSIX_FLAGS_ENABLE);
}
@@ -1436,10 +1482,11 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
int debug_msix_enabled_old;
+ uint16_t *data = cfg_entry->ptr.half_word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+ *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
@@ -1492,6 +1539,19 @@ static XenPTRegInfo xen_pt_emu_reg_msix[] = {
},
};
+static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
+ /* Intel IGFX OpRegion reg */
+ {
+ .offset = 0x0,
+ .size = 4,
+ .init_val = 0,
+ .u.dw.read = xen_pt_intel_opregion_read,
+ .u.dw.write = xen_pt_intel_opregion_write,
+ },
+ {
+ .size = 0,
+ },
+};
/****************************
* Capabilities
@@ -1511,8 +1571,7 @@ static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
const XenPTRegGroupInfo *grp_reg,
uint32_t base_offset, uint8_t *size)
{
- *size = pci_get_byte(s->dev.config + base_offset + 0x02);
- return 0;
+ return xen_host_pci_get_byte(&s->real_device, base_offset + 0x02, size);
}
/* get PCI Express Capability Structure register group size */
static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
@@ -1591,12 +1650,15 @@ static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
const XenPTRegGroupInfo *grp_reg,
uint32_t base_offset, uint8_t *size)
{
- PCIDevice *d = &s->dev;
uint16_t msg_ctrl = 0;
uint8_t msi_size = 0xa;
+ int rc;
- msg_ctrl = pci_get_word(d->config + (base_offset + PCI_MSI_FLAGS));
-
+ rc = xen_host_pci_get_word(&s->real_device, base_offset + PCI_MSI_FLAGS,
+ &msg_ctrl);
+ if (rc) {
+ return rc;
+ }
/* check if 64-bit address is capable of per-vector masking */
if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
msi_size += 4;
@@ -1729,6 +1791,14 @@ static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
.size_init = xen_pt_msix_size_init,
.emu_regs = xen_pt_emu_reg_msix,
},
+ /* Intel IGD Opregion group */
+ {
+ .grp_id = XEN_PCI_INTEL_OPREGION,
+ .grp_type = XEN_PT_GRP_TYPE_EMU,
+ .grp_size = 0x4,
+ .size_init = xen_pt_reg_grp_size_init,
+ .emu_regs = xen_pt_emu_reg_igd_opregion,
+ },
{
.grp_size = 0,
},
@@ -1739,11 +1809,14 @@ static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
XenPTRegInfo *reg, uint32_t real_offset,
uint32_t *data)
{
- int i;
- uint8_t *config = s->dev.config;
- uint32_t reg_field = pci_get_byte(config + real_offset);
+ int i, rc;
+ uint8_t reg_field;
uint8_t cap_id = 0;
+ rc = xen_host_pci_get_byte(&s->real_device, real_offset, &reg_field);
+ if (rc) {
+ return rc;
+ }
/* find capability offset */
while (reg_field) {
for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
@@ -1752,7 +1825,13 @@ static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
continue;
}
- cap_id = pci_get_byte(config + reg_field + PCI_CAP_LIST_ID);
+ rc = xen_host_pci_get_byte(&s->real_device,
+ reg_field + PCI_CAP_LIST_ID, &cap_id);
+ if (rc) {
+ XEN_PT_ERR(&s->dev, "Failed to read capability @0x%x (rc:%d)\n",
+ reg_field + PCI_CAP_LIST_ID, rc);
+ return rc;
+ }
if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
goto out;
@@ -1763,7 +1842,11 @@ static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
}
/* next capability */
- reg_field = pci_get_byte(config + reg_field + PCI_CAP_LIST_NEXT);
+ rc = xen_host_pci_get_byte(&s->real_device,
+ reg_field + PCI_CAP_LIST_NEXT, &reg_field);
+ if (rc) {
+ return rc;
+ }
}
out:
@@ -1779,7 +1862,7 @@ out:
static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
{
uint8_t id;
- unsigned max_cap = PCI_CAP_MAX;
+ unsigned max_cap = XEN_PCI_CAP_MAX;
uint8_t pos = PCI_CAPABILITY_LIST;
uint8_t status = 0;
@@ -1827,6 +1910,10 @@ static int xen_pt_config_reg_init(XenPCIPassthroughState *s,
reg_entry->reg = reg;
if (reg->init) {
+ uint32_t host_mask, size_mask;
+ unsigned int offset;
+ uint32_t val;
+
/* initialize emulate register */
rc = reg->init(s, reg_entry->reg,
reg_grp->base_offset + reg->offset, &data);
@@ -1839,8 +1926,67 @@ static int xen_pt_config_reg_init(XenPCIPassthroughState *s,
g_free(reg_entry);
return 0;
}
- /* set register value */
- reg_entry->data = data;
+ /* Sync up the data to dev.config */
+ offset = reg_grp->base_offset + reg->offset;
+ size_mask = 0xFFFFFFFF >> ((4 - reg->size) << 3);
+
+ switch (reg->size) {
+ case 1: rc = xen_host_pci_get_byte(&s->real_device, offset, (uint8_t *)&val);
+ break;
+ case 2: rc = xen_host_pci_get_word(&s->real_device, offset, (uint16_t *)&val);
+ break;
+ case 4: rc = xen_host_pci_get_long(&s->real_device, offset, &val);
+ break;
+ default: assert(1);
+ }
+ if (rc) {
+ /* Serious issues when we cannot read the host values! */
+ g_free(reg_entry);
+ return rc;
+ }
+ /* Set bits in emu_mask are the ones we emulate. The dev.config shall
+ * contain the emulated view of the guest - therefore we flip the mask
+ * to mask out the host values (which dev.config initially has) . */
+ host_mask = size_mask & ~reg->emu_mask;
+
+ if ((data & host_mask) != (val & host_mask)) {
+ uint32_t new_val;
+
+ /* Mask out host (including past size). */
+ new_val = val & host_mask;
+ /* Merge emulated ones (excluding the non-emulated ones). */
+ new_val |= data & host_mask;
+ /* Leave intact host and emulated values past the size - even though
+ * we do not care as we write per reg->size granularity, but for the
+ * logging below lets have the proper value. */
+ new_val |= ((val | data)) & ~size_mask;
+ XEN_PT_LOG(&s->dev,"Offset 0x%04x mismatch! Emulated=0x%04x, host=0x%04x, syncing to 0x%04x.\n",
+ offset, data, val, new_val);
+ val = new_val;
+ } else
+ val = data;
+
+ if (val & ~size_mask) {
+ XEN_PT_ERR(&s->dev,"Offset 0x%04x:0x%04x expands past register size(%d)!\n",
+ offset, val, reg->size);
+ g_free(reg_entry);
+ return -ENXIO;
+ }
+ /* This could be just pci_set_long as we don't modify the bits
+ * past reg->size, but in case this routine is run in parallel or the
+ * init value is larger, we do not want to over-write registers. */
+ switch (reg->size) {
+ case 1: pci_set_byte(s->dev.config + offset, (uint8_t)val);
+ break;
+ case 2: pci_set_word(s->dev.config + offset, (uint16_t)val);
+ break;
+ case 4: pci_set_long(s->dev.config + offset, val);
+ break;
+ default: assert(1);
+ }
+ /* set register value pointer to the data. */
+ reg_entry->ptr.byte = s->dev.config + offset;
+
}
/* list add register entry */
QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
@@ -1858,7 +2004,8 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
uint32_t reg_grp_offset = 0;
XenPTRegGroup *reg_grp_entry = NULL;
- if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) {
+ if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
+ && xen_pt_emu_reg_grps[i].grp_id != XEN_PCI_INTEL_OPREGION) {
if (xen_pt_hide_dev_cap(&s->real_device,
xen_pt_emu_reg_grps[i].grp_id)) {
continue;
@@ -1871,6 +2018,15 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
}
}
+ /*
+ * By default we will trap up to 0x40 in the cfg space.
+ * If an intel device is pass through we need to trap 0xfc,
+ * therefore the size should be 0xff.
+ */
+ if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) {
+ reg_grp_offset = XEN_PCI_INTEL_OPREGION;
+ }
+
reg_grp_entry = g_new0(XenPTRegGroup, 1);
QLIST_INIT(&reg_grp_entry->reg_tbl_list);
QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
@@ -1883,6 +2039,9 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
reg_grp_offset,
&reg_grp_entry->size);
if (rc < 0) {
+ XEN_PT_LOG(&s->dev, "Failed to initialize %d/%ld, type=0x%x, rc:%d\n",
+ i, ARRAY_SIZE(xen_pt_emu_reg_grps),
+ xen_pt_emu_reg_grps[i].grp_type, rc);
xen_pt_config_delete(s);
return rc;
}
@@ -1897,6 +2056,10 @@ int xen_pt_config_init(XenPCIPassthroughState *s)
/* initialize capability register */
rc = xen_pt_config_reg_init(s, reg_grp_entry, regs);
if (rc < 0) {
+ XEN_PT_LOG(&s->dev, "Failed to initialize %d/%ld reg 0x%x in grp_type=0x%x (%d/%ld), rc=%d\n",
+ j, ARRAY_SIZE(xen_pt_emu_reg_grps[i].emu_regs),
+ regs->offset, xen_pt_emu_reg_grps[i].grp_type,
+ i, ARRAY_SIZE(xen_pt_emu_reg_grps), rc);
xen_pt_config_delete(s);
return rc;
}
@@ -1918,9 +2081,7 @@ void xen_pt_config_delete(XenPCIPassthroughState *s)
if (s->msix) {
xen_pt_msix_delete(s);
}
- if (s->msi) {
- g_free(s->msi);
- }
+ g_free(s->msi);
/* free all register group entry */
QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
new file mode 100644
index 0000000000..df6069bf63
--- /dev/null
+++ b/hw/xen/xen_pt_graphics.c
@@ -0,0 +1,272 @@
+/*
+ * graphics passthrough
+ */
+#include "xen_pt.h"
+#include "xen-host-pci-device.h"
+#include "hw/xen/xen_backend.h"
+
+static unsigned long igd_guest_opregion;
+static unsigned long igd_host_opregion;
+
+#define XEN_PCI_INTEL_OPREGION_MASK 0xfff
+
+typedef struct VGARegion {
+ int type; /* Memory or port I/O */
+ uint64_t guest_base_addr;
+ uint64_t machine_base_addr;
+ uint64_t size; /* size of the region */
+ int rc;
+} VGARegion;
+
+#define IORESOURCE_IO 0x00000100
+#define IORESOURCE_MEM 0x00000200
+
+static struct VGARegion vga_args[] = {
+ {
+ .type = IORESOURCE_IO,
+ .guest_base_addr = 0x3B0,
+ .machine_base_addr = 0x3B0,
+ .size = 0xC,
+ .rc = -1,
+ },
+ {
+ .type = IORESOURCE_IO,
+ .guest_base_addr = 0x3C0,
+ .machine_base_addr = 0x3C0,
+ .size = 0x20,
+ .rc = -1,
+ },
+ {
+ .type = IORESOURCE_MEM,
+ .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
+ .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
+ .size = 0x20,
+ .rc = -1,
+ },
+};
+
+/*
+ * register VGA resources for the domain with assigned gfx
+ */
+int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
+{
+ int i = 0;
+
+ if (!is_igd_vga_passthrough(dev)) {
+ return 0;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
+ if (vga_args[i].type == IORESOURCE_IO) {
+ vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
+ vga_args[i].guest_base_addr,
+ vga_args[i].machine_base_addr,
+ vga_args[i].size, DPCI_ADD_MAPPING);
+ } else {
+ vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
+ vga_args[i].guest_base_addr,
+ vga_args[i].machine_base_addr,
+ vga_args[i].size, DPCI_ADD_MAPPING);
+ }
+
+ if (vga_args[i].rc) {
+ XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
+ vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
+ vga_args[i].rc);
+ return vga_args[i].rc;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * unregister VGA resources for the domain with assigned gfx
+ */
+int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
+{
+ int i = 0;
+ int ret = 0;
+
+ if (!is_igd_vga_passthrough(dev)) {
+ return 0;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
+ if (vga_args[i].type == IORESOURCE_IO) {
+ vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
+ vga_args[i].guest_base_addr,
+ vga_args[i].machine_base_addr,
+ vga_args[i].size, DPCI_REMOVE_MAPPING);
+ } else {
+ vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
+ vga_args[i].guest_base_addr,
+ vga_args[i].machine_base_addr,
+ vga_args[i].size, DPCI_REMOVE_MAPPING);
+ }
+
+ if (vga_args[i].rc) {
+ XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
+ vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
+ vga_args[i].rc);
+ return vga_args[i].rc;
+ }
+ }
+
+ if (igd_guest_opregion) {
+ ret = xc_domain_memory_mapping(xen_xc, xen_domid,
+ (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
+ 3,
+ DPCI_REMOVE_MAPPING);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void *get_vgabios(XenPCIPassthroughState *s, int *size,
+ XenHostPCIDevice *dev)
+{
+ return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
+ dev->domain, dev->bus,
+ dev->dev, dev->func);
+}
+
+/* Refer to Seabios. */
+struct rom_header {
+ uint16_t signature;
+ uint8_t size;
+ uint8_t initVector[4];
+ uint8_t reserved[17];
+ uint16_t pcioffset;
+ uint16_t pnpoffset;
+} __attribute__((packed));
+
+struct pci_data {
+ uint32_t signature;
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t vitaldata;
+ uint16_t dlen;
+ uint8_t drevision;
+ uint8_t class_lo;
+ uint16_t class_hi;
+ uint16_t ilen;
+ uint16_t irevision;
+ uint8_t type;
+ uint8_t indicator;
+ uint16_t reserved;
+} __attribute__((packed));
+
+int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev)
+{
+ unsigned char *bios = NULL;
+ struct rom_header *rom;
+ int bios_size;
+ char *c = NULL;
+ char checksum = 0;
+ uint32_t len = 0;
+ struct pci_data *pd = NULL;
+
+ if (!is_igd_vga_passthrough(dev)) {
+ return -1;
+ }
+
+ bios = get_vgabios(s, &bios_size, dev);
+ if (!bios) {
+ XEN_PT_ERR(&s->dev, "VGA: Can't getting VBIOS!\n");
+ return -1;
+ }
+
+ /* Currently we fixed this address as a primary. */
+ rom = (struct rom_header *)bios;
+ pd = (void *)(bios + (unsigned char)rom->pcioffset);
+
+ /* We may need to fixup Device Identification. */
+ if (pd->device != s->real_device.device_id) {
+ pd->device = s->real_device.device_id;
+
+ len = rom->size * 512;
+ /* Then adjust the bios checksum */
+ for (c = (char *)bios; c < ((char *)bios + len); c++) {
+ checksum += *c;
+ }
+ if (checksum) {
+ bios[len - 1] -= checksum;
+ XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
+ checksum);
+ }
+ }
+
+ /* Currently we fixed this address as a primary for legacy BIOS. */
+ cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
+ return 0;
+}
+
+uint32_t igd_read_opregion(XenPCIPassthroughState *s)
+{
+ uint32_t val = 0;
+
+ if (!igd_guest_opregion) {
+ return val;
+ }
+
+ val = igd_guest_opregion;
+
+ XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
+ return val;
+}
+
+#define XEN_PCI_INTEL_OPREGION_PAGES 0x3
+#define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
+void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
+{
+ int ret;
+
+ if (igd_guest_opregion) {
+ XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
+ val);
+ return;
+ }
+
+ /* We just work with LE. */
+ xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
+ (uint8_t *)&igd_host_opregion, 4);
+ igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
+ | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
+
+ ret = xc_domain_iomem_permission(xen_xc, xen_domid,
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
+ XEN_PCI_INTEL_OPREGION_PAGES,
+ XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
+
+ if (ret) {
+ XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
+ " 0x%lx.\n", ret,
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
+ igd_guest_opregion = 0;
+ return;
+ }
+
+ ret = xc_domain_memory_mapping(xen_xc, xen_domid,
+ (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
+ XEN_PCI_INTEL_OPREGION_PAGES,
+ DPCI_ADD_MAPPING);
+
+ if (ret) {
+ XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
+ " guest opregion:0x%lx.\n", ret,
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
+ (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
+ igd_guest_opregion = 0;
+ return;
+ }
+
+ XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
+ (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
+ (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
+}
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index 263e0514a2..e3d71945cd 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -75,19 +75,29 @@ static int msi_msix_enable(XenPCIPassthroughState *s,
bool enable)
{
uint16_t val = 0;
+ int rc;
if (!address) {
return -1;
}
- xen_host_pci_get_word(&s->real_device, address, &val);
+ rc = xen_host_pci_get_word(&s->real_device, address, &val);
+ if (rc) {
+ XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
+ address, rc);
+ return rc;
+ }
if (enable) {
val |= flag;
} else {
val &= ~flag;
}
- xen_host_pci_set_word(&s->real_device, address, val);
- return 0;
+ rc = xen_host_pci_set_word(&s->real_device, address, val);
+ if (rc) {
+ XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
+ address, rc);
+ }
+ return rc;
}
static int msi_msix_setup(XenPCIPassthroughState *s,
@@ -220,7 +230,7 @@ static int msi_msix_disable(XenPCIPassthroughState *s,
* MSI virtualization functions
*/
-int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
+static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
{
XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
@@ -276,7 +286,7 @@ void xen_pt_msi_disable(XenPCIPassthroughState *s)
return;
}
- xen_pt_msi_set_enable(s, false);
+ (void)xen_pt_msi_set_enable(s, false);
msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
msi->initialized);