From 7b6d7b84da328d5d1fffb862b8388d511e085812 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 23 Jul 2018 15:21:25 +0100 Subject: [PATCH 1/5] hw/microblaze/xlnx-zynqmp-pmu: Fix introspection problem in 'xlnx, zynqmp-pmu-soc' Valgrind complains: echo "{'execute':'qmp_capabilities'} {'execute':'device-list-properties'," \ "'arguments':{'typename':'xlnx,zynqmp-pmu-soc'}}" \ "{'execute': 'human-monitor-command', " \ "'arguments': {'command-line': 'info qtree'}}" | \ valgrind -q microblazeel-softmmu/qemu-system-microblazeel -M none,accel=qtest -qmp stdio [...] ==13605== Invalid read of size 8 ==13605== at 0x2AC69A: qdev_print (qdev-monitor.c:686) ==13605== by 0x2AC69A: qbus_print (qdev-monitor.c:719) ==13605== by 0x2591E8: handle_hmp_command (monitor.c:3446) Use the new object_initialize_child() and sysbus_init_child_obj() to fix the issue. Signed-off-by: Thomas Huth Reviewed-by: Edgar E. Iglesias Message-id: 1531839343-13828-1-git-send-email-thuth@redhat.com Signed-off-by: Peter Maydell --- hw/microblaze/xlnx-zynqmp-pmu.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 999a5657cf..57dc1ccd42 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -62,13 +62,11 @@ static void xlnx_zynqmp_pmu_soc_init(Object *obj) { XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(obj); - object_initialize(&s->cpu, sizeof(s->cpu), - TYPE_MICROBLAZE_CPU); - object_property_add_child(obj, "pmu-cpu", OBJECT(&s->cpu), - &error_abort); + object_initialize_child(obj, "pmu-cpu", &s->cpu, sizeof(s->cpu), + TYPE_MICROBLAZE_CPU, &error_abort, NULL); - object_initialize(&s->intc, sizeof(s->intc), TYPE_XLNX_PMU_IO_INTC); - qdev_set_parent_bus(DEVICE(&s->intc), sysbus_get_default()); + sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc), + TYPE_XLNX_PMU_IO_INTC); } static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) From 03a31776e8fb239fee98625dd83b85f5cbe3ccba Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 23 Jul 2018 15:21:26 +0100 Subject: [PATCH 2/5] hw/sd/bcm2835_sdhost: Fix PIO mode writes Writes in PIO mode have two requirements: - A data interrupt must be generated after a write command has been issued to indicate that the chip is ready to receive data. - A block interrupt must be generated after each block to indicate that the chip is ready to receive the next data block. Rearrange the code to make this happen. Tested on raspi3 (in PIO mode) and raspi2 (in DMA mode). Signed-off-by: Guenter Roeck Message-id: 1531779837-20557-1-git-send-email-linux@roeck-us.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/sd/bcm2835_sdhost.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c index 4df4de7d67..1b760b2a7c 100644 --- a/hw/sd/bcm2835_sdhost.c +++ b/hw/sd/bcm2835_sdhost.c @@ -179,9 +179,11 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) uint32_t value = 0; int n; int is_read; + int is_write; is_read = (s->cmd & SDCMD_READ_CMD) != 0; - if (s->datacnt != 0 && (!is_read || sdbus_data_ready(&s->sdbus))) { + is_write = (s->cmd & SDCMD_WRITE_CMD) != 0; + if (s->datacnt != 0 && (is_write || sdbus_data_ready(&s->sdbus))) { if (is_read) { n = 0; while (s->datacnt && s->fifo_len < BCM2835_SDHOST_FIFO_LEN) { @@ -201,8 +203,11 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) if (n != 0) { bcm2835_sdhost_fifo_push(s, value); s->status |= SDHSTS_DATA_FLAG; + if (s->config & SDHCFG_DATA_IRPT_EN) { + s->status |= SDHSTS_SDIO_IRPT; + } } - } else { /* write */ + } else if (is_write) { /* write */ n = 0; while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { if (n == 0) { @@ -223,11 +228,18 @@ static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) s->edm &= ~SDEDM_FSM_MASK; s->edm |= SDEDM_FSM_DATAMODE; trace_bcm2835_sdhost_edm_change("datacnt 0", s->edm); - - if ((s->cmd & SDCMD_WRITE_CMD) && + } + if (is_write) { + /* set block interrupt at end of each block transfer */ + if (s->hbct && s->datacnt % s->hbct == 0 && (s->config & SDHCFG_BLOCK_IRPT_EN)) { s->status |= SDHSTS_BLOCK_IRPT; } + /* set data interrupt after each transfer */ + s->status |= SDHSTS_DATA_FLAG; + if (s->config & SDHCFG_DATA_IRPT_EN) { + s->status |= SDHSTS_SDIO_IRPT; + } } } From 9d2b5a58f85be2d8e129c4b53d6708ecf8796e54 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 23 Jul 2018 15:21:26 +0100 Subject: [PATCH 3/5] target/arm: Correctly handle overlapping small MPU regions To correctly handle small (less than TARGET_PAGE_SIZE) MPU regions, we must correctly handle the case where the address being looked up hits in an MPU region that is not small but the address is in the same page as a small region. For instance if MPU region 1 covers an entire page from 0x2000 to 0x2400 and MPU region 2 is small and covers only 0x2200 to 0x2280, then for an access to 0x2000 we must not return a result covering the full page even though we hit the page-sized region 1. Otherwise we will then cache that result in the TLB and accesses that should hit region 2 will incorrectly find the region 1 information. Check for the case where we miss an MPU region but it is still within the same page, and in that case narrow the size we will pass to tlb_set_page_with_attrs() for whatever the final outcome is of the MPU lookup. Reported-by: Adithya Baglody Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20180716133302.25989-1-peter.maydell@linaro.org --- target/arm/helper.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 0604a0efbe..22d812240a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -17,6 +17,7 @@ #include "exec/semihost.h" #include "sysemu/kvm.h" #include "fpu/softfloat.h" +#include "qemu/range.h" #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ @@ -9669,6 +9670,20 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } if (address < base || address > base + rmask) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (ranges_overlap(base, rmask, + address & TARGET_PAGE_MASK, + TARGET_PAGE_SIZE)) { + *page_size = 1; + } continue; } @@ -9888,6 +9903,22 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, sattrs->srvalid = true; sattrs->sregion = r; } + } else { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result + * in incorrect TLB hits for subsequent accesses to + * addresses that are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + sattrs->subpage = true; + } } } } @@ -9963,6 +9994,21 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, } if (address < base || address > limit) { + /* + * Address not in this region. We must check whether the + * region covers addresses in the same page as our address. + * In that case we must not report a size that covers the + * whole page for a subsequent hit against a different MPU + * region or the background region, because it would result in + * incorrect TLB hits for subsequent accesses to addresses that + * are in this MPU region. + */ + if (limit >= base && + ranges_overlap(base, limit - base + 1, + addr_page_base, + TARGET_PAGE_SIZE)) { + *is_subpage = true; + } continue; } From 07bc425ea32dc5d78790c7bd23bffb77fbc727e0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 23 Jul 2018 15:21:26 +0100 Subject: [PATCH 4/5] hw/arm/spitz: Move problematic nand_init() code to realize function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nand_init() does not only create the NAND device, it also realizes the device with qdev_init_nofail() already. So we must not call nand_init() from an instance_init function like sl_nand_init(), otherwise we get superfluous NAND devices in the QOM tree after introspecting the 'sl-nand' device. So move the nand_init() to the realize function of 'sl-nand' instead. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 1532006134-7701-1-git-send-email-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/spitz.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 3cc27a1e44..c4bc3deedf 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -169,16 +169,22 @@ static void sl_nand_init(Object *obj) { SLNANDState *s = SL_NAND(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - DriveInfo *nand; s->ctl = 0; + + memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40); + sysbus_init_mmio(dev, &s->iomem); +} + +static void sl_nand_realize(DeviceState *dev, Error **errp) +{ + SLNANDState *s = SL_NAND(dev); + DriveInfo *nand; + /* FIXME use a qdev drive property instead of drive_get() */ nand = drive_get(IF_MTD, 0, 0); s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL, s->manf_id, s->chip_id); - - memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40); - sysbus_init_mmio(dev, &s->iomem); } /* Spitz Keyboard */ @@ -1079,6 +1085,7 @@ static void sl_nand_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sl_nand_info; dc->props = sl_nand_properties; + dc->realize = sl_nand_realize; /* Reason: init() method uses drive_get() */ dc->user_creatable = false; } From 1ddc9b98c3cb89fe23a55ba924000fd645253e87 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 23 Jul 2018 15:21:27 +0100 Subject: [PATCH 5/5] hw/intc/exynos4210_gic: Turn instance_init into realize function The instance_init function of the "exynos4210.gic" device creates a new "arm_gic" device and immediately realizes it with qdev_init_nofail(). This will leave a lot of object in the QOM tree during introspection of the "exynos4210.gic" device, e.g. reproducible by starting QEMU like this: qemu-system-aarch64 -M none -nodefaults -nographic -monitor stdio And then by running "info qom-tree" at the HMP monitor, followed by "device_add exynos4210.gic,help" and finally checking "info qom-tree" again. Also note that qdev_init_nofail() can exit QEMU in case of errors - and this must never happen during an instance_init function, otherwise QEMU could terminate unexpectedly during introspection of a device. Since most of the code that follows the qdev_init_nofail() depends on the realized "gicbusdev", the easiest solution to the problem is to turn the whole instance_init function into a realize function instead. Signed-off-by: Thomas Huth Message-id: 1532337784-334-1-git-send-email-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/exynos4210_gic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index b6b00a4f58..69f9c18d73 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -281,9 +281,9 @@ static void exynos4210_gic_set_irq(void *opaque, int irq, int level) qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } -static void exynos4210_gic_init(Object *obj) +static void exynos4210_gic_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(obj); + Object *obj = OBJECT(dev); Exynos4210GicState *s = EXYNOS4210_GIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; @@ -347,13 +347,13 @@ static void exynos4210_gic_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->props = exynos4210_gic_properties; + dc->realize = exynos4210_gic_realize; } static const TypeInfo exynos4210_gic_info = { .name = TYPE_EXYNOS4210_GIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210GicState), - .instance_init = exynos4210_gic_init, .class_init = exynos4210_gic_class_init, };