aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/Makefile.objs1
-rw-r--r--hw/adc/Makefile.objs1
-rw-r--r--hw/adc/stm32f2xx_adc.c306
-rw-r--r--hw/arm/integratorcp.c35
-rw-r--r--hw/arm/mainstone.c5
-rw-r--r--hw/arm/stm32f205_soc.c92
-rw-r--r--hw/arm/virt-acpi-build.c12
-rw-r--r--hw/arm/virt.c66
-rw-r--r--hw/core/Makefile.objs3
-rw-r--r--hw/core/generic-loader.c211
-rw-r--r--hw/core/or-irq.c107
-rw-r--r--hw/dma/rc4030.c81
-rw-r--r--hw/i386/xen/xen_platform.c2
-rw-r--r--hw/ide/piix.c4
-rw-r--r--hw/input/tsc2005.c190
-rw-r--r--hw/input/tsc210x.c227
-rw-r--r--hw/intc/Makefile.objs2
-rw-r--r--hw/intc/arm_gic_kvm.c12
-rw-r--r--hw/intc/arm_gicv3_its_common.c148
-rw-r--r--hw/intc/arm_gicv3_its_kvm.c121
-rw-r--r--hw/intc/arm_gicv3_kvm.c13
-rw-r--r--hw/net/cadence_gem.c22
-rw-r--r--hw/ppc/spapr.c104
-rw-r--r--hw/ppc/spapr_cpu_core.c8
-rw-r--r--hw/s390x/css.c12
-rw-r--r--hw/s390x/s390-pci-bus.c48
-rw-r--r--hw/s390x/s390-pci-bus.h4
-rw-r--r--hw/s390x/s390-pci-inst.c6
-rw-r--r--hw/scsi/spapr_vscsi.c2
-rw-r--r--hw/scsi/trace-events2
-rw-r--r--hw/smbios/smbios.c2
-rw-r--r--hw/ssi/Makefile.objs1
-rw-r--r--hw/ssi/stm32f2xx_spi.c225
-rw-r--r--hw/timer/stm32f2xx_timer.c9
-rw-r--r--hw/xenpv/xen_domainbuild.c2
35 files changed, 1660 insertions, 426 deletions
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 4a07ed4344..0ffd281145 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,5 +1,6 @@
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
devices-dirs-$(CONFIG_ACPI) += acpi/
+devices-dirs-$(CONFIG_SOFTMMU) += adc/
devices-dirs-$(CONFIG_SOFTMMU) += audio/
devices-dirs-$(CONFIG_SOFTMMU) += block/
devices-dirs-$(CONFIG_SOFTMMU) += bt/
diff --git a/hw/adc/Makefile.objs b/hw/adc/Makefile.objs
new file mode 100644
index 0000000000..3f6dfdedae
--- /dev/null
+++ b/hw/adc/Makefile.objs
@@ -0,0 +1 @@
+obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o
diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c
new file mode 100644
index 0000000000..90fe9de299
--- /dev/null
+++ b/hw/adc/stm32f2xx_adc.c
@@ -0,0 +1,306 @@
+/*
+ * STM32F2XX ADC
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "hw/adc/stm32f2xx_adc.h"
+
+#ifndef STM_ADC_ERR_DEBUG
+#define STM_ADC_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+ if (STM_ADC_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_adc_reset(DeviceState *dev)
+{
+ STM32F2XXADCState *s = STM32F2XX_ADC(dev);
+
+ s->adc_sr = 0x00000000;
+ s->adc_cr1 = 0x00000000;
+ s->adc_cr2 = 0x00000000;
+ s->adc_smpr1 = 0x00000000;
+ s->adc_smpr2 = 0x00000000;
+ s->adc_jofr[0] = 0x00000000;
+ s->adc_jofr[1] = 0x00000000;
+ s->adc_jofr[2] = 0x00000000;
+ s->adc_jofr[3] = 0x00000000;
+ s->adc_htr = 0x00000FFF;
+ s->adc_ltr = 0x00000000;
+ s->adc_sqr1 = 0x00000000;
+ s->adc_sqr2 = 0x00000000;
+ s->adc_sqr3 = 0x00000000;
+ s->adc_jsqr = 0x00000000;
+ s->adc_jdr[0] = 0x00000000;
+ s->adc_jdr[1] = 0x00000000;
+ s->adc_jdr[2] = 0x00000000;
+ s->adc_jdr[3] = 0x00000000;
+ s->adc_dr = 0x00000000;
+}
+
+static uint32_t stm32f2xx_adc_generate_value(STM32F2XXADCState *s)
+{
+ /* Attempts to fake some ADC values */
+ s->adc_dr = s->adc_dr + 7;
+
+ switch ((s->adc_cr1 & ADC_CR1_RES) >> 24) {
+ case 0:
+ /* 12-bit */
+ s->adc_dr &= 0xFFF;
+ break;
+ case 1:
+ /* 10-bit */
+ s->adc_dr &= 0x3FF;
+ break;
+ case 2:
+ /* 8-bit */
+ s->adc_dr &= 0xFF;
+ break;
+ default:
+ /* 6-bit */
+ s->adc_dr &= 0x3F;
+ }
+
+ if (s->adc_cr2 & ADC_CR2_ALIGN) {
+ return (s->adc_dr << 1) & 0xFFF0;
+ } else {
+ return s->adc_dr;
+ }
+}
+
+static uint64_t stm32f2xx_adc_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F2XXADCState *s = opaque;
+
+ DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
+
+ if (addr >= ADC_COMMON_ADDRESS) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: ADC Common Register Unsupported\n", __func__);
+ }
+
+ switch (addr) {
+ case ADC_SR:
+ return s->adc_sr;
+ case ADC_CR1:
+ return s->adc_cr1;
+ case ADC_CR2:
+ return s->adc_cr2 & 0xFFFFFFF;
+ case ADC_SMPR1:
+ return s->adc_smpr1;
+ case ADC_SMPR2:
+ return s->adc_smpr2;
+ case ADC_JOFR1:
+ case ADC_JOFR2:
+ case ADC_JOFR3:
+ case ADC_JOFR4:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ return s->adc_jofr[(addr - ADC_JOFR1) / 4];
+ case ADC_HTR:
+ return s->adc_htr;
+ case ADC_LTR:
+ return s->adc_ltr;
+ case ADC_SQR1:
+ return s->adc_sqr1;
+ case ADC_SQR2:
+ return s->adc_sqr2;
+ case ADC_SQR3:
+ return s->adc_sqr3;
+ case ADC_JSQR:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ return s->adc_jsqr;
+ case ADC_JDR1:
+ case ADC_JDR2:
+ case ADC_JDR3:
+ case ADC_JDR4:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ return s->adc_jdr[(addr - ADC_JDR1) / 4] -
+ s->adc_jofr[(addr - ADC_JDR1) / 4];
+ case ADC_DR:
+ if ((s->adc_cr2 & ADC_CR2_ADON) && (s->adc_cr2 & ADC_CR2_SWSTART)) {
+ s->adc_cr2 ^= ADC_CR2_SWSTART;
+ return stm32f2xx_adc_generate_value(s);
+ } else {
+ return 0;
+ }
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_adc_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F2XXADCState *s = opaque;
+ uint32_t value = (uint32_t) val64;
+
+ DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n",
+ addr, value);
+
+ if (addr >= 0x100) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: ADC Common Register Unsupported\n", __func__);
+ }
+
+ switch (addr) {
+ case ADC_SR:
+ s->adc_sr &= (value & 0x3F);
+ break;
+ case ADC_CR1:
+ s->adc_cr1 = value;
+ break;
+ case ADC_CR2:
+ s->adc_cr2 = value;
+ break;
+ case ADC_SMPR1:
+ s->adc_smpr1 = value;
+ break;
+ case ADC_SMPR2:
+ s->adc_smpr2 = value;
+ break;
+ case ADC_JOFR1:
+ case ADC_JOFR2:
+ case ADC_JOFR3:
+ case ADC_JOFR4:
+ s->adc_jofr[(addr - ADC_JOFR1) / 4] = (value & 0xFFF);
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ break;
+ case ADC_HTR:
+ s->adc_htr = value;
+ break;
+ case ADC_LTR:
+ s->adc_ltr = value;
+ break;
+ case ADC_SQR1:
+ s->adc_sqr1 = value;
+ break;
+ case ADC_SQR2:
+ s->adc_sqr2 = value;
+ break;
+ case ADC_SQR3:
+ s->adc_sqr3 = value;
+ break;
+ case ADC_JSQR:
+ s->adc_jsqr = value;
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ break;
+ case ADC_JDR1:
+ case ADC_JDR2:
+ case ADC_JDR3:
+ case ADC_JDR4:
+ s->adc_jdr[(addr - ADC_JDR1) / 4] = value;
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Injection ADC is not implemented, the registers are " \
+ "included for compatibility\n", __func__);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps stm32f2xx_adc_ops = {
+ .read = stm32f2xx_adc_read,
+ .write = stm32f2xx_adc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stm32f2xx_adc = {
+ .name = TYPE_STM32F2XX_ADC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(adc_sr, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_cr1, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_cr2, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_smpr1, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_smpr2, STM32F2XXADCState),
+ VMSTATE_UINT32_ARRAY(adc_jofr, STM32F2XXADCState, 4),
+ VMSTATE_UINT32(adc_htr, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_ltr, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_sqr1, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_sqr2, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_sqr3, STM32F2XXADCState),
+ VMSTATE_UINT32(adc_jsqr, STM32F2XXADCState),
+ VMSTATE_UINT32_ARRAY(adc_jdr, STM32F2XXADCState, 4),
+ VMSTATE_UINT32(adc_dr, STM32F2XXADCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32f2xx_adc_init(Object *obj)
+{
+ STM32F2XXADCState *s = STM32F2XX_ADC(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s,
+ TYPE_STM32F2XX_ADC, 0xFF);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f2xx_adc_reset;
+ dc->vmsd = &vmstate_stm32f2xx_adc;
+}
+
+static const TypeInfo stm32f2xx_adc_info = {
+ .name = TYPE_STM32F2XX_ADC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F2XXADCState),
+ .instance_init = stm32f2xx_adc_init,
+ .class_init = stm32f2xx_adc_class_init,
+};
+
+static void stm32f2xx_adc_register_types(void)
+{
+ type_register_static(&stm32f2xx_adc_info);
+}
+
+type_init(stm32f2xx_adc_register_types)
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 96dc150025..039812a3fd 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -252,6 +252,26 @@ static void integratorcm_init(Object *obj)
/* ??? What should the high bits of this value be? */
s->cm_auxosc = 0x0007feff;
s->cm_sdram = 0x00011122;
+ memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
+ s->cm_init = 0x00000112;
+ s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
+ 1000);
+ memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
+ &error_fatal);
+ vmstate_register_ram_global(&s->flash);
+
+ memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
+ "integratorcm", 0x00800000);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ integratorcm_do_remap(s);
+ /* ??? Save/restore. */
+}
+
+static void integratorcm_realize(DeviceState *d, Error **errp)
+{
+ IntegratorCMState *s = INTEGRATOR_CM(d);
+
if (s->memsz >= 256) {
integrator_spd[31] = 64;
s->cm_sdram |= 0x10;
@@ -267,20 +287,6 @@ static void integratorcm_init(Object *obj)
} else {
integrator_spd[31] = 2;
}
- memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
- s->cm_init = 0x00000112;
- s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
- 1000);
- memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
- &error_fatal);
- vmstate_register_ram_global(&s->flash);
-
- memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
- "integratorcm", 0x00800000);
- sysbus_init_mmio(dev, &s->iomem);
-
- integratorcm_do_remap(s);
- /* ??? Save/restore. */
}
/* Integrator/CP hardware emulation. */
@@ -633,6 +639,7 @@ static void core_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = core_properties;
+ dc->realize = integratorcm_realize;
}
static const TypeInfo core_info = {
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index 454acc5d2b..f962236cf4 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -73,8 +73,10 @@ static const struct keymap map[0xE0] = {
[0x2f] = {3,3}, /* v */
[0x11] = {3,4}, /* w */
[0x2d] = {3,5}, /* x */
+ [0x34] = {4,0}, /* . */
[0x15] = {4,2}, /* y */
[0x2c] = {4,3}, /* z */
+ [0x35] = {4,4}, /* / */
[0xc7] = {5,0}, /* Home */
[0x2a] = {5,1}, /* shift */
/*
@@ -88,7 +90,8 @@ static const struct keymap map[0xE0] = {
* Matrix position {5,4} and other keys are missing here.
* TODO: Compare with Linux code and test real hardware.
*/
- [0x1c] = {5,5}, /* enter (TODO: might be wrong) */
+ [0x1c] = {5,4}, /* enter */
+ [0x0e] = {5,5}, /* backspace */
[0xc8] = {6,0}, /* up */
[0xd0] = {6,1}, /* down */
[0xcb] = {6,2}, /* left */
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index de26b8caff..38425bda6c 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -34,9 +34,15 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
0x40000800, 0x40000C00 };
static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
+static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
+ 0x40012200 };
+static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800,
+ 0x40003C00 };
static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
+#define ADC_IRQ 18
+static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51};
static void stm32f205_soc_initfn(Object *obj)
{
@@ -57,13 +63,27 @@ static void stm32f205_soc_initfn(Object *obj)
TYPE_STM32F2XX_TIMER);
qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
}
+
+ s->adc_irqs = OR_IRQ(object_new(TYPE_OR_IRQ));
+
+ for (i = 0; i < STM_NUM_ADCS; i++) {
+ object_initialize(&s->adc[i], sizeof(s->adc[i]),
+ TYPE_STM32F2XX_ADC);
+ qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < STM_NUM_SPIS; i++) {
+ object_initialize(&s->spi[i], sizeof(s->spi[i]),
+ TYPE_STM32F2XX_SPI);
+ qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
+ }
}
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
{
STM32F205State *s = STM32F205_SOC(dev_soc);
- DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
- SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
+ DeviceState *dev, *nvic;
+ SysBusDevice *busdev;
Error *err = NULL;
int i;
@@ -94,44 +114,80 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
s->kernel_filename, s->cpu_model);
/* System configuration controller */
- syscfgdev = DEVICE(&s->syscfg);
+ dev = DEVICE(&s->syscfg);
object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
- syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
- sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
- sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71));
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, 0x40013800);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, 71));
/* Attach UART (uses USART registers) and USART controllers */
for (i = 0; i < STM_NUM_USARTS; i++) {
- usartdev = DEVICE(&(s->usart[i]));
- qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
+ dev = DEVICE(&(s->usart[i]));
+ qdev_prop_set_chr(dev, "chardev",
+ i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
- usartbusdev = SYS_BUS_DEVICE(usartdev);
- sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
- sysbus_connect_irq(usartbusdev, 0,
- qdev_get_gpio_in(nvic, usart_irq[i]));
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, usart_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, usart_irq[i]));
}
/* Timer 2 to 5 */
for (i = 0; i < STM_NUM_TIMERS; i++) {
- timerdev = DEVICE(&(s->timer[i]));
- qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
+ dev = DEVICE(&(s->timer[i]));
+ qdev_prop_set_uint64(dev, "clock-frequency", 1000000000);
object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
- timerbusdev = SYS_BUS_DEVICE(timerdev);
- sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
- sysbus_connect_irq(timerbusdev, 0,
- qdev_get_gpio_in(nvic, timer_irq[i]));
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, timer_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
+ }
+
+ /* ADC 1 to 3 */
+ object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS,
+ "num-lines", &err);
+ object_property_set_bool(OBJECT(s->adc_irqs), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(s->adc_irqs), 0,
+ qdev_get_gpio_in(nvic, ADC_IRQ));
+
+ for (i = 0; i < STM_NUM_ADCS; i++) {
+ dev = DEVICE(&(s->adc[i]));
+ object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, adc_addr[i]);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(DEVICE(s->adc_irqs), i));
+ }
+
+ /* SPI 1 and 2 */
+ for (i = 0; i < STM_NUM_SPIS; i++) {
+ dev = DEVICE(&(s->spi[i]));
+ object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, spi_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, spi_irq[i]));
}
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 295ec86828..7b39b1d2d6 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -44,6 +44,7 @@
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
#include "sysemu/numa.h"
+#include "kvm_arm.h"
#define ARM_SPI_BASE 32
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
@@ -546,6 +547,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
}
if (guest_info->gic_version == 3) {
+ AcpiMadtGenericTranslator *gic_its;
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
sizeof *gicr);
@@ -553,6 +555,16 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
gicr->length = sizeof(*gicr);
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
+
+ if (!its_class_name()) {
+ return;
+ }
+
+ gic_its = acpi_data_push(table_data, sizeof *gic_its);
+ gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR;
+ gic_its->length = sizeof(*gic_its);
+ gic_its->translation_id = 0;
+ gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base);
} else {
gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a193b5a95b..0f6305d3c7 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -76,7 +76,7 @@ typedef struct VirtBoardInfo {
int fdt_size;
uint32_t clock_phandle;
uint32_t gic_phandle;
- uint32_t v2m_phandle;
+ uint32_t msi_phandle;
bool using_psci;
} VirtBoardInfo;
@@ -423,9 +423,22 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
}
}
+static void fdt_add_its_gic_node(VirtBoardInfo *vbi)
+{
+ vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+ qemu_fdt_add_subnode(vbi->fdt, "/intc/its");
+ qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible",
+ "arm,gic-v3-its");
+ qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0);
+ qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg",
+ 2, vbi->memmap[VIRT_GIC_ITS].base,
+ 2, vbi->memmap[VIRT_GIC_ITS].size);
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle);
+}
+
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
{
- vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+ vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
"arm,gic-v2m-frame");
@@ -433,7 +446,7 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
2, vbi->memmap[VIRT_GIC_V2M].base,
2, vbi->memmap[VIRT_GIC_V2M].size);
- qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle);
}
static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
@@ -500,6 +513,26 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
}
}
+static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev)
+{
+ const char *itsclass = its_class_name();
+ DeviceState *dev;
+
+ if (!itsclass) {
+ /* Do nothing if not supported */
+ return;
+ }
+
+ dev = qdev_create(NULL, itsclass);
+
+ object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3",
+ &error_abort);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base);
+
+ fdt_add_its_gic_node(vbi);
+}
+
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
{
int i;
@@ -583,7 +616,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
fdt_add_gic_node(vbi, type);
- if (type == 2) {
+ if (type == 3) {
+ create_its(vbi, gicdev);
+ } else {
create_v2m(vbi, pic);
}
}
@@ -1025,9 +1060,9 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
nr_pcie_buses - 1);
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
- if (vbi->v2m_phandle) {
+ if (vbi->msi_phandle) {
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
- vbi->v2m_phandle);
+ vbi->msi_phandle);
}
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
@@ -1479,7 +1514,7 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
-static void virt_2_7_instance_init(Object *obj)
+static void virt_2_8_instance_init(Object *obj)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -1512,10 +1547,25 @@ static void virt_2_7_instance_init(Object *obj)
"Valid values are 2, 3 and host", NULL);
}
+static void virt_machine_2_8_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(2, 8)
+
+#define VIRT_COMPAT_2_7 \
+ HW_COMPAT_2_7
+
+static void virt_2_7_instance_init(Object *obj)
+{
+ virt_2_8_instance_init(obj);
+}
+
static void virt_machine_2_7_options(MachineClass *mc)
{
+ virt_machine_2_8_options(mc);
+ SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(2, 7)
+DEFINE_VIRT_MACHINE(2, 7)
#define VIRT_COMPAT_2_6 \
HW_COMPAT_2_6
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index cfd4840397..a4c94e522d 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -16,4 +16,7 @@ common-obj-$(CONFIG_SOFTMMU) += null-machine.o
common-obj-$(CONFIG_SOFTMMU) += loader.o
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
common-obj-$(CONFIG_SOFTMMU) += register.o
+common-obj-$(CONFIG_SOFTMMU) += or-irq.o
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
+
+obj-$(CONFIG_SOFTMMU) += generic-loader.o
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
new file mode 100644
index 0000000000..79ab6df357
--- /dev/null
+++ b/hw/core/generic-loader.c
@@ -0,0 +1,211 @@
+/*
+ * Generic Loader
+ *
+ * Copyright (C) 2014 Li Guang
+ * Copyright (C) 2016 Xilinx Inc.
+ * Written by Li Guang <lig.fnst@cn.fujitsu.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.
+ *
+ */
+
+/*
+ * Internally inside QEMU this is a device. It is a strange device that
+ * provides no hardware interface but allows QEMU to monkey patch memory
+ * specified when it is created. To be able to do this it has a reset
+ * callback that does the memory operations.
+
+ * This device allows the user to monkey patch memory. To be able to do
+ * this it needs a backend to manage the datas, the same as other
+ * memory-related devices. In this case as the backend is so trivial we
+ * have merged it with the frontend instead of creating and maintaining a
+ * seperate backend.
+ */
+
+#include "qemu/osdep.h"
+#include "qom/cpu.h"
+#include "hw/sysbus.h"
+#include "sysemu/dma.h"
+#include "hw/loader.h"
+#include "qapi/error.h"
+#include "hw/core/generic-loader.h"
+
+#define CPU_NONE 0xFFFFFFFF
+
+static void generic_loader_reset(void *opaque)
+{
+ GenericLoaderState *s = GENERIC_LOADER(opaque);
+
+ if (s->set_pc) {
+ CPUClass *cc = CPU_GET_CLASS(s->cpu);
+ cpu_reset(s->cpu);
+ if (cc) {
+ cc->set_pc(s->cpu, s->addr);
+ }
+ }
+
+ if (s->data_len) {
+ assert(s->data_len < sizeof(s->data));
+ dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len);
+ }
+}
+
+static void generic_loader_realize(DeviceState *dev, Error **errp)
+{
+ GenericLoaderState *s = GENERIC_LOADER(dev);
+ hwaddr entry;
+ int big_endian;
+ int size = 0;
+
+ s->set_pc = false;
+
+ /* Perform some error checking on the user's options */
+ if (s->data || s->data_len || s->data_be) {
+ /* User is loading memory values */
+ if (s->file) {
+ error_setg(errp, "Specifying a file is not supported when loading "
+ "memory values");
+ return;
+ } else if (s->force_raw) {
+ error_setg(errp, "Specifying force-raw is not supported when "
+ "loading memory values");
+ return;
+ } else if (!s->data_len) {
+ /* We cant' check for !data here as a value of 0 is still valid. */
+ error_setg(errp, "Both data and data-len must be specified");
+ return;
+ } else if (s->data_len > 8) {
+ error_setg(errp, "data-len cannot be greater then 8 bytes");
+ return;
+ }
+ } else if (s->file || s->force_raw) {
+ /* User is loading an image */
+ if (s->data || s->data_len || s->data_be) {
+ error_setg(errp, "data can not be specified when loading an "
+ "image");
+ return;
+ }
+ s->set_pc = true;
+ } else if (s->addr) {
+ /* User is setting the PC */
+ if (s->data || s->data_len || s->data_be) {
+ error_setg(errp, "data can not be specified when setting a "
+ "program counter");
+ return;
+ } else if (!s->cpu_num) {
+ error_setg(errp, "cpu_num must be specified when setting a "
+ "program counter");
+ return;
+ }
+ s->set_pc = true;
+ } else {
+ /* Did the user specify anything? */
+ error_setg(errp, "please include valid arguments");
+ return;
+ }
+
+ qemu_register_reset(generic_loader_reset, dev);
+
+ if (s->cpu_num != CPU_NONE) {
+ s->cpu = qemu_get_cpu(s->cpu_num);
+ if (!s->cpu) {
+ error_setg(errp, "Specified boot CPU#%d is nonexistent",
+ s->cpu_num);
+ return;
+ }
+ } else {
+ s->cpu = first_cpu;
+ }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
+
+ if (s->file) {
+ if (!s->force_raw) {
+ size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL,
+ big_endian, 0, 0, 0, s->cpu->as);
+
+ if (size < 0) {
+ size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
+ s->cpu->as);
+ }
+ }
+
+ if (size < 0 || s->force_raw) {
+ /* Default to the maximum size being the machine's ram size */
+ size = load_image_targphys_as(s->file, s->addr, ram_size,
+ s->cpu->as);
+ } else {
+ s->addr = entry;
+ }
+
+ if (size < 0) {
+ error_setg(errp, "Cannot load specified image %s", s->file);
+ return;
+ }
+ }
+
+ /* Convert the data endiannes */
+ if (s->data_be) {
+ s->data = cpu_to_be64(s->data);
+ } else {
+ s->data = cpu_to_le64(s->data);
+ }
+}
+
+static void generic_loader_unrealize(DeviceState *dev, Error **errp)
+{
+ qemu_unregister_reset(generic_loader_reset, dev);
+}
+
+static Property generic_loader_props[] = {
+ DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
+ DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
+ DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
+ DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false),
+ DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
+ DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
+ DEFINE_PROP_STRING("file", GenericLoaderState, file),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void generic_loader_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ /* The reset function is not registered here and is instead registered in
+ * the realize function to allow this device to be added via the device_add
+ * command in the QEMU monitor.
+ * TODO: Improve the device_add functionality to allow resets to be
+ * connected
+ */
+ dc->realize = generic_loader_realize;
+ dc->unrealize = generic_loader_unrealize;
+ dc->props = generic_loader_props;
+ dc->desc = "Generic Loader";
+}
+
+static TypeInfo generic_loader_info = {
+ .name = TYPE_GENERIC_LOADER,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(GenericLoaderState),
+ .class_init = generic_loader_class_init,
+};
+
+static void generic_loader_register_type(void)
+{
+ type_register_static(&generic_loader_info);
+}
+
+type_init(generic_loader_register_type)
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
new file mode 100644
index 0000000000..1ac090d1a4
--- /dev/null
+++ b/hw/core/or-irq.c
@@ -0,0 +1,107 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/or-irq.h"
+
+static void or_irq_handler(void *opaque, int n, int level)
+{
+ qemu_or_irq *s = OR_IRQ(opaque);
+ int or_level = 0;
+ int i;
+
+ s->levels[n] = level;
+
+ for (i = 0; i < s->num_lines; i++) {
+ or_level |= s->levels[i];
+ }
+
+ qemu_set_irq(s->out_irq, or_level);
+}
+
+static void or_irq_reset(DeviceState *dev)
+{
+ qemu_or_irq *s = OR_IRQ(dev);
+ int i;
+
+ for (i = 0; i < MAX_OR_LINES; i++) {
+ s->levels[i] = false;
+ }
+}
+
+static void or_irq_realize(DeviceState *dev, Error **errp)
+{
+ qemu_or_irq *s = OR_IRQ(dev);
+
+ assert(s->num_lines < MAX_OR_LINES);
+
+ qdev_init_gpio_in(dev, or_irq_handler, s->num_lines);
+}
+
+static void or_irq_init(Object *obj)
+{
+ qemu_or_irq *s = OR_IRQ(obj);
+
+ qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
+}
+
+static const VMStateDescription vmstate_or_irq = {
+ .name = TYPE_OR_IRQ,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static Property or_irq_properties[] = {
+ DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void or_irq_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = or_irq_reset;
+ dc->props = or_irq_properties;
+ dc->realize = or_irq_realize;
+ dc->vmsd = &vmstate_or_irq;
+}
+
+static const TypeInfo or_irq_type_info = {
+ .name = TYPE_OR_IRQ,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(qemu_or_irq),
+ .instance_init = or_irq_init,
+ .class_init = or_irq_class_init,
+};
+
+static void or_irq_register_types(void)
+{
+ type_register_static(&or_irq_type_info);
+}
+
+type_init(or_irq_register_types)
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index 2f2576fafb..17c8518fea 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -616,34 +616,9 @@ static void rc4030_reset(DeviceState *dev)
qemu_irq_lower(s->jazz_bus_irq);
}
-static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
+static int rc4030_post_load(void *opaque, int version_id)
{
rc4030State* s = opaque;
- int i, j;
-
- if (version_id != 2)
- return -EINVAL;
-
- s->config = qemu_get_be32(f);
- s->invalid_address_register = qemu_get_be32(f);
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- s->dma_regs[i][j] = qemu_get_be32(f);
- s->dma_tl_base = qemu_get_be32(f);
- s->dma_tl_limit = qemu_get_be32(f);
- s->cache_maint = qemu_get_be32(f);
- s->remote_failed_address = qemu_get_be32(f);
- s->memory_failed_address = qemu_get_be32(f);
- s->cache_ptag = qemu_get_be32(f);
- s->cache_ltag = qemu_get_be32(f);
- s->cache_bmask = qemu_get_be32(f);
- s->memory_refresh_rate = qemu_get_be32(f);
- s->nvram_protect = qemu_get_be32(f);
- for (i = 0; i < 15; i++)
- s->rem_speed[i] = qemu_get_be32(f);
- s->imr_jazz = qemu_get_be32(f);
- s->isr_jazz = qemu_get_be32(f);
- s->itr = qemu_get_be32(f);
set_next_tick(s);
update_jazz_irq(s);
@@ -651,32 +626,31 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static void rc4030_save(QEMUFile *f, void *opaque)
-{
- rc4030State* s = opaque;
- int i, j;
-
- qemu_put_be32(f, s->config);
- qemu_put_be32(f, s->invalid_address_register);
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- qemu_put_be32(f, s->dma_regs[i][j]);
- qemu_put_be32(f, s->dma_tl_base);
- qemu_put_be32(f, s->dma_tl_limit);
- qemu_put_be32(f, s->cache_maint);
- qemu_put_be32(f, s->remote_failed_address);
- qemu_put_be32(f, s->memory_failed_address);
- qemu_put_be32(f, s->cache_ptag);
- qemu_put_be32(f, s->cache_ltag);
- qemu_put_be32(f, s->cache_bmask);
- qemu_put_be32(f, s->memory_refresh_rate);
- qemu_put_be32(f, s->nvram_protect);
- for (i = 0; i < 15; i++)
- qemu_put_be32(f, s->rem_speed[i]);
- qemu_put_be32(f, s->imr_jazz);
- qemu_put_be32(f, s->isr_jazz);
- qemu_put_be32(f, s->itr);
-}
+static const VMStateDescription vmstate_rc4030 = {
+ .name = "rc4030",
+ .version_id = 3,
+ .post_load = rc4030_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(config, rc4030State),
+ VMSTATE_UINT32(invalid_address_register, rc4030State),
+ VMSTATE_UINT32_2DARRAY(dma_regs, rc4030State, 8, 4),
+ VMSTATE_UINT32(dma_tl_base, rc4030State),
+ VMSTATE_UINT32(dma_tl_limit, rc4030State),
+ VMSTATE_UINT32(cache_maint, rc4030State),
+ VMSTATE_UINT32(remote_failed_address, rc4030State),
+ VMSTATE_UINT32(memory_failed_address, rc4030State),
+ VMSTATE_UINT32(cache_ptag, rc4030State),
+ VMSTATE_UINT32(cache_ltag, rc4030State),
+ VMSTATE_UINT32(cache_bmask, rc4030State),
+ VMSTATE_UINT32(memory_refresh_rate, rc4030State),
+ VMSTATE_UINT32(nvram_protect, rc4030State),
+ VMSTATE_UINT32_ARRAY(rem_speed, rc4030State, 16),
+ VMSTATE_UINT32(imr_jazz, rc4030State),
+ VMSTATE_UINT32(isr_jazz, rc4030State),
+ VMSTATE_UINT32(itr, rc4030State),
+ VMSTATE_END_OF_LIST()
+ }
+};
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
{
@@ -753,8 +727,6 @@ static void rc4030_initfn(Object *obj)
sysbus_init_irq(sysbus, &s->timer_irq);
sysbus_init_irq(sysbus, &s->jazz_bus_irq);
- register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
-
sysbus_init_mmio(sysbus, &s->iomem_chipset);
sysbus_init_mmio(sysbus, &s->iomem_jazzio);
}
@@ -813,6 +785,7 @@ static void rc4030_class_init(ObjectClass *klass, void *class_data)
dc->realize = rc4030_realize;
dc->unrealize = rc4030_unrealize;
dc->reset = rc4030_reset;
+ dc->vmsd = &vmstate_rc4030;
}
static const TypeInfo rc4030_info = {
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index aa7839324c..f85635cc9a 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -134,8 +134,6 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
devices, and bit 2 the non-primary-master IDE devices. */
if (val & UNPLUG_ALL_IDE_DISKS) {
DPRINTF("unplug disks\n");
- blk_drain_all();
- blk_flush_all();
pci_unplug_disks(pci_dev->bus);
}
if (val & UNPLUG_ALL_NICS) {
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index c190fcaa3c..d5777fd0b3 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -179,6 +179,10 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
if (di != NULL && !di->media_cd) {
BlockBackend *blk = blk_by_legacy_dinfo(di);
DeviceState *ds = blk_get_attached_dev(blk);
+
+ blk_drain(blk);
+ blk_flush(blk);
+
if (ds) {
blk_detach_dev(blk, ds);
}
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
index 9b359aaec0..eb5320af40 100644
--- a/hw/input/tsc2005.c
+++ b/hw/input/tsc2005.c
@@ -31,30 +31,31 @@ typedef struct {
QEMUTimer *timer;
uint16_t model;
- int x, y;
- int pressure;
+ int32_t x, y;
+ bool pressure;
- int state, reg, irq, command;
+ uint8_t reg, state;
+ bool irq, command;
uint16_t data, dav;
- int busy;
- int enabled;
- int host_mode;
- int function;
- int nextfunction;
- int precision;
- int nextprecision;
- int filter;
- int pin_func;
- int timing[2];
- int noise;
- int reset;
- int pdst;
- int pnd0;
+ bool busy;
+ bool enabled;
+ bool host_mode;
+ int8_t function;
+ int8_t nextfunction;
+ bool precision;
+ bool nextprecision;
+ uint16_t filter;
+ uint8_t pin_func;
+ uint16_t timing[2];
+ uint8_t noise;
+ bool reset;
+ bool pdst;
+ bool pnd0;
uint16_t temp_thr[2];
uint16_t aux_thr[2];
- int tr[8];
+ int32_t tr[8];
} TSC2005State;
enum {
@@ -149,7 +150,7 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg)
ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
mode_regs[TSC_MODE_TS_TEST]);
- s->reset = 1;
+ s->reset = true;
return ret;
case 0x8: /* AUX high treshold */
@@ -196,14 +197,14 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
break;
case 0xc: /* CFR0 */
- s->host_mode = data >> 15;
+ s->host_mode = (data >> 15) != 0;
if (s->enabled != !(data & 0x4000)) {
s->enabled = !(data & 0x4000);
fprintf(stderr, "%s: touchscreen sense %sabled\n",
__FUNCTION__, s->enabled ? "en" : "dis");
if (s->busy && !s->enabled)
timer_del(s->timer);
- s->busy &= s->enabled;
+ s->busy = s->busy && s->enabled;
}
s->nextprecision = (data >> 13) & 1;
s->timing[0] = data & 0x1fff;
@@ -229,7 +230,7 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
static void tsc2005_pin_update(TSC2005State *s)
{
int64_t expires;
- int pin_state;
+ bool pin_state;
switch (s->pin_func) {
case 0:
@@ -253,7 +254,7 @@ static void tsc2005_pin_update(TSC2005State *s)
case TSC_MODE_XYZ_SCAN:
case TSC_MODE_XY_SCAN:
if (!s->host_mode && s->dav)
- s->enabled = 0;
+ s->enabled = false;
if (!s->pressure)
return;
/* Fall through */
@@ -273,7 +274,7 @@ static void tsc2005_pin_update(TSC2005State *s)
case TSC_MODE_Y_TEST:
case TSC_MODE_TS_TEST:
if (s->dav)
- s->enabled = 0;
+ s->enabled = false;
break;
case TSC_MODE_RESERVED:
@@ -287,7 +288,7 @@ static void tsc2005_pin_update(TSC2005State *s)
if (!s->enabled || s->busy)
return;
- s->busy = 1;
+ s->busy = true;
s->precision = s->nextprecision;
s->function = s->nextfunction;
s->pdst = !s->pnd0; /* Synchronised on internal clock */
@@ -300,17 +301,17 @@ static void tsc2005_reset(TSC2005State *s)
{
s->state = 0;
s->pin_func = 0;
- s->enabled = 0;
- s->busy = 0;
- s->nextprecision = 0;
+ s->enabled = false;
+ s->busy = false;
+ s->nextprecision = false;
s->nextfunction = 0;
s->timing[0] = 0;
s->timing[1] = 0;
- s->irq = 0;
+ s->irq = false;
s->dav = 0;
- s->reset = 0;
- s->pdst = 1;
- s->pnd0 = 0;
+ s->reset = false;
+ s->pdst = true;
+ s->pnd0 = false;
s->function = -1;
s->temp_thr[0] = 0x000;
s->temp_thr[1] = 0xfff;
@@ -340,7 +341,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
__FUNCTION__, s->enabled ? "en" : "dis");
if (s->busy && !s->enabled)
timer_del(s->timer);
- s->busy &= s->enabled;
+ s->busy = s->busy && s->enabled;
}
tsc2005_pin_update(s);
}
@@ -407,7 +408,7 @@ static void tsc2005_timer_tick(void *opaque)
if (!s->busy)
return;
- s->busy = 0;
+ s->busy = false;
s->dav |= mode_regs[s->function];
s->function = -1;
tsc2005_pin_update(s);
@@ -434,86 +435,9 @@ static void tsc2005_touchscreen_event(void *opaque,
tsc2005_pin_update(s);
}
-static void tsc2005_save(QEMUFile *f, void *opaque)
+static int tsc2005_post_load(void *opaque, int version_id)
{
TSC2005State *s = (TSC2005State *) opaque;
- int i;
-
- qemu_put_be16(f, s->x);
- qemu_put_be16(f, s->y);
- qemu_put_byte(f, s->pressure);
-
- qemu_put_byte(f, s->state);
- qemu_put_byte(f, s->reg);
- qemu_put_byte(f, s->command);
-
- qemu_put_byte(f, s->irq);
- qemu_put_be16s(f, &s->dav);
- qemu_put_be16s(f, &s->data);
-
- timer_put(f, s->timer);
- qemu_put_byte(f, s->enabled);
- qemu_put_byte(f, s->host_mode);
- qemu_put_byte(f, s->function);
- qemu_put_byte(f, s->nextfunction);
- qemu_put_byte(f, s->precision);
- qemu_put_byte(f, s->nextprecision);
- qemu_put_be16(f, s->filter);
- qemu_put_byte(f, s->pin_func);
- qemu_put_be16(f, s->timing[0]);
- qemu_put_be16(f, s->timing[1]);
- qemu_put_be16s(f, &s->temp_thr[0]);
- qemu_put_be16s(f, &s->temp_thr[1]);
- qemu_put_be16s(f, &s->aux_thr[0]);
- qemu_put_be16s(f, &s->aux_thr[1]);
- qemu_put_be32(f, s->noise);
- qemu_put_byte(f, s->reset);
- qemu_put_byte(f, s->pdst);
- qemu_put_byte(f, s->pnd0);
-
- for (i = 0; i < 8; i ++)
- qemu_put_be32(f, s->tr[i]);
-}
-
-static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
-{
- TSC2005State *s = (TSC2005State *) opaque;
- int i;
-
- s->x = qemu_get_be16(f);
- s->y = qemu_get_be16(f);
- s->pressure = qemu_get_byte(f);
-
- s->state = qemu_get_byte(f);
- s->reg = qemu_get_byte(f);
- s->command = qemu_get_byte(f);
-
- s->irq = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dav);
- qemu_get_be16s(f, &s->data);
-
- timer_get(f, s->timer);
- s->enabled = qemu_get_byte(f);
- s->host_mode = qemu_get_byte(f);
- s->function = qemu_get_byte(f);
- s->nextfunction = qemu_get_byte(f);
- s->precision = qemu_get_byte(f);
- s->nextprecision = qemu_get_byte(f);
- s->filter = qemu_get_be16(f);
- s->pin_func = qemu_get_byte(f);
- s->timing[0] = qemu_get_be16(f);
- s->timing[1] = qemu_get_be16(f);
- qemu_get_be16s(f, &s->temp_thr[0]);
- qemu_get_be16s(f, &s->temp_thr[1]);
- qemu_get_be16s(f, &s->aux_thr[0]);
- qemu_get_be16s(f, &s->aux_thr[1]);
- s->noise = qemu_get_be32(f);
- s->reset = qemu_get_byte(f);
- s->pdst = qemu_get_byte(f);
- s->pnd0 = qemu_get_byte(f);
-
- for (i = 0; i < 8; i ++)
- s->tr[i] = qemu_get_be32(f);
s->busy = timer_pending(s->timer);
tsc2005_pin_update(s);
@@ -521,6 +445,42 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static const VMStateDescription vmstate_tsc2005 = {
+ .name = "tsc2005",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .post_load = tsc2005_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_BOOL(pressure, TSC2005State),
+ VMSTATE_BOOL(irq, TSC2005State),
+ VMSTATE_BOOL(command, TSC2005State),
+ VMSTATE_BOOL(enabled, TSC2005State),
+ VMSTATE_BOOL(host_mode, TSC2005State),
+ VMSTATE_BOOL(reset, TSC2005State),
+ VMSTATE_BOOL(pdst, TSC2005State),
+ VMSTATE_BOOL(pnd0, TSC2005State),
+ VMSTATE_BOOL(precision, TSC2005State),
+ VMSTATE_BOOL(nextprecision, TSC2005State),
+ VMSTATE_UINT8(reg, TSC2005State),
+ VMSTATE_UINT8(state, TSC2005State),
+ VMSTATE_UINT16(data, TSC2005State),
+ VMSTATE_UINT16(dav, TSC2005State),
+ VMSTATE_UINT16(filter, TSC2005State),
+ VMSTATE_INT8(nextfunction, TSC2005State),
+ VMSTATE_INT8(function, TSC2005State),
+ VMSTATE_INT32(x, TSC2005State),
+ VMSTATE_INT32(y, TSC2005State),
+ VMSTATE_TIMER_PTR(timer, TSC2005State),
+ VMSTATE_UINT8(pin_func, TSC2005State),
+ VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
+ VMSTATE_UINT8(noise, TSC2005State),
+ VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
+ VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
+ VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
void *tsc2005_init(qemu_irq pintdav)
{
TSC2005State *s;
@@ -529,8 +489,8 @@ void *tsc2005_init(qemu_irq pintdav)
g_malloc0(sizeof(TSC2005State));
s->x = 400;
s->y = 240;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
+ s->pressure = false;
+ s->precision = s->nextprecision = false;
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
s->pint = pintdav;
s->model = 0x2005;
@@ -550,7 +510,7 @@ void *tsc2005_init(qemu_irq pintdav)
"QEMU TSC2005-driven Touchscreen");
qemu_register_reset((void *) tsc2005_reset, s);
- register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
+ vmstate_register(NULL, 0, &vmstate_tsc2005, s);
return s;
}
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
index 93ca374fcd..b068343771 100644
--- a/hw/input/tsc210x.c
+++ b/hw/input/tsc210x.c
@@ -47,24 +47,25 @@ typedef struct {
uint8_t out_fifo[16384];
uint16_t model;
- int x, y;
- int pressure;
-
- int state, page, offset, irq;
- uint16_t command, dav;
-
- int busy;
- int enabled;
- int host_mode;
- int function;
- int nextfunction;
- int precision;
- int nextprecision;
- int filter;
- int pin_func;
- int ref;
- int timing;
- int noise;
+ int32_t x, y;
+ bool pressure;
+
+ uint8_t page, offset;
+ uint16_t dav;
+
+ bool state;
+ bool irq;
+ bool command;
+ bool busy;
+ bool enabled;
+ bool host_mode;
+ uint8_t function, nextfunction;
+ uint8_t precision, nextprecision;
+ uint8_t filter;
+ uint8_t pin_func;
+ uint8_t ref;
+ uint8_t timing;
+ uint8_t noise;
uint16_t audio_ctrl1;
uint16_t audio_ctrl2;
@@ -72,7 +73,7 @@ typedef struct {
uint16_t pll[3];
uint16_t volume;
int64_t volume_change;
- int softstep;
+ bool softstep;
uint16_t dac_power;
int64_t powerdown;
uint16_t filter_data[0x14];
@@ -93,6 +94,7 @@ typedef struct {
int mode;
int intr;
} kb;
+ int64_t now; /* Time at migration */
} TSC210xState;
static const int resolution[4] = { 12, 8, 10, 12 };
@@ -154,14 +156,14 @@ static const uint16_t mode_regs[16] = {
static void tsc210x_reset(TSC210xState *s)
{
- s->state = 0;
+ s->state = false;
s->pin_func = 2;
- s->enabled = 0;
- s->busy = 0;
+ s->enabled = false;
+ s->busy = false;
s->nextfunction = 0;
s->ref = 0;
s->timing = 0;
- s->irq = 0;
+ s->irq = false;
s->dav = 0;
s->audio_ctrl1 = 0x0000;
@@ -172,7 +174,7 @@ static void tsc210x_reset(TSC210xState *s)
s->pll[2] = 0x1fff;
s->volume = 0xffff;
s->dac_power = 0x8540;
- s->softstep = 1;
+ s->softstep = true;
s->volume_change = 0;
s->powerdown = 0;
s->filter_data[0x00] = 0x6be3;
@@ -566,7 +568,7 @@ static void tsc2102_control_register_write(
s->enabled = !(value & 0x4000);
if (s->busy && !s->enabled)
timer_del(s->timer);
- s->busy &= s->enabled;
+ s->busy = s->busy && s->enabled;
s->nextfunction = (value >> 10) & 0xf;
s->nextprecision = (value >> 8) & 3;
s->filter = value & 0xff;
@@ -773,7 +775,7 @@ static void tsc2102_audio_register_write(
static void tsc210x_pin_update(TSC210xState *s)
{
int64_t expires;
- int pin_state;
+ bool pin_state;
switch (s->pin_func) {
case 0:
@@ -788,7 +790,7 @@ static void tsc210x_pin_update(TSC210xState *s)
}
if (!s->enabled)
- pin_state = 0;
+ pin_state = false;
if (pin_state != s->irq) {
s->irq = pin_state;
@@ -814,7 +816,7 @@ static void tsc210x_pin_update(TSC210xState *s)
case TSC_MODE_TEMP1:
case TSC_MODE_TEMP2:
if (s->dav)
- s->enabled = 0;
+ s->enabled = false;
break;
case TSC_MODE_AUX_SCAN:
@@ -832,7 +834,7 @@ static void tsc210x_pin_update(TSC210xState *s)
if (!s->enabled || s->busy || s->dav)
return;
- s->busy = 1;
+ s->busy = true;
s->precision = s->nextprecision;
s->function = s->nextfunction;
expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
@@ -867,7 +869,7 @@ static uint16_t tsc210x_read(TSC210xState *s)
/* Allow sequential reads. */
s->offset ++;
- s->state = 0;
+ s->state = false;
return ret;
}
@@ -878,10 +880,10 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
* command and data every second time.
*/
if (!s->state) {
- s->command = value >> 15;
+ s->command = (value >> 15) != 0;
s->page = (value >> 11) & 0x0f;
s->offset = (value >> 5) & 0x3f;
- s->state = 1;
+ s->state = true;
} else {
if (s->command)
fprintf(stderr, "tsc210x_write: SPI overrun!\n");
@@ -901,7 +903,7 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
}
tsc210x_pin_update(s);
- s->state = 0;
+ s->state = false;
}
}
@@ -933,7 +935,7 @@ static void tsc210x_timer_tick(void *opaque)
if (!s->busy)
return;
- s->busy = 0;
+ s->busy = false;
s->dav |= mode_regs[s->function];
tsc210x_pin_update(s);
qemu_irq_lower(s->davint);
@@ -974,108 +976,34 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
s->i2s_rx_rate = in;
}
-static void tsc210x_save(QEMUFile *f, void *opaque)
+static void tsc210x_pre_save(void *opaque)
{
TSC210xState *s = (TSC210xState *) opaque;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int i;
-
- qemu_put_be16(f, s->x);
- qemu_put_be16(f, s->y);
- qemu_put_byte(f, s->pressure);
-
- qemu_put_byte(f, s->state);
- qemu_put_byte(f, s->page);
- qemu_put_byte(f, s->offset);
- qemu_put_byte(f, s->command);
-
- qemu_put_byte(f, s->irq);
- qemu_put_be16s(f, &s->dav);
-
- timer_put(f, s->timer);
- qemu_put_byte(f, s->enabled);
- qemu_put_byte(f, s->host_mode);
- qemu_put_byte(f, s->function);
- qemu_put_byte(f, s->nextfunction);
- qemu_put_byte(f, s->precision);
- qemu_put_byte(f, s->nextprecision);
- qemu_put_byte(f, s->filter);
- qemu_put_byte(f, s->pin_func);
- qemu_put_byte(f, s->ref);
- qemu_put_byte(f, s->timing);
- qemu_put_be32(f, s->noise);
-
- qemu_put_be16s(f, &s->audio_ctrl1);
- qemu_put_be16s(f, &s->audio_ctrl2);
- qemu_put_be16s(f, &s->audio_ctrl3);
- qemu_put_be16s(f, &s->pll[0]);
- qemu_put_be16s(f, &s->pll[1]);
- qemu_put_be16s(f, &s->volume);
- qemu_put_sbe64(f, (s->volume_change - now));
- qemu_put_sbe64(f, (s->powerdown - now));
- qemu_put_byte(f, s->softstep);
- qemu_put_be16s(f, &s->dac_power);
-
- for (i = 0; i < 0x14; i ++)
- qemu_put_be16s(f, &s->filter_data[i]);
+ s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
-static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
+static int tsc210x_post_load(void *opaque, int version_id)
{
TSC210xState *s = (TSC210xState *) opaque;
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int i;
-
- s->x = qemu_get_be16(f);
- s->y = qemu_get_be16(f);
- s->pressure = qemu_get_byte(f);
-
- s->state = qemu_get_byte(f);
- s->page = qemu_get_byte(f);
- s->offset = qemu_get_byte(f);
- s->command = qemu_get_byte(f);
- s->irq = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dav);
-
- timer_get(f, s->timer);
- s->enabled = qemu_get_byte(f);
- s->host_mode = qemu_get_byte(f);
- s->function = qemu_get_byte(f);
- if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) {
+ if (s->function >= ARRAY_SIZE(mode_regs)) {
return -EINVAL;
}
- s->nextfunction = qemu_get_byte(f);
- if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) {
+ if (s->nextfunction >= ARRAY_SIZE(mode_regs)) {
return -EINVAL;
}
- s->precision = qemu_get_byte(f);
- if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) {
+ if (s->precision >= ARRAY_SIZE(resolution)) {
return -EINVAL;
}
- s->nextprecision = qemu_get_byte(f);
- if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) {
+ if (s->nextprecision >= ARRAY_SIZE(resolution)) {
return -EINVAL;
}
- s->filter = qemu_get_byte(f);
- s->pin_func = qemu_get_byte(f);
- s->ref = qemu_get_byte(f);
- s->timing = qemu_get_byte(f);
- s->noise = qemu_get_be32(f);
-
- qemu_get_be16s(f, &s->audio_ctrl1);
- qemu_get_be16s(f, &s->audio_ctrl2);
- qemu_get_be16s(f, &s->audio_ctrl3);
- qemu_get_be16s(f, &s->pll[0]);
- qemu_get_be16s(f, &s->pll[1]);
- qemu_get_be16s(f, &s->volume);
- s->volume_change = qemu_get_sbe64(f) + now;
- s->powerdown = qemu_get_sbe64(f) + now;
- s->softstep = qemu_get_byte(f);
- qemu_get_be16s(f, &s->dac_power);
-
- for (i = 0; i < 0x14; i ++)
- qemu_get_be16s(f, &s->filter_data[i]);
+
+ s->volume_change -= s->now;
+ s->volume_change += now;
+ s->powerdown -= s->now;
+ s->powerdown += now;
s->busy = timer_pending(s->timer);
qemu_set_irq(s->pint, !s->irq);
@@ -1084,6 +1012,60 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static VMStateField vmstatefields_tsc210x[] = {
+ VMSTATE_BOOL(enabled, TSC210xState),
+ VMSTATE_BOOL(host_mode, TSC210xState),
+ VMSTATE_BOOL(irq, TSC210xState),
+ VMSTATE_BOOL(command, TSC210xState),
+ VMSTATE_BOOL(pressure, TSC210xState),
+ VMSTATE_BOOL(softstep, TSC210xState),
+ VMSTATE_BOOL(state, TSC210xState),
+ VMSTATE_UINT16(dav, TSC210xState),
+ VMSTATE_INT32(x, TSC210xState),
+ VMSTATE_INT32(y, TSC210xState),
+ VMSTATE_UINT8(offset, TSC210xState),
+ VMSTATE_UINT8(page, TSC210xState),
+ VMSTATE_UINT8(filter, TSC210xState),
+ VMSTATE_UINT8(pin_func, TSC210xState),
+ VMSTATE_UINT8(ref, TSC210xState),
+ VMSTATE_UINT8(timing, TSC210xState),
+ VMSTATE_UINT8(noise, TSC210xState),
+ VMSTATE_UINT8(function, TSC210xState),
+ VMSTATE_UINT8(nextfunction, TSC210xState),
+ VMSTATE_UINT8(precision, TSC210xState),
+ VMSTATE_UINT8(nextprecision, TSC210xState),
+ VMSTATE_UINT16(audio_ctrl1, TSC210xState),
+ VMSTATE_UINT16(audio_ctrl2, TSC210xState),
+ VMSTATE_UINT16(audio_ctrl3, TSC210xState),
+ VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3),
+ VMSTATE_UINT16(volume, TSC210xState),
+ VMSTATE_UINT16(dac_power, TSC210xState),
+ VMSTATE_INT64(volume_change, TSC210xState),
+ VMSTATE_INT64(powerdown, TSC210xState),
+ VMSTATE_INT64(now, TSC210xState),
+ VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14),
+ VMSTATE_TIMER_PTR(timer, TSC210xState),
+ VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_tsc2102 = {
+ .name = "tsc2102",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = tsc210x_pre_save,
+ .post_load = tsc210x_post_load,
+ .fields = vmstatefields_tsc210x,
+};
+
+static const VMStateDescription vmstate_tsc2301 = {
+ .name = "tsc2301",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = tsc210x_pre_save,
+ .post_load = tsc210x_post_load,
+ .fields = vmstatefields_tsc210x,
+};
+
uWireSlave *tsc2102_init(qemu_irq pint)
{
TSC210xState *s;
@@ -1125,8 +1107,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
AUD_register_card(s->name, &s->card);
qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(NULL, s->name, -1, 0,
- tsc210x_save, tsc210x_load, s);
+ vmstate_register(NULL, 0, &vmstate_tsc2102, s);
return &s->chip;
}
@@ -1174,7 +1155,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
AUD_register_card(s->name, &s->card);
qemu_register_reset((void *) tsc210x_reset, s);
- register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
+ vmstate_register(NULL, 0, &vmstate_tsc2301, s);
return &s->chip;
}
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index f24c837118..2f44a2da26 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -16,12 +16,14 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
common-obj-y += intc.o
obj-$(CONFIG_APIC) += apic.o apic_common.o
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
+obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
obj-$(CONFIG_GRLIB) += grlib_irqmp.o
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index 5593cdb3e4..ae7ac58ffd 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -577,6 +577,18 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
"not support vGICv2 migration");
migrate_add_blocker(s->migration_blocker);
}
+
+ if (kvm_has_gsi_routing()) {
+ /* set up irq routing */
+ kvm_init_irq_routing(kvm_state);
+ for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
+ }
+
+ kvm_gsi_routing_allowed = true;
+
+ kvm_irqchip_commit_routes(kvm_state);
+ }
}
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
new file mode 100644
index 0000000000..9d67c5c1ee
--- /dev/null
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -0,0 +1,148 @@
+/*
+ * ITS base class for a GICv3-based system
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Written by Pavel Fedin
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/pci/msi.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "qemu/log.h"
+
+static void gicv3_its_pre_save(void *opaque)
+{
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
+ GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
+
+ if (c->pre_save) {
+ c->pre_save(s);
+ }
+}
+
+static int gicv3_its_post_load(void *opaque, int version_id)
+{
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
+ GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
+
+ if (c->post_load) {
+ c->post_load(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_its = {
+ .name = "arm_gicv3_its",
+ .pre_save = gicv3_its_pre_save,
+ .post_load = gicv3_its_post_load,
+ .unmigratable = true,
+};
+
+static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset);
+ return MEMTX_ERROR;
+}
+
+static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ if (offset == 0x0040 && ((size == 2) || (size == 4))) {
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(opaque);
+ GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
+ int ret = c->send_msi(s, le64_to_cpu(value), attrs.requester_id);
+
+ if (ret <= 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ITS: Error sending MSI: %s\n", strerror(-ret));
+ return MEMTX_DECODE_ERROR;
+ }
+
+ return MEMTX_OK;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ITS write at bad offset 0x%"PRIx64"\n", offset);
+ return MEMTX_DECODE_ERROR;
+ }
+}
+
+static const MemoryRegionOps gicv3_its_trans_ops = {
+ .read_with_attrs = gicv3_its_trans_read,
+ .write_with_attrs = gicv3_its_trans_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(s);
+
+ memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
+ "control", ITS_CONTROL_SIZE);
+ memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
+ &gicv3_its_trans_ops, s,
+ "translation", ITS_TRANS_SIZE);
+
+ /* Our two regions are always adjacent, therefore we now combine them
+ * into a single one in order to make our users' life easier.
+ */
+ memory_region_init(&s->iomem_main, OBJECT(s), "gicv3_its", ITS_SIZE);
+ memory_region_add_subregion(&s->iomem_main, 0, &s->iomem_its_cntrl);
+ memory_region_add_subregion(&s->iomem_main, ITS_CONTROL_SIZE,
+ &s->iomem_its_translation);
+ sysbus_init_mmio(sbd, &s->iomem_main);
+
+ msi_nonbroken = true;
+}
+
+static void gicv3_its_common_reset(DeviceState *dev)
+{
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
+
+ s->ctlr = 0;
+ s->cbaser = 0;
+ s->cwriter = 0;
+ s->creadr = 0;
+ memset(&s->baser, 0, sizeof(s->baser));
+
+ gicv3_its_post_load(s, 0);
+}
+
+static void gicv3_its_common_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = gicv3_its_common_reset;
+ dc->vmsd = &vmstate_its;
+}
+
+static const TypeInfo gicv3_its_common_info = {
+ .name = TYPE_ARM_GICV3_ITS_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GICv3ITSState),
+ .class_size = sizeof(GICv3ITSCommonClass),
+ .class_init = gicv3_its_common_class_init,
+ .abstract = true,
+};
+
+static void gicv3_its_common_register_types(void)
+{
+ type_register_static(&gicv3_its_common_info);
+}
+
+type_init(gicv3_its_common_register_types)
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
new file mode 100644
index 0000000000..fc246e0cb5
--- /dev/null
+++ b/hw/intc/arm_gicv3_its_kvm.c
@@ -0,0 +1,121 @@
+/*
+ * KVM-based ITS implementation for a GICv3-based system
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Written by Pavel Fedin <p.fedin@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+#include "migration/migration.h"
+
+#define TYPE_KVM_ARM_ITS "arm-its-kvm"
+#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
+
+static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
+{
+ struct kvm_msi msi;
+
+ if (unlikely(!s->translater_gpa_known)) {
+ MemoryRegion *mr = &s->iomem_its_translation;
+ MemoryRegionSection mrs;
+
+ mrs = memory_region_find(mr, 0, 1);
+ memory_region_unref(mrs.mr);
+ s->gits_translater_gpa = mrs.offset_within_address_space + 0x40;
+ s->translater_gpa_known = true;
+ }
+
+ msi.address_lo = extract64(s->gits_translater_gpa, 0, 32);
+ msi.address_hi = extract64(s->gits_translater_gpa, 32, 32);
+ msi.data = le32_to_cpu(value);
+ msi.flags = KVM_MSI_VALID_DEVID;
+ msi.devid = devid;
+ memset(msi.pad, 0, sizeof(msi.pad));
+
+ return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
+}
+
+static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
+{
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
+
+ s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
+ if (s->dev_fd < 0) {
+ error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
+ return;
+ }
+
+ /* explicit init of the ITS */
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
+
+ /* register the base address */
+ kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd);
+
+ gicv3_its_init_mmio(s, NULL);
+
+ /*
+ * Block migration of a KVM GICv3 ITS device: the API for saving and
+ * restoring the state in the kernel is not yet available
+ */
+ error_setg(&s->migration_blocker, "vITS migration is not implemented");
+ migrate_add_blocker(s->migration_blocker);
+
+ kvm_msi_use_devid = true;
+ kvm_gsi_direct_mapping = false;
+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
+}
+
+static void kvm_arm_its_init(Object *obj)
+{
+ GICv3ITSState *s = KVM_ARM_ITS(obj);
+
+ object_property_add_link(obj, "parent-gicv3",
+ "kvm-arm-gicv3", (Object **)&s->gicv3,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ &error_abort);
+}
+
+static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
+
+ dc->realize = kvm_arm_its_realize;
+ icc->send_msi = kvm_its_send_msi;
+}
+
+static const TypeInfo kvm_arm_its_info = {
+ .name = TYPE_KVM_ARM_ITS,
+ .parent = TYPE_ARM_GICV3_ITS_COMMON,
+ .instance_size = sizeof(GICv3ITSState),
+ .instance_init = kvm_arm_its_init,
+ .class_init = kvm_arm_its_class_init,
+};
+
+static void kvm_arm_its_register_types(void)
+{
+ type_register_static(&kvm_arm_its_info);
+}
+
+type_init(kvm_arm_its_register_types)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 711fde38f3..199a439ccf 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -85,6 +85,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
GICv3State *s = KVM_ARM_GICV3(dev);
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
Error *local_err = NULL;
+ int i;
DPRINTF("kvm_arm_gicv3_realize\n");
@@ -127,6 +128,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
*/
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
migrate_add_blocker(s->migration_blocker);
+
+ if (kvm_has_gsi_routing()) {
+ /* set up irq routing */
+ kvm_init_irq_routing(kvm_state);
+ for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
+ }
+
+ kvm_gsi_routing_allowed = true;
+
+ kvm_irqchip_commit_routes(kvm_state);
+ }
}
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 8618e7acac..7915732f74 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -147,25 +147,19 @@
#define GEM_INT_Q1_MASK (0x00000640 / 4)
#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4)
-#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14)
+#define GEM_TRANSMIT_Q7_PTR (GEM_TRANSMIT_Q1_PTR + 6)
#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4)
-#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14)
+#define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6)
#define GEM_INT_Q1_ENABLE (0x00000600 / 4)
#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6)
-#define GEM_INT_Q8_ENABLE (0x00000660 / 4)
-#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7)
#define GEM_INT_Q1_DISABLE (0x00000620 / 4)
#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6)
-#define GEM_INT_Q8_DISABLE (0x00000680 / 4)
-#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7)
#define GEM_INT_Q1_MASK (0x00000640 / 4)
#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6)
-#define GEM_INT_Q8_MASK (0x000006A0 / 4)
-#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7)
#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4)
@@ -1372,13 +1366,13 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
case GEM_RXQBASE:
s->rx_desc_addr[0] = val;
break;
- case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR:
+ case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q7_PTR:
s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val;
break;
case GEM_TXQBASE:
s->tx_desc_addr[0] = val;
break;
- case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR:
+ case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q7_PTR:
s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val;
break;
case GEM_RXSTATUS:
@@ -1392,10 +1386,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
gem_update_int_status(s);
break;
- case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE:
- s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val;
- gem_update_int_status(s);
- break;
case GEM_IDR:
s->regs[GEM_IMR] |= val;
gem_update_int_status(s);
@@ -1404,10 +1394,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val;
gem_update_int_status(s);
break;
- case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE:
- s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val;
- gem_update_int_status(s);
- break;
case GEM_SPADDR1LO:
case GEM_SPADDR2LO:
case GEM_SPADDR3LO:
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 14b6821a94..03e38039e8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -546,6 +546,51 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
return 0;
}
+/* Populate the "ibm,pa-features" property */
+static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset)
+{
+ uint8_t pa_features_206[] = { 6, 0,
+ 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
+ uint8_t pa_features_207[] = { 24, 0,
+ 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 };
+ uint8_t *pa_features;
+ size_t pa_size;
+
+ switch (env->mmu_model) {
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06a:
+ pa_features = pa_features_206;
+ pa_size = sizeof(pa_features_206);
+ break;
+ case POWERPC_MMU_2_07:
+ case POWERPC_MMU_2_07a:
+ pa_features = pa_features_207;
+ pa_size = sizeof(pa_features_207);
+ break;
+ default:
+ return;
+ }
+
+ if (env->ci_large_pages) {
+ /*
+ * Note: we keep CI large pages off by default because a 64K capable
+ * guest provisioned with large pages might otherwise try to map a qemu
+ * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
+ * even if that qemu runs on a 4k host.
+ * We dd this bit back here if we are confident this is not an issue
+ */
+ pa_features[3] |= 0x20;
+ }
+ if (kvmppc_has_cap_htm() && pa_size > 24) {
+ pa_features[24] |= 0x80; /* Transactional memory support */
+ }
+
+ _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
+}
+
static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
sPAPRMachineState *spapr)
{
@@ -573,24 +618,6 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
_FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
}
- /* Note: we keep CI large pages off for now because a 64K capable guest
- * provisioned with large pages might otherwise try to map a qemu
- * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
- * even if that qemu runs on a 4k host.
- *
- * We can later add this bit back when we are confident this is not
- * an issue (!HV KVM or 64K host)
- */
- uint8_t pa_features_206[] = { 6, 0,
- 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
- uint8_t pa_features_207[] = { 24, 0,
- 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
- uint8_t *pa_features;
- size_t pa_size;
-
_FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
@@ -657,18 +684,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
page_sizes_prop, page_sizes_prop_size)));
}
- /* Do the ibm,pa-features property, adjust it for ci-large-pages */
- if (env->mmu_model == POWERPC_MMU_2_06) {
- pa_features = pa_features_206;
- pa_size = sizeof(pa_features_206);
- } else /* env->mmu_model == POWERPC_MMU_2_07 */ {
- pa_features = pa_features_207;
- pa_size = sizeof(pa_features_207);
- }
- if (env->ci_large_pages) {
- pa_features[3] |= 0x20;
- }
- _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
+ spapr_populate_pa_features(env, fdt, offset);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
cs->cpu_index / vcpus_per_socket)));
@@ -1759,7 +1775,7 @@ static void ppc_spapr_init(MachineState *machine)
/* init CPUs */
if (machine->cpu_model == NULL) {
- machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
+ machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
}
ppc_cpu_parse_features(machine->cpu_model);
@@ -2386,6 +2402,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
smc->dr_lmb_enabled = true;
+ smc->tcg_default_cpu = "POWER8";
mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
fwc->get_dev_path = spapr_get_fw_dev_path;
nc->nmi_monitor_handler = spapr_nmi;
@@ -2437,18 +2454,39 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
+ * pseries-2.8
+ */
+static void spapr_machine_2_8_instance_options(MachineState *machine)
+{
+}
+
+static void spapr_machine_2_8_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(2_8, "2.8", true);
+
+/*
* pseries-2.7
*/
+#define SPAPR_COMPAT_2_7 \
+ HW_COMPAT_2_7 \
+
static void spapr_machine_2_7_instance_options(MachineState *machine)
{
}
static void spapr_machine_2_7_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+
+ spapr_machine_2_8_class_options(mc);
+ smc->tcg_default_cpu = "POWER7";
+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7);
}
-DEFINE_SPAPR_MACHINE(2_7, "2.7", true);
+DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
/*
* pseries-2.6
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 6f0533c342..35d1873b9f 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -92,20 +92,20 @@ char *spapr_get_cpu_core_type(const char *model)
gchar **model_pieces = g_strsplit(model, ",", 2);
core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE);
- g_strfreev(model_pieces);
/* Check whether it exists or whether we have to look up an alias name */
if (!object_class_by_name(core_type)) {
const char *realmodel;
g_free(core_type);
- realmodel = ppc_cpu_lookup_alias(model);
+ core_type = NULL;
+ realmodel = ppc_cpu_lookup_alias(model_pieces[0]);
if (realmodel) {
- return spapr_get_cpu_core_type(realmodel);
+ core_type = spapr_get_cpu_core_type(realmodel);
}
- return NULL;
}
+ g_strfreev(model_pieces);
return core_type;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index b0e81efc27..0f2580d644 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -775,7 +775,7 @@ int css_do_xsch(SubchDev *sch)
PMCW *p = &sch->curr_status.pmcw;
int ret;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
ret = -ENODEV;
goto out;
}
@@ -815,7 +815,7 @@ int css_do_csch(SubchDev *sch)
PMCW *p = &sch->curr_status.pmcw;
int ret;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
ret = -ENODEV;
goto out;
}
@@ -837,7 +837,7 @@ int css_do_hsch(SubchDev *sch)
PMCW *p = &sch->curr_status.pmcw;
int ret;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
ret = -ENODEV;
goto out;
}
@@ -913,7 +913,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
PMCW *p = &sch->curr_status.pmcw;
int ret;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
ret = -ENODEV;
goto out;
}
@@ -990,7 +990,7 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
uint16_t stctl;
IRB irb;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return 3;
}
@@ -1196,7 +1196,7 @@ int css_do_rsch(SubchDev *sch)
PMCW *p = &sch->curr_status.pmcw;
int ret;
- if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+ if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
ret = -ENODEV;
goto out;
}
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index ac8f06d9e7..b7f8bca1fd 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -383,7 +383,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
uint64_t pte;
uint32_t flags;
S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr);
- S390pciState *s;
IOMMUTLBEntry ret = {
.target_as = &address_space_memory,
.iova = 0,
@@ -405,19 +404,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
- s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent);
- /* s390 does not have an APIC mapped to main storage so we use
- * a separate AddressSpace only for msix notifications
- */
- if (addr == ZPCI_MSI_ADDR) {
- ret.target_as = &s->msix_notify_as;
- ret.iova = addr;
- ret.translated_addr = addr;
- ret.addr_mask = 0xfff;
- ret.perm = IOMMU_RW;
- return ret;
- }
-
if (addr < pbdev->pba || addr > pbdev->pal) {
return ret;
}
@@ -476,7 +462,7 @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
- S390PCIBusDevice *pbdev;
+ S390PCIBusDevice *pbdev = opaque;
uint32_t io_int_word;
uint32_t idx = data >> ZPCI_MSI_VEC_BITS;
uint32_t vec = data & ZPCI_MSI_VEC_MASK;
@@ -486,7 +472,6 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec);
- pbdev = s390_pci_find_dev_by_idx(idx);
if (!pbdev) {
e |= (vec << ERR_EVENT_MVN_OFFSET);
s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e);
@@ -548,10 +533,6 @@ static void s390_pcihost_init_as(S390pciState *s)
s->iommu[i] = iommu;
}
-
- memory_region_init_io(&s->msix_notify_mr, OBJECT(s),
- &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX);
- address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci");
}
static int s390_pcihost_init(SysBusDevice *dev)
@@ -581,7 +562,7 @@ static int s390_pcihost_init(SysBusDevice *dev)
return 0;
}
-static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
+static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
{
uint8_t pos;
uint16_t ctrl;
@@ -609,6 +590,26 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
return 0;
}
+static void s390_pci_msix_init(S390PCIBusDevice *pbdev)
+{
+ char *name;
+
+ name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
+
+ memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
+ &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
+ memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR,
+ &pbdev->msix_notify_mr);
+
+ g_free(name);
+}
+
+static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
+{
+ memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr);
+ object_unparent(OBJECT(&pbdev->msix_notify_mr));
+}
+
static S390PCIBusDevice *s390_pci_device_new(const char *target)
{
DeviceState *dev = NULL;
@@ -662,7 +663,9 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
pbdev->pdev = pdev;
pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)];
pbdev->state = ZPCI_FS_STANDBY;
- s390_pcihost_setup_msix(pbdev);
+
+ s390_pci_msix_init(pbdev);
+ s390_pci_setup_msix(pbdev);
if (dev->hotplugged) {
s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
@@ -749,6 +752,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
pbdev->fh, pbdev->fid);
object_unparent(OBJECT(pci_dev));
+ s390_pci_msix_free(pbdev);
pbdev->pdev = NULL;
pbdev->state = ZPCI_FS_RESERVED;
out:
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 4f564e02f2..7f2701301e 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -82,6 +82,7 @@
#define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL
#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_DEFAULT_ACC 0
#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
@@ -283,6 +284,7 @@ typedef struct S390PCIBusDevice {
AdapterRoutes routes;
S390PCIIOMMU *iommu;
MemoryRegion iommu_mr;
+ MemoryRegion msix_notify_mr;
IndAddr *summary_ind;
IndAddr *indicator;
QEMUTimer *release_timer;
@@ -297,8 +299,6 @@ typedef struct S390pciState {
S390PCIBus *bus;
S390PCIBusDevice *pbdev[PCI_SLOT_MAX];
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
- AddressSpace msix_notify_as;
- MemoryRegion msix_notify_mr;
QTAILQ_HEAD(, SeiContainer) pending_sei;
} S390pciState;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index f069b110b4..80a51049ca 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -315,6 +315,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
S390PCIBusDevice *pbdev;
uint64_t offset;
uint64_t data;
+ MemoryRegion *mr;
uint8_t len;
uint32_t fh;
uint8_t pcias;
@@ -363,7 +364,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
program_interrupt(env, PGM_OPERAND, 4);
return 0;
}
- MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory;
+ mr = pbdev->pdev->io_regions[pcias].memory;
memory_region_dispatch_read(mr, offset, &data, len,
MEMTXATTRS_UNSPECIFIED);
} else if (pcias == 15) {
@@ -442,6 +443,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
CPUS390XState *env = &cpu->env;
uint64_t offset, data;
S390PCIBusDevice *pbdev;
+ MemoryRegion *mr;
uint8_t len;
uint32_t fh;
uint8_t pcias;
@@ -491,7 +493,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
program_interrupt(env, PGM_OPERAND, 4);
return 0;
}
- MemoryRegion *mr;
+
if (trap_msix(pbdev, offset, pcias)) {
offset = offset - pbdev->msix.table_offset;
mr = &pbdev->pdev->msix_table_mmio;
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index d8a2296b7b..6090a204a0 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -658,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
uint64_t tag = iu->srp.rsp.tag;
- trace_spapr_vscsi__process_login();
+ trace_spapr_vscsi_process_login();
/* TODO handle case that requested size is wrong and
* buffer format is wrong
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index d1995b84f8..4a2e5d66df 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -225,7 +225,7 @@ spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10,
spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32
spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x"
spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x"
-spapr_vscsi__process_login(void) "Got login, sending response !"
+spapr_vscsi_process_login(void) "Got login, sending response !"
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive"
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 9a6552aa60..3a96cededd 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -486,7 +486,7 @@ static void smbios_build_type_0_table(void)
*/
static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in)
{
- memcpy(uuid, &in, 16);
+ memcpy(uuid, in, 16);
if (smbios_uuid_encoded) {
uuid->time_low = bswap32(uuid->time_low);
uuid->time_mid = bswap16(uuid->time_mid);
diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs
index c79a8dcd86..487add2879 100644
--- a/hw/ssi/Makefile.objs
+++ b/hw/ssi/Makefile.objs
@@ -3,6 +3,7 @@ common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
+common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o
obj-$(CONFIG_OMAP) += omap_spi.o
obj-$(CONFIG_IMX) += imx_spi.o
diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c
new file mode 100644
index 0000000000..26a1b4ddf5
--- /dev/null
+++ b/hw/ssi/stm32f2xx_spi.c
@@ -0,0 +1,225 @@
+/*
+ * STM32F405 SPI
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "hw/ssi/stm32f2xx_spi.h"
+
+#ifndef STM_SPI_ERR_DEBUG
+#define STM_SPI_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+ if (STM_SPI_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_spi_reset(DeviceState *dev)
+{
+ STM32F2XXSPIState *s = STM32F2XX_SPI(dev);
+
+ s->spi_cr1 = 0x00000000;
+ s->spi_cr2 = 0x00000000;
+ s->spi_sr = 0x0000000A;
+ s->spi_dr = 0x0000000C;
+ s->spi_crcpr = 0x00000007;
+ s->spi_rxcrcr = 0x00000000;
+ s->spi_txcrcr = 0x00000000;
+ s->spi_i2scfgr = 0x00000000;
+ s->spi_i2spr = 0x00000002;
+}
+
+static void stm32f2xx_spi_transfer(STM32F2XXSPIState *s)
+{
+ DB_PRINT("Data to send: 0x%x\n", s->spi_dr);
+
+ s->spi_dr = ssi_transfer(s->ssi, s->spi_dr);
+ s->spi_sr |= STM_SPI_SR_RXNE;
+
+ DB_PRINT("Data received: 0x%x\n", s->spi_dr);
+}
+
+static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F2XXSPIState *s = opaque;
+
+ DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
+
+ switch (addr) {
+ case STM_SPI_CR1:
+ return s->spi_cr1;
+ case STM_SPI_CR2:
+ qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n",
+ __func__);
+ return s->spi_cr2;
+ case STM_SPI_SR:
+ return s->spi_sr;
+ case STM_SPI_DR:
+ stm32f2xx_spi_transfer(s);
+ s->spi_sr &= ~STM_SPI_SR_RXNE;
+ return s->spi_dr;
+ case STM_SPI_CRCPR:
+ qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+ "are included for compatibility\n", __func__);
+ return s->spi_crcpr;
+ case STM_SPI_RXCRCR:
+ qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+ "are included for compatibility\n", __func__);
+ return s->spi_rxcrcr;
+ case STM_SPI_TXCRCR:
+ qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+ "are included for compatibility\n", __func__);
+ return s->spi_txcrcr;
+ case STM_SPI_I2SCFGR:
+ qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+ "are included for compatibility\n", __func__);
+ return s->spi_i2scfgr;
+ case STM_SPI_I2SPR:
+ qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+ "are included for compatibility\n", __func__);
+ return s->spi_i2spr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_spi_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F2XXSPIState *s = opaque;
+ uint32_t value = val64;
+
+ DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", addr, value);
+
+ switch (addr) {
+ case STM_SPI_CR1:
+ s->spi_cr1 = value;
+ return;
+ case STM_SPI_CR2:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "Interrupts and DMA are not implemented\n", __func__);
+ s->spi_cr2 = value;
+ return;
+ case STM_SPI_SR:
+ /* Read only register, except for clearing the CRCERR bit, which
+ * is not supported
+ */
+ return;
+ case STM_SPI_DR:
+ s->spi_dr = value;
+ stm32f2xx_spi_transfer(s);
+ return;
+ case STM_SPI_CRCPR:
+ qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented\n", __func__);
+ return;
+ case STM_SPI_RXCRCR:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
+ "0x%" HWADDR_PRIx "\n", __func__, addr);
+ return;
+ case STM_SPI_TXCRCR:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
+ "0x%" HWADDR_PRIx "\n", __func__, addr);
+ return;
+ case STM_SPI_I2SCFGR:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "I2S is not implemented\n", __func__);
+ return;
+ case STM_SPI_I2SPR:
+ qemu_log_mask(LOG_UNIMP, "%s: " \
+ "I2S is not implemented\n", __func__);
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps stm32f2xx_spi_ops = {
+ .read = stm32f2xx_spi_read,
+ .write = stm32f2xx_spi_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stm32f2xx_spi = {
+ .name = TYPE_STM32F2XX_SPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(spi_cr1, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_cr2, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_sr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_dr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_crcpr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_rxcrcr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_txcrcr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_i2scfgr, STM32F2XXSPIState),
+ VMSTATE_UINT32(spi_i2spr, STM32F2XXSPIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32f2xx_spi_init(Object *obj)
+{
+ STM32F2XXSPIState *s = STM32F2XX_SPI(obj);
+ DeviceState *dev = DEVICE(obj);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f2xx_spi_ops, s,
+ TYPE_STM32F2XX_SPI, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ s->ssi = ssi_create_bus(dev, "ssi");
+}
+
+static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f2xx_spi_reset;
+ dc->vmsd = &vmstate_stm32f2xx_spi;
+}
+
+static const TypeInfo stm32f2xx_spi_info = {
+ .name = TYPE_STM32F2XX_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F2XXSPIState),
+ .instance_init = stm32f2xx_spi_init,
+ .class_init = stm32f2xx_spi_class_init,
+};
+
+static void stm32f2xx_spi_register_types(void)
+{
+ type_register_static(&stm32f2xx_spi_info);
+}
+
+type_init(stm32f2xx_spi_register_types)
diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
index bf0fb288c4..8c4c1f9f05 100644
--- a/hw/timer/stm32f2xx_timer.c
+++ b/hw/timer/stm32f2xx_timer.c
@@ -51,6 +51,15 @@ static void stm32f2xx_timer_interrupt(void *opaque)
qemu_irq_pulse(s->irq);
stm32f2xx_timer_set_alarm(s, s->hit_time);
}
+
+ if (s->tim_ccmr1 & (TIM_CCMR1_OC2M2 | TIM_CCMR1_OC2M1) &&
+ !(s->tim_ccmr1 & TIM_CCMR1_OC2M0) &&
+ s->tim_ccmr1 & TIM_CCMR1_OC2PE &&
+ s->tim_ccer & TIM_CCER_CC2E) {
+ /* PWM 2 - Mode 1 */
+ DB_PRINT("PWM2 Duty Cycle: %d%%\n",
+ s->tim_ccr2 / (100 * (s->tim_psc + 1)));
+ }
}
static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t)
diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c
index b439b0ed5d..457a8976c3 100644
--- a/hw/xenpv/xen_domainbuild.c
+++ b/hw/xenpv/xen_domainbuild.c
@@ -232,7 +232,7 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk,
unsigned long xenstore_mfn = 0, console_mfn = 0;
int rc;
- memcpy(uuid, qemu_uuid, sizeof(uuid));
+ memcpy(uuid, &qemu_uuid, sizeof(uuid));
rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_create() failed\n");