From 79c857a35f3e829d0baac23a355a1365714d2a1a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 4 Sep 2017 15:21:52 +0100 Subject: hw/intc/armv7m_nvic.c: Remove out of date comment Remove an out of date comment which says there's only one item in the NVIC container region -- we put systick into its own device object a while back and so now there are two things in the container. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 1501692241-23310-6-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 323e2d4..2e8166a 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1036,10 +1036,6 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) * 0xd00..0xd3c - SCS registers * 0xd40..0xeff - Reserved or Not implemented * 0xf00 - STIR - * - * At the moment there is only one thing in the container region, - * but we leave it in place to allow us to pull systick out into - * its own device object later. */ memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000); /* The system register region goes at the bottom of the priority -- cgit v1.1 From e6ae5981ea4b0f6feb223009a5108582e7644f8f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 4 Sep 2017 15:21:52 +0100 Subject: target/arm: Don't store M profile PRIMASK and FAULTMASK in daif We currently store the M profile CPU register state PRIMASK and FAULTMASK in the daif field of the CPU state in its I and F bits. This is a legacy from the original implementation, which tried to share the cpu_exec_interrupt code between A profile and M profile. We've since separated out the two cases because they are significantly different, so now there is no common code between M and A profile which looks at env->daif: all the uses are either in A-only or M-only code paths. Sharing the state fields now is just confusing, and will make things awkward when we implement v8M, where the PRIMASK and FAULTMASK registers are banked between security states. Switch M profile over to using v7m.faultmask and v7m.primask fields for these registers. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1501692241-23310-10-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 2e8166a..343bc16 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -167,9 +167,9 @@ static inline int nvic_exec_prio(NVICState *s) CPUARMState *env = &s->cpu->env; int running; - if (env->daif & PSTATE_F) { /* FAULTMASK */ + if (env->v7m.faultmask) { running = -1; - } else if (env->daif & PSTATE_I) { /* PRIMASK */ + } else if (env->v7m.primask) { running = 0; } else if (env->v7m.basepri > 0) { running = env->v7m.basepri & nvic_gprio_mask(s); -- cgit v1.1 From d2db1de6ff15aad4c8898a416c6d8f2d93ff0282 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 4 Sep 2017 15:21:53 +0100 Subject: armv7m_nvic.h: Move from include/hw/arm to include/hw/intc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The armv7m_nvic.h header file was accidentally placed in include/hw/arm; move it to include/hw/intc to match where its corresponding .c file lives. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 1501692241-23310-15-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 343bc16..5a18025 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -17,7 +17,7 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/arm/arm.h" -#include "hw/arm/armv7m_nvic.h" +#include "hw/intc/armv7m_nvic.h" #include "target/arm/cpu.h" #include "exec/exec-all.h" #include "qemu/log.h" -- cgit v1.1 From eb578a2394c55f7d598f60796c8318e40b1c0241 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 4 Sep 2017 15:21:53 +0100 Subject: nvic: Implement "user accesses BusFault" SCS region behaviour The ARMv7M architecture specifies that most of the addresses in the PPB region (which includes the NVIC, systick and system registers) are not accessible to unprivileged accesses, which should BusFault with a few exceptions: * the STIR is configurably user-accessible * the ITM (which we don't implement at all) is always user-accessible Implement this by switching the register access functions to the _with_attrs scheme that lets us distinguish user mode accesses. This allows us to pull the handling of the CCR.USERSETMPEND flag up to the level where we can make it generate a BusFault as it should for non-permitted accesses. Note that until the core ARM CPU code implements turning MEMTX_ERROR into a BusFault the registers will continue to act as RAZ/WI to user accesses. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 1501692241-23310-16-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 58 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 5a18025..bbfe2d5 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -733,11 +733,8 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value) } case 0xf00: /* Software Triggered Interrupt Register */ { - /* user mode can only write to STIR if CCR.USERSETMPEND permits it */ int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ; - if (excnum < s->num_irq && - (arm_current_el(&cpu->env) || - (cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) { + if (excnum < s->num_irq) { armv7m_nvic_set_pending(s, excnum); } break; @@ -748,14 +745,32 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value) } } -static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, - unsigned size) +static bool nvic_user_access_ok(NVICState *s, hwaddr offset) +{ + /* Return true if unprivileged access to this register is permitted. */ + switch (offset) { + case 0xf00: /* STIR: accessible only if CCR.USERSETMPEND permits */ + return s->cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK; + default: + /* All other user accesses cause a BusFault unconditionally */ + return false; + } +} + +static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) { NVICState *s = (NVICState *)opaque; uint32_t offset = addr; unsigned i, startvec, end; uint32_t val; + if (attrs.user && !nvic_user_access_ok(s, addr)) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + switch (offset) { /* reads of set and clear both return the status */ case 0x100 ... 0x13f: /* NVIC Set enable */ @@ -826,11 +841,13 @@ static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, } trace_nvic_sysreg_read(addr, val, size); - return val; + *data = val; + return MEMTX_OK; } -static void nvic_sysreg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) +static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) { NVICState *s = (NVICState *)opaque; uint32_t offset = addr; @@ -839,6 +856,11 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, trace_nvic_sysreg_write(addr, value, size); + if (attrs.user && !nvic_user_access_ok(s, addr)) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + switch (offset) { case 0x100 ... 0x13f: /* NVIC Set enable */ offset += 0x80; @@ -853,7 +875,7 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return; + return MEMTX_OK; case 0x200 ... 0x23f: /* NVIC Set pend */ /* the special logic in armv7m_nvic_set_pending() * is not needed since IRQs are never escalated @@ -870,9 +892,9 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return; + return MEMTX_OK; case 0x300 ... 0x33f: /* NVIC Active */ - return; /* R/O */ + return MEMTX_OK; /* R/O */ case 0x400 ... 0x5ef: /* NVIC Priority */ startvec = 8 * (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */ @@ -880,26 +902,28 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, set_prio(s, startvec + i, (value >> (i * 8)) & 0xff); } nvic_irq_update(s); - return; + return MEMTX_OK; case 0xd18 ... 0xd23: /* System Handler Priority. */ for (i = 0; i < size; i++) { unsigned hdlidx = (offset - 0xd14) + i; set_prio(s, hdlidx, (value >> (i * 8)) & 0xff); } nvic_irq_update(s); - return; + return MEMTX_OK; } if (size == 4) { nvic_writel(s, offset, value); - return; + return MEMTX_OK; } qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad write of size %d at offset 0x%x\n", size, offset); + /* This is UNPREDICTABLE; treat as RAZ/WI */ + return MEMTX_OK; } static const MemoryRegionOps nvic_sysreg_ops = { - .read = nvic_sysreg_read, - .write = nvic_sysreg_write, + .read_with_attrs = nvic_sysreg_read, + .write_with_attrs = nvic_sysreg_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -- cgit v1.1 From c2de81e2b24dd62876b919da2dd4714cadad34d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 4 Sep 2017 15:21:53 +0100 Subject: hw/arm: use defined type name instead of hard-coded string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/armv7m.c | 4 ++-- hw/arm/exynos4210.c | 4 ++-- hw/arm/highbank.c | 11 +++++++---- hw/arm/realview.c | 6 ++++-- hw/arm/vexpress.c | 6 ++++-- hw/arm/xilinx_zynq.c | 14 ++++++++------ 6 files changed, 27 insertions(+), 18 deletions(-) (limited to 'hw') diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index c8a11f2..d2477e8 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -146,7 +146,7 @@ static void armv7m_instance_init(Object *obj) &error_abort); memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX); - object_initialize(&s->nvic, sizeof(s->nvic), "armv7m_nvic"); + object_initialize(&s->nvic, sizeof(s->nvic), TYPE_NVIC); qdev_set_parent_bus(DEVICE(&s->nvic), sysbus_get_default()); object_property_add_alias(obj, "num-irq", OBJECT(&s->nvic), "num-irq", &error_abort); @@ -293,7 +293,7 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, cpu_model = "cortex-m3"; } - armv7m = qdev_create(NULL, "armv7m"); + armv7m = qdev_create(NULL, TYPE_ARMV7M); qdev_prop_set_uint32(armv7m, "num-irq", num_irq); qdev_prop_set_string(armv7m, "cpu-model", cpu_model); object_property_set_link(OBJECT(armv7m), OBJECT(get_system_memory()), diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index f9e79f3..ee1438a 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -33,7 +33,7 @@ #include "hw/arm/arm.h" #include "hw/loader.h" #include "hw/arm/exynos4210.h" -#include "hw/sd/sd.h" +#include "hw/sd/sdhci.h" #include "hw/usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -381,7 +381,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem) BlockBackend *blk; DriveInfo *di; - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_prop_set_uint32(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); qdev_init_nofail(dev); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 20e60f1..942d5a8 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -31,6 +31,9 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" +#include "hw/ide/ahci.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/cpu/a15mpcore.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -300,10 +303,10 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff12000); - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); break; case CALXEDA_MIDWAY: - dev = qdev_create(NULL, "a15mpcore_priv"); + dev = qdev_create(NULL, TYPE_A15MPCORE_PRIV); break; } qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); @@ -329,7 +332,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) sysbus_connect_irq(busdev, 0, pic[18]); pl011_create(0xfff36000, pic[20], serial_hds[0]); - dev = qdev_create(NULL, "highbank-regs"); + dev = qdev_create(NULL, TYPE_HIGHBANK_REGISTERS); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff3c000); @@ -341,7 +344,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) sysbus_create_simple("pl031", 0xfff35000, pic[19]); sysbus_create_simple("pl022", 0xfff39000, pic[23]); - sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); + sysbus_create_simple(TYPE_SYSBUS_AHCI, 0xffe08000, pic[83]); if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], "xgmac"); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 76ff557..2736156 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -24,6 +24,8 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/intc/realview_gic.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -172,7 +174,7 @@ static void realview_init(MachineState *machine, sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); if (is_mpcore) { - dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); + dev = qdev_create(NULL, is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -186,7 +188,7 @@ static void realview_init(MachineState *machine, } else { uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; /* For now just create the nIRQ GIC, and ignore the others. */ - dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]); + dev = sysbus_create_simple(TYPE_REALVIEW_GIC, gic_addr, cpu_irq[0]); } for (n = 0; n < 64; n++) { pic[n] = qdev_get_gpio_in(dev, n); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 528c65d..571dd36 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -40,6 +40,8 @@ #include "qemu/error-report.h" #include #include "hw/char/pl011.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/cpu/a15mpcore.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -293,7 +295,7 @@ static void a9_daughterboard_init(const VexpressMachineState *vms, memory_region_add_subregion(sysmem, 0x60000000, ram); /* 0x1e000000 A9MPCore (SCU) private memory region */ - init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure); + init_cpus(cpu_model, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, vms->secure); /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ @@ -378,7 +380,7 @@ static void a15_daughterboard_init(const VexpressMachineState *vms, memory_region_add_subregion(sysmem, 0x80000000, ram); /* 0x2c000000 A15MPCore private memory region (GIC) */ - init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure); + init_cpus(cpu_model, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure); /* A15 daughterboard peripherals: */ diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 6b11a75..a750959 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -31,8 +31,10 @@ #include "hw/misc/zynq-xadc.h" #include "hw/ssi/ssi.h" #include "qemu/error-report.h" -#include "hw/sd/sd.h" +#include "hw/sd/sdhci.h" #include "hw/char/cadence_uart.h" +#include "hw/net/cadence_gem.h" +#include "hw/cpu/a9mpcore.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -96,9 +98,9 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "cadence_gem"); + dev = qdev_create(NULL, TYPE_CADENCE_GEM); if (nd->used) { - qemu_check_nic_model(nd, "cadence_gem"); + qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } qdev_init_nofail(dev); @@ -222,7 +224,7 @@ static void zynq_init(MachineState *machine) qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", 1); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -252,7 +254,7 @@ static void zynq_init(MachineState *machine) gem_init(&nd_table[0], 0xE000B000, pic[54-IRQ_OFFSET]); gem_init(&nd_table[1], 0xE000C000, pic[77-IRQ_OFFSET]); - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); @@ -263,7 +265,7 @@ static void zynq_init(MachineState *machine) qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); -- cgit v1.1 From 07f48730bc4ec99f128901705336eb455f674694 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 4 Sep 2017 15:21:53 +0100 Subject: hw/arm/virt: add pmu interrupt state Mimicking gicv3-maintenance-interrupt, add the PMU's interrupt to CPU state. Signed-off-by: Andrew Jones Reviewed-by: Peter Maydell Message-id: 1500471597-2517-2-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6b7a0fe..a06ec13 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -610,6 +610,9 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0, qdev_get_gpio_in(gicdev, ppibase + ARCH_GICV3_MAINT_IRQ)); + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, + qdev_get_gpio_in(gicdev, ppibase + + VIRTUAL_PMU_IRQ)); sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, -- cgit v1.1 From 3f07cb2aabdfcc27ee30cf85c39619a82d364f83 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 4 Sep 2017 15:21:54 +0100 Subject: target/arm/kvm: pmu: split init and set-irq stages When adding a PMU with a userspace irqchip we skip the set-irq stage of device creation. Split the 'create' function into two functions 'init' and 'set-irq' so they may be called separately. Signed-off-by: Andrew Jones Reviewed-by: Christoffer Dall Message-id: 1500471597-2517-3-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a06ec13..d6e2486 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -492,10 +492,17 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) CPU_FOREACH(cpu) { armcpu = ARM_CPU(cpu); - if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU) || - (kvm_enabled() && !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ)))) { + if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { return; } + if (kvm_enabled()) { + if (!kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ))) { + return; + } + if (!kvm_arm_pmu_init(cpu)) { + return; + } + } } if (vms->gic_version == 2) { -- cgit v1.1 From b16595275bc9b9ce6a36bfb0344d514ab77e6b98 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 4 Sep 2017 15:21:54 +0100 Subject: hw/arm/virt: allow pmu instantiation with userspace irqchip Move the in-kernel-irqchip test to only guard the set-irq stage, not the init stage of the PMU. Also add the PMU to the KVM device irq line synchronization to enable its use. Signed-off-by: Andrew Jones Reviewed-by: Christoffer Dall Message-id: 1500471597-2517-4-git-send-email-drjones@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d6e2486..999f448 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -496,7 +496,8 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) return; } if (kvm_enabled()) { - if (!kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ))) { + if (kvm_irqchip_in_kernel() && + !kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ))) { return; } if (!kvm_arm_pmu_init(cpu)) { -- cgit v1.1 From b2bfe9f7f1f7e3aa5edf9c3c4c7408082778ae17 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 4 Sep 2017 15:21:54 +0100 Subject: target/arm/kvm: pmu: improve error handling If a KVM PMU init or set-irq attr call fails we just silently stop the PMU DT node generation. The only way they could fail, though, is if the attr's respective KVM has-attr call fails. But that should never happen if KVM advertises the PMU capability, because both attrs have been available since the capability was introduced. Let's just abort if this should-never-happen stuff does happen, because, if it does, then something is obviously horribly wrong. Signed-off-by: Andrew Jones Reviewed-by: Christoffer Dall Message-id: 1500471597-2517-5-git-send-email-drjones@redhat.com [PMM: change kvm32.c kvm_arm_pmu_init() to the new API too] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 999f448..fe96557 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -496,13 +496,10 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) return; } if (kvm_enabled()) { - if (kvm_irqchip_in_kernel() && - !kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ))) { - return; - } - if (!kvm_arm_pmu_init(cpu)) { - return; + if (kvm_irqchip_in_kernel()) { + kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); } + kvm_arm_pmu_init(cpu); } } -- cgit v1.1 From f55d613bc97cd8d08487eddec313c3298a906a91 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Mon, 4 Sep 2017 15:21:54 +0100 Subject: watchdog: wdt_aspeed: Add support for the reset width register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reset width register controls how the pulse on the SoC's WDTRST{1,2} pins behaves. A pulse is emitted if the external reset bit is set in WDT_CTRL. On the AST2500 WDT_RESET_WIDTH can consume magic bit patterns to configure push-pull/open-drain and active-high/active-low behaviours and thus needs some special handling in the write path. As some of the capabilities depend on the SoC version a silicon-rev property is introduced, which is used to guard version-specific behaviour. Signed-off-by: Andrew Jeffery Reviewed-by: Cédric Le Goater Signed-off-by: Peter Maydell --- hw/watchdog/wdt_aspeed.c | 93 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 8bbe579..22bce36 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -8,16 +8,19 @@ */ #include "qemu/osdep.h" + +#include "qapi/error.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "sysemu/watchdog.h" +#include "hw/misc/aspeed_scu.h" #include "hw/sysbus.h" -#include "qemu/timer.h" #include "hw/watchdog/wdt_aspeed.h" -#define WDT_STATUS (0x00 / 4) -#define WDT_RELOAD_VALUE (0x04 / 4) -#define WDT_RESTART (0x08 / 4) -#define WDT_CTRL (0x0C / 4) +#define WDT_STATUS (0x00 / 4) +#define WDT_RELOAD_VALUE (0x04 / 4) +#define WDT_RESTART (0x08 / 4) +#define WDT_CTRL (0x0C / 4) #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) #define WDT_CTRL_1MHZ_CLK BIT(4) @@ -25,18 +28,41 @@ #define WDT_CTRL_WDT_INTR BIT(2) #define WDT_CTRL_RESET_SYSTEM BIT(1) #define WDT_CTRL_ENABLE BIT(0) +#define WDT_RESET_WIDTH (0x18 / 4) +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) +#define WDT_POLARITY_MASK (0xFF << 24) +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) +#define WDT_ACTIVE_LOW_MAGIC (0x5A << 24) +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) +#define WDT_OPEN_DRAIN_MAGIC (0x8A << 24) -#define WDT_TIMEOUT_STATUS (0x10 / 4) -#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESET_WDITH (0x18 / 4) +#define WDT_TIMEOUT_STATUS (0x10 / 4) +#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESTART_MAGIC 0x4755 +#define WDT_RESTART_MAGIC 0x4755 static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) { return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; } +static bool is_ast2500(const AspeedWDTState *s) +{ + switch (s->silicon_rev) { + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + return true; + case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: + default: + break; + } + + return false; +} + static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); @@ -55,9 +81,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) return 0; case WDT_CTRL: return s->regs[WDT_CTRL]; + case WDT_RESET_WIDTH: + return s->regs[WDT_RESET_WIDTH]; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: - case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -119,9 +146,27 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, timer_del(s->timer); } break; + case WDT_RESET_WIDTH: + { + uint32_t property = data & WDT_POLARITY_MASK; + + if (property && is_ast2500(s)) { + if (property == WDT_ACTIVE_HIGH_MAGIC) { + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH; + } else if (property == WDT_ACTIVE_LOW_MAGIC) { + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH; + } else if (property == WDT_PUSH_PULL_MAGIC) { + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL; + } else if (property == WDT_OPEN_DRAIN_MAGIC) { + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL; + } + } + s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask; + s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask; + break; + } case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: - case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -167,6 +212,7 @@ static void aspeed_wdt_reset(DeviceState *dev) s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; s->regs[WDT_RESTART] = 0; s->regs[WDT_CTRL] = 0; + s->regs[WDT_RESET_WIDTH] = 0xFF; timer_del(s->timer); } @@ -187,6 +233,25 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedWDTState *s = ASPEED_WDT(dev); + if (!is_supported_silicon_rev(s->silicon_rev)) { + error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, + s->silicon_rev); + return; + } + + switch (s->silicon_rev) { + case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: + s->ext_pulse_width_mask = 0xff; + break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + s->ext_pulse_width_mask = 0xfffff; + break; + default: + g_assert_not_reached(); + } + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev); /* FIXME: This setting should be derived from the SCU hw strapping @@ -199,6 +264,11 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } +static Property aspeed_wdt_properties[] = { + DEFINE_PROP_UINT32("silicon-rev", AspeedWDTState, silicon_rev, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void aspeed_wdt_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -207,6 +277,7 @@ static void aspeed_wdt_class_init(ObjectClass *klass, void *data) dc->reset = aspeed_wdt_reset; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->vmsd = &vmstate_aspeed_wdt; + dc->props = aspeed_wdt_properties; } static const TypeInfo aspeed_wdt_info = { -- cgit v1.1 From 429789cc772514971e3d1190d1553f514054dd5c Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Mon, 4 Sep 2017 15:21:54 +0100 Subject: aspeed_soc: Propagate silicon-rev to watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to configure differences in behaviour between the AST2400 and AST2500 watchdog IPs. Signed-off-by: Andrew Jeffery Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 5529024..22dcac9 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -183,6 +183,8 @@ static void aspeed_soc_init(Object *obj) object_initialize(&s->wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT); object_property_add_child(obj, "wdt[*]", OBJECT(&s->wdt[i]), NULL); qdev_set_parent_bus(DEVICE(&s->wdt[i]), sysbus_get_default()); + qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev", + sc->info->silicon_rev); } object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100); -- cgit v1.1 From 469f3da42ef4af347fa7831e1cc0bd35d17f5b83 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 4 Sep 2017 15:21:55 +0100 Subject: hw/arm/aspeed_soc: Mark devices as user_creatable = false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU currently aborts if the user is accidentially trying to do something like this: $ aarch64-softmmu/qemu-system-aarch64 -S -M integratorcp -nographic QEMU 2.9.93 monitor - type 'help' for more information (qemu) device_add ast2400 Unexpected error in error_set_from_qdev_prop_error() at hw/core/qdev-properties.c:1032: Aborted (core dumped) The ast2400 SoC devices are clearly not creatable by the user since they are using the serial_hds and nd_table arrays directly in their realize function, so mark them with user_creatable = false. Signed-off-by: Thomas Huth Reviewed-by: Peter Maydell Reviewed-by: Cédric Le Goater Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 22dcac9..13c6393 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -340,6 +340,8 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data) sc->info = (AspeedSoCInfo *) data; dc->realize = aspeed_soc_realize; + /* Reason: Uses serial_hds and nd_table in realize() directly */ + dc->user_creatable = false; } static const TypeInfo aspeed_soc_type_info = { -- cgit v1.1 From f58f25599b72c7479e6a1ff67c7f671823aa14da Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 4 Sep 2017 15:21:55 +0100 Subject: hw/arm/digic: Mark device with user_creatable = false QEMU currently shows some unexpected behavior when the user trys to do a "device_add digic" on an unrelated ARM machine like integratorcp in "-nographic" mode (the device_add command does not immediately return to the monitor prompt), and trying to "device_del" the device later results in a "qemu/qdev-monitor.c:872:qdev_unplug: assertion failed: (hotplug_ctrl)" error condition. Looking at the realize function of the device, it uses serial_hds directly and this means that the device can not be added a second time, so let's simply mark it with "user_creatable = false" now. Signed-off-by: Thomas Huth Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/digic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 94f3263..6184020 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -101,6 +101,8 @@ static void digic_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = digic_realize; + /* Reason: Uses serial_hds in the realize function --> not usable twice */ + dc->user_creatable = false; } static const TypeInfo digic_type_info = { -- cgit v1.1 From 7229ec5825df6b933f150b54a8a2bedd2de1864c Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Mon, 4 Sep 2017 15:21:56 +0100 Subject: arm_gicv3_kvm: Fix compile warning Fix the following warning: /home/pranith/qemu/hw/intc/arm_gicv3_kvm.c:296:17: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses] if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { ^ ~ /home/pranith/qemu/hw/intc/arm_gicv3_kvm.c:296:17: note: add parentheses after the '!' to evaluate the bitwise operator first if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { ^ /home/pranith/qemu/hw/intc/arm_gicv3_kvm.c:296:17: note: add parentheses around left hand side expression to silence this warning if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { ^ This logic error meant we were not setting the PTZ bit when we should -- luckily as the comment suggests this wouldn't have had any effects beyond making GIC initialization take a little longer. Signed-off-by: Pranith Kumar Message-id: 20170829173226.7625-1-bobby.prani@gmail.com Cc: qemu-stable@nongnu.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 6051c77..481fe54 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -293,7 +293,7 @@ static void kvm_arm_gicv3_put(GICv3State *s) kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, true); reg64 = c->gicr_pendbaser; - if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { + if (!(c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) { /* Setting PTZ is advised if LPIs are disabled, to reduce * GIC initialization time. */ -- cgit v1.1