aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-10-04 13:48:25 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-10-04 13:48:25 +0100
commit6e11eb2d2b96790e647aa4c744ed2ed03a77fbbd (patch)
tree764d96006cedc488328f6c346115d4e2e423bd0e
parent1bb47107057c645945971cf4e13eb8b524915b71 (diff)
parent9b6a3ea7a699594162ed3d11e4e04b98568dc5c0 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20161004' into staging
target-arm queue: * Netduino 2 improvements (SPI, ADC devices) * fix some Mainstone key mappings * vmstateify tsc210x, tsc2005 * virt: add 2.8 machine type * virt: support in-kernel GICv3 ITS * generic-loader device * A64: fix iss_sf decoding in disas_ld_lit * correctly handle 'sub pc, pc, 1' for ARMv6 # gpg: Signature made Tue 04 Oct 2016 13:41:34 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20161004: (27 commits) target-arm: Correctly handle 'sub pc, pc, 1' for ARMv6 target-arm: A64: Fix decoding of iss_sf in disas_ld_lit cadence_gem: Fix priority queue out of bounds access docs: Add a generic loader explanation document generic-loader: Add a generic loader ARM: Virt: ACPI: Add GIC ITS description in ACPI MADT table ACPI: Add GIC Interrupt Translation Service Structure definition arm/virt: Add ITS to the virt board hw/intc/arm_gicv3_its: Implement support for in-kernel ITS emulation kvm-all: Pass requester ID to MSI routing functions target-arm: move gicv3_class_name from machine to kvm_arm.h hw/intc/arm_gicv3_its: Implement ITS base class hw/intc/arm_gic(v3)_kvm: Initialize gsi routing hw/arm/virt: add 2.8 machine type vmstateify tsc210x vmstateify tsc2005 hw/arm: Fix Integrator/CM initialization mainstone: Add mapping for dot, slash and backspace. mainstone: Fix incorrect key mapping for Enter key. MAINTAINERS: Add Alistair to the maintainers list ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS21
-rw-r--r--default-configs/arm-softmmu.mak2
-rw-r--r--docs/generic-loader.txt84
-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/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/ssi/Makefile.objs1
-rw-r--r--hw/ssi/stm32f2xx_spi.c225
-rw-r--r--hw/timer/stm32f2xx_timer.c9
-rw-r--r--include/hw/acpi/acpi-defs.h13
-rw-r--r--include/hw/adc/stm32f2xx_adc.h87
-rw-r--r--include/hw/arm/stm32f205_soc.h9
-rw-r--r--include/hw/core/generic-loader.h46
-rw-r--r--include/hw/intc/arm_gicv3_its_common.h78
-rw-r--r--include/hw/or-irq.h44
-rw-r--r--include/hw/ssi/stm32f2xx_spi.h72
-rw-r--r--include/sysemu/kvm.h9
-rw-r--r--kvm-all.c9
-rw-r--r--kvm-stub.c1
-rw-r--r--target-arm/kvm_arm.h35
-rw-r--r--target-arm/machine.c15
-rw-r--r--target-arm/translate-a64.c2
-rw-r--r--target-arm/translate.c7
39 files changed, 2027 insertions, 316 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 63cf21fdb1..76a0fdb2c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -479,6 +479,21 @@ S: Maintained
F: hw/arm/virt-acpi-build.c
F: include/hw/arm/virt-acpi-build.h
+STM32F205
+M: Alistair Francis <alistair@alistair23.me>
+S: Maintained
+F: hw/arm/stm32f205_soc.c
+F: hw/misc/stm32f2xx_syscfg.c
+F: hw/char/stm32f2xx_usart.c
+F: hw/timer/stm32f2xx_timer.c
+F: hw/adc/*
+F: hw/ssi/stm32f2xx_spi.c
+
+Netduino 2
+M: Alistair Francis <alistair@alistair23.me>
+S: Maintained
+F: hw/arm/netduino2.c
+
CRIS Machines
-------------
Axis Dev88
@@ -1014,6 +1029,12 @@ M: Dmitry Fleytman <dmitry@daynix.com>
S: Maintained
F: hw/net/e1000e*
+Generic Loader
+M: Alistair Francis <alistair.francis@xilinx.com>
+S: Maintained
+F: hw/core/generic-loader.c
+F: include/hw/core/generic-loader.h
+
Subsystems
----------
Audio
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e1243602e9..6de3e16a3e 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -86,6 +86,8 @@ CONFIG_ZYNQ=y
CONFIG_STM32F2XX_TIMER=y
CONFIG_STM32F2XX_USART=y
CONFIG_STM32F2XX_SYSCFG=y
+CONFIG_STM32F2XX_ADC=y
+CONFIG_STM32F2XX_SPI=y
CONFIG_STM32F205_SOC=y
CONFIG_VERSATILE_PCI=y
diff --git a/docs/generic-loader.txt b/docs/generic-loader.txt
new file mode 100644
index 0000000000..8fcb550414
--- /dev/null
+++ b/docs/generic-loader.txt
@@ -0,0 +1,84 @@
+Copyright (c) 2016 Xilinx Inc.
+
+This work is licensed under the terms of the GNU GPL, version 2 or later. See
+the COPYING file in the top-level directory.
+
+
+The 'loader' device allows the user to load multiple images or values into
+QEMU at startup.
+
+Loading Data into Memory Values
+---------------------
+The loader device allows memory values to be set from the command line. This
+can be done by following the syntax below:
+
+ -device loader,addr=<addr>,data=<data>,data-len=<data-len>
+ [,data-be=<data-be>][,cpu-num=<cpu-num>]
+
+ <addr> - The address to store the data in.
+ <data> - The value to be written to the address. The maximum size of
+ the data is 8 bytes.
+ <data-len> - The length of the data in bytes. This argument must be
+ included if the data argument is.
+ <data-be> - Set to true if the data to be stored on the guest should be
+ written as big endian data. The default is to write little
+ endian data.
+ <cpu-num> - The number of the CPU's address space where the data should
+ be loaded. If not specified the address space of the first
+ CPU is used.
+
+All values are parsed using the standard QemuOps parsing. This allows the user
+to specify any values in any format supported. By default the values
+will be parsed as decimal. To use hex values the user should prefix the number
+with a '0x'.
+
+An example of loading value 0x8000000e to address 0xfd1a0104 is:
+ -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
+
+Setting a CPU's Program Counter
+---------------------
+The loader device allows the CPU's PC to be set from the command line. This
+can be done by following the syntax below:
+
+ -device loader,addr=<addr>,cpu-num=<cpu-num>
+
+ <addr> - The value to use as the CPU's PC.
+ <cpu-num> - The number of the CPU whose PC should be set to the
+ specified value.
+
+All values are parsed using the standard QemuOps parsing. This allows the user
+to specify any values in any format supported. By default the values
+will be parsed as decimal. To use hex values the user should prefix the number
+with a '0x'.
+
+An example of setting CPU 0's PC to 0x8000 is:
+ -device loader,addr=0x8000,cpu-num=0
+
+Loading Files
+---------------------
+The loader device also allows files to be loaded into memory. This can be done
+similarly to setting memory values. The syntax is shown below:
+
+ -device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>]
+
+ <file> - A file to be loaded into memory
+ <addr> - The addr in memory that the file should be loaded. This is
+ ignored if you are using an ELF (unless force-raw is true).
+ This is required if you aren't loading an ELF.
+ <cpu-num> - This specifies the CPU that should be used. This is an
+ optional argument and will cause the CPU's PC to be set to
+ where the image is stored or in the case of an ELF file to
+ the value in the header. This option should only be used
+ for the boot image.
+ This will also cause the image to be written to the specified
+ CPU's address space. If not specified, the default is CPU 0.
+ <force-raw> - Forces the file to be treated as a raw image. This can be
+ used to specify the load address of ELF files.
+
+All values are parsed using the standard QemuOps parsing. This allows the user
+to specify any values in any format supported. By default the values
+will be parsed as decimal. To use hex values the user should prefix the number
+with a '0x'.
+
+An example of loading an ELF file which CPU0 will boot is shown below:
+ -device loader,file=./images/boot.elf,cpu-num=0
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/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 05ec21b21e..9cca2800d3 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -16,11 +16,13 @@ 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
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/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/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 41c1d95c4c..9c1b7cb5d6 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -294,7 +294,8 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable;
#define ACPI_APIC_GENERIC_DISTRIBUTOR 12
#define ACPI_APIC_GENERIC_MSI_FRAME 13
#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14
-#define ACPI_APIC_RESERVED 15 /* 15 and greater are reserved */
+#define ACPI_APIC_GENERIC_TRANSLATOR 15
+#define ACPI_APIC_RESERVED 16 /* 16 and greater are reserved */
/*
* MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
@@ -395,6 +396,16 @@ struct AcpiMadtGenericRedistributor {
typedef struct AcpiMadtGenericRedistributor AcpiMadtGenericRedistributor;
+struct AcpiMadtGenericTranslator {
+ ACPI_SUB_HEADER_DEF
+ uint16_t reserved;
+ uint32_t translation_id;
+ uint64_t base_address;
+ uint32_t reserved2;
+} QEMU_PACKED;
+
+typedef struct AcpiMadtGenericTranslator AcpiMadtGenericTranslator;
+
/*
* Generic Timer Description Table (GTDT)
*/
diff --git a/include/hw/adc/stm32f2xx_adc.h b/include/hw/adc/stm32f2xx_adc.h
new file mode 100644
index 0000000000..a72f734eb1
--- /dev/null
+++ b/include/hw/adc/stm32f2xx_adc.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef HW_STM32F2XX_ADC_H
+#define HW_STM32F2XX_ADC_H
+
+#define ADC_SR 0x00
+#define ADC_CR1 0x04
+#define ADC_CR2 0x08
+#define ADC_SMPR1 0x0C
+#define ADC_SMPR2 0x10
+#define ADC_JOFR1 0x14
+#define ADC_JOFR2 0x18
+#define ADC_JOFR3 0x1C
+#define ADC_JOFR4 0x20
+#define ADC_HTR 0x24
+#define ADC_LTR 0x28
+#define ADC_SQR1 0x2C
+#define ADC_SQR2 0x30
+#define ADC_SQR3 0x34
+#define ADC_JSQR 0x38
+#define ADC_JDR1 0x3C
+#define ADC_JDR2 0x40
+#define ADC_JDR3 0x44
+#define ADC_JDR4 0x48
+#define ADC_DR 0x4C
+
+#define ADC_CR2_ADON 0x01
+#define ADC_CR2_CONT 0x02
+#define ADC_CR2_ALIGN 0x800
+#define ADC_CR2_SWSTART 0x40000000
+
+#define ADC_CR1_RES 0x3000000
+
+#define ADC_COMMON_ADDRESS 0x100
+
+#define TYPE_STM32F2XX_ADC "stm32f2xx-adc"
+#define STM32F2XX_ADC(obj) \
+ OBJECT_CHECK(STM32F2XXADCState, (obj), TYPE_STM32F2XX_ADC)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion mmio;
+
+ uint32_t adc_sr;
+ uint32_t adc_cr1;
+ uint32_t adc_cr2;
+ uint32_t adc_smpr1;
+ uint32_t adc_smpr2;
+ uint32_t adc_jofr[4];
+ uint32_t adc_htr;
+ uint32_t adc_ltr;
+ uint32_t adc_sqr1;
+ uint32_t adc_sqr2;
+ uint32_t adc_sqr3;
+ uint32_t adc_jsqr;
+ uint32_t adc_jdr[4];
+ uint32_t adc_dr;
+
+ qemu_irq irq;
+} STM32F2XXADCState;
+
+#endif /* HW_STM32F2XX_ADC_H */
diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h
index 779b5da2dc..133214195b 100644
--- a/include/hw/arm/stm32f205_soc.h
+++ b/include/hw/arm/stm32f205_soc.h
@@ -28,6 +28,9 @@
#include "hw/misc/stm32f2xx_syscfg.h"
#include "hw/timer/stm32f2xx_timer.h"
#include "hw/char/stm32f2xx_usart.h"
+#include "hw/adc/stm32f2xx_adc.h"
+#include "hw/or-irq.h"
+#include "hw/ssi/stm32f2xx_spi.h"
#define TYPE_STM32F205_SOC "stm32f205-soc"
#define STM32F205_SOC(obj) \
@@ -35,6 +38,8 @@
#define STM_NUM_USARTS 6
#define STM_NUM_TIMERS 4
+#define STM_NUM_ADCS 3
+#define STM_NUM_SPIS 3
#define FLASH_BASE_ADDRESS 0x08000000
#define FLASH_SIZE (1024 * 1024)
@@ -52,6 +57,10 @@ typedef struct STM32F205State {
STM32F2XXSyscfgState syscfg;
STM32F2XXUsartState usart[STM_NUM_USARTS];
STM32F2XXTimerState timer[STM_NUM_TIMERS];
+ STM32F2XXADCState adc[STM_NUM_ADCS];
+ STM32F2XXSPIState spi[STM_NUM_SPIS];
+
+ qemu_or_irq *adc_irqs;
} STM32F205State;
#endif
diff --git a/include/hw/core/generic-loader.h b/include/hw/core/generic-loader.h
new file mode 100644
index 0000000000..dd27c42ab0
--- /dev/null
+++ b/include/hw/core/generic-loader.h
@@ -0,0 +1,46 @@
+/*
+ * Generic Loader
+ *
+ * Copyright (C) 2014 Li Guang
+ * 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.
+ */
+
+#ifndef GENERIC_LOADER_H
+#define GENERIC_LOADER_H
+
+#include "elf.h"
+
+typedef struct GenericLoaderState {
+ /* <private> */
+ DeviceState parent_obj;
+
+ /* <public> */
+ CPUState *cpu;
+
+ uint64_t addr;
+ uint64_t data;
+ uint8_t data_len;
+ uint32_t cpu_num;
+
+ char *file;
+
+ bool force_raw;
+ bool data_be;
+ bool set_pc;
+} GenericLoaderState;
+
+#define TYPE_GENERIC_LOADER "loader"
+#define GENERIC_LOADER(obj) OBJECT_CHECK(GenericLoaderState, (obj), \
+ TYPE_GENERIC_LOADER)
+
+#endif
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
new file mode 100644
index 0000000000..1ba18944cf
--- /dev/null
+++ b/include/hw/intc/arm_gicv3_its_common.h
@@ -0,0 +1,78 @@
+/*
+ * ITS support for ARM GICv3
+ *
+ * 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/>.
+ */
+
+#ifndef QEMU_ARM_GICV3_ITS_COMMON_H
+#define QEMU_ARM_GICV3_ITS_COMMON_H
+
+#include "hw/sysbus.h"
+#include "hw/intc/arm_gicv3_common.h"
+
+#define ITS_CONTROL_SIZE 0x10000
+#define ITS_TRANS_SIZE 0x10000
+#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
+
+struct GICv3ITSState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem_main;
+ MemoryRegion iomem_its_cntrl;
+ MemoryRegion iomem_its_translation;
+
+ GICv3State *gicv3;
+
+ int dev_fd; /* kvm device fd if backed by kvm vgic support */
+ uint64_t gits_translater_gpa;
+ bool translater_gpa_known;
+
+ /* Registers */
+ uint32_t ctlr;
+ uint64_t cbaser;
+ uint64_t cwriter;
+ uint64_t creadr;
+ uint64_t baser[8];
+
+ Error *migration_blocker;
+};
+
+typedef struct GICv3ITSState GICv3ITSState;
+
+void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
+
+#define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
+#define ARM_GICV3_ITS_COMMON(obj) \
+ OBJECT_CHECK(GICv3ITSState, (obj), TYPE_ARM_GICV3_ITS_COMMON)
+#define ARM_GICV3_ITS_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(GICv3ITSCommonClass, (klass), TYPE_ARM_GICV3_ITS_COMMON)
+#define ARM_GICV3_ITS_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(GICv3ITSCommonClass, (obj), TYPE_ARM_GICV3_ITS_COMMON)
+
+struct GICv3ITSCommonClass {
+ /*< private >*/
+ SysBusDeviceClass parent_class;
+ /*< public >*/
+
+ int (*send_msi)(GICv3ITSState *s, uint32_t data, uint16_t devid);
+ void (*pre_save)(GICv3ITSState *s);
+ void (*post_load)(GICv3ITSState *s);
+};
+
+typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;
+
+#endif
diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h
new file mode 100644
index 0000000000..d400a8120b
--- /dev/null
+++ b/include/hw/or-irq.h
@@ -0,0 +1,44 @@
+/*
+ * 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 "hw/irq.h"
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_OR_IRQ "or-irq"
+
+#define MAX_OR_LINES 16
+
+typedef struct OrIRQState qemu_or_irq;
+
+#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ)
+
+struct OrIRQState {
+ DeviceState parent_obj;
+
+ qemu_irq out_irq;
+ qemu_irq *in_irqs;
+ bool levels[MAX_OR_LINES];
+ uint16_t num_lines;
+};
diff --git a/include/hw/ssi/stm32f2xx_spi.h b/include/hw/ssi/stm32f2xx_spi.h
new file mode 100644
index 0000000000..1cd73e4cd4
--- /dev/null
+++ b/include/hw/ssi/stm32f2xx_spi.h
@@ -0,0 +1,72 @@
+/*
+ * STM32F2XX 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.
+ */
+
+#ifndef HW_STM32F2XX_SPI_H
+#define HW_STM32F2XX_SPI_H
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/ssi/ssi.h"
+
+#define STM_SPI_CR1 0x00
+#define STM_SPI_CR2 0x04
+#define STM_SPI_SR 0x08
+#define STM_SPI_DR 0x0C
+#define STM_SPI_CRCPR 0x10
+#define STM_SPI_RXCRCR 0x14
+#define STM_SPI_TXCRCR 0x18
+#define STM_SPI_I2SCFGR 0x1C
+#define STM_SPI_I2SPR 0x20
+
+#define STM_SPI_CR1_SPE (1 << 6)
+#define STM_SPI_CR1_MSTR (1 << 2)
+
+#define STM_SPI_SR_RXNE 1
+
+#define TYPE_STM32F2XX_SPI "stm32f2xx-spi"
+#define STM32F2XX_SPI(obj) \
+ OBJECT_CHECK(STM32F2XXSPIState, (obj), TYPE_STM32F2XX_SPI)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion mmio;
+
+ uint32_t spi_cr1;
+ uint32_t spi_cr2;
+ uint32_t spi_sr;
+ uint32_t spi_dr;
+ uint32_t spi_crcpr;
+ uint32_t spi_rxcrcr;
+ uint32_t spi_txcrcr;
+ uint32_t spi_i2scfgr;
+ uint32_t spi_i2spr;
+
+ qemu_irq irq;
+ SSIBus *ssi;
+} STM32F2XXSPIState;
+
+#endif /* HW_STM32F2XX_SPI_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 3e17ba76ce..df67cc0672 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -53,6 +53,7 @@ extern bool kvm_gsi_direct_mapping;
extern bool kvm_readonly_mem_allowed;
extern bool kvm_direct_msi_allowed;
extern bool kvm_ioeventfd_any_length_allowed;
+extern bool kvm_msi_use_devid;
#if defined CONFIG_KVM || !defined NEED_CPU_H
#define kvm_enabled() (kvm_allowed)
@@ -169,6 +170,13 @@ extern bool kvm_ioeventfd_any_length_allowed;
*/
#define kvm_ioeventfd_any_length_enabled() (kvm_ioeventfd_any_length_allowed)
+/**
+ * kvm_msi_devid_required:
+ * Returns: true if KVM requires a device id to be provided while
+ * defining an MSI routing entry.
+ */
+#define kvm_msi_devid_required() (kvm_msi_use_devid)
+
#else
#define kvm_enabled() (0)
#define kvm_irqchip_in_kernel() (false)
@@ -184,6 +192,7 @@ extern bool kvm_ioeventfd_any_length_allowed;
#define kvm_readonly_mem_enabled() (false)
#define kvm_direct_msi_enabled() (false)
#define kvm_ioeventfd_any_length_enabled() (false)
+#define kvm_msi_devid_required() (false)
#endif
struct kvm_run;
diff --git a/kvm-all.c b/kvm-all.c
index fc2898a951..efb5fe37e2 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -119,6 +119,7 @@ bool kvm_readonly_mem_allowed;
bool kvm_vm_attributes_allowed;
bool kvm_direct_msi_allowed;
bool kvm_ioeventfd_any_length_allowed;
+bool kvm_msi_use_devid;
static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_INFO(USER_MEMORY),
@@ -1275,6 +1276,10 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
kroute.u.msi.address_lo = (uint32_t)msg.address;
kroute.u.msi.address_hi = msg.address >> 32;
kroute.u.msi.data = le32_to_cpu(msg.data);
+ if (kvm_msi_devid_required()) {
+ kroute.flags = KVM_MSI_VALID_DEVID;
+ kroute.u.msi.devid = pci_requester_id(dev);
+ }
if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
kvm_irqchip_release_virq(s, virq);
return -EINVAL;
@@ -1308,6 +1313,10 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
kroute.u.msi.address_lo = (uint32_t)msg.address;
kroute.u.msi.address_hi = msg.address >> 32;
kroute.u.msi.data = le32_to_cpu(msg.data);
+ if (kvm_msi_devid_required()) {
+ kroute.flags = KVM_MSI_VALID_DEVID;
+ kroute.u.msi.devid = pci_requester_id(dev);
+ }
if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
return -EINVAL;
}
diff --git a/kvm-stub.c b/kvm-stub.c
index 322712764f..b1b6b96c96 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -31,6 +31,7 @@ bool kvm_gsi_direct_mapping;
bool kvm_allowed;
bool kvm_readonly_mem_allowed;
bool kvm_ioeventfd_any_length_allowed;
+bool kvm_msi_use_devid;
int kvm_destroy_vcpu(CPUState *cpu)
{
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
index a4193684a8..633d08828a 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -13,6 +13,7 @@
#include "sysemu/kvm.h"
#include "exec/memory.h"
+#include "qemu/error-report.h"
/**
* kvm_arm_vcpu_init:
@@ -223,7 +224,20 @@ static inline const char *gic_class_name(void)
*
* Returns: class name to use
*/
-const char *gicv3_class_name(void);
+static inline const char *gicv3_class_name(void)
+{
+ if (kvm_irqchip_in_kernel()) {
+#ifdef TARGET_AARCH64
+ return "kvm-arm-gicv3";
+#else
+ error_report("KVM GICv3 acceleration is not supported on this "
+ "platform");
+ exit(1);
+#endif
+ } else {
+ return "arm-gicv3";
+ }
+}
/**
* kvm_arm_handle_debug:
@@ -255,4 +269,23 @@ struct kvm_guest_debug_arch;
void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
+/**
+ * its_class_name
+ *
+ * Return the ITS class name to use depending on whether KVM acceleration
+ * and KVM CAP_SIGNAL_MSI are supported
+ *
+ * Returns: class name to use or NULL
+ */
+static inline const char *its_class_name(void)
+{
+ if (kvm_irqchip_in_kernel()) {
+ /* KVM implementation requires this capability */
+ return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
+ } else {
+ /* Software emulation is not implemented yet */
+ return NULL;
+ }
+}
+
#endif
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 7a6ca31a8e..d90943b6db 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -331,18 +331,3 @@ const VMStateDescription vmstate_arm_cpu = {
NULL
}
};
-
-const char *gicv3_class_name(void)
-{
- if (kvm_irqchip_in_kernel()) {
-#ifdef TARGET_AARCH64
- return "kvm-arm-gicv3";
-#else
- error_report("KVM GICv3 acceleration is not supported on this "
- "platform");
- exit(1);
-#endif
- } else {
- return "arm-gicv3";
- }
-}
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index ddf52f5e79..307e281557 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2025,7 +2025,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
do_fp_ld(s, rt, tcg_addr, size);
} else {
/* Only unsigned 32bit loads target 32bit registers. */
- bool iss_sf = opc == 0 ? 32 : 64;
+ bool iss_sf = opc != 0;
do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false,
true, rt, iss_sf, false);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 693d4bc6a2..8df24bf35a 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -180,7 +180,12 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg)
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
{
if (reg == 15) {
- tcg_gen_andi_i32(var, var, ~1);
+ /* In Thumb mode, we must ignore bit 0.
+ * In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0]
+ * are not 0b00, but for ARMv6 and above, we must ignore bits [1:0].
+ * We choose to ignore [1:0] in ARM mode for all architecture versions.
+ */
+ tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
s->is_jmp = DISAS_JUMP;
}
tcg_gen_mov_i32(cpu_R[reg], var);