aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p-local.c16
-rw-r--r--hw/9pfs/9p.c42
-rw-r--r--hw/9pfs/9p.h2
-rw-r--r--hw/9pfs/virtio-9p-device.c12
-rw-r--r--hw/9pfs/xen-9p-backend.c13
-rw-r--r--hw/acpi/cpu.c18
-rw-r--r--hw/acpi/generic_event_device.c2
-rw-r--r--hw/acpi/trace-events1
-rw-r--r--hw/arm/Kconfig10
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm/allwinner-a10.c39
-rw-r--r--hw/arm/exynos4210.c77
-rw-r--r--hw/arm/fsl-imx25.c11
-rw-r--r--hw/arm/netduinoplus2.c52
-rw-r--r--hw/arm/stellaris.c2
-rw-r--r--hw/arm/stm32f405_soc.c302
-rw-r--r--hw/arm/virt.c6
-rw-r--r--hw/char/exynos4210_uart.c245
-rw-r--r--hw/char/trace-events20
-rw-r--r--hw/core/qdev.c3
-rw-r--r--hw/display/ads7846.c2
-rw-r--r--hw/dma/pl330.c88
-rw-r--r--hw/dma/trace-events24
-rw-r--r--hw/i2c/core.c2
-rw-r--r--hw/i386/acpi-build.c1
-rw-r--r--hw/i386/pc.c4
-rw-r--r--hw/input/stellaris_input.c3
-rw-r--r--hw/intc/apic_common.c7
-rw-r--r--hw/intc/arm_gicv3_cpuif.c3
-rw-r--r--hw/misc/Kconfig6
-rw-r--r--hw/misc/Makefile.objs3
-rw-r--r--hw/misc/imx_rngc.c278
-rw-r--r--hw/misc/max111x.c3
-rw-r--r--hw/misc/stm32f4xx_exti.c188
-rw-r--r--hw/misc/stm32f4xx_syscfg.c171
-rw-r--r--hw/misc/trace-events11
-rw-r--r--hw/net/eepro100.c3
-rw-r--r--hw/pci-host/q35.c84
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--hw/scsi/virtio-scsi.c6
-rw-r--r--hw/timer/arm_timer.c2
-rw-r--r--hw/tpm/tpm_emulator.c3
-rw-r--r--hw/virtio/vhost-user.c2
-rw-r--r--hw/virtio/vhost-vsock.c12
-rw-r--r--hw/virtio/vhost.c39
46 files changed, 1580 insertions, 244 deletions
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index ca641390fb..54e012e5b4 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -947,7 +947,7 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
local_is_mapped_file_metadata(ctx, name)) {
errno = EINVAL;
- return -1;
+ goto out;
}
odirfd = local_opendir_nofollow(ctx, odirpath);
@@ -1076,7 +1076,7 @@ out:
static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
int flags)
{
- int ret = -1;
+ int ret;
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
int map_dirfd;
@@ -1094,12 +1094,12 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
fd = openat_dir(dirfd, name);
if (fd == -1) {
- goto err_out;
+ return -1;
}
ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
close_preserve_errno(fd);
if (ret < 0 && errno != ENOENT) {
- goto err_out;
+ return -1;
}
}
map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
@@ -1107,16 +1107,14 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
ret = unlinkat(map_dirfd, name, 0);
close_preserve_errno(map_dirfd);
if (ret < 0 && errno != ENOENT) {
- goto err_out;
+ return -1;
}
} else if (errno != ENOENT) {
- goto err_out;
+ return -1;
}
}
- ret = unlinkat(dirfd, name, flags);
-err_out:
- return ret;
+ return unlinkat(dirfd, name, flags);
}
static int local_remove(FsContext *ctx, const char *path)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 520177f40c..b0e445d6bd 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -2090,22 +2090,29 @@ out_nofid:
* with qemu_iovec_destroy().
*/
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
- size_t skip, size_t size,
+ size_t skip, size_t *size,
bool is_write)
{
QEMUIOVector elem;
struct iovec *iov;
unsigned int niov;
+ size_t alloc_size = *size + skip;
if (is_write) {
- pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
+ pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, alloc_size);
} else {
- pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
+ pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, &alloc_size);
+ }
+
+ if (alloc_size < skip) {
+ *size = 0;
+ } else {
+ *size = alloc_size - skip;
}
qemu_iovec_init_external(&elem, iov, niov);
qemu_iovec_init(qiov, niov);
- qemu_iovec_concat(qiov, &elem, skip, size);
+ qemu_iovec_concat(qiov, &elem, skip, *size);
}
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
@@ -2113,15 +2120,14 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
{
ssize_t err;
size_t offset = 7;
- uint64_t read_count;
+ size_t read_count;
QEMUIOVector qiov_full;
if (fidp->fs.xattr.len < off) {
read_count = 0;
- } else {
+ } else if (fidp->fs.xattr.len - off < max_count) {
read_count = fidp->fs.xattr.len - off;
- }
- if (read_count > max_count) {
+ } else {
read_count = max_count;
}
err = pdu_marshal(pdu, offset, "d", read_count);
@@ -2130,7 +2136,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
}
offset += err;
- v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false);
+ v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &read_count, false);
err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0,
((char *)fidp->fs.xattr.value) + off,
read_count);
@@ -2259,9 +2265,11 @@ static void coroutine_fn v9fs_read(void *opaque)
QEMUIOVector qiov_full;
QEMUIOVector qiov;
int32_t len;
+ size_t size = max_count;
- v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
+ v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, &size, false);
qemu_iovec_init(&qiov, qiov_full.niov);
+ max_count = size;
do {
qemu_iovec_reset(&qiov);
qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
@@ -2464,8 +2472,7 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
if (fidp->fs.xattr.len < off) {
- err = -ENOSPC;
- goto out;
+ return -ENOSPC;
}
write_count = fidp->fs.xattr.len - off;
if (write_count > count) {
@@ -2491,7 +2498,7 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
off += to_copy;
write_count -= to_copy;
}
-out:
+
return err;
}
@@ -2504,6 +2511,7 @@ static void coroutine_fn v9fs_write(void *opaque)
int32_t len = 0;
int32_t total = 0;
size_t offset = 7;
+ size_t size;
V9fsFidState *fidp;
V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s;
@@ -2516,7 +2524,9 @@ static void coroutine_fn v9fs_write(void *opaque)
return;
}
offset += err;
- v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
+ size = count;
+ v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &size, true);
+ count = size;
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
fidp = get_fid(pdu, fid);
@@ -3056,8 +3066,7 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
if (newdirfid != -1) {
dirfidp = get_fid(pdu, newdirfid);
if (dirfidp == NULL) {
- err = -ENOENT;
- goto out_nofid;
+ return -ENOENT;
}
if (fidp->fid_type != P9_FID_NONE) {
err = -EINVAL;
@@ -3100,7 +3109,6 @@ out:
put_fid(pdu, dirfidp);
}
v9fs_path_free(&new_path);
-out_nofid:
return err;
}
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index 3904f82901..8d07a0b301 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -425,7 +425,7 @@ struct V9fsTransport {
ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt,
va_list ap);
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
- unsigned int *pniov, size_t size);
+ unsigned int *pniov, size_t *size);
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
unsigned int *pniov, size_t size);
void (*push_and_notify)(V9fsPDU *pdu);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index b5a7c03f26..1d1c50409c 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -147,19 +147,22 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
}
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
- unsigned int *pniov, size_t size)
+ unsigned int *pniov, size_t *size)
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
size_t buf_size = iov_size(elem->in_sg, elem->in_num);
- if (buf_size < size) {
+ if (buf_size < P9_IOHDRSZ) {
VirtIODevice *vdev = VIRTIO_DEVICE(v);
virtio_error(vdev,
- "VirtFS reply type %d needs %zu bytes, buffer has %zu",
- pdu->id + 1, size, buf_size);
+ "VirtFS reply type %d needs %zu bytes, buffer has %zu, less than minimum",
+ pdu->id + 1, *size, buf_size);
+ }
+ if (buf_size < *size) {
+ *size = buf_size;
}
*piov = elem->in_sg;
@@ -215,6 +218,7 @@ static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
V9fsVirtioState *v = VIRTIO_9P(dev);
V9fsState *s = &v->state;
+ virtio_delete_queue(v->vq);
virtio_cleanup(vdev);
v9fs_device_unrealize_common(s, errp);
}
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index 71eebe12dd..18fe5b7c92 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -187,7 +187,7 @@ static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
struct iovec **piov,
unsigned int *pniov,
- size_t size)
+ size_t *size)
{
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
@@ -197,16 +197,19 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
g_free(ring->sg);
ring->sg = g_new0(struct iovec, 2);
- xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
+ xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, *size);
buf_size = iov_size(ring->sg, num);
- if (buf_size < size) {
+ if (buf_size < P9_IOHDRSZ) {
xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d"
- "needs %zu bytes, buffer has %zu\n", pdu->id, size,
- buf_size);
+ "needs %zu bytes, buffer has %zu, less than minimum\n",
+ pdu->id, *size, buf_size);
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
xen_9pfs_disconnect(&xen_9pfs->xendev);
}
+ if (buf_size < *size) {
+ *size = buf_size;
+ }
*piov = ring->sg;
*pniov = num;
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 87f30a31d7..e2c957ce00 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -12,11 +12,13 @@
#define ACPI_CPU_FLAGS_OFFSET_RW 4
#define ACPI_CPU_CMD_OFFSET_WR 5
#define ACPI_CPU_CMD_DATA_OFFSET_RW 8
+#define ACPI_CPU_CMD_DATA2_OFFSET_R 0
enum {
CPHP_GET_NEXT_CPU_WITH_EVENT_CMD = 0,
CPHP_OST_EVENT_CMD = 1,
CPHP_OST_STATUS_CMD = 2,
+ CPHP_GET_CPU_ID_CMD = 3,
CPHP_CMD_MAX
};
@@ -74,11 +76,27 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
case CPHP_GET_NEXT_CPU_WITH_EVENT_CMD:
val = cpu_st->selector;
break;
+ case CPHP_GET_CPU_ID_CMD:
+ val = cdev->arch_id & 0xFFFFFFFF;
+ break;
default:
break;
}
trace_cpuhp_acpi_read_cmd_data(cpu_st->selector, val);
break;
+ case ACPI_CPU_CMD_DATA2_OFFSET_R:
+ switch (cpu_st->command) {
+ case CPHP_GET_NEXT_CPU_WITH_EVENT_CMD:
+ val = 0;
+ break;
+ case CPHP_GET_CPU_ID_CMD:
+ val = cdev->arch_id >> 32;
+ break;
+ default:
+ break;
+ }
+ trace_cpuhp_acpi_read_cmd_data2(cpu_st->selector, val);
+ break;
default:
break;
}
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 9cee90cc70..55eb29d80a 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -175,7 +175,7 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
AcpiGedState *s = ACPI_GED(hotplug_dev);
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events
index 96b8273297..afbc77de1c 100644
--- a/hw/acpi/trace-events
+++ b/hw/acpi/trace-events
@@ -23,6 +23,7 @@ cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] flags: 0x%"
cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32
cpuhp_acpi_write_cmd(uint32_t idx, uint8_t cmd) "idx[0x%"PRIx32"] cmd: 0x%"PRIx8
cpuhp_acpi_read_cmd_data(uint32_t idx, uint32_t data) "idx[0x%"PRIx32"] data: 0x%"PRIx32
+cpuhp_acpi_read_cmd_data2(uint32_t idx, uint32_t data) "idx[0x%"PRIx32"] data: 0x%"PRIx32
cpuhp_acpi_cpu_has_events(uint32_t idx, bool ins, bool rm) "idx[0x%"PRIx32"] inserting: %d, removing: %d"
cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c6e7782580..3d86691ae0 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -101,6 +101,10 @@ config NETDUINO2
bool
select STM32F205_SOC
+config NETDUINOPLUS2
+ bool
+ select STM32F405_SOC
+
config NSERIES
bool
select OMAP
@@ -307,6 +311,12 @@ config STM32F205_SOC
select STM32F2XX_ADC
select STM32F2XX_SPI
+config STM32F405_SOC
+ bool
+ select ARM_V7M
+ select STM32F4XX_SYSCFG
+ select STM32F4XX_EXTI
+
config XLNX_ZYNQMP_ARM
bool
select AHCI
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index fe749f65fd..336f6dd374 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -11,6 +11,7 @@ obj-$(CONFIG_MAINSTONE) += mainstone.o
obj-$(CONFIG_MICROBIT) += microbit.o
obj-$(CONFIG_MUSICPAL) += musicpal.o
obj-$(CONFIG_NETDUINO2) += netduino2.o
+obj-$(CONFIG_NETDUINOPLUS2) += netduinoplus2.o
obj-$(CONFIG_NSERIES) += nseries.o
obj-$(CONFIG_SX1) += omap_sx1.o
obj-$(CONFIG_CHEETAH) += palm.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_STRONGARM) += strongarm.o
obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
+obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o
obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 118032c8c7..1cde165611 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -25,6 +25,12 @@
#include "hw/misc/unimp.h"
#include "sysemu/sysemu.h"
+#define AW_A10_PIC_REG_BASE 0x01c20400
+#define AW_A10_PIT_REG_BASE 0x01c20c00
+#define AW_A10_UART0_REG_BASE 0x01c28000
+#define AW_A10_EMAC_BASE 0x01c0b000
+#define AW_A10_SATA_BASE 0x01c18000
+
static void aw_a10_init(Object *obj)
{
AwA10State *s = AW_A10(obj);
@@ -49,8 +55,6 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
{
AwA10State *s = AW_A10(dev);
SysBusDevice *sysbusdev;
- uint8_t i;
- qemu_irq fiq, irq;
Error *err = NULL;
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
@@ -58,8 +62,6 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
- irq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
- fiq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
object_property_set_bool(OBJECT(&s->intc), true, "realized", &err);
if (err != NULL) {
@@ -68,11 +70,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
}
sysbusdev = SYS_BUS_DEVICE(&s->intc);
sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
- sysbus_connect_irq(sysbusdev, 0, irq);
- sysbus_connect_irq(sysbusdev, 1, fiq);
- for (i = 0; i < AW_A10_PIC_INT_NR; i++) {
- s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
- }
+ sysbus_connect_irq(sysbusdev, 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
+ sysbus_connect_irq(sysbusdev, 1,
+ qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
+ qdev_pass_gpios(DEVICE(&s->intc), dev, NULL);
object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
if (err != NULL) {
@@ -81,12 +83,12 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
}
sysbusdev = SYS_BUS_DEVICE(&s->timer);
sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
- sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
- sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
- sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
- sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
- sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
- sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
+ sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(dev, 22));
+ sysbus_connect_irq(sysbusdev, 1, qdev_get_gpio_in(dev, 23));
+ sysbus_connect_irq(sysbusdev, 2, qdev_get_gpio_in(dev, 24));
+ sysbus_connect_irq(sysbusdev, 3, qdev_get_gpio_in(dev, 25));
+ sysbus_connect_irq(sysbusdev, 4, qdev_get_gpio_in(dev, 67));
+ sysbus_connect_irq(sysbusdev, 5, qdev_get_gpio_in(dev, 68));
memory_region_init_ram(&s->sram_a, OBJECT(dev), "sram A", 48 * KiB,
&error_fatal);
@@ -105,7 +107,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
}
sysbusdev = SYS_BUS_DEVICE(&s->emac);
sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE);
- sysbus_connect_irq(sysbusdev, 0, s->irq[55]);
+ sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(dev, 55));
object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
if (err) {
@@ -113,10 +115,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, qdev_get_gpio_in(dev, 56));
/* FIXME use a qdev chardev prop instead of serial_hd() */
- serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
+ serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2,
+ qdev_get_gpio_in(dev, 1),
115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
}
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 77fbe1baab..59a27bdd68 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -166,17 +166,37 @@ static uint64_t exynos4210_calc_affinity(int cpu)
return (0x9 << ARM_AFF1_SHIFT) | cpu;
}
-static void pl330_create(uint32_t base, qemu_irq irq, int nreq)
+static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate,
+ qemu_irq irq, int nreq, int nevents, int width)
{
SysBusDevice *busdev;
DeviceState *dev;
+ int i;
dev = qdev_create(NULL, "pl330");
+ qdev_prop_set_uint8(dev, "num_events", nevents);
+ qdev_prop_set_uint8(dev, "num_chnls", 8);
qdev_prop_set_uint8(dev, "num_periph_req", nreq);
+
+ qdev_prop_set_uint8(dev, "wr_cap", 4);
+ qdev_prop_set_uint8(dev, "wr_q_dep", 8);
+ qdev_prop_set_uint8(dev, "rd_cap", 4);
+ qdev_prop_set_uint8(dev, "rd_q_dep", 8);
+ qdev_prop_set_uint8(dev, "data_width", width);
+ qdev_prop_set_uint16(dev, "data_buffer_dep", width);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, base);
- sysbus_connect_irq(busdev, 0, irq);
+
+ object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines",
+ &error_abort);
+ object_property_set_bool(OBJECT(orgate), true, "realized", &error_abort);
+
+ for (i = 0; i < nevents + 1; i++) {
+ sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
+ }
+ qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
+ return dev;
}
static void exynos4210_realize(DeviceState *socdev, Error **errp)
@@ -185,7 +205,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
MemoryRegion *system_mem = get_system_memory();
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
SysBusDevice *busdev;
- DeviceState *dev;
+ DeviceState *dev, *uart[4], *pl330[3];
int i, n;
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
@@ -371,19 +391,19 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
/*** UARTs ***/
- exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
+ uart[0] = exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
- exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
+ uart[1] = exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
- exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
+ uart[2] = exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
- exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
+ uart[3] = exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
@@ -431,12 +451,42 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
s->irq_table[exynos4210_get_irq(28, 3)]);
/*** DMA controllers ***/
- pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(35, 1)]), 32);
- pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(36, 1)]), 32);
- pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(34, 1)]), 1);
+ pl330[0] = pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
+ &s->pl330_irq_orgate[0],
+ s->irq_table[exynos4210_get_irq(21, 0)],
+ 32, 32, 32);
+ pl330[1] = pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
+ &s->pl330_irq_orgate[1],
+ s->irq_table[exynos4210_get_irq(21, 1)],
+ 32, 32, 32);
+ pl330[2] = pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
+ &s->pl330_irq_orgate[2],
+ s->irq_table[exynos4210_get_irq(20, 1)],
+ 1, 31, 64);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[0]), 1,
+ qdev_get_gpio_in(pl330[0], 15));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[1]), 1,
+ qdev_get_gpio_in(pl330[1], 15));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[2]), 1,
+ qdev_get_gpio_in(pl330[0], 17));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[3]), 1,
+ qdev_get_gpio_in(pl330[1], 17));
+}
+
+static void exynos4210_init(Object *obj)
+{
+ Exynos4210State *s = EXYNOS4210_SOC(obj);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->pl330_irq_orgate); i++) {
+ char *name = g_strdup_printf("pl330-irq-orgate%d", i);
+ qemu_or_irq *orgate = &s->pl330_irq_orgate[i];
+
+ object_initialize_child(obj, name, orgate, sizeof(*orgate),
+ TYPE_OR_IRQ, &error_abort, NULL);
+ g_free(name);
+ }
}
static void exynos4210_class_init(ObjectClass *klass, void *data)
@@ -450,6 +500,7 @@ static const TypeInfo exynos4210_info = {
.name = TYPE_EXYNOS4210_SOC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210State),
+ .instance_init = exynos4210_init,
.class_init = exynos4210_class_init,
};
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 3cb5a8fdfd..da3471b395 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -62,6 +62,9 @@ static void fsl_imx25_init(Object *obj)
sysbus_init_child_obj(obj, "fec", &s->fec, sizeof(s->fec), TYPE_IMX_FEC);
+ sysbus_init_child_obj(obj, "rngc", &s->rngc, sizeof(s->rngc),
+ TYPE_IMX_RNGC);
+
for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
sysbus_init_child_obj(obj, "i2c[*]", &s->i2c[i], sizeof(s->i2c[i]),
TYPE_IMX_I2C);
@@ -188,6 +191,14 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
+ object_property_set_bool(OBJECT(&s->rngc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rngc), 0, FSL_IMX25_RNGC_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rngc), 0,
+ qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_RNGC_IRQ));
/* Initialize all I2C */
for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c
new file mode 100644
index 0000000000..e5e247edbe
--- /dev/null
+++ b/hw/arm/netduinoplus2.c
@@ -0,0 +1,52 @@
+/*
+ * Netduino Plus 2 Machine Model
+ *
+ * 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 "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "qemu/error-report.h"
+#include "hw/arm/stm32f405_soc.h"
+#include "hw/arm/boot.h"
+
+static void netduinoplus2_init(MachineState *machine)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, TYPE_STM32F405_SOC);
+ qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
+ object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
+
+ armv7m_load_kernel(ARM_CPU(first_cpu),
+ machine->kernel_filename,
+ FLASH_SIZE);
+}
+
+static void netduinoplus2_machine_init(MachineClass *mc)
+{
+ mc->desc = "Netduino Plus 2 Machine";
+ mc->init = netduinoplus2_init;
+}
+
+DEFINE_MACHINE("netduinoplus2", netduinoplus2_machine_init)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index b198066b54..bb025e0bd0 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -708,7 +708,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000);
memory_region_add_subregion(get_system_memory(), base, &s->iomem);
ssys_reset(s);
- vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_stellaris_sys, s);
return 0;
}
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
new file mode 100644
index 0000000000..f22516fdf7
--- /dev/null
+++ b/hw/arm/stm32f405_soc.c
@@ -0,0 +1,302 @@
+/*
+ * STM32F405 SoC
+ *
+ * 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-common.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/stm32f405_soc.h"
+#include "hw/misc/unimp.h"
+
+#define SYSCFG_ADD 0x40013800
+static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
+ 0x40004C00, 0x40005000, 0x40011400,
+ 0x40007800, 0x40007C00 };
+/* At the moment only Timer 2 to 5 are modelled */
+static const uint32_t timer_addr[] = { 0x40000000, 0x40000400,
+ 0x40000800, 0x40000C00 };
+#define ADC_ADDR 0x40012000
+static const uint32_t spi_addr[] = { 0x40013000, 0x40003800, 0x40003C00,
+ 0x40013400, 0x40015000, 0x40015400 };
+#define EXTI_ADDR 0x40013C00
+
+#define SYSCFG_IRQ 71
+static const int usart_irq[] = { 37, 38, 39, 52, 53, 71, 82, 83 };
+static const int timer_irq[] = { 28, 29, 30, 50 };
+#define ADC_IRQ 18
+static const int spi_irq[] = { 35, 36, 51, 0, 0, 0 };
+static const int exti_irq[] = { 6, 7, 8, 9, 10, 23, 23, 23, 23, 23, 40,
+ 40, 40, 40, 40, 40} ;
+
+
+static void stm32f405_soc_initfn(Object *obj)
+{
+ STM32F405State *s = STM32F405_SOC(obj);
+ int i;
+
+ sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m),
+ TYPE_ARMV7M);
+
+ sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg),
+ TYPE_STM32F4XX_SYSCFG);
+
+ for (i = 0; i < STM_NUM_USARTS; i++) {
+ sysbus_init_child_obj(obj, "usart[*]", &s->usart[i],
+ sizeof(s->usart[i]), TYPE_STM32F2XX_USART);
+ }
+
+ for (i = 0; i < STM_NUM_TIMERS; i++) {
+ sysbus_init_child_obj(obj, "timer[*]", &s->timer[i],
+ sizeof(s->timer[i]), TYPE_STM32F2XX_TIMER);
+ }
+
+ for (i = 0; i < STM_NUM_ADCS; i++) {
+ sysbus_init_child_obj(obj, "adc[*]", &s->adc[i], sizeof(s->adc[i]),
+ TYPE_STM32F2XX_ADC);
+ }
+
+ for (i = 0; i < STM_NUM_SPIS; i++) {
+ sysbus_init_child_obj(obj, "spi[*]", &s->spi[i], sizeof(s->spi[i]),
+ TYPE_STM32F2XX_SPI);
+ }
+
+ sysbus_init_child_obj(obj, "exti", &s->exti, sizeof(s->exti),
+ TYPE_STM32F4XX_EXTI);
+}
+
+static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ STM32F405State *s = STM32F405_SOC(dev_soc);
+ MemoryRegion *system_memory = get_system_memory();
+ DeviceState *dev, *armv7m;
+ SysBusDevice *busdev;
+ Error *err = NULL;
+ int i;
+
+ memory_region_init_ram(&s->flash, NULL, "STM32F405.flash", FLASH_SIZE,
+ &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_init_alias(&s->flash_alias, NULL, "STM32F405.flash.alias",
+ &s->flash, 0, FLASH_SIZE);
+
+ memory_region_set_readonly(&s->flash, true);
+ memory_region_set_readonly(&s->flash_alias, true);
+
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
+ memory_region_add_subregion(system_memory, 0, &s->flash_alias);
+
+ memory_region_init_ram(&s->sram, NULL, "STM32F405.sram", SRAM_SIZE,
+ &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
+
+ armv7m = DEVICE(&s->armv7m);
+ qdev_prop_set_uint32(armv7m, "num-irq", 96);
+ qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ object_property_set_link(OBJECT(&s->armv7m), OBJECT(system_memory),
+ "memory", &error_abort);
+ object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ /* System configuration controller */
+ dev = DEVICE(&s->syscfg);
+ object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, SYSCFG_ADD);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, SYSCFG_IRQ));
+
+ /* Attach UART (uses USART registers) and USART controllers */
+ for (i = 0; i < STM_NUM_USARTS; i++) {
+ dev = DEVICE(&(s->usart[i]));
+ qdev_prop_set_chr(dev, "chardev", serial_hd(i));
+ object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, usart_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i]));
+ }
+
+ /* Timer 2 to 5 */
+ for (i = 0; i < STM_NUM_TIMERS; i++) {
+ 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;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, timer_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, timer_irq[i]));
+ }
+
+ /* ADC device, the IRQs are ORed together */
+ object_initialize_child(OBJECT(s), "adc-orirq", &s->adc_irqs,
+ sizeof(s->adc_irqs), TYPE_OR_IRQ,
+ &err, NULL);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ 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(armv7m, ADC_IRQ));
+
+ 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);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(DEVICE(&s->adc_irqs), i));
+
+ /* SPI devices */
+ 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(armv7m, spi_irq[i]));
+ }
+
+ /* EXTI device */
+ dev = DEVICE(&s->exti);
+ object_property_set_bool(OBJECT(&s->exti), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, EXTI_ADDR);
+ for (i = 0; i < 16; i++) {
+ sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
+ }
+ for (i = 0; i < 16; i++) {
+ qdev_connect_gpio_out(DEVICE(&s->syscfg), i, qdev_get_gpio_in(dev, i));
+ }
+
+ create_unimplemented_device("timer[7]", 0x40001400, 0x400);
+ create_unimplemented_device("timer[12]", 0x40001800, 0x400);
+ create_unimplemented_device("timer[6]", 0x40001000, 0x400);
+ create_unimplemented_device("timer[13]", 0x40001C00, 0x400);
+ create_unimplemented_device("timer[14]", 0x40002000, 0x400);
+ create_unimplemented_device("RTC and BKP", 0x40002800, 0x400);
+ create_unimplemented_device("WWDG", 0x40002C00, 0x400);
+ create_unimplemented_device("IWDG", 0x40003000, 0x400);
+ create_unimplemented_device("I2S2ext", 0x40003000, 0x400);
+ create_unimplemented_device("I2S3ext", 0x40004000, 0x400);
+ create_unimplemented_device("I2C1", 0x40005400, 0x400);
+ create_unimplemented_device("I2C2", 0x40005800, 0x400);
+ create_unimplemented_device("I2C3", 0x40005C00, 0x400);
+ create_unimplemented_device("CAN1", 0x40006400, 0x400);
+ create_unimplemented_device("CAN2", 0x40006800, 0x400);
+ create_unimplemented_device("PWR", 0x40007000, 0x400);
+ create_unimplemented_device("DAC", 0x40007400, 0x400);
+ create_unimplemented_device("timer[1]", 0x40010000, 0x400);
+ create_unimplemented_device("timer[8]", 0x40010400, 0x400);
+ create_unimplemented_device("SDIO", 0x40012C00, 0x400);
+ create_unimplemented_device("timer[9]", 0x40014000, 0x400);
+ create_unimplemented_device("timer[10]", 0x40014400, 0x400);
+ create_unimplemented_device("timer[11]", 0x40014800, 0x400);
+ create_unimplemented_device("GPIOA", 0x40020000, 0x400);
+ create_unimplemented_device("GPIOB", 0x40020400, 0x400);
+ create_unimplemented_device("GPIOC", 0x40020800, 0x400);
+ create_unimplemented_device("GPIOD", 0x40020C00, 0x400);
+ create_unimplemented_device("GPIOE", 0x40021000, 0x400);
+ create_unimplemented_device("GPIOF", 0x40021400, 0x400);
+ create_unimplemented_device("GPIOG", 0x40021800, 0x400);
+ create_unimplemented_device("GPIOH", 0x40021C00, 0x400);
+ create_unimplemented_device("GPIOI", 0x40022000, 0x400);
+ create_unimplemented_device("CRC", 0x40023000, 0x400);
+ create_unimplemented_device("RCC", 0x40023800, 0x400);
+ create_unimplemented_device("Flash Int", 0x40023C00, 0x400);
+ create_unimplemented_device("BKPSRAM", 0x40024000, 0x400);
+ create_unimplemented_device("DMA1", 0x40026000, 0x400);
+ create_unimplemented_device("DMA2", 0x40026400, 0x400);
+ create_unimplemented_device("Ethernet", 0x40028000, 0x1400);
+ create_unimplemented_device("USB OTG HS", 0x40040000, 0x30000);
+ create_unimplemented_device("USB OTG FS", 0x50000000, 0x31000);
+ create_unimplemented_device("DCMI", 0x50050000, 0x400);
+ create_unimplemented_device("RNG", 0x50060800, 0x400);
+}
+
+static Property stm32f405_soc_properties[] = {
+ DEFINE_PROP_STRING("cpu-type", STM32F405State, cpu_type),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f405_soc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = stm32f405_soc_realize;
+ dc->props = stm32f405_soc_properties;
+ /* No vmstate or reset required: device has no internal state */
+}
+
+static const TypeInfo stm32f405_soc_info = {
+ .name = TYPE_STM32F405_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F405State),
+ .instance_init = stm32f405_soc_initfn,
+ .class_init = stm32f405_soc_class_init,
+};
+
+static void stm32f405_soc_types(void)
+{
+ type_register_static(&stm32f405_soc_info);
+}
+
+type_init(stm32f405_soc_types)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 39ab5f47e0..656b0081c2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1934,7 +1934,6 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
static void virt_memory_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- HotplugHandlerClass *hhc;
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
Error *local_err = NULL;
@@ -1943,8 +1942,9 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev,
goto out;
}
- hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev);
- hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort);
+ hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev),
+ dev, &error_abort);
+
out:
error_propagate(errp, local_err);
}
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 7e5c5ce789..20d8509107 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -24,6 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "qemu/timer.h"
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"
@@ -31,45 +32,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#undef DEBUG_UART
-#undef DEBUG_UART_EXTEND
-#undef DEBUG_IRQ
-#undef DEBUG_Rx_DATA
-#undef DEBUG_Tx_DATA
-
-#define DEBUG_UART 0
-#define DEBUG_UART_EXTEND 0
-#define DEBUG_IRQ 0
-#define DEBUG_Rx_DATA 0
-#define DEBUG_Tx_DATA 0
-
-#if DEBUG_UART
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_UART_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) \
- do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
+#include "trace.h"
/*
* Offsets for UART registers relative to SFR base address
@@ -156,6 +119,7 @@ static const Exynos4210UartReg exynos4210_uart_regs[] = {
#define ULCON_STOP_BIT_SHIFT 1
/* UART Tx/Rx Status */
+#define UTRSTAT_Rx_TIMEOUT 0x8
#define UTRSTAT_TRANSMITTER_EMPTY 0x4
#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
@@ -185,16 +149,19 @@ typedef struct Exynos4210UartState {
Exynos4210UartFIFO rx;
Exynos4210UartFIFO tx;
+ QEMUTimer *fifo_timeout_timer;
+ uint64_t wordtime; /* word time in ns */
+
CharBackend chr;
qemu_irq irq;
+ qemu_irq dmairq;
uint32_t channel;
} Exynos4210UartState;
-#if DEBUG_UART
-/* Used only for debugging inside PRINT_DEBUG_... macros */
+/* Used only for tracing */
static const char *exynos4210_uart_regname(hwaddr offset)
{
@@ -208,7 +175,6 @@ static const char *exynos4210_uart_regname(hwaddr offset)
return NULL;
}
-#endif
static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
@@ -249,15 +215,12 @@ static void fifo_reset(Exynos4210UartFIFO *q)
q->rp = 0;
}
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
+static uint32_t exynos4210_uart_FIFO_trigger_level(uint32_t channel,
+ uint32_t reg)
{
- uint32_t level = 0;
- uint32_t reg;
-
- reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
- UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
+ uint32_t level;
- switch (s->channel) {
+ switch (channel) {
case 0:
level = reg * 32;
break;
@@ -271,12 +234,52 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState
break;
default:
level = 0;
- PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
+ trace_exynos_uart_channel_error(channel);
+ break;
}
-
return level;
}
+static uint32_t
+exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
+{
+ uint32_t reg;
+
+ reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+ UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
+
+ return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
+}
+
+static uint32_t
+exynos4210_uart_Rx_FIFO_trigger_level(const Exynos4210UartState *s)
+{
+ uint32_t reg;
+
+ reg = ((s->reg[I_(UFCON)] & UFCON_Rx_FIFO_TRIGGER_LEVEL) >>
+ UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT) + 1;
+
+ return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
+}
+
+/*
+ * Update Rx DMA busy signal if Rx DMA is enabled. For simplicity,
+ * mark DMA as busy if DMA is enabled and the receive buffer is empty.
+ */
+static void exynos4210_uart_update_dmabusy(Exynos4210UartState *s)
+{
+ bool rx_dma_enabled = (s->reg[I_(UCON)] & 0x03) == 0x02;
+ uint32_t count = fifo_elements_number(&s->rx);
+
+ if (rx_dma_enabled && !count) {
+ qemu_irq_raise(s->dmairq);
+ trace_exynos_uart_dmabusy(s->channel);
+ } else {
+ qemu_irq_lower(s->dmairq);
+ trace_exynos_uart_dmaready(s->channel);
+ }
+}
+
static void exynos4210_uart_update_irq(Exynos4210UartState *s)
{
/*
@@ -284,27 +287,53 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
* transmit FIFO is smaller than the trigger level.
*/
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
-
uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
UFSTAT_Tx_FIFO_COUNT_SHIFT;
if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
s->reg[I_(UINTSP)] |= UINTSP_TXD;
}
+
+ /*
+ * Rx interrupt if trigger level is reached or if rx timeout
+ * interrupt is disabled and there is data in the receive buffer
+ */
+ count = fifo_elements_number(&s->rx);
+ if ((count && !(s->reg[I_(UCON)] & 0x80)) ||
+ count >= exynos4210_uart_Rx_FIFO_trigger_level(s)) {
+ exynos4210_uart_update_dmabusy(s);
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ timer_del(s->fifo_timeout_timer);
+ }
+ } else if (s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) {
+ exynos4210_uart_update_dmabusy(s);
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
}
s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
if (s->reg[I_(UINTP)]) {
qemu_irq_raise(s->irq);
-
-#if DEBUG_IRQ
- fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
- s->channel, s->reg[I_(UINTP)]);
-#endif
-
+ trace_exynos_uart_irq_raised(s->channel, s->reg[I_(UINTP)]);
} else {
qemu_irq_lower(s->irq);
+ trace_exynos_uart_irq_lowered(s->channel);
+ }
+}
+
+static void exynos4210_uart_timeout_int(void *opaque)
+{
+ Exynos4210UartState *s = opaque;
+
+ trace_exynos_uart_rx_timeout(s->channel, s->reg[I_(UTRSTAT)],
+ s->reg[I_(UINTSP)]);
+
+ if ((s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) ||
+ (s->reg[I_(UCON)] & (1 << 11))) {
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_TIMEOUT;
+ exynos4210_uart_update_dmabusy(s);
+ exynos4210_uart_update_irq(s);
}
}
@@ -346,10 +375,24 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits;
+ s->wordtime = NANOSECONDS_PER_SECOND * (data_bits + stop_bits + 1) / speed;
+
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
- s->channel, speed, parity, data_bits, stop_bits);
+ trace_exynos_uart_update_params(
+ s->channel, speed, parity, data_bits, stop_bits, s->wordtime);
+}
+
+static void exynos4210_uart_rx_timeout_set(Exynos4210UartState *s)
+{
+ if (s->reg[I_(UCON)] & 0x80) {
+ uint32_t timeout = ((s->reg[I_(UCON)] >> 12) & 0x0f) * s->wordtime;
+
+ timer_mod(s->fifo_timeout_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
+ } else {
+ timer_del(s->fifo_timeout_timer);
+ }
}
static void exynos4210_uart_write(void *opaque, hwaddr offset,
@@ -358,8 +401,8 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
Exynos4210UartState *s = (Exynos4210UartState *)opaque;
uint8_t ch;
- PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
- offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
+ trace_exynos_uart_write(s->channel, offset,
+ exynos4210_uart_regname(offset), val);
switch (offset) {
case ULCON:
@@ -373,12 +416,12 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
if (val & UFCON_Rx_FIFO_RESET) {
fifo_reset(&s->rx);
s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
+ trace_exynos_uart_rx_fifo_reset(s->channel);
}
if (val & UFCON_Tx_FIFO_RESET) {
fifo_reset(&s->tx);
s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
+ trace_exynos_uart_tx_fifo_reset(s->channel);
}
break;
@@ -390,9 +433,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
-#if DEBUG_Tx_DATA
- fprintf(stderr, "%c", ch);
-#endif
+ trace_exynos_uart_tx(s->channel, ch);
s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY;
s->reg[I_(UINTSP)] |= UINTSP_TXD;
@@ -403,16 +444,19 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
case UINTP:
s->reg[I_(UINTP)] &= ~val;
s->reg[I_(UINTSP)] &= ~val;
- PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
- s->channel, offset, s->reg[I_(UINTP)]);
+ trace_exynos_uart_intclr(s->channel, s->reg[I_(UINTP)]);
exynos4210_uart_update_irq(s);
break;
case UTRSTAT:
+ if (val & UTRSTAT_Rx_TIMEOUT) {
+ s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_TIMEOUT;
+ }
+ break;
case UERSTAT:
case UFSTAT:
case UMSTAT:
case URXH:
- PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
+ trace_exynos_uart_ro_write(
s->channel, exynos4210_uart_regname(offset), offset);
break;
case UINTSP:
@@ -429,6 +473,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
break;
}
}
+
static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
unsigned size)
{
@@ -439,6 +484,8 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
case UERSTAT: /* Read Only */
res = s->reg[I_(UERSTAT)];
s->reg[I_(UERSTAT)] = 0;
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset), res);
return res;
case UFSTAT: /* Read Only */
s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
@@ -446,20 +493,22 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
s->reg[I_(UFSTAT)] &= ~0xff;
}
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset),
+ s->reg[I_(UFSTAT)]);
return s->reg[I_(UFSTAT)];
case URXH:
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
if (fifo_elements_number(&s->rx)) {
res = fifo_retrieve(&s->rx);
-#if DEBUG_Rx_DATA
- fprintf(stderr, "%c", res);
-#endif
+ trace_exynos_uart_rx(s->channel, res);
if (!fifo_elements_number(&s->rx)) {
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
} else {
s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
} else {
+ trace_exynos_uart_rx_error(s->channel);
s->reg[I_(UINTSP)] |= UINTSP_ERROR;
exynos4210_uart_update_irq(s);
res = 0;
@@ -468,15 +517,23 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
res = s->reg[I_(URXH)];
}
+ exynos4210_uart_update_dmabusy(s);
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset), res);
return res;
case UTXH:
- PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
+ trace_exynos_uart_wo_read(s->channel, exynos4210_uart_regname(offset),
+ offset);
break;
default:
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset),
+ s->reg[I_(offset)]);
return s->reg[I_(offset)];
}
+ trace_exynos_uart_read(s->channel, offset, exynos4210_uart_regname(offset),
+ 0);
return 0;
}
@@ -497,7 +554,6 @@ static int exynos4210_uart_can_receive(void *opaque)
return fifo_empty_elements_number(&s->rx);
}
-
static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
{
Exynos4210UartState *s = (Exynos4210UartState *)opaque;
@@ -505,24 +561,17 @@ static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
if (fifo_empty_elements_number(&s->rx) < size) {
- for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
- fifo_store(&s->rx, buf[i]);
- }
+ size = fifo_empty_elements_number(&s->rx);
s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- for (i = 0; i < size; i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
- /* XXX: Around here we maybe should check Rx trigger level */
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ for (i = 0; i < size; i++) {
+ fifo_store(&s->rx, buf[i]);
+ }
+ exynos4210_uart_rx_timeout_set(s);
} else {
s->reg[I_(URXH)] = buf[0];
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
exynos4210_uart_update_irq(s);
}
@@ -555,13 +604,24 @@ static void exynos4210_uart_reset(DeviceState *dev)
fifo_reset(&s->rx);
fifo_reset(&s->tx);
- PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
+ trace_exynos_uart_rxsize(s->channel, s->rx.size);
+}
+
+static int exynos4210_uart_post_load(void *opaque, int version_id)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+ exynos4210_uart_update_parameters(s);
+ exynos4210_uart_rx_timeout_set(s);
+
+ return 0;
}
static const VMStateDescription vmstate_exynos4210_uart_fifo = {
.name = "exynos4210.uart.fifo",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
@@ -614,12 +674,17 @@ static void exynos4210_uart_init(Object *obj)
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
Exynos4210UartState *s = EXYNOS4210_UART(dev);
+ s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ exynos4210_uart_timeout_int, s);
+ s->wordtime = NANOSECONDS_PER_SECOND * 10 / 9600;
+
/* memory mapping */
memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
"exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(dev, &s->dmairq);
}
static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 2ce7f2f998..6f938301d9 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -77,3 +77,23 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1"
# nrf51_uart.c
nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
+
+# exynos4210_uart.c
+exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)"
+exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready"
+exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised: 0x%08"PRIx32
+exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered"
+exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int data, int stop, uint64_t wordtime) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: %d wordtime: %"PRId64"ns"
+exynos_uart_write(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s <- 0x%" PRIx64
+exynos_uart_read(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s -> 0x%" PRIx64
+exynos_uart_rx_fifo_reset(uint32_t channel) "UART%d: Rx FIFO Reset"
+exynos_uart_tx_fifo_reset(uint32_t channel) "UART%d: Tx FIFO Reset"
+exynos_uart_tx(uint32_t channel, uint8_t ch) "UART%d: Tx 0x%02"PRIx32
+exynos_uart_intclr(uint32_t channel, uint32_t reg) "UART%d: interrupts cleared: 0x%08"PRIx32
+exynos_uart_ro_write(uint32_t channel, const char *name, uint32_t reg) "UART%d: Trying to write into RO register: %s [0x%04"PRIx32"]"
+exynos_uart_rx(uint32_t channel, uint8_t ch) "UART%d: Rx 0x%02"PRIx32
+exynos_uart_rx_error(uint32_t channel) "UART%d: Rx error"
+exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UART%d: Trying to read from WO register: %s [0x%04"PRIx32"]"
+exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size: %d"
+exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d"
+exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d: Rx timeout stat=0x%x intsp=0x%x"
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 9f1753f5cf..58e87d336d 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -879,7 +879,8 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (qdev_get_vmsd(dev)) {
if (vmstate_register_with_alias_id(VMSTATE_IF(dev),
- -1, qdev_get_vmsd(dev), dev,
+ VMSTATE_INSTANCE_ID_ANY,
+ qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
dev->alias_required_for_version,
&local_err) < 0) {
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
index c12272ae72..9228b40b1a 100644
--- a/hw/display/ads7846.c
+++ b/hw/display/ads7846.c
@@ -154,7 +154,7 @@ static void ads7846_realize(SSISlave *d, Error **errp)
ads7846_int_update(s);
- vmstate_register(NULL, -1, &vmstate_ads7846, s);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s);
}
static void ads7846_class_init(ObjectClass *klass, void *data)
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
index f2bb2d9ac1..64519971ef 100644
--- a/hw/dma/pl330.c
+++ b/hw/dma/pl330.c
@@ -25,19 +25,12 @@
#include "sysemu/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
#ifndef PL330_ERR_DEBUG
#define PL330_ERR_DEBUG 0
#endif
-#define DB_PRINT_L(lvl, fmt, args...) do {\
- if (PL330_ERR_DEBUG >= lvl) {\
- fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
- } \
-} while (0)
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
#define PL330_PERIPH_NUM 32
#define PL330_MAX_BURST_LEN 128
#define PL330_INSN_MAXSIZE 6
@@ -319,6 +312,26 @@ typedef struct PL330InsnDesc {
void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
} PL330InsnDesc;
+static void pl330_hexdump(uint8_t *buf, size_t size)
+{
+ unsigned int b, i, len;
+ char tmpbuf[80];
+
+ for (b = 0; b < size; b += 16) {
+ len = size - b;
+ if (len > 16) {
+ len = 16;
+ }
+ tmpbuf[0] = '\0';
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0) {
+ strcat(tmpbuf, " ");
+ }
+ sprintf(tmpbuf + strlen(tmpbuf), " %02x", buf[b + i]);
+ }
+ trace_pl330_hexdump(b, tmpbuf);
+ }
+}
/* MFIFO Implementation
*
@@ -582,7 +595,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
{
- DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
+ trace_pl330_fault(ch, flags);
ch->fault_type |= flags;
if (ch->state == pl330_chan_fault) {
return;
@@ -590,7 +603,7 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
ch->state = pl330_chan_fault;
ch->parent->num_faulting++;
if (ch->parent->num_faulting == 1) {
- DB_PRINT("abort interrupt raised\n");
+ trace_pl330_fault_abort();
qemu_irq_raise(ch->parent->irq_abort);
}
}
@@ -648,7 +661,7 @@ static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
return;
}
}
- DB_PRINT("DMA ending!\n");
+ trace_pl330_dmaend();
pl330_fifo_tagged_remove(&s->fifo, ch->tag);
pl330_queue_remove_tagged(&s->read_queue, ch->tag);
pl330_queue_remove_tagged(&s->write_queue, ch->tag);
@@ -683,7 +696,7 @@ static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
uint32_t pc;
PL330Chan *s;
- DB_PRINT("\n");
+ trace_pl330_dmago();
if (!ch->is_manager) {
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
@@ -740,9 +753,7 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
size, num, inc, 0, ch->tag);
if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
+ trace_pl330_dmald(ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
}
}
@@ -782,7 +793,7 @@ static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->fault_type = 0;
ch->parent->num_faulting--;
if (ch->parent->num_faulting == 0) {
- DB_PRINT("abort interrupt lowered\n");
+ trace_pl330_dmakill();
qemu_irq_lower(ch->parent->irq_abort);
}
}
@@ -800,6 +811,8 @@ static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
uint8_t bs = opcode & 3;
uint8_t lc = (opcode & 4) >> 2;
+ trace_pl330_dmalpend(nf, bs, lc, ch->lc[lc], ch->request_flag);
+
if (bs == 2) {
pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
return;
@@ -813,12 +826,12 @@ static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
if (nf) {
ch->lc[lc]--;
}
- DB_PRINT("loop reiteration\n");
+ trace_pl330_dmalpiter();
ch->pc -= args[0];
ch->pc -= len + 1;
/* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
} else {
- DB_PRINT("loop fallthrough\n");
+ trace_pl330_dmalpfallthrough();
}
}
@@ -886,10 +899,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
}
if (ch->parent->inten & (1 << ev_id)) {
ch->parent->int_status |= (1 << ev_id);
- DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
+ trace_pl330_dmasev_evirq(ev_id);
qemu_irq_raise(ch->parent->irq[ev_id]);
}
- DB_PRINT("event raised %" PRId8 "\n", ev_id);
+ trace_pl330_dmasev_event(ev_id);
ch->parent->ev_status |= (1 << ev_id);
}
@@ -914,9 +927,7 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
size, num, inc, 0, ch->tag);
if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
+ trace_pl330_dmast(ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
}
}
@@ -992,7 +1003,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
}
}
ch->parent->ev_status &= ~(1 << ev_id);
- DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
+ trace_pl330_dmawfe(ev_id);
} else {
ch->stall = 1;
}
@@ -1135,7 +1146,7 @@ static int pl330_chan_exec(PL330Chan *ch)
ch->stall = 0;
insn = pl330_fetch_insn(ch);
if (!insn) {
- DB_PRINT("pl330 undefined instruction\n");
+ trace_pl330_chan_exec_undef();
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
return 0;
}
@@ -1175,10 +1186,9 @@ static int pl330_exec_cycle(PL330Chan *channel)
int len = q->len - (q->addr & (q->len - 1));
dma_memory_read(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
- q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
+ trace_pl330_exec_cycle(q->addr, len);
+ if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) {
+ pl330_hexdump(buf, len);
}
fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
if (fifo_res == PL330_FIFO_OK) {
@@ -1207,10 +1217,9 @@ static int pl330_exec_cycle(PL330Chan *channel)
}
if (fifo_res == PL330_FIFO_OK || q->z) {
dma_memory_write(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32
- " (size = %08x):\n", q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
+ trace_pl330_exec_cycle(q->addr, len);
+ if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) {
+ pl330_hexdump(buf, len);
}
if (q->inc) {
q->addr += len;
@@ -1252,8 +1261,8 @@ static int pl330_exec_channel(PL330Chan *channel)
static inline void pl330_exec(PL330State *s)
{
- DB_PRINT("\n");
int i, insr_exec;
+ trace_pl330_exec();
do {
insr_exec = pl330_exec_channel(&s->manager);
@@ -1298,7 +1307,7 @@ static void pl330_debug_exec(PL330State *s)
args[2] = (s->dbg[1] >> 8) & 0xff;
args[3] = (s->dbg[1] >> 16) & 0xff;
args[4] = (s->dbg[1] >> 24) & 0xff;
- DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
+ trace_pl330_debug_exec(chan_id);
if (s->dbg[0] & 1) {
ch = &s->chan[chan_id];
} else {
@@ -1320,6 +1329,7 @@ static void pl330_debug_exec(PL330State *s)
ch->fault_type |= PL330_FAULT_DBG_INSTR;
}
if (ch->stall) {
+ trace_pl330_debug_exec_stall();
qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
"implemented\n");
}
@@ -1334,7 +1344,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
PL330State *s = (PL330State *) opaque;
int i;
- DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
+ trace_pl330_iomem_write((unsigned)offset, (unsigned)value);
switch (offset) {
case PL330_REG_INTEN:
@@ -1343,7 +1353,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
case PL330_REG_INTCLR:
for (i = 0; i < s->num_events; i++) {
if (s->int_status & s->inten & value & (1 << i)) {
- DB_PRINT("event interrupt lowered %d\n", i);
+ trace_pl330_iomem_write_clr(i);
qemu_irq_lower(s->irq[i]);
}
}
@@ -1361,11 +1371,9 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
}
break;
case PL330_REG_DBGINST0:
- DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
s->dbg[0] = value;
break;
case PL330_REG_DBGINST1:
- DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
s->dbg[1] = value;
break;
default:
@@ -1489,7 +1497,7 @@ static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
unsigned size)
{
uint32_t ret = pl330_iomem_read_imp(opaque, offset);
- DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
+ trace_pl330_iomem_read((uint32_t)offset, ret);
return ret;
}
diff --git a/hw/dma/trace-events b/hw/dma/trace-events
index e4498428c5..44893995f6 100644
--- a/hw/dma/trace-events
+++ b/hw/dma/trace-events
@@ -20,3 +20,27 @@ sparc32_dma_enable_lower(void) "Lower DMA enable"
# i8257.c
i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
+
+# pl330.c
+pl330_fault(void *ptr, uint32_t flags) "ch: %p, flags: 0x%"PRIx32
+pl330_fault_abort(void) "abort interrupt raised"
+pl330_dmaend(void) "DMA ending"
+pl330_dmago(void) "DMA run"
+pl330_dmald(uint8_t chan, uint32_t addr, uint32_t size, uint32_t num, char ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32"%c"
+pl330_dmakill(void) "abort interrupt lowered"
+pl330_dmalpend(uint8_t nf, uint8_t bs, uint8_t lc, uint8_t ch, uint8_t flag) "nf=0x%02x bs=0x%02x lc=0x%02x ch=0x%02x flag=0x%02x"
+pl330_dmalpiter(void) "loop reiteration"
+pl330_dmalpfallthrough(void) "loop fallthrough"
+pl330_dmasev_evirq(uint8_t ev_id) "event interrupt raised %"PRId8
+pl330_dmasev_event(uint8_t ev_id) "event raised %"PRId8
+pl330_dmast(uint8_t chan, uint32_t addr, uint32_t sz, uint32_t num, char ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32" %c"
+pl330_dmawfe(uint8_t ev_id) "event lowered 0x%"PRIx8
+pl330_chan_exec_undef(void) "undefined instruction"
+pl330_exec_cycle(uint32_t addr, uint32_t size) "PL330 read from memory @0x%08"PRIx32" (size = 0x%08"PRIx32")"
+pl330_hexdump(uint32_t offset, char *str) " 0x%04"PRIx32":%s"
+pl330_exec(void) "pl330_exec"
+pl330_debug_exec(uint8_t ch) "chan id: 0x%"PRIx8
+pl330_debug_exec_stall(void) "stall of debug instruction not implemented"
+pl330_iomem_write(uint32_t offset, uint32_t value) "addr: 0x%08"PRIx32" data: 0x%08"PRIx32
+pl330_iomem_write_clr(int i) "event interrupt lowered %d"
+pl330_iomem_read(uint32_t addr, uint32_t data) "addr: 0x%08"PRIx32" data: 0x%08"PRIx32
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 92cd489069..d770035ba0 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -61,7 +61,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name));
QLIST_INIT(&bus->current_devs);
- vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus);
return bus;
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index e25df838f0..9c4e46fa74 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1816,7 +1816,6 @@ static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func)
Aml *scope = aml_scope("_SB.PCI0");
Aml *dev = aml_device("SMB0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0005")));
aml_append(dev, aml_name_decl("_ADR", aml_int(devnr << 16 | func)));
build_acpi_ipmi_devices(dev, BUS(smbus), "\\_SB.PCI0.SMB0");
aml_append(scope, dev);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 8054bc4147..a6302a772d 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -93,7 +93,9 @@
#include "fw_cfg.h"
#include "trace.h"
-GlobalProperty pc_compat_4_2[] = {};
+GlobalProperty pc_compat_4_2[] = {
+ { "mch", "smbase-smram", "off" },
+};
const size_t pc_compat_4_2_len = G_N_ELEMENTS(pc_compat_4_2);
GlobalProperty pc_compat_4_1[] = {};
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
index 59892b07fc..e6ee5e11f1 100644
--- a/hw/input/stellaris_input.c
+++ b/hw/input/stellaris_input.c
@@ -88,5 +88,6 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
}
s->num_buttons = n;
qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
- vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
+ &vmstate_stellaris_gamepad, s);
}
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 375cb6abe9..b5dbeb6206 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -268,7 +268,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info;
static DeviceState *vapic;
- int instance_id = s->id;
+ uint32_t instance_id = s->initial_apic_id;
+
+ /* Normally initial APIC ID should be no more than hundreds */
+ assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
info = APIC_COMMON_GET_CLASS(s);
info->realize(dev, errp);
@@ -284,7 +287,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
}
if (s->legacy_instance_id) {
- instance_id = -1;
+ instance_id = VMSTATE_INSTANCE_ID_ANY;
}
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
s, -1, 0, NULL);
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index a254b0ce87..08e000e33c 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -664,6 +664,9 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
trace_gicv3_icv_iar_read(ri->crm == 8 ? 0 : 1,
gicv3_redist_affid(cs), intid);
+
+ gicv3_cpuif_virt_update(cs);
+
return intid;
}
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 2164646553..bdd77d8020 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -82,6 +82,12 @@ config IMX
config STM32F2XX_SYSCFG
bool
+config STM32F4XX_SYSCFG
+ bool
+
+config STM32F4XX_EXTI
+ bool
+
config MIPS_ITU
bool
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index ba898a5781..da993f45b7 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -42,6 +42,7 @@ common-obj-$(CONFIG_IMX) += imx7_ccm.o
common-obj-$(CONFIG_IMX) += imx2_wdt.o
common-obj-$(CONFIG_IMX) += imx7_snvs.o
common-obj-$(CONFIG_IMX) += imx7_gpr.o
+common-obj-$(CONFIG_IMX) += imx_rngc.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
@@ -58,6 +59,8 @@ common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
+common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o
+common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o
obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
obj-$(CONFIG_MIPS_ITU) += mips_itu.o
diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c
new file mode 100644
index 0000000000..4c270df2db
--- /dev/null
+++ b/hw/misc/imx_rngc.c
@@ -0,0 +1,278 @@
+/*
+ * Freescale i.MX RNGC emulation
+ *
+ * Copyright (C) 2020 Martin Kaiser <martin@kaiser.cx>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This driver provides the minimum functionality to initialize and seed
+ * an rngc and to read random numbers. The rngb that is found in imx25
+ * chipsets is also supported.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "qemu/guest-random.h"
+#include "hw/irq.h"
+#include "hw/misc/imx_rngc.h"
+#include "migration/vmstate.h"
+
+#define RNGC_NAME "i.MX RNGC"
+
+#define RNGC_VER_ID 0x00
+#define RNGC_COMMAND 0x04
+#define RNGC_CONTROL 0x08
+#define RNGC_STATUS 0x0C
+#define RNGC_FIFO 0x14
+
+/* These version info are reported by the rngb in an imx258 chip. */
+#define RNG_TYPE_RNGB 0x1
+#define V_MAJ 0x2
+#define V_MIN 0x40
+
+#define RNGC_CMD_BIT_SW_RST 0x40
+#define RNGC_CMD_BIT_CLR_ERR 0x20
+#define RNGC_CMD_BIT_CLR_INT 0x10
+#define RNGC_CMD_BIT_SEED 0x02
+#define RNGC_CMD_BIT_SELF_TEST 0x01
+
+#define RNGC_CTRL_BIT_MASK_ERR 0x40
+#define RNGC_CTRL_BIT_MASK_DONE 0x20
+#define RNGC_CTRL_BIT_AUTO_SEED 0x10
+
+/* the current status for self-test and seed operations */
+#define OP_IDLE 0
+#define OP_RUN 1
+#define OP_DONE 2
+
+static uint64_t imx_rngc_read(void *opaque, hwaddr offset, unsigned size)
+{
+ IMXRNGCState *s = IMX_RNGC(opaque);
+ uint64_t val = 0;
+
+ switch (offset) {
+ case RNGC_VER_ID:
+ val |= RNG_TYPE_RNGB << 28 | V_MAJ << 8 | V_MIN;
+ break;
+
+ case RNGC_COMMAND:
+ if (s->op_seed == OP_RUN) {
+ val |= RNGC_CMD_BIT_SEED;
+ }
+ if (s->op_self_test == OP_RUN) {
+ val |= RNGC_CMD_BIT_SELF_TEST;
+ }
+ break;
+
+ case RNGC_CONTROL:
+ /*
+ * The CTL_ACC and VERIF_MODE bits are not supported yet.
+ * They read as 0.
+ */
+ val |= s->mask;
+ if (s->auto_seed) {
+ val |= RNGC_CTRL_BIT_AUTO_SEED;
+ }
+ /*
+ * We don't have an internal fifo like the real hardware.
+ * There's no need for strategy to handle fifo underflows.
+ * We return the FIFO_UFLOW_RESPONSE bits as 0.
+ */
+ break;
+
+ case RNGC_STATUS:
+ /*
+ * We never report any statistics test or self-test errors or any
+ * other errors. STAT_TEST_PF, ST_PF and ERROR are always 0.
+ */
+
+ /*
+ * We don't have an internal fifo, see above. Therefore, we
+ * report back the default fifo size (5 32-bit words) and
+ * indicate that our fifo is always full.
+ */
+ val |= 5 << 12 | 5 << 8;
+
+ /* We always have a new seed available. */
+ val |= 1 << 6;
+
+ if (s->op_seed == OP_DONE) {
+ val |= 1 << 5;
+ }
+ if (s->op_self_test == OP_DONE) {
+ val |= 1 << 4;
+ }
+ if (s->op_seed == OP_RUN || s->op_self_test == OP_RUN) {
+ /*
+ * We're busy if self-test is running or if we're
+ * seeding the prng.
+ */
+ val |= 1 << 1;
+ } else {
+ /*
+ * We're ready to provide secure random numbers whenever
+ * we're not busy.
+ */
+ val |= 1;
+ }
+ break;
+
+ case RNGC_FIFO:
+ qemu_guest_getrandom_nofail(&val, sizeof(val));
+ break;
+ }
+
+ return val;
+}
+
+static void imx_rngc_do_reset(IMXRNGCState *s)
+{
+ s->op_self_test = OP_IDLE;
+ s->op_seed = OP_IDLE;
+ s->mask = 0;
+ s->auto_seed = false;
+}
+
+static void imx_rngc_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMXRNGCState *s = IMX_RNGC(opaque);
+
+ switch (offset) {
+ case RNGC_COMMAND:
+ if (value & RNGC_CMD_BIT_SW_RST) {
+ imx_rngc_do_reset(s);
+ }
+
+ /*
+ * For now, both CLR_ERR and CLR_INT clear the interrupt. We
+ * don't report any errors yet.
+ */
+ if (value & (RNGC_CMD_BIT_CLR_ERR | RNGC_CMD_BIT_CLR_INT)) {
+ qemu_irq_lower(s->irq);
+ }
+
+ if (value & RNGC_CMD_BIT_SEED) {
+ s->op_seed = OP_RUN;
+ qemu_bh_schedule(s->seed_bh);
+ }
+
+ if (value & RNGC_CMD_BIT_SELF_TEST) {
+ s->op_self_test = OP_RUN;
+ qemu_bh_schedule(s->self_test_bh);
+ }
+ break;
+
+ case RNGC_CONTROL:
+ /*
+ * The CTL_ACC and VERIF_MODE bits are not supported yet.
+ * We ignore them if they're set by the caller.
+ */
+
+ if (value & RNGC_CTRL_BIT_MASK_ERR) {
+ s->mask |= RNGC_CTRL_BIT_MASK_ERR;
+ } else {
+ s->mask &= ~RNGC_CTRL_BIT_MASK_ERR;
+ }
+
+ if (value & RNGC_CTRL_BIT_MASK_DONE) {
+ s->mask |= RNGC_CTRL_BIT_MASK_DONE;
+ } else {
+ s->mask &= ~RNGC_CTRL_BIT_MASK_DONE;
+ }
+
+ if (value & RNGC_CTRL_BIT_AUTO_SEED) {
+ s->auto_seed = true;
+ } else {
+ s->auto_seed = false;
+ }
+ break;
+ }
+}
+
+static const MemoryRegionOps imx_rngc_ops = {
+ .read = imx_rngc_read,
+ .write = imx_rngc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_rngc_self_test(void *opaque)
+{
+ IMXRNGCState *s = IMX_RNGC(opaque);
+
+ s->op_self_test = OP_DONE;
+ if (!(s->mask & RNGC_CTRL_BIT_MASK_DONE)) {
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void imx_rngc_seed(void *opaque)
+{
+ IMXRNGCState *s = IMX_RNGC(opaque);
+
+ s->op_seed = OP_DONE;
+ if (!(s->mask & RNGC_CTRL_BIT_MASK_DONE)) {
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void imx_rngc_realize(DeviceState *dev, Error **errp)
+{
+ IMXRNGCState *s = IMX_RNGC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &imx_rngc_ops, s,
+ TYPE_IMX_RNGC, 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ sysbus_init_irq(sbd, &s->irq);
+ s->self_test_bh = qemu_bh_new(imx_rngc_self_test, s);
+ s->seed_bh = qemu_bh_new(imx_rngc_seed, s);
+}
+
+static void imx_rngc_reset(DeviceState *dev)
+{
+ IMXRNGCState *s = IMX_RNGC(dev);
+
+ imx_rngc_do_reset(s);
+}
+
+static const VMStateDescription vmstate_imx_rngc = {
+ .name = RNGC_NAME,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(op_self_test, IMXRNGCState),
+ VMSTATE_UINT8(op_seed, IMXRNGCState),
+ VMSTATE_UINT8(mask, IMXRNGCState),
+ VMSTATE_BOOL(auto_seed, IMXRNGCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void imx_rngc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = imx_rngc_realize;
+ dc->reset = imx_rngc_reset;
+ dc->desc = RNGC_NAME,
+ dc->vmsd = &vmstate_imx_rngc;
+}
+
+static const TypeInfo imx_rngc_info = {
+ .name = TYPE_IMX_RNGC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXRNGCState),
+ .class_init = imx_rngc_class_init,
+};
+
+static void imx_rngc_register_types(void)
+{
+ type_register_static(&imx_rngc_info);
+}
+
+type_init(imx_rngc_register_types)
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index 211008ce02..2b87bdee5b 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -146,7 +146,8 @@ static int max111x_init(SSISlave *d, int inputs)
s->input[7] = 0x80;
s->com = 0;
- vmstate_register(VMSTATE_IF(dev), -1, &vmstate_max111x, s);
+ vmstate_register(VMSTATE_IF(dev), VMSTATE_INSTANCE_ID_ANY,
+ &vmstate_max111x, s);
return 0;
}
diff --git a/hw/misc/stm32f4xx_exti.c b/hw/misc/stm32f4xx_exti.c
new file mode 100644
index 0000000000..02e7810046
--- /dev/null
+++ b/hw/misc/stm32f4xx_exti.c
@@ -0,0 +1,188 @@
+/*
+ * STM32F4XX EXTI
+ *
+ * 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 "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32f4xx_exti.h"
+
+static void stm32f4xx_exti_reset(DeviceState *dev)
+{
+ STM32F4xxExtiState *s = STM32F4XX_EXTI(dev);
+
+ s->exti_imr = 0x00000000;
+ s->exti_emr = 0x00000000;
+ s->exti_rtsr = 0x00000000;
+ s->exti_ftsr = 0x00000000;
+ s->exti_swier = 0x00000000;
+ s->exti_pr = 0x00000000;
+}
+
+static void stm32f4xx_exti_set_irq(void *opaque, int irq, int level)
+{
+ STM32F4xxExtiState *s = opaque;
+
+ trace_stm32f4xx_exti_set_irq(irq, level);
+
+ if (((1 << irq) & s->exti_rtsr) && level) {
+ /* Rising Edge */
+ s->exti_pr |= 1 << irq;
+ }
+
+ if (((1 << irq) & s->exti_ftsr) && !level) {
+ /* Falling Edge */
+ s->exti_pr |= 1 << irq;
+ }
+
+ if (!((1 << irq) & s->exti_imr)) {
+ /* Interrupt is masked */
+ return;
+ }
+ qemu_irq_pulse(s->irq[irq]);
+}
+
+static uint64_t stm32f4xx_exti_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F4xxExtiState *s = opaque;
+
+ trace_stm32f4xx_exti_read(addr);
+
+ switch (addr) {
+ case EXTI_IMR:
+ return s->exti_imr;
+ case EXTI_EMR:
+ return s->exti_emr;
+ case EXTI_RTSR:
+ return s->exti_rtsr;
+ case EXTI_FTSR:
+ return s->exti_ftsr;
+ case EXTI_SWIER:
+ return s->exti_swier;
+ case EXTI_PR:
+ return s->exti_pr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STM32F4XX_exti_read: Bad offset %x\n", (int)addr);
+ return 0;
+ }
+ return 0;
+}
+
+static void stm32f4xx_exti_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F4xxExtiState *s = opaque;
+ uint32_t value = (uint32_t) val64;
+
+ trace_stm32f4xx_exti_write(addr, value);
+
+ switch (addr) {
+ case EXTI_IMR:
+ s->exti_imr = value;
+ return;
+ case EXTI_EMR:
+ s->exti_emr = value;
+ return;
+ case EXTI_RTSR:
+ s->exti_rtsr = value;
+ return;
+ case EXTI_FTSR:
+ s->exti_ftsr = value;
+ return;
+ case EXTI_SWIER:
+ s->exti_swier = value;
+ return;
+ case EXTI_PR:
+ /* This bit is cleared by writing a 1 to it */
+ s->exti_pr &= ~value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STM32F4XX_exti_write: Bad offset %x\n", (int)addr);
+ }
+}
+
+static const MemoryRegionOps stm32f4xx_exti_ops = {
+ .read = stm32f4xx_exti_read,
+ .write = stm32f4xx_exti_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f4xx_exti_init(Object *obj)
+{
+ STM32F4xxExtiState *s = STM32F4XX_EXTI(obj);
+ int i;
+
+ for (i = 0; i < NUM_INTERRUPT_OUT_LINES; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]);
+ }
+
+ memory_region_init_io(&s->mmio, obj, &stm32f4xx_exti_ops, s,
+ TYPE_STM32F4XX_EXTI, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_in(DEVICE(obj), stm32f4xx_exti_set_irq,
+ NUM_GPIO_EVENT_IN_LINES);
+}
+
+static const VMStateDescription vmstate_stm32f4xx_exti = {
+ .name = TYPE_STM32F4XX_EXTI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(exti_imr, STM32F4xxExtiState),
+ VMSTATE_UINT32(exti_emr, STM32F4xxExtiState),
+ VMSTATE_UINT32(exti_rtsr, STM32F4xxExtiState),
+ VMSTATE_UINT32(exti_ftsr, STM32F4xxExtiState),
+ VMSTATE_UINT32(exti_swier, STM32F4xxExtiState),
+ VMSTATE_UINT32(exti_pr, STM32F4xxExtiState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32f4xx_exti_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f4xx_exti_reset;
+ dc->vmsd = &vmstate_stm32f4xx_exti;
+}
+
+static const TypeInfo stm32f4xx_exti_info = {
+ .name = TYPE_STM32F4XX_EXTI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F4xxExtiState),
+ .instance_init = stm32f4xx_exti_init,
+ .class_init = stm32f4xx_exti_class_init,
+};
+
+static void stm32f4xx_exti_register_types(void)
+{
+ type_register_static(&stm32f4xx_exti_info);
+}
+
+type_init(stm32f4xx_exti_register_types)
diff --git a/hw/misc/stm32f4xx_syscfg.c b/hw/misc/stm32f4xx_syscfg.c
new file mode 100644
index 0000000000..f960e4ea1e
--- /dev/null
+++ b/hw/misc/stm32f4xx_syscfg.c
@@ -0,0 +1,171 @@
+/*
+ * STM32F4xx SYSCFG
+ *
+ * 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 "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32f4xx_syscfg.h"
+
+static void stm32f4xx_syscfg_reset(DeviceState *dev)
+{
+ STM32F4xxSyscfgState *s = STM32F4XX_SYSCFG(dev);
+
+ s->syscfg_memrmp = 0x00000000;
+ s->syscfg_pmc = 0x00000000;
+ s->syscfg_exticr[0] = 0x00000000;
+ s->syscfg_exticr[1] = 0x00000000;
+ s->syscfg_exticr[2] = 0x00000000;
+ s->syscfg_exticr[3] = 0x00000000;
+ s->syscfg_cmpcr = 0x00000000;
+}
+
+static void stm32f4xx_syscfg_set_irq(void *opaque, int irq, int level)
+{
+ STM32F4xxSyscfgState *s = opaque;
+ int icrreg = irq / 4;
+ int startbit = (irq & 3) * 4;
+ uint8_t config = irq / 16;
+
+ trace_stm32f4xx_syscfg_set_irq(irq / 16, irq % 16, level);
+
+ g_assert(icrreg < SYSCFG_NUM_EXTICR);
+
+ if (extract32(s->syscfg_exticr[icrreg], startbit, 4) == config) {
+ qemu_set_irq(s->gpio_out[irq], level);
+ trace_stm32f4xx_pulse_exti(irq);
+ }
+}
+
+static uint64_t stm32f4xx_syscfg_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F4xxSyscfgState *s = opaque;
+
+ trace_stm32f4xx_syscfg_read(addr);
+
+ switch (addr) {
+ case SYSCFG_MEMRMP:
+ return s->syscfg_memrmp;
+ case SYSCFG_PMC:
+ return s->syscfg_pmc;
+ case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
+ return s->syscfg_exticr[addr / 4 - SYSCFG_EXTICR1 / 4];
+ case SYSCFG_CMPCR:
+ return s->syscfg_cmpcr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ return 0;
+ }
+}
+
+static void stm32f4xx_syscfg_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F4xxSyscfgState *s = opaque;
+ uint32_t value = val64;
+
+ trace_stm32f4xx_syscfg_write(value, addr);
+
+ switch (addr) {
+ case SYSCFG_MEMRMP:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Changing the memory mapping isn't supported " \
+ "in QEMU\n", __func__);
+ return;
+ case SYSCFG_PMC:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Changing the memory mapping isn't supported " \
+ "in QEMU\n", __func__);
+ return;
+ case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
+ s->syscfg_exticr[addr / 4 - SYSCFG_EXTICR1 / 4] = (value & 0xFFFF);
+ return;
+ case SYSCFG_CMPCR:
+ s->syscfg_cmpcr = value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps stm32f4xx_syscfg_ops = {
+ .read = stm32f4xx_syscfg_read,
+ .write = stm32f4xx_syscfg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f4xx_syscfg_init(Object *obj)
+{
+ STM32F4xxSyscfgState *s = STM32F4XX_SYSCFG(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f4xx_syscfg_ops, s,
+ TYPE_STM32F4XX_SYSCFG, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_in(DEVICE(obj), stm32f4xx_syscfg_set_irq, 16 * 9);
+ qdev_init_gpio_out(DEVICE(obj), s->gpio_out, 16);
+}
+
+static const VMStateDescription vmstate_stm32f4xx_syscfg = {
+ .name = TYPE_STM32F4XX_SYSCFG,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(syscfg_memrmp, STM32F4xxSyscfgState),
+ VMSTATE_UINT32(syscfg_pmc, STM32F4xxSyscfgState),
+ VMSTATE_UINT32_ARRAY(syscfg_exticr, STM32F4xxSyscfgState,
+ SYSCFG_NUM_EXTICR),
+ VMSTATE_UINT32(syscfg_cmpcr, STM32F4xxSyscfgState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32f4xx_syscfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f4xx_syscfg_reset;
+ dc->vmsd = &vmstate_stm32f4xx_syscfg;
+}
+
+static const TypeInfo stm32f4xx_syscfg_info = {
+ .name = TYPE_STM32F4XX_SYSCFG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F4xxSyscfgState),
+ .instance_init = stm32f4xx_syscfg_init,
+ .class_init = stm32f4xx_syscfg_class_init,
+};
+
+static void stm32f4xx_syscfg_register_types(void)
+{
+ type_register_static(&stm32f4xx_syscfg_info);
+}
+
+type_init(stm32f4xx_syscfg_register_types)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 2e0c820834..7f0f5dff3a 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -84,6 +84,17 @@ mos6522_set_sr_int(void) "set sr_int"
mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
+# stm32f4xx_syscfg
+stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
+stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
+stm32f4xx_syscfg_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
+stm32f4xx_syscfg_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+
+# stm32f4xx_exti
+stm32f4xx_exti_set_irq(int irq, int leve) "Set EXTI: %d to %d"
+stm32f4xx_exti_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
+stm32f4xx_exti_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+
# tz-mpc.c
tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs read: offset 0x%x data 0x%" PRIx64 " size %u"
tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs write: offset 0x%x data 0x%" PRIx64 " size %u"
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index cc71a7a036..6cc97769d9 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -1874,7 +1874,8 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp)
s->vmstate = g_memdup(&vmstate_eepro100, sizeof(vmstate_eepro100));
s->vmstate->name = qemu_get_queue(s->nic)->model;
- vmstate_register(VMSTATE_IF(&pci_dev->qdev), -1, s->vmstate, s);
+ vmstate_register(VMSTATE_IF(&pci_dev->qdev), VMSTATE_INSTANCE_ID_ANY,
+ s->vmstate, s);
}
static void eepro100_instance_init(Object *obj)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 158d270b9f..6342f73b9f 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -275,20 +275,20 @@ static const TypeInfo q35_host_info = {
* MCH D0:F0
*/
-static uint64_t tseg_blackhole_read(void *ptr, hwaddr reg, unsigned size)
+static uint64_t blackhole_read(void *ptr, hwaddr reg, unsigned size)
{
return 0xffffffff;
}
-static void tseg_blackhole_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
+static void blackhole_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
{
/* nothing */
}
-static const MemoryRegionOps tseg_blackhole_ops = {
- .read = tseg_blackhole_read,
- .write = tseg_blackhole_write,
+static const MemoryRegionOps blackhole_ops = {
+ .read = blackhole_read,
+ .write = blackhole_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
@@ -430,6 +430,46 @@ static void mch_update_ext_tseg_mbytes(MCHPCIState *mch)
}
}
+static void mch_update_smbase_smram(MCHPCIState *mch)
+{
+ PCIDevice *pd = PCI_DEVICE(mch);
+ uint8_t *reg = pd->config + MCH_HOST_BRIDGE_F_SMBASE;
+ bool lck;
+
+ if (!mch->has_smram_at_smbase) {
+ return;
+ }
+
+ if (*reg == MCH_HOST_BRIDGE_F_SMBASE_QUERY) {
+ pd->wmask[MCH_HOST_BRIDGE_F_SMBASE] =
+ MCH_HOST_BRIDGE_F_SMBASE_LCK;
+ *reg = MCH_HOST_BRIDGE_F_SMBASE_IN_RAM;
+ return;
+ }
+
+ /*
+ * default/reset state, discard written value
+ * which will disable SMRAM balackhole at SMBASE
+ */
+ if (pd->wmask[MCH_HOST_BRIDGE_F_SMBASE] == 0xff) {
+ *reg = 0x00;
+ }
+
+ memory_region_transaction_begin();
+ if (*reg & MCH_HOST_BRIDGE_F_SMBASE_LCK) {
+ /* disable all writes */
+ pd->wmask[MCH_HOST_BRIDGE_F_SMBASE] &=
+ ~MCH_HOST_BRIDGE_F_SMBASE_LCK;
+ *reg = MCH_HOST_BRIDGE_F_SMBASE_LCK;
+ lck = true;
+ } else {
+ lck = false;
+ }
+ memory_region_set_enabled(&mch->smbase_blackhole, lck);
+ memory_region_set_enabled(&mch->smbase_window, lck);
+ memory_region_transaction_commit();
+}
+
static void mch_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
@@ -456,6 +496,10 @@ static void mch_write_config(PCIDevice *d,
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE)) {
mch_update_ext_tseg_mbytes(mch);
}
+
+ if (ranges_overlap(address, len, MCH_HOST_BRIDGE_F_SMBASE, 1)) {
+ mch_update_smbase_smram(mch);
+ }
}
static void mch_update(MCHPCIState *mch)
@@ -464,6 +508,7 @@ static void mch_update(MCHPCIState *mch)
mch_update_pam(mch);
mch_update_smram(mch);
mch_update_ext_tseg_mbytes(mch);
+ mch_update_smbase_smram(mch);
/*
* pci hole goes from end-of-low-ram to io-apic.
@@ -514,6 +559,9 @@ static void mch_reset(DeviceState *qdev)
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
}
+ d->config[MCH_HOST_BRIDGE_F_SMBASE] = 0;
+ d->wmask[MCH_HOST_BRIDGE_F_SMBASE] = 0xff;
+
mch_update(mch);
}
@@ -563,7 +611,7 @@ static void mch_realize(PCIDevice *d, Error **errp)
memory_region_add_subregion(&mch->smram, 0xfeda0000, &mch->high_smram);
memory_region_init_io(&mch->tseg_blackhole, OBJECT(mch),
- &tseg_blackhole_ops, NULL,
+ &blackhole_ops, NULL,
"tseg-blackhole", 0);
memory_region_set_enabled(&mch->tseg_blackhole, false);
memory_region_add_subregion_overlap(mch->system_memory,
@@ -575,6 +623,27 @@ static void mch_realize(PCIDevice *d, Error **errp)
memory_region_set_enabled(&mch->tseg_window, false);
memory_region_add_subregion(&mch->smram, mch->below_4g_mem_size,
&mch->tseg_window);
+
+ /*
+ * This is not what hardware does, so it's QEMU specific hack.
+ * See commit message for details.
+ */
+ memory_region_init_io(&mch->smbase_blackhole, OBJECT(mch), &blackhole_ops,
+ NULL, "smbase-blackhole",
+ MCH_HOST_BRIDGE_SMBASE_SIZE);
+ memory_region_set_enabled(&mch->smbase_blackhole, false);
+ memory_region_add_subregion_overlap(mch->system_memory,
+ MCH_HOST_BRIDGE_SMBASE_ADDR,
+ &mch->smbase_blackhole, 1);
+
+ memory_region_init_alias(&mch->smbase_window, OBJECT(mch),
+ "smbase-window", mch->ram_memory,
+ MCH_HOST_BRIDGE_SMBASE_ADDR,
+ MCH_HOST_BRIDGE_SMBASE_SIZE);
+ memory_region_set_enabled(&mch->smbase_window, false);
+ memory_region_add_subregion(&mch->smram, MCH_HOST_BRIDGE_SMBASE_ADDR,
+ &mch->smbase_window);
+
object_property_add_const_link(qdev_get_machine(), "smram",
OBJECT(&mch->smram), &error_abort);
@@ -601,6 +670,7 @@ uint64_t mch_mcfg_base(void)
static Property mch_props[] = {
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
16),
+ DEFINE_PROP_BOOL("smbase-smram", MCHPCIState, has_smram_at_smbase, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e3d310365d..3ac7961451 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -122,7 +122,7 @@ static void pci_bus_realize(BusState *qbus, Error **errp)
bus->machine_done.notify = pcibus_machine_done;
qemu_add_machine_init_done_notifier(&bus->machine_done);
- vmstate_register(NULL, -1, &vmstate_pcibus, bus);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_pcibus, bus);
}
static void pcie_bus_realize(BusState *qbus, Error **errp)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 30a5fbd3be..02cf53fc5b 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2948,7 +2948,7 @@ static void spapr_machine_init(MachineState *machine)
* interface, this is a legacy from the sPAPREnvironment structure
* which predated MachineState but had a similar function */
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
- register_savevm_live("spapr/htab", -1, 1,
+ register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
&savevm_htab_handlers, spapr);
qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 4bc73a370e..d3af42ef92 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -943,7 +943,13 @@ void virtio_scsi_common_unrealize(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
+ int i;
+ virtio_delete_queue(vs->ctrl_vq);
+ virtio_delete_queue(vs->event_vq);
+ for (i = 0; i < vs->conf.num_queues; i++) {
+ virtio_delete_queue(vs->cmd_vqs[i]);
+ }
g_free(vs->cmd_vqs);
virtio_cleanup(vdev);
}
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index af524fabf7..beaa285685 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -180,7 +180,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
s->control = TIMER_CTRL_IE;
s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT);
- vmstate_register(NULL, -1, &vmstate_arm_timer, s);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s);
return s;
}
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
index 10d587ed40..3a0fc442f3 100644
--- a/hw/tpm/tpm_emulator.c
+++ b/hw/tpm/tpm_emulator.c
@@ -914,7 +914,8 @@ static void tpm_emulator_inst_init(Object *obj)
tpm_emu->cur_locty_number = ~0;
qemu_mutex_init(&tpm_emu->mutex);
- vmstate_register(NULL, -1, &vmstate_tpm_emulator, obj);
+ vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
+ &vmstate_tpm_emulator, obj);
}
/*
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index d27a10fcc6..2e81f5514f 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1061,7 +1061,7 @@ static void slave_read(void *opaque)
fd[0]);
break;
default:
- error_report("Received unexpected msg type.");
+ error_report("Received unexpected msg type: %d.", hdr.request);
ret = -EINVAL;
}
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index f5744363a8..b6cee479bb 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -335,8 +335,10 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
sizeof(struct virtio_vsock_config));
/* Receive and transmit queues belong to vhost */
- virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, vhost_vsock_handle_output);
- virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, vhost_vsock_handle_output);
+ vsock->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
+ vhost_vsock_handle_output);
+ vsock->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
+ vhost_vsock_handle_output);
/* The event queue belongs to QEMU */
vsock->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
@@ -363,6 +365,9 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
err_vhost_dev:
vhost_dev_cleanup(&vsock->vhost_dev);
err_virtio:
+ virtio_delete_queue(vsock->recv_vq);
+ virtio_delete_queue(vsock->trans_vq);
+ virtio_delete_queue(vsock->event_vq);
virtio_cleanup(vdev);
close(vhostfd);
return;
@@ -379,6 +384,9 @@ static void vhost_vsock_device_unrealize(DeviceState *dev, Error **errp)
vhost_vsock_set_status(vdev, 0);
vhost_dev_cleanup(&vsock->vhost_dev);
+ virtio_delete_queue(vsock->recv_vq);
+ virtio_delete_queue(vsock->trans_vq);
+ virtio_delete_queue(vsock->event_vq);
virtio_cleanup(vdev);
}
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 4da0d5a6c5..9edfadc81d 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -547,26 +547,28 @@ static void vhost_region_add_section(struct vhost_dev *dev,
uintptr_t mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
section->offset_within_region;
RAMBlock *mrs_rb = section->mr->ram_block;
- size_t mrs_page = qemu_ram_pagesize(mrs_rb);
trace_vhost_region_add_section(section->mr->name, mrs_gpa, mrs_size,
mrs_host);
- /* Round the section to it's page size */
- /* First align the start down to a page boundary */
- uint64_t alignage = mrs_host & (mrs_page - 1);
- if (alignage) {
- mrs_host -= alignage;
- mrs_size += alignage;
- mrs_gpa -= alignage;
- }
- /* Now align the size up to a page boundary */
- alignage = mrs_size & (mrs_page - 1);
- if (alignage) {
- mrs_size += mrs_page - alignage;
+ if (dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER) {
+ /* Round the section to it's page size */
+ /* First align the start down to a page boundary */
+ size_t mrs_page = qemu_ram_pagesize(mrs_rb);
+ uint64_t alignage = mrs_host & (mrs_page - 1);
+ if (alignage) {
+ mrs_host -= alignage;
+ mrs_size += alignage;
+ mrs_gpa -= alignage;
+ }
+ /* Now align the size up to a page boundary */
+ alignage = mrs_size & (mrs_page - 1);
+ if (alignage) {
+ mrs_size += mrs_page - alignage;
+ }
+ trace_vhost_region_add_section_aligned(section->mr->name, mrs_gpa,
+ mrs_size, mrs_host);
}
- trace_vhost_region_add_section_aligned(section->mr->name, mrs_gpa, mrs_size,
- mrs_host);
if (dev->n_tmp_sections) {
/* Since we already have at least one section, lets see if
@@ -590,9 +592,10 @@ static void vhost_region_add_section(struct vhost_dev *dev,
* match up in the same RAMBlock if they do.
*/
if (mrs_gpa < prev_gpa_start) {
- error_report("%s:Section rounded to %"PRIx64
- " prior to previous %"PRIx64,
- __func__, mrs_gpa, prev_gpa_start);
+ error_report("%s:Section '%s' rounded to %"PRIx64
+ " prior to previous '%s' %"PRIx64,
+ __func__, section->mr->name, mrs_gpa,
+ prev_sec->mr->name, prev_gpa_start);
/* A way to cleanly fail here would be better */
return;
}