From 26d320220778973310de0afa96974a2e9e987caf Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 7 Feb 2017 18:29:58 +0000 Subject: integratorcp: adding vmstate for save/restore VMState added by this patch preserves correct loading of the integratorcp device state. Signed-off-by: Pavel Dovgalyuk Message-id: 20170131114310.6768.79416.stgit@PASHA-ISP [PMM: removed unnecessary minimum_version_id_old lines] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/integratorcp.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'hw') diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 039812a..f81634d 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -53,6 +53,26 @@ static uint8_t integrator_spd[128] = { 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 }; +static const VMStateDescription vmstate_integratorcm = { + .name = "integratorcm", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cm_osc, IntegratorCMState), + VMSTATE_UINT32(cm_ctrl, IntegratorCMState), + VMSTATE_UINT32(cm_lock, IntegratorCMState), + VMSTATE_UINT32(cm_auxosc, IntegratorCMState), + VMSTATE_UINT32(cm_sdram, IntegratorCMState), + VMSTATE_UINT32(cm_init, IntegratorCMState), + VMSTATE_UINT32(cm_flags, IntegratorCMState), + VMSTATE_UINT32(cm_nvflags, IntegratorCMState), + VMSTATE_UINT32(int_level, IntegratorCMState), + VMSTATE_UINT32(irq_enabled, IntegratorCMState), + VMSTATE_UINT32(fiq_enabled, IntegratorCMState), + VMSTATE_END_OF_LIST() + } +}; + static uint64_t integratorcm_read(void *opaque, hwaddr offset, unsigned size) { @@ -309,6 +329,18 @@ typedef struct icp_pic_state { qemu_irq parent_fiq; } icp_pic_state; +static const VMStateDescription vmstate_icp_pic = { + .name = "icp_pic", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(level, icp_pic_state), + VMSTATE_UINT32(irq_enabled, icp_pic_state), + VMSTATE_UINT32(fiq_enabled, icp_pic_state), + VMSTATE_END_OF_LIST() + } +}; + static void icp_pic_update(icp_pic_state *s) { uint32_t flags; @@ -438,6 +470,16 @@ typedef struct ICPCtrlRegsState { #define ICP_INTREG_WPROT (1 << 0) #define ICP_INTREG_CARDIN (1 << 3) +static const VMStateDescription vmstate_icp_control = { + .name = "icp_control", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(intreg_state, ICPCtrlRegsState), + VMSTATE_END_OF_LIST() + } +}; + static uint64_t icp_control_read(void *opaque, hwaddr offset, unsigned size) { @@ -640,6 +682,21 @@ static void core_class_init(ObjectClass *klass, void *data) dc->props = core_properties; dc->realize = integratorcm_realize; + dc->vmsd = &vmstate_integratorcm; +} + +static void icp_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_icp_pic; +} + +static void icp_control_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_icp_control; } static const TypeInfo core_info = { @@ -655,6 +712,7 @@ static const TypeInfo icp_pic_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pic_state), .instance_init = icp_pic_init, + .class_init = icp_pic_class_init, }; static const TypeInfo icp_ctrl_regs_info = { @@ -662,6 +720,7 @@ static const TypeInfo icp_ctrl_regs_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ICPCtrlRegsState), .instance_init = icp_control_init, + .class_init = icp_control_class_init, }; static void integratorcp_register_types(void) -- cgit v1.1 From 854123bf8d4b8f4dcedcb03d0201e4305da45fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 7 Feb 2017 18:29:59 +0000 Subject: wdt: Add Aspeed watchdog device model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Aspeed SoC includes a set of watchdog timers using 32-bit decrement counters, which can be based either on the APB clock or a 1 MHz clock. The watchdog timer is designed to prevent system deadlock and, in general, it should be restarted before timeout. When a timeout occurs, different types of signals can be generated, ARM reset, SOC reset, System reset, CPU Interrupt, external signal or boot from alternate block. The current model only performs the system reset function as this is used by U-Boot and Linux. Signed-off-by: Joel Stanley Message-id: 1485452251-1593-2-git-send-email-clg@kaod.org [clg: - fixed compile breakage - fixed io region size - added watchdog_perform_action() on timer expiry - wrote a commit log - merged fixes from Andrew Jeffery to scale the reload value ] Signed-off-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/watchdog/Makefile.objs | 1 + hw/watchdog/wdt_aspeed.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 hw/watchdog/wdt_aspeed.c (limited to 'hw') diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs index 72e3ffd..9589bed 100644 --- a/hw/watchdog/Makefile.objs +++ b/hw/watchdog/Makefile.objs @@ -2,3 +2,4 @@ common-obj-y += watchdog.o common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o +common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c new file mode 100644 index 0000000..8bbe579 --- /dev/null +++ b/hw/watchdog/wdt_aspeed.c @@ -0,0 +1,225 @@ +/* + * ASPEED Watchdog Controller + * + * Copyright (C) 2016-2017 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "sysemu/watchdog.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_CTRL_RESET_MODE_SOC (0x00 << 5) +#define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) +#define WDT_CTRL_1MHZ_CLK BIT(4) +#define WDT_CTRL_WDT_EXT BIT(3) +#define WDT_CTRL_WDT_INTR BIT(2) +#define WDT_CTRL_RESET_SYSTEM BIT(1) +#define WDT_CTRL_ENABLE BIT(0) + +#define WDT_TIMEOUT_STATUS (0x10 / 4) +#define WDT_TIMEOUT_CLEAR (0x14 / 4) +#define WDT_RESET_WDITH (0x18 / 4) + +#define WDT_RESTART_MAGIC 0x4755 + +static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) +{ + return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; +} + +static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) +{ + AspeedWDTState *s = ASPEED_WDT(opaque); + + offset >>= 2; + + switch (offset) { + case WDT_STATUS: + return s->regs[WDT_STATUS]; + case WDT_RELOAD_VALUE: + return s->regs[WDT_RELOAD_VALUE]; + case WDT_RESTART: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: read from write-only reg at offset 0x%" + HWADDR_PRIx "\n", __func__, offset); + return 0; + case WDT_CTRL: + return s->regs[WDT_CTRL]; + 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); + return 0; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return 0; + } + +} + +static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk) +{ + uint32_t reload; + + if (pclk) { + reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND, + s->pclk_freq); + } else { + reload = s->regs[WDT_RELOAD_VALUE] * 1000; + } + + if (aspeed_wdt_is_enabled(s)) { + timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload); + } +} + +static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedWDTState *s = ASPEED_WDT(opaque); + bool enable = data & WDT_CTRL_ENABLE; + + offset >>= 2; + + switch (offset) { + case WDT_STATUS: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to read-only reg at offset 0x%" + HWADDR_PRIx "\n", __func__, offset); + break; + case WDT_RELOAD_VALUE: + s->regs[WDT_RELOAD_VALUE] = data; + break; + case WDT_RESTART: + if ((data & 0xFFFF) == WDT_RESTART_MAGIC) { + s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE]; + aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK)); + } + break; + case WDT_CTRL: + if (enable && !aspeed_wdt_is_enabled(s)) { + s->regs[WDT_CTRL] = data; + aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK)); + } else if (!enable && aspeed_wdt_is_enabled(s)) { + s->regs[WDT_CTRL] = data; + timer_del(s->timer); + } + 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); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } + return; +} + +static WatchdogTimerModel model = { + .wdt_name = TYPE_ASPEED_WDT, + .wdt_description = "Aspeed watchdog device", +}; + +static const VMStateDescription vmstate_aspeed_wdt = { + .name = "vmstate_aspeed_wdt", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_TIMER_PTR(timer, AspeedWDTState), + VMSTATE_UINT32_ARRAY(regs, AspeedWDTState, ASPEED_WDT_REGS_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static const MemoryRegionOps aspeed_wdt_ops = { + .read = aspeed_wdt_read, + .write = aspeed_wdt_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .valid.unaligned = false, +}; + +static void aspeed_wdt_reset(DeviceState *dev) +{ + AspeedWDTState *s = ASPEED_WDT(dev); + + s->regs[WDT_STATUS] = 0x3EF1480; + s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; + s->regs[WDT_RESTART] = 0; + s->regs[WDT_CTRL] = 0; + + timer_del(s->timer); +} + +static void aspeed_wdt_timer_expired(void *dev) +{ + AspeedWDTState *s = ASPEED_WDT(dev); + + qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n"); + watchdog_perform_action(); + timer_del(s->timer); +} + +#define PCLK_HZ 24000000 + +static void aspeed_wdt_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedWDTState *s = ASPEED_WDT(dev); + + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev); + + /* FIXME: This setting should be derived from the SCU hw strapping + * register SCU70 + */ + s->pclk_freq = PCLK_HZ; + + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops, s, + TYPE_ASPEED_WDT, ASPEED_WDT_REGS_MAX * 4); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void aspeed_wdt_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = aspeed_wdt_realize; + dc->reset = aspeed_wdt_reset; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->vmsd = &vmstate_aspeed_wdt; +} + +static const TypeInfo aspeed_wdt_info = { + .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_ASPEED_WDT, + .instance_size = sizeof(AspeedWDTState), + .class_init = aspeed_wdt_class_init, +}; + +static void wdt_aspeed_register_types(void) +{ + watchdog_add_model(&model); + type_register_static(&aspeed_wdt_info); +} + +type_init(wdt_aspeed_register_types) -- cgit v1.1 From 013befe1ca055f555062c8ead083b3c214be97b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 7 Feb 2017 18:29:59 +0000 Subject: aspeed: add a watchdog controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables reboot of a guest from U-Boot and Linux. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-id: 1485452251-1593-3-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'hw') diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index b3e7f07..571e4f0 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -31,6 +31,7 @@ #define ASPEED_SOC_SCU_BASE 0x1E6E2000 #define ASPEED_SOC_SRAM_BASE 0x1E720000 #define ASPEED_SOC_TIMER_BASE 0x1E782000 +#define ASPEED_SOC_WDT_BASE 0x1E785000 #define ASPEED_SOC_I2C_BASE 0x1E78A000 static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; @@ -170,6 +171,10 @@ static void aspeed_soc_init(Object *obj) sc->info->silicon_rev); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), "ram-size", &error_abort); + + object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT); + object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL); + qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default()); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -286,6 +291,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE); + + /* Watch dog */ + object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE); } static void aspeed_soc_class_init(ObjectClass *oc, void *data) -- cgit v1.1 From 42922105beb14c2fc58185ea022b9f72fb5465e9 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Tue, 7 Feb 2017 18:29:59 +0000 Subject: sd: sdhci: check data length during dma_memory_read While doing multi block SDMA transfer in routine 'sdhci_sdma_transfer_multi_blocks', the 's->fifo_buffer' starting index 'begin' and data length 's->data_count' could end up to be same. This could lead to an OOB access issue. Correct transfer data length to avoid it. Cc: qemu-stable@nongnu.org Reported-by: Jiang Xin Signed-off-by: Prasad J Pandit Reviewed-by: Peter Maydell Message-id: 20170130064736.9236-1-ppandit@redhat.com Signed-off-by: Peter Maydell --- hw/sd/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 01fbf22..5bd5ab6 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -536,7 +536,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) boundary_count -= block_size - begin; } dma_memory_read(&address_space_memory, s->sdmasysad, - &s->fifo_buffer[begin], s->data_count); + &s->fifo_buffer[begin], s->data_count - begin); s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { for (n = 0; n < block_size; n++) { -- cgit v1.1 From 00909b585861ee3dca15f3d7624aac9be0f9080f Mon Sep 17 00:00:00 2001 From: Julian Brown Date: Tue, 7 Feb 2017 18:29:59 +0000 Subject: hw/arm/integratorcp: Support specifying features via -cpu Since the integratorcp board creates the CPU object directly rather than via cpu_arm_init(), we have to call the CPU class parse_features() method ourselves if we want to support the user passing features via the -cpu command line argument as well as just the cpu name. Do so. Signed-off-by: Julian Brown [PMM: split out into its own patch] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/integratorcp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index f81634d..5610ffc 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -577,27 +577,42 @@ static void integratorcp_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; + char **cpustr; ObjectClass *cpu_oc; + CPUClass *cc; Object *cpuobj; ARMCPU *cpu; + const char *typename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); qemu_irq pic[32]; DeviceState *dev, *sic, *icp; int i; + Error *err = NULL; if (!cpu_model) { cpu_model = "arm926"; } - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); + cpustr = g_strsplit(cpu_model, ",", 2); + + cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); if (!cpu_oc) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + typename = object_class_get_name(cpu_oc); + + cc = CPU_CLASS(cpu_oc); + cc->parse_features(typename, cpustr[1], &err); + g_strfreev(cpustr); + if (err) { + error_report_err(err); + exit(1); + } - cpuobj = object_new(object_class_get_name(cpu_oc)); + cpuobj = object_new(typename); /* By default ARM1176 CPUs have EL3 enabled. This board does not * currently support EL3 so the CPU EL3 property is disabled before -- cgit v1.1 From 394c8bbfb7aeaa788c2bc99ca972d359847a6459 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Feb 2017 18:30:00 +0000 Subject: stellaris: Document memory map and which SoC devices are unimplemented Add a comment documenting the memory map of the SoC devices and which are not implemented. Signed-off-by: Peter Maydell Message-id: 1484247815-15279-2-git-send-email-peter.maydell@linaro.org --- hw/arm/stellaris.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'hw') diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 794a3ad..5c4b707 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1220,6 +1220,40 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, 0x40024000, 0x40025000, 0x40026000}; static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; + /* Memory map of SoC devices, from + * Stellaris LM3S6965 Microcontroller Data Sheet (rev I) + * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf + * + * 40000000 wdtimer (unimplemented) + * 40002000 i2c (unimplemented) + * 40004000 GPIO + * 40005000 GPIO + * 40006000 GPIO + * 40007000 GPIO + * 40008000 SSI + * 4000c000 UART + * 4000d000 UART + * 4000e000 UART + * 40020000 i2c + * 40021000 i2c (unimplemented) + * 40024000 GPIO + * 40025000 GPIO + * 40026000 GPIO + * 40028000 PWM (unimplemented) + * 4002c000 QEI (unimplemented) + * 4002d000 QEI (unimplemented) + * 40030000 gptimer + * 40031000 gptimer + * 40032000 gptimer + * 40033000 gptimer + * 40038000 ADC + * 4003c000 analogue comparator (unimplemented) + * 40048000 ethernet + * 400fc000 hibernation module (unimplemented) + * 400fd000 flash memory control (unimplemented) + * 400fe000 system control + */ + DeviceState *gpio_dev[7], *nvic; qemu_irq gpio_in[7][8]; qemu_irq gpio_out[7][8]; -- cgit v1.1 From f5095aa3805f8cf91c4df6e7e1dab0d914bc40bc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Feb 2017 18:30:00 +0000 Subject: hw/misc: New "unimplemented" sysbus device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new "unimplemented" sysbus device, which simply accepts all read and write accesses, and implements them as read-as-zero, write-ignored, with logging of the access as LOG_UNIMP. This is useful for stubbing out bits of an SoC or board model which haven't been written yet. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 1484247815-15279-3-git-send-email-peter.maydell@linaro.org --- hw/misc/Makefile.objs | 2 + hw/misc/unimp.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 hw/misc/unimp.c (limited to 'hw') diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 1a89615..898e4cc 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -6,6 +6,8 @@ common-obj-$(CONFIG_SGA) += sga.o common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o +common-obj-y += unimp.o + obj-$(CONFIG_VMPORT) += vmport.o # ARM devices diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c new file mode 100644 index 0000000..bcbb585 --- /dev/null +++ b/hw/misc/unimp.c @@ -0,0 +1,107 @@ +/* "Unimplemented" device + * + * This is a dummy device which accepts and logs all accesses. + * It's useful for stubbing out regions of an SoC or board + * map which correspond to devices that have not yet been + * implemented. This is often sufficient to placate initial + * guest device driver probing such that the system will + * come up. + * + * Copyright Linaro Limited, 2017 + * Written by Peter Maydell + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/unimp.h" +#include "qemu/log.h" +#include "qapi/error.h" + +#define UNIMPLEMENTED_DEVICE(obj) \ + OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE) + +typedef struct { + SysBusDevice parent_obj; + MemoryRegion iomem; + char *name; + uint64_t size; +} UnimplementedDeviceState; + +static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size) +{ + UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " + "(size %d, offset 0x%" HWADDR_PRIx ")\n", + s->name, size, offset); + return 0; +} + +static void unimp_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " + "(size %d, value 0x%" PRIx64 + ", offset 0x%" HWADDR_PRIx ")\n", + s->name, size, value, offset); +} + +static const MemoryRegionOps unimp_ops = { + .read = unimp_read, + .write = unimp_write, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void unimp_realize(DeviceState *dev, Error **errp) +{ + UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(dev); + + if (s->size == 0) { + error_setg(errp, "property 'size' not specified or zero"); + return; + } + + if (s->name == NULL) { + error_setg(errp, "property 'name' not specified"); + return; + } + + memory_region_init_io(&s->iomem, OBJECT(s), &unimp_ops, s, + s->name, s->size); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); +} + +static Property unimp_properties[] = { + DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0), + DEFINE_PROP_STRING("name", UnimplementedDeviceState, name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void unimp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = unimp_realize; + dc->props = unimp_properties; +} + +static const TypeInfo unimp_info = { + .name = TYPE_UNIMPLEMENTED_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UnimplementedDeviceState), + .class_init = unimp_class_init, +}; + +static void unimp_register_types(void) +{ + type_register_static(&unimp_info); +} + +type_init(unimp_register_types) -- cgit v1.1 From aecfbbc97a2e52bbee34a53c32f961a182046a95 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Feb 2017 18:30:00 +0000 Subject: stellaris: Use the 'unimplemented' device for parts we don't implement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the 'unimplemented' dummy device to cover regions of the SoC device memory map which we don't have proper device implementations for yet. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 1484247815-15279-4-git-send-email-peter.maydell@linaro.org --- hw/arm/stellaris.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'hw') diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 5c4b707..9edcd49 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -21,6 +21,7 @@ #include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "hw/char/pl011.h" +#include "hw/misc/unimp.h" #define GPIO_A 0 #define GPIO_B 1 @@ -1404,6 +1405,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } } } + + /* Add dummy regions for the devices we don't implement yet, + * so guest accesses don't cause unlogged crashes. + */ + create_unimplemented_device("wdtimer", 0x40000000, 0x1000); + create_unimplemented_device("i2c-0", 0x40002000, 0x1000); + create_unimplemented_device("i2c-2", 0x40021000, 0x1000); + create_unimplemented_device("PWM", 0x40028000, 0x1000); + create_unimplemented_device("QEI-0", 0x4002c000, 0x1000); + create_unimplemented_device("QEI-1", 0x4002d000, 0x1000); + create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000); + create_unimplemented_device("hibernation", 0x400fc000, 0x1000); + create_unimplemented_device("flash-control", 0x400fd000, 0x1000); } /* FIXME: Figure out how to generate these from stellaris_boards. */ -- cgit v1.1