diff options
Diffstat (limited to 'qemu/hw/arm')
48 files changed, 3920 insertions, 889 deletions
diff --git a/qemu/hw/arm/Makefile.objs b/qemu/hw/arm/Makefile.objs index cf346c1d0..954c9fe15 100644 --- a/qemu/hw/arm/Makefile.objs +++ b/qemu/hw/arm/Makefile.objs @@ -1,6 +1,6 @@ obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o obj-$(CONFIG_DIGIC) += digic_boards.o -obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o +obj-y += integratorcp.o mainstone.o musicpal.o nseries.o obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o obj-$(CONFIG_ACPI) += virt-acpi-build.o @@ -11,5 +11,9 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o obj-$(CONFIG_DIGIC) += digic.o obj-y += omap1.o omap2.o 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_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o +obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o +obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o +obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o diff --git a/qemu/hw/arm/allwinner-a10.c b/qemu/hw/arm/allwinner-a10.c index ff249af33..ca15d1c8c 100644 --- a/qemu/hw/arm/allwinner-a10.c +++ b/qemu/hw/arm/allwinner-a10.c @@ -15,6 +15,10 @@ * for more details. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/devices.h" #include "hw/arm/allwinner-a10.h" @@ -39,6 +43,9 @@ static void aw_a10_init(Object *obj) qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); } + + object_initialize(&s->sata, sizeof(s->sata), TYPE_ALLWINNER_AHCI); + qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); } static void aw_a10_realize(DeviceState *dev, Error **errp) @@ -93,6 +100,14 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); sysbus_connect_irq(sysbusdev, 0, s->irq[55]); + object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); + if (err) { + error_propagate(errp, err); + 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]); + /* FIXME use a qdev chardev prop instead of serial_hds[] */ serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1], 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); @@ -103,6 +118,12 @@ static void aw_a10_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = aw_a10_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo aw_a10_type_info = { diff --git a/qemu/hw/arm/armv7m.c b/qemu/hw/arm/armv7m.c index c6eab6de3..bb2a22d96 100644 --- a/qemu/hw/arm/armv7m.c +++ b/qemu/hw/arm/armv7m.c @@ -7,6 +7,10 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/loader.h" @@ -166,17 +170,15 @@ static void armv7m_reset(void *opaque) mem_size is in bytes. Returns the NVIC array. */ -qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, +DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, const char *kernel_filename, const char *cpu_model) { ARMCPU *cpu; CPUARMState *env; DeviceState *nvic; - qemu_irq *pic = g_new(qemu_irq, num_irq); int image_size; uint64_t entry; uint64_t lowaddr; - int i; int big_endian; MemoryRegion *hack = g_new(MemoryRegion, 1); @@ -198,9 +200,6 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, qdev_init_nofail(nvic); sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); - for (i = 0; i < num_irq; i++) { - pic[i] = qdev_get_gpio_in(nvic, i); - } #ifdef TARGET_WORDS_BIGENDIAN big_endian = 1; @@ -215,7 +214,7 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, if (kernel_filename) { image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, - NULL, big_endian, ELF_MACHINE, 1); + NULL, big_endian, EM_ARM, 1, 0); if (image_size < 0) { image_size = load_image_targphys(kernel_filename, 0, mem_size); lowaddr = 0; @@ -229,12 +228,12 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, /* Hack to map an additional page of ram at the top of the address space. This stops qemu complaining about executing code outside RAM when returning from an exception. */ - memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_abort); + memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal); vmstate_register_ram_global(hack); memory_region_add_subregion(system_memory, 0xfffff000, hack); qemu_register_reset(armv7m_reset, cpu); - return pic; + return nvic; } static Property bitband_properties[] = { diff --git a/qemu/hw/arm/ast2400.c b/qemu/hw/arm/ast2400.c new file mode 100644 index 000000000..03f993863 --- /dev/null +++ b/qemu/hw/arm/ast2400.c @@ -0,0 +1,140 @@ +/* + * AST2400 SoC + * + * Andrew Jeffery <andrew@aj.id.au> + * Jeremy Kerr <jk@ozlabs.org> + * + * Copyright 2016 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 "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/arm/ast2400.h" +#include "hw/char/serial.h" + +#define AST2400_UART_5_BASE 0x00184000 +#define AST2400_IOMEM_SIZE 0x00200000 +#define AST2400_IOMEM_BASE 0x1E600000 +#define AST2400_VIC_BASE 0x1E6C0000 +#define AST2400_TIMER_BASE 0x1E782000 + +static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; +static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; + +/* + * IO handlers: simply catch any reads/writes to IO addresses that aren't + * handled by a device mapping. + */ + +static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", + __func__, offset, size); + return 0; +} + +static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", + __func__, offset, value, size); +} + +static const MemoryRegionOps ast2400_io_ops = { + .read = ast2400_io_read, + .write = ast2400_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void ast2400_init(Object *obj) +{ + AST2400State *s = AST2400(obj); + + s->cpu = cpu_arm_init("arm926"); + + object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); + object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); + qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); + + object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); + object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); + qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); +} + +static void ast2400_realize(DeviceState *dev, Error **errp) +{ + int i; + AST2400State *s = AST2400(dev); + Error *err = NULL; + + /* IO space */ + memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, + "ast2400.io", AST2400_IOMEM_SIZE); + memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, + &s->iomem, -1); + + /* VIC */ + object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); + + /* Timer */ + object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); + for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { + qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); + } + + /* UART - attach an 8250 to the IO space as our UART5 */ + if (serial_hds[0]) { + qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); + serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, + uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); + } +} + +static void ast2400_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ast2400_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; +} + +static const TypeInfo ast2400_type_info = { + .name = TYPE_AST2400, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AST2400State), + .instance_init = ast2400_init, + .class_init = ast2400_class_init, +}; + +static void ast2400_register_types(void) +{ + type_register_static(&ast2400_type_info); +} + +type_init(ast2400_register_types) diff --git a/qemu/hw/arm/bcm2835_peripherals.c b/qemu/hw/arm/bcm2835_peripherals.c new file mode 100644 index 000000000..234d51843 --- /dev/null +++ b/qemu/hw/arm/bcm2835_peripherals.c @@ -0,0 +1,312 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous + * + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft + * Written by Andrew Baumann + * + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/arm/bcm2835_peripherals.h" +#include "hw/misc/bcm2835_mbox_defs.h" +#include "hw/arm/raspi_platform.h" +#include "sysemu/char.h" + +/* Peripheral base address on the VC (GPU) system bus */ +#define BCM2835_VC_PERI_BASE 0x7e000000 + +/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */ +#define BCM2835_SDHC_CAPAREG 0x52034b4 + +static void bcm2835_peripherals_init(Object *obj) +{ + BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj); + + /* Memory region for peripheral devices, which we export to our parent */ + memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000); + object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr); + + /* Internal memory region for peripheral bus addresses (not exported) */ + memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32); + object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL); + + /* Internal memory region for request/response communication with + * mailbox-addressable peripherals (not exported) + */ + memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox", + MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT); + + /* Interrupt Controller */ + object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC); + object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL); + qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default()); + + /* UART0 */ + s->uart0 = SYS_BUS_DEVICE(object_new("pl011")); + object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL); + qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default()); + + /* AUX / UART1 */ + object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX); + object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL); + qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default()); + + /* Mailboxes */ + object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX); + object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL); + qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", + OBJECT(&s->mbox_mr), &error_abort); + + /* Framebuffer */ + object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB); + object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL); + object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size", + &error_abort); + qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->fb), "dma-mr", + OBJECT(&s->gpu_bus_mr), &error_abort); + + /* Property channel */ + object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY); + object_property_add_child(obj, "property", OBJECT(&s->property), NULL); + object_property_add_alias(obj, "board-rev", OBJECT(&s->property), + "board-rev", &error_abort); + qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->property), "fb", + OBJECT(&s->fb), &error_abort); + object_property_add_const_link(OBJECT(&s->property), "dma-mr", + OBJECT(&s->gpu_bus_mr), &error_abort); + + /* Extended Mass Media Controller */ + object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI); + object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL); + qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default()); + + /* DMA Channels */ + object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA); + object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL); + qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->dma), "dma-mr", + OBJECT(&s->gpu_bus_mr), &error_abort); +} + +static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) +{ + BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev); + Object *obj; + MemoryRegion *ram; + Error *err = NULL; + uint32_t ram_size, vcram_size; + CharDriverState *chr; + int n; + + obj = object_property_get_link(OBJECT(dev), "ram", &err); + if (obj == NULL) { + error_setg(errp, "%s: required ram link not found: %s", + __func__, error_get_pretty(err)); + return; + } + + ram = MEMORY_REGION(obj); + ram_size = memory_region_size(ram); + + /* Map peripherals and RAM into the GPU address space. */ + memory_region_init_alias(&s->peri_mr_alias, OBJECT(s), + "bcm2835-peripherals", &s->peri_mr, 0, + memory_region_size(&s->peri_mr)); + + memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE, + &s->peri_mr_alias, 1); + + /* RAM is aliased four times (different cache configurations) on the GPU */ + for (n = 0; n < 4; n++) { + memory_region_init_alias(&s->ram_alias[n], OBJECT(s), + "bcm2835-gpu-ram-alias[*]", ram, 0, ram_size); + memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30, + &s->ram_alias[n], 0); + } + + /* Interrupt Controller */ + object_property_set_bool(OBJECT(&s->ic), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0)); + sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); + + /* UART0 */ + object_property_set_bool(OBJECT(s->uart0), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, UART0_OFFSET, + sysbus_mmio_get_region(s->uart0, 0)); + sysbus_connect_irq(s->uart0, 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_UART)); + + /* AUX / UART1 */ + /* TODO: don't call qemu_char_get_next_serial() here, instead set + * chardev properties for each uart at the board level, once pl011 + * (uart0) has been updated to avoid qemu_char_get_next_serial() + */ + chr = qemu_char_get_next_serial(); + if (chr == NULL) { + chr = qemu_chr_new("bcm2835.uart1", "null", NULL); + } + qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr); + + object_property_set_bool(OBJECT(&s->aux), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, UART1_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_AUX)); + + /* Mailboxes */ + object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mboxes), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mboxes), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, + INTERRUPT_ARM_MAILBOX)); + + /* Framebuffer */ + vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size", + &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size, + "vcram-base", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->fb), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0, + qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB)); + + /* Property channel */ + object_property_set_bool(OBJECT(&s->property), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->mbox_mr, + MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0, + qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); + + /* Extended Mass Media Controller */ + object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg", + &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk", + &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_ARASANSDIO)); + object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->sdhci), "sd-bus", + &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* DMA Channels */ + object_property_set_bool(OBJECT(&s->dma), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, DMA_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0)); + memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1)); + + for (n = 0; n <= 12; n++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n, + qdev_get_gpio_in_named(DEVICE(&s->ic), + BCM2835_IC_GPU_IRQ, + INTERRUPT_DMA0 + n)); + } +} + +static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = bcm2835_peripherals_realize; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; +} + +static const TypeInfo bcm2835_peripherals_type_info = { + .name = TYPE_BCM2835_PERIPHERALS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835PeripheralState), + .instance_init = bcm2835_peripherals_init, + .class_init = bcm2835_peripherals_class_init, +}; + +static void bcm2835_peripherals_register_types(void) +{ + type_register_static(&bcm2835_peripherals_type_info); +} + +type_init(bcm2835_peripherals_register_types) diff --git a/qemu/hw/arm/bcm2836.c b/qemu/hw/arm/bcm2836.c new file mode 100644 index 000000000..8451190a1 --- /dev/null +++ b/qemu/hw/arm/bcm2836.c @@ -0,0 +1,184 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous + * + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft + * Written by Andrew Baumann + * + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/bcm2836.h" +#include "hw/arm/raspi_platform.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + +/* Peripheral base address seen by the CPU */ +#define BCM2836_PERI_BASE 0x3F000000 + +/* "QA7" (Pi2) interrupt controller and mailboxes etc. */ +#define BCM2836_CONTROL_BASE 0x40000000 + +static void bcm2836_init(Object *obj) +{ + BCM2836State *s = BCM2836(obj); + int n; + + for (n = 0; n < BCM2836_NCPUS; n++) { + object_initialize(&s->cpus[n], sizeof(s->cpus[n]), + "cortex-a15-" TYPE_ARM_CPU); + object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]), + &error_abort); + } + + object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL); + object_property_add_child(obj, "control", OBJECT(&s->control), NULL); + qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default()); + + object_initialize(&s->peripherals, sizeof(s->peripherals), + TYPE_BCM2835_PERIPHERALS); + object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals), + &error_abort); + object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), + "board-rev", &error_abort); + object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), + "vcram-size", &error_abort); + qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default()); +} + +static void bcm2836_realize(DeviceState *dev, Error **errp) +{ + BCM2836State *s = BCM2836(dev); + Object *obj; + Error *err = NULL; + int n; + + /* common peripherals from bcm2835 */ + + obj = object_property_get_link(OBJECT(dev), "ram", &err); + if (obj == NULL) { + error_setg(errp, "%s: required ram link not found: %s", + __func__, error_get_pretty(err)); + return; + } + + object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), + "sd-bus", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, + BCM2836_PERI_BASE, 1); + + /* bcm2836 interrupt controller (and mailboxes, etc.) */ + object_property_set_bool(OBJECT(&s->control), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, + qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, + qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); + + for (n = 0; n < BCM2836_NCPUS; n++) { + /* Mirror bcm2836, which has clusterid set to 0xf + * TODO: this should be converted to a property of ARM_CPU + */ + s->cpus[n].mp_affinity = 0xF00 | n; + + /* set periphbase/CBAR value for CPU-local registers */ + object_property_set_int(OBJECT(&s->cpus[n]), + BCM2836_PERI_BASE + MCORE_OFFSET, + "reset-cbar", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* start powered off if not enabled */ + object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, + "start-powered-off", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* Connect irq/fiq outputs from the interrupt controller. */ + qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, + qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); + qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, + qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); + + /* Connect timers from the CPU to the interrupt controller */ + qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, + qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); + qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, + qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); + qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP, + qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); + qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC, + qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); + } +} + +static Property bcm2836_props[] = { + DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS), + DEFINE_PROP_END_OF_LIST() +}; + +static void bcm2836_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->props = bcm2836_props; + dc->realize = bcm2836_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; +} + +static const TypeInfo bcm2836_type_info = { + .name = TYPE_BCM2836, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2836State), + .instance_init = bcm2836_init, + .class_init = bcm2836_class_init, +}; + +static void bcm2836_register_types(void) +{ + type_register_static(&bcm2836_type_info); +} + +type_init(bcm2836_register_types) diff --git a/qemu/hw/arm/boot.c b/qemu/hw/arm/boot.c index 5b969cda1..587694557 100644 --- a/qemu/hw/arm/boot.c +++ b/qemu/hw/arm/boot.c @@ -7,9 +7,12 @@ * This code is licensed under the GPL. */ -#include "config.h" +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/arm/arm.h" +#include "hw/arm/linux-boot-if.h" +#include "sysemu/kvm.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" @@ -27,14 +30,15 @@ #define KERNEL64_LOAD_ADDR 0x00080000 typedef enum { - FIXUP_NONE = 0, /* do nothing */ - FIXUP_TERMINATOR, /* end of insns */ - FIXUP_BOARDID, /* overwrite with board ID number */ - FIXUP_ARGPTR, /* overwrite with pointer to kernel args */ - FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */ - FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ - FIXUP_BOOTREG, /* overwrite with boot register address */ - FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ + FIXUP_NONE = 0, /* do nothing */ + FIXUP_TERMINATOR, /* end of insns */ + FIXUP_BOARDID, /* overwrite with board ID number */ + FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */ + FIXUP_ARGPTR, /* overwrite with pointer to kernel args */ + FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */ + FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ + FIXUP_BOOTREG, /* overwrite with boot register address */ + FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ FIXUP_MAX, } FixupType; @@ -57,8 +61,17 @@ static const ARMInsnFixup bootloader_aarch64[] = { { 0, FIXUP_TERMINATOR } }; -/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ +/* A very small bootloader: call the board-setup code (if needed), + * set r0-r2, then jump to the kernel. + * If we're not calling boot setup code then we don't copy across + * the first BOOTLOADER_NO_BOARD_SETUP_OFFSET insns in this array. + */ + static const ARMInsnFixup bootloader[] = { + { 0xe28fe004 }, /* add lr, pc, #4 */ + { 0xe51ff004 }, /* ldr pc, [pc, #-4] */ + { 0, FIXUP_BOARD_SETUP }, +#define BOOTLOADER_NO_BOARD_SETUP_OFFSET 3 { 0xe3a00000 }, /* mov r0, #0 */ { 0xe59f1004 }, /* ldr r1, [pc, #4] */ { 0xe59f2004 }, /* ldr r2, [pc, #4] */ @@ -130,6 +143,7 @@ static void write_bootloader(const char *name, hwaddr addr, case FIXUP_NONE: break; case FIXUP_BOARDID: + case FIXUP_BOARD_SETUP: case FIXUP_ARGPTR: case FIXUP_ENTRYPOINT: case FIXUP_GIC_CPU_IF: @@ -165,6 +179,57 @@ static void default_write_secondary(ARMCPU *cpu, smpboot, fixupcontext); } +void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, + const struct arm_boot_info *info, + hwaddr mvbar_addr) +{ + int n; + uint32_t mvbar_blob[] = { + /* mvbar_addr: secure monitor vectors + * Default unimplemented and unused vectors to spin. Makes it + * easier to debug (as opposed to the CPU running away). + */ + 0xeafffffe, /* (spin) */ + 0xeafffffe, /* (spin) */ + 0xe1b0f00e, /* movs pc, lr ;SMC exception return */ + 0xeafffffe, /* (spin) */ + 0xeafffffe, /* (spin) */ + 0xeafffffe, /* (spin) */ + 0xeafffffe, /* (spin) */ + 0xeafffffe, /* (spin) */ + }; + uint32_t board_setup_blob[] = { + /* board setup addr */ + 0xe3a00e00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */ + 0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 ;set MVBAR */ + 0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 ;read SCR */ + 0xe3800031, /* orr r0, #0x31 ;enable AW, FW, NS */ + 0xee010f11, /* mcr p15, 0, r0, c1, c1, 0 ;write SCR */ + 0xe1a0100e, /* mov r1, lr ;save LR across SMC */ + 0xe1600070, /* smc #0 ;call monitor to flush SCR */ + 0xe1a0f001, /* mov pc, r1 ;return */ + }; + + /* check that mvbar_addr is correctly aligned and relocatable (using MOV) */ + assert((mvbar_addr & 0x1f) == 0 && (mvbar_addr >> 4) < 0x100); + + /* check that these blobs don't overlap */ + assert((mvbar_addr + sizeof(mvbar_blob) <= info->board_setup_addr) + || (info->board_setup_addr + sizeof(board_setup_blob) <= mvbar_addr)); + + for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) { + mvbar_blob[n] = tswap32(mvbar_blob[n]); + } + rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob), + mvbar_addr); + + for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { + board_setup_blob[n] = tswap32(board_setup_blob[n]); + } + rom_add_blob_fixed("board-setup", board_setup_blob, + sizeof(board_setup_blob), info->board_setup_addr); +} + static void default_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -373,8 +438,10 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, return 0; } - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", + NULL, &error_fatal); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", + NULL, &error_fatal); if (acells == 0 || scells == 0) { fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); goto fail; @@ -452,9 +519,34 @@ static void do_cpu_reset(void *opaque) cpu_reset(cs); if (info) { if (!info->is_linux) { + int i; /* Jump to the entry point. */ uint64_t entry = info->entry; + switch (info->endianness) { + case ARM_ENDIANNESS_LE: + env->cp15.sctlr_el[1] &= ~SCTLR_E0E; + for (i = 1; i < 4; ++i) { + env->cp15.sctlr_el[i] &= ~SCTLR_EE; + } + env->uncached_cpsr &= ~CPSR_E; + break; + case ARM_ENDIANNESS_BE8: + env->cp15.sctlr_el[1] |= SCTLR_E0E; + for (i = 1; i < 4; ++i) { + env->cp15.sctlr_el[i] |= SCTLR_EE; + } + env->uncached_cpsr |= CPSR_E; + break; + case ARM_ENDIANNESS_BE32: + env->cp15.sctlr_el[1] |= SCTLR_B; + break; + case ARM_ENDIANNESS_UNKNOWN: + break; /* Board's decision */ + default: + g_assert_not_reached(); + } + if (!env->aarch64) { env->thumb = info->entry & 1; entry &= 0xfffffffe; @@ -475,7 +567,9 @@ static void do_cpu_reset(void *opaque) * adjust. */ if (env->aarch64) { + env->cp15.scr_el3 |= SCR_RW; if (arm_feature(env, ARM_FEATURE_EL2)) { + env->cp15.hcr_el2 |= HCR_RW; env->pstate = PSTATE_MODE_EL2h; } else { env->pstate = PSTATE_MODE_EL1h; @@ -483,7 +577,8 @@ static void do_cpu_reset(void *opaque) } /* Set to non-secure if not a secure boot */ - if (!info->secure_boot) { + if (!info->secure_boot && + (cs != first_cpu || !info->secure_board_setup)) { /* Linux expects non-secure state */ env->cp15.scr_el3 |= SCR_NS; } @@ -555,6 +650,76 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, fw_cfg_add_bytes(fw_cfg, data_key, data, size); } +static int do_arm_linux_init(Object *obj, void *opaque) +{ + if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) { + ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj); + ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj); + struct arm_boot_info *info = opaque; + + if (albifc->arm_linux_init) { + albifc->arm_linux_init(albif, info->secure_boot); + } + } + return 0; +} + +static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, + uint64_t *lowaddr, uint64_t *highaddr, + int elf_machine) +{ + bool elf_is64; + union { + Elf32_Ehdr h32; + Elf64_Ehdr h64; + } elf_header; + int data_swab = 0; + bool big_endian; + uint64_t ret = -1; + Error *err = NULL; + + + load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err); + if (err) { + return ret; + } + + if (elf_is64) { + big_endian = elf_header.h64.e_ident[EI_DATA] == ELFDATA2MSB; + info->endianness = big_endian ? ARM_ENDIANNESS_BE8 + : ARM_ENDIANNESS_LE; + } else { + big_endian = elf_header.h32.e_ident[EI_DATA] == ELFDATA2MSB; + if (big_endian) { + if (bswap32(elf_header.h32.e_flags) & EF_ARM_BE8) { + info->endianness = ARM_ENDIANNESS_BE8; + } else { + info->endianness = ARM_ENDIANNESS_BE32; + /* In BE32, the CPU has a different view of the per-byte + * address map than the rest of the system. BE32 ELF files + * are organised such that they can be programmed through + * the CPU's per-word byte-reversed view of the world. QEMU + * however loads ELF files independently of the CPU. So + * tell the ELF loader to byte reverse the data for us. + */ + data_swab = 2; + } + } else { + info->endianness = ARM_ENDIANNESS_LE; + } + } + + ret = load_elf(info->kernel_filename, NULL, NULL, + pentry, lowaddr, highaddr, big_endian, elf_machine, + 1, data_swab); + if (ret <= 0) { + /* The header loaded but the image didn't */ + exit(1); + } + + return ret; +} + static void arm_load_kernel_notify(Notifier *notifier, void *data) { CPUState *cs; @@ -564,7 +729,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) uint64_t elf_entry, elf_low_addr, elf_high_addr; int elf_machine; hwaddr entry, kernel_load_offset; - int big_endian; static const ARMInsnFixup *primary_loader; ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier, notifier, notifier); @@ -572,6 +736,12 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) struct arm_boot_info *info = container_of(n, struct arm_boot_info, load_kernel_notifier); + /* The board code is not supposed to set secure_board_setup unless + * running its code in secure mode is actually possible, and KVM + * doesn't support secure. + */ + assert(!(info->secure_board_setup && kvm_enabled())); + /* Load the kernel. */ if (!info->kernel_filename || info->firmware_loaded) { @@ -625,6 +795,9 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) elf_machine = EM_AARCH64; } else { primary_loader = bootloader; + if (!info->write_board_setup) { + primary_loader += BOOTLOADER_NO_BOARD_SETUP_OFFSET; + } kernel_load_offset = KERNEL_LOAD_ADDR; elf_machine = EM_ARM; } @@ -641,12 +814,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) if (info->nb_cpus == 0) info->nb_cpus = 1; -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - /* We want to put the initrd far enough into RAM that when the * kernel is uncompressed it will not clobber the initrd. However * on boards without much RAM we must ensure that we still leave @@ -661,9 +828,8 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) MIN(info->ram_size / 2, 128 * 1024 * 1024); /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, - &elf_low_addr, &elf_high_addr, big_endian, - elf_machine, 1); + kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr, + &elf_high_addr, elf_machine); if (kernel_size > 0 && have_dtb(info)) { /* If there is still some room left at the base of RAM, try and put * the DTB there like we do for images loaded with -bios or -pflash. @@ -730,6 +896,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) info->initrd_size = initrd_size; fixupcontext[FIXUP_BOARDID] = info->board_id; + fixupcontext[FIXUP_BOARD_SETUP] = info->board_setup_addr; /* for device tree boot, we pass the DTB directly in r2. Otherwise * we point to the kernel args. @@ -778,6 +945,15 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) if (info->nb_cpus > 1) { info->write_secondary_boot(cpu, info); } + if (info->write_board_setup) { + info->write_board_setup(cpu, info); + } + + /* Notify devices which need to fake up firmware initialization + * that we're doing a direct kernel boot. + */ + object_child_foreach_recursive(object_get_root(), + do_arm_linux_init, info); } info->is_linux = is_linux; @@ -803,3 +979,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); } } + +static const TypeInfo arm_linux_boot_if_info = { + .name = TYPE_ARM_LINUX_BOOT_IF, + .parent = TYPE_INTERFACE, + .class_size = sizeof(ARMLinuxBootIfClass), +}; + +static void arm_linux_boot_register_types(void) +{ + type_register_static(&arm_linux_boot_if_info); +} + +type_init(arm_linux_boot_register_types) diff --git a/qemu/hw/arm/collie.c b/qemu/hw/arm/collie.c index 6c9b82fc5..8bb308a42 100644 --- a/qemu/hw/arm/collie.c +++ b/qemu/hw/arm/collie.c @@ -8,6 +8,7 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/boards.h" @@ -58,15 +59,10 @@ static void collie_init(MachineState *machine) arm_load_kernel(s->cpu, &collie_binfo); } -static QEMUMachine collie_machine = { - .name = "collie", - .desc = "Collie PDA (SA-1110)", - .init = collie_init, -}; - -static void collie_machine_init(void) +static void collie_machine_init(MachineClass *mc) { - qemu_register_machine(&collie_machine); + mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)"; + mc->init = collie_init; } -machine_init(collie_machine_init) +DEFINE_MACHINE("collie", collie_machine_init) diff --git a/qemu/hw/arm/cubieboard.c b/qemu/hw/arm/cubieboard.c index 1582250eb..fbd78ed01 100644 --- a/qemu/hw/arm/cubieboard.c +++ b/qemu/hw/arm/cubieboard.c @@ -15,6 +15,10 @@ * for more details. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/devices.h" #include "hw/boards.h" @@ -39,27 +43,26 @@ static void cubieboard_init(MachineState *machine) object_property_set_int(OBJECT(&s->a10->emac), 1, "phy-addr", &err); if (err != NULL) { - error_report("Couldn't set phy address: %s", error_get_pretty(err)); + error_reportf_err(err, "Couldn't set phy address: "); exit(1); } object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err); if (err != NULL) { - error_report("Couldn't set clk0 frequency: %s", error_get_pretty(err)); + error_reportf_err(err, "Couldn't set clk0 frequency: "); exit(1); } object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq", &err); if (err != NULL) { - error_report("Couldn't set clk1 frequency: %s", error_get_pretty(err)); + error_reportf_err(err, "Couldn't set clk1 frequency: "); exit(1); } object_property_set_bool(OBJECT(s->a10), true, "realized", &err); if (err != NULL) { - error_report("Couldn't realize Allwinner A10: %s", - error_get_pretty(err)); + error_reportf_err(err, "Couldn't realize Allwinner A10: "); exit(1); } @@ -74,16 +77,10 @@ static void cubieboard_init(MachineState *machine) arm_load_kernel(&s->a10->cpu, &cubieboard_binfo); } -static QEMUMachine cubieboard_machine = { - .name = "cubieboard", - .desc = "cubietech cubieboard", - .init = cubieboard_init, -}; - - -static void cubieboard_machine_init(void) +static void cubieboard_machine_init(MachineClass *mc) { - qemu_register_machine(&cubieboard_machine); + mc->desc = "cubietech cubieboard"; + mc->init = cubieboard_init; } -machine_init(cubieboard_machine_init) +DEFINE_MACHINE("cubieboard", cubieboard_machine_init) diff --git a/qemu/hw/arm/digic.c b/qemu/hw/arm/digic.c index ec8c33060..e0f973032 100644 --- a/qemu/hw/arm/digic.c +++ b/qemu/hw/arm/digic.c @@ -20,6 +20,8 @@ * */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/arm/digic.h" #define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100) @@ -97,6 +99,12 @@ static void digic_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = digic_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo digic_type_info = { diff --git a/qemu/hw/arm/digic_boards.c b/qemu/hw/arm/digic_boards.c index f8ba9e595..520c8e9ff 100644 --- a/qemu/hw/arm/digic_boards.c +++ b/qemu/hw/arm/digic_boards.c @@ -23,6 +23,10 @@ * */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/boards.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" @@ -64,8 +68,7 @@ static void digic4_board_init(DigicBoard *board) s->digic = DIGIC(object_new(TYPE_DIGIC)); object_property_set_bool(OBJECT(s->digic), true, "realized", &err); if (err != NULL) { - error_report("Couldn't realize DIGIC SoC: %s", - error_get_pretty(err)); + error_reportf_err(err, "Couldn't realize DIGIC SoC: "); exit(1); } @@ -148,15 +151,10 @@ static void canon_a1100_init(MachineState *machine) digic4_board_init(&digic4_board_canon_a1100); } -static QEMUMachine canon_a1100 = { - .name = "canon-a1100", - .desc = "Canon PowerShot A1100 IS", - .init = &canon_a1100_init, -}; - -static void digic_register_machines(void) +static void canon_a1100_machine_init(MachineClass *mc) { - qemu_register_machine(&canon_a1100); + mc->desc = "Canon PowerShot A1100 IS"; + mc->init = &canon_a1100_init; } -machine_init(digic_register_machines) +DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init) diff --git a/qemu/hw/arm/exynos4210.c b/qemu/hw/arm/exynos4210.c index c55fab813..be3c96d21 100644 --- a/qemu/hw/arm/exynos4210.c +++ b/qemu/hw/arm/exynos4210.c @@ -21,6 +21,10 @@ * */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/boards.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" @@ -150,27 +154,18 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, for (n = 0; n < EXYNOS4210_NCPUS; n++) { Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - Error *err = NULL; /* By default A9 CPUs have EL3 enabled. This board does not currently * support EL3 so the CPU EL3 property is disabled before realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } s->cpu[n] = ARM_CPU(cpuobj); object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR, "reset-cbar", &error_abort); - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); } /*** IRQs ***/ @@ -259,7 +254,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, /* Internal ROM */ memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom", - EXYNOS4210_IROM_SIZE, &error_abort); + EXYNOS4210_IROM_SIZE, &error_fatal); vmstate_register_ram_global(&s->irom_mem); memory_region_set_readonly(&s->irom_mem, true); memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, @@ -275,7 +270,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, /* Internal RAM */ memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram", - EXYNOS4210_IRAM_SIZE, &error_abort); + EXYNOS4210_IRAM_SIZE, &error_fatal); vmstate_register_ram_global(&s->iram_mem); memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, &s->iram_mem); @@ -284,14 +279,14 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, mem_size = ram_size; if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", - mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_abort); + mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_fatal); vmstate_register_ram_global(&s->dram1_mem); memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, &s->dram1_mem); mem_size = EXYNOS4210_DRAM_MAX_SIZE; } memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->dram0_mem); memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, &s->dram0_mem); diff --git a/qemu/hw/arm/exynos4_boards.c b/qemu/hw/arm/exynos4_boards.c index d644db1ef..0efa19405 100644 --- a/qemu/hw/arm/exynos4_boards.c +++ b/qemu/hw/arm/exynos4_boards.c @@ -21,6 +21,9 @@ * */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "hw/sysbus.h" @@ -74,8 +77,6 @@ static struct arm_boot_info exynos4_board_binfo = { .write_secondary_boot = exynos4210_write_secondary, }; -static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS]; - static void lan9215_init(uint32_t base, qemu_irq irq) { DeviceState *dev; @@ -97,11 +98,12 @@ static void lan9215_init(uint32_t base, qemu_irq irq) static Exynos4210State *exynos4_boards_init_common(MachineState *machine, Exynos4BoardType board_type) { + MachineClass *mc = MACHINE_GET_CLASS(machine); + if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus" " value.\n", - exynos4_machines[board_type].name, - exynos4_machines[board_type].max_cpus); + mc->name, EXYNOS4210_NCPUS); } exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; @@ -145,25 +147,40 @@ static void smdkc210_init(MachineState *machine) arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); } -static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = { - .name = "nuri", - .desc = "Samsung NURI board (Exynos4210)", - .init = nuri_init, - .max_cpus = EXYNOS4210_NCPUS, - }, - [EXYNOS4_BOARD_SMDKC210] = { - .name = "smdkc210", - .desc = "Samsung SMDKC210 board (Exynos4210)", - .init = smdkc210_init, - .max_cpus = EXYNOS4210_NCPUS, - }, +static void nuri_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Samsung NURI board (Exynos4210)"; + mc->init = nuri_init; + mc->max_cpus = EXYNOS4210_NCPUS; +} + +static const TypeInfo nuri_type = { + .name = MACHINE_TYPE_NAME("nuri"), + .parent = TYPE_MACHINE, + .class_init = nuri_class_init, +}; + +static void smdkc210_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Samsung SMDKC210 board (Exynos4210)"; + mc->init = smdkc210_init; + mc->max_cpus = EXYNOS4210_NCPUS; +} + +static const TypeInfo smdkc210_type = { + .name = MACHINE_TYPE_NAME("smdkc210"), + .parent = TYPE_MACHINE, + .class_init = smdkc210_class_init, }; -static void exynos4_machine_init(void) +static void exynos4_machines_init(void) { - qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]); - qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]); + type_register_static(&nuri_type); + type_register_static(&smdkc210_type); } -machine_init(exynos4_machine_init); +type_init(exynos4_machines_init) diff --git a/qemu/hw/arm/fsl-imx25.c b/qemu/hw/arm/fsl-imx25.c new file mode 100644 index 000000000..2f878b935 --- /dev/null +++ b/qemu/hw/arm/fsl-imx25.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> + * + * i.MX25 SOC emulation. + * + * Based on hw/arm/xlnx-zynqmp.c + * + * Copyright (C) 2015 Xilinx Inc + * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/fsl-imx25.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "hw/boards.h" +#include "sysemu/char.h" + +static void fsl_imx25_init(Object *obj) +{ + FslIMX25State *s = FSL_IMX25(obj); + int i; + + object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU); + + object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC); + qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default()); + + object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM); + qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default()); + + for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) { + object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); + qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); + } + + for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { + object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT); + qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default()); + } + + for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) { + object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT); + qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default()); + } + + object_initialize(&s->fec, sizeof(s->fec), TYPE_IMX_FEC); + qdev_set_parent_bus(DEVICE(&s->fec), sysbus_get_default()); + + for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) { + object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C); + qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default()); + } + + for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) { + object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); + qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default()); + } +} + +static void fsl_imx25_realize(DeviceState *dev, Error **errp) +{ + FslIMX25State *s = FSL_IMX25(dev); + uint8_t i; + Error *err = NULL; + + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0, + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); + + object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR); + + /* Initialize all UARTs */ + for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } serial_table[FSL_IMX25_NUM_UARTS] = { + { FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ }, + { FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ }, + { FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ }, + { FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ }, + { FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ } + }; + + if (i < MAX_SERIAL_PORTS) { + CharDriverState *chr; + + chr = serial_hds[i]; + + if (!chr) { + char label[20]; + snprintf(label, sizeof(label), "imx31.uart%d", i); + chr = qemu_chr_new(label, "null", NULL); + } + + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); + } + + object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + serial_table[i].irq)); + } + + /* Initialize all GPT timers */ + for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } gpt_table[FSL_IMX25_NUM_GPTS] = { + { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ }, + { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ }, + { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ }, + { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ } + }; + + s->gpt[i].ccm = IMX_CCM(&s->ccm); + + object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + gpt_table[i].irq)); + } + + /* Initialize all EPIT timers */ + for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } epit_table[FSL_IMX25_NUM_EPITS] = { + { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ }, + { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ } + }; + + s->epit[i].ccm = IMX_CCM(&s->ccm); + + object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + epit_table[i].irq)); + } + + qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); + object_property_set_bool(OBJECT(&s->fec), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0, + qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ)); + + + /* Initialize all I2C */ + for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } i2c_table[FSL_IMX25_NUM_I2CS] = { + { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ }, + { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ }, + { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ } + }; + + object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + i2c_table[i].irq)); + } + + /* Initialize all GPIOs */ + for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } gpio_table[FSL_IMX25_NUM_GPIOS] = { + { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ }, + { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ }, + { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ }, + { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ } + }; + + object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); + /* Connect GPIO IRQ to PIC */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + gpio_table[i].irq)); + } + + /* initialize 2 x 16 KB ROM */ + memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL, + "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR, + &s->rom[0]); + memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL, + "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR, + &s->rom[1]); + + /* initialize internal RAM (128 KB) */ + memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE, + &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR, + &s->iram); + vmstate_register_ram_global(&s->iram); + + /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */ + memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias", + &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE); + memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR, + &s->iram_alias); +} + +static void fsl_imx25_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = fsl_imx25_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; + dc->desc = "i.MX25 SOC"; +} + +static const TypeInfo fsl_imx25_type_info = { + .name = TYPE_FSL_IMX25, + .parent = TYPE_DEVICE, + .instance_size = sizeof(FslIMX25State), + .instance_init = fsl_imx25_init, + .class_init = fsl_imx25_class_init, +}; + +static void fsl_imx25_register_types(void) +{ + type_register_static(&fsl_imx25_type_info); +} + +type_init(fsl_imx25_register_types) diff --git a/qemu/hw/arm/fsl-imx31.c b/qemu/hw/arm/fsl-imx31.c new file mode 100644 index 000000000..31a3a8791 --- /dev/null +++ b/qemu/hw/arm/fsl-imx31.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> + * + * i.MX31 SOC emulation. + * + * Based on hw/arm/fsl-imx31.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/fsl-imx31.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "hw/boards.h" +#include "sysemu/char.h" + +static void fsl_imx31_init(Object *obj) +{ + FslIMX31State *s = FSL_IMX31(obj); + int i; + + object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU); + + object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC); + qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default()); + + object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM); + qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default()); + + for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { + object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); + qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); + } + + object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT); + qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default()); + + for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { + object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT); + qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default()); + } + + for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { + object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C); + qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default()); + } + + for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { + object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); + qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default()); + } +} + +static void fsl_imx31_realize(DeviceState *dev, Error **errp) +{ + FslIMX31State *s = FSL_IMX31(dev); + uint16_t i; + Error *err = NULL; + + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0, + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); + + object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR); + + /* Initialize all UARTS */ + for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } serial_table[FSL_IMX31_NUM_UARTS] = { + { FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ }, + { FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ }, + }; + + if (i < MAX_SERIAL_PORTS) { + CharDriverState *chr; + + chr = serial_hds[i]; + + if (!chr) { + char label[20]; + snprintf(label, sizeof(label), "imx31.uart%d", i); + chr = qemu_chr_new(label, "null", NULL); + } + + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); + } + + object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + serial_table[i].irq)); + } + + s->gpt.ccm = IMX_CCM(&s->ccm); + + object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX31_GPT_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0, + qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ)); + + /* Initialize all EPIT timers */ + for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } epit_table[FSL_IMX31_NUM_EPITS] = { + { FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ }, + { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ }, + }; + + s->epit[i].ccm = IMX_CCM(&s->ccm); + + object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + epit_table[i].irq)); + } + + /* Initialize all I2C */ + for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } i2c_table[FSL_IMX31_NUM_I2CS] = { + { FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ }, + { FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ }, + { FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ } + }; + + /* Initialize the I2C */ + object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + /* Map I2C memory */ + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); + /* Connect I2C IRQ to PIC */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + i2c_table[i].irq)); + } + + /* Initialize all GPIOs */ + for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } gpio_table[FSL_IMX31_NUM_GPIOS] = { + { FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ }, + { FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ }, + { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ } + }; + + object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel", + &error_abort); + object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); + /* Connect GPIO IRQ to PIC */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, + qdev_get_gpio_in(DEVICE(&s->avic), + gpio_table[i].irq)); + } + + /* On a real system, the first 16k is a `secure boot rom' */ + memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL, + "imx31.secure_rom", + FSL_IMX31_SECURE_ROM_SIZE, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR, + &s->secure_rom); + + /* There is also a 16k ROM */ + memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom", + FSL_IMX31_ROM_SIZE, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR, + &s->rom); + + /* initialize internal RAM (16 KB) */ + memory_region_init_ram(&s->iram, NULL, "imx31.iram", FSL_IMX31_IRAM_SIZE, + &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR, + &s->iram); + vmstate_register_ram_global(&s->iram); + + /* internal RAM (16 KB) is aliased over 256 MB - 16 KB */ + memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias", + &s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE); + memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR, + &s->iram_alias); +} + +static void fsl_imx31_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = fsl_imx31_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; + dc->desc = "i.MX31 SOC"; +} + +static const TypeInfo fsl_imx31_type_info = { + .name = TYPE_FSL_IMX31, + .parent = TYPE_DEVICE, + .instance_size = sizeof(FslIMX31State), + .instance_init = fsl_imx31_init, + .class_init = fsl_imx31_class_init, +}; + +static void fsl_imx31_register_types(void) +{ + type_register_static(&fsl_imx31_type_info); +} + +type_init(fsl_imx31_register_types) diff --git a/qemu/hw/arm/gumstix.c b/qemu/hw/arm/gumstix.c index 8103278b1..d59d9ba4e 100644 --- a/qemu/hw/arm/gumstix.c +++ b/qemu/hw/arm/gumstix.c @@ -34,6 +34,7 @@ * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "net/net.h" @@ -121,22 +122,38 @@ static void verdex_init(MachineState *machine) qdev_get_gpio_in(cpu->gpio, 99)); } -static QEMUMachine connex_machine = { - .name = "connex", - .desc = "Gumstix Connex (PXA255)", - .init = connex_init, +static void connex_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Gumstix Connex (PXA255)"; + mc->init = connex_init; +} + +static const TypeInfo connex_type = { + .name = MACHINE_TYPE_NAME("connex"), + .parent = TYPE_MACHINE, + .class_init = connex_class_init, }; -static QEMUMachine verdex_machine = { - .name = "verdex", - .desc = "Gumstix Verdex (PXA270)", - .init = verdex_init, +static void verdex_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Gumstix Verdex (PXA270)"; + mc->init = verdex_init; +} + +static const TypeInfo verdex_type = { + .name = MACHINE_TYPE_NAME("verdex"), + .parent = TYPE_MACHINE, + .class_init = verdex_class_init, }; static void gumstix_machine_init(void) { - qemu_register_machine(&connex_machine); - qemu_register_machine(&verdex_machine); + type_register_static(&connex_type); + type_register_static(&verdex_type); } -machine_init(gumstix_machine_init); +type_init(gumstix_machine_init) diff --git a/qemu/hw/arm/highbank.c b/qemu/hw/arm/highbank.c index f8353a787..d9930c0d3 100644 --- a/qemu/hw/arm/highbank.c +++ b/qemu/hw/arm/highbank.c @@ -17,11 +17,14 @@ * */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/devices.h" #include "hw/loader.h" #include "net/net.h" +#include "sysemu/kvm.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "sysemu/block-backend.h" @@ -32,10 +35,19 @@ #define SMP_BOOT_REG 0x40 #define MPCORE_PERIPHBASE 0xfff10000 +#define MVBAR_ADDR 0x200 +#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t)) + #define NIRQ_GIC 160 /* Board init. */ +static void hb_write_board_setup(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR); +} + static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; @@ -223,52 +235,37 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) MemoryRegion *sysmem; char *sysboot_filename; - if (!cpu_model) { - switch (machine_id) { - case CALXEDA_HIGHBANK: - cpu_model = "cortex-a9"; - break; - case CALXEDA_MIDWAY: - cpu_model = "cortex-a15"; - break; - } + switch (machine_id) { + case CALXEDA_HIGHBANK: + cpu_model = "cortex-a9"; + break; + case CALXEDA_MIDWAY: + cpu_model = "cortex-a15"; + break; } for (n = 0; n < smp_cpus; n++) { ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); Object *cpuobj; ARMCPU *cpu; - Error *err = NULL; - - if (!oc) { - error_report("Unable to find CPU definition"); - exit(1); - } cpuobj = object_new(object_class_get_name(oc)); cpu = ARM_CPU(cpuobj); - /* By default A9 and A15 CPUs have EL3 enabled. This board does not - * currently support EL3 so the CPU EL3 property is disabled before - * realization. - */ - if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_SMC, + "psci-conduit", &error_abort); + + if (n) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(cpuobj, true, + "start-powered-off", &error_abort); } if (object_property_find(cpuobj, "reset-cbar", NULL)) { object_property_set_int(cpuobj, MPCORE_PERIPHBASE, "reset-cbar", &error_abort); } - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ); } @@ -281,17 +278,19 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) sysram = g_new(MemoryRegion, 1); memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000, - &error_abort); + &error_fatal); memory_region_add_subregion(sysmem, 0xfff88000, sysram); if (bios_name != NULL) { sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (sysboot_filename != NULL) { if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) { - hw_error("Unable to load %s\n", bios_name); + error_report("Unable to load %s", bios_name); + exit(1); } g_free(sysboot_filename); } else { - hw_error("Unable to find %s\n", bios_name); + error_report("Unable to find %s", bios_name); + exit(1); } } @@ -378,6 +377,16 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) highbank_binfo.loader_start = 0; highbank_binfo.write_secondary_boot = hb_write_secondary; highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; + if (!kvm_enabled()) { + highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR; + highbank_binfo.write_board_setup = hb_write_board_setup; + highbank_binfo.secure_board_setup = true; + } else { + error_report("WARNING: cannot load built-in Monitor support " + "if KVM is enabled. Some guests (such as Linux) " + "may not boot."); + } + arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); } @@ -391,26 +400,42 @@ static void midway_init(MachineState *machine) calxeda_init(machine, CALXEDA_MIDWAY); } -static QEMUMachine highbank_machine = { - .name = "highbank", - .desc = "Calxeda Highbank (ECX-1000)", - .init = highbank_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, +static void highbank_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Calxeda Highbank (ECX-1000)"; + mc->init = highbank_init; + mc->block_default_type = IF_SCSI; + mc->max_cpus = 4; +} + +static const TypeInfo highbank_type = { + .name = MACHINE_TYPE_NAME("highbank"), + .parent = TYPE_MACHINE, + .class_init = highbank_class_init, }; -static QEMUMachine midway_machine = { - .name = "midway", - .desc = "Calxeda Midway (ECX-2000)", - .init = midway_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, +static void midway_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Calxeda Midway (ECX-2000)"; + mc->init = midway_init; + mc->block_default_type = IF_SCSI; + mc->max_cpus = 4; +} + +static const TypeInfo midway_type = { + .name = MACHINE_TYPE_NAME("midway"), + .parent = TYPE_MACHINE, + .class_init = midway_class_init, }; static void calxeda_machines_init(void) { - qemu_register_machine(&highbank_machine); - qemu_register_machine(&midway_machine); + type_register_static(&highbank_type); + type_register_static(&midway_type); } -machine_init(calxeda_machines_init); +type_init(calxeda_machines_init) diff --git a/qemu/hw/arm/imx25_pdk.c b/qemu/hw/arm/imx25_pdk.c new file mode 100644 index 000000000..025b60843 --- /dev/null +++ b/qemu/hw/arm/imx25_pdk.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> + * + * PDK Board System emulation. + * + * Based on hw/arm/kzm.c + * + * Copyright (c) 2008 OKL and 2011 NICTA + * Written by Hans at OK-Labs + * Updated by Peter Chubb. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/fsl-imx25.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "exec/address-spaces.h" +#include "sysemu/qtest.h" +#include "hw/i2c/i2c.h" + +/* Memory map for PDK Emulation Baseboard: + * 0x00000000-0x7fffffff See i.MX25 SOC fr support + * 0x80000000-0x87ffffff RAM + Alias EMULATED + * 0x90000000-0x9fffffff RAM + Alias EMULATED + * 0xa0000000-0xa7ffffff Flash IGNORED + * 0xa8000000-0xafffffff Flash IGNORED + * 0xb0000000-0xb1ffffff SRAM IGNORED + * 0xb2000000-0xb3ffffff SRAM IGNORED + * 0xb4000000-0xb5ffffff CS4 IGNORED + * 0xb6000000-0xb8000fff Reserved IGNORED + * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED + * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED + * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED + * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED + * 0xb8005000-0xbaffffff Reserved IGNORED + * 0xbb000000-0xbb000fff NAND flash area buf IGNORED + * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED + * 0xbb001200-0xbb001dff Reserved IGNORED + * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED + * 0xbb012000-0xbfffffff Reserved IGNORED + * 0xc0000000-0xffffffff Reserved IGNORED + */ + +typedef struct IMX25PDK { + FslIMX25State soc; + MemoryRegion ram; + MemoryRegion ram_alias; +} IMX25PDK; + +static struct arm_boot_info imx25_pdk_binfo; + +static void imx25_pdk_init(MachineState *machine) +{ + IMX25PDK *s = g_new0(IMX25PDK, 1); + unsigned int ram_size; + unsigned int alias_offset; + int i; + + object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), + &error_abort); + + object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + + /* We need to initialize our memory */ + if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { + error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " + "reduced to %x", machine->ram_size, + FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE); + machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE; + } + + memory_region_allocate_system_memory(&s->ram, NULL, "imx25.ram", + machine->ram_size); + memory_region_add_subregion(get_system_memory(), FSL_IMX25_SDRAM0_ADDR, + &s->ram); + + /* initialize the alias memory if any */ + for (i = 0, ram_size = machine->ram_size, alias_offset = 0; + (i < 2) && ram_size; i++) { + unsigned int size; + static const struct { + hwaddr addr; + unsigned int size; + } ram[2] = { + { FSL_IMX25_SDRAM0_ADDR, FSL_IMX25_SDRAM0_SIZE }, + { FSL_IMX25_SDRAM1_ADDR, FSL_IMX25_SDRAM1_SIZE }, + }; + + size = MIN(ram_size, ram[i].size); + + ram_size -= size; + + if (size < ram[i].size) { + memory_region_init_alias(&s->ram_alias, NULL, "ram.alias", + &s->ram, alias_offset, ram[i].size - size); + memory_region_add_subregion(get_system_memory(), + ram[i].addr + size, &s->ram_alias); + } + + alias_offset += ram[i].size; + } + + imx25_pdk_binfo.ram_size = machine->ram_size; + imx25_pdk_binfo.kernel_filename = machine->kernel_filename; + imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline; + imx25_pdk_binfo.initrd_filename = machine->initrd_filename; + imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR; + imx25_pdk_binfo.board_id = 1771, + imx25_pdk_binfo.nb_cpus = 1; + + /* + * We test explicitly for qtest here as it is not done (yet?) in + * arm_load_kernel(). Without this the "make check" command would + * fail. + */ + if (!qtest_enabled()) { + arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo); + } else { + /* + * This I2C device doesn't exist on the real board. + * We add it here (only on qtest usage) to be able to do a bit + * of simple qtest. See "make check" for details. + */ + i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]), + "i2c"), + "ds1338", 0x68); + } +} + +static void imx25_pdk_machine_init(MachineClass *mc) +{ + mc->desc = "ARM i.MX25 PDK board (ARM926)"; + mc->init = imx25_pdk_init; +} + +DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init) diff --git a/qemu/hw/arm/integratorcp.c b/qemu/hw/arm/integratorcp.c index 0fbbf997e..e31bca6e7 100644 --- a/qemu/hw/arm/integratorcp.c +++ b/qemu/hw/arm/integratorcp.c @@ -7,6 +7,10 @@ * This code is licensed under the GPL */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/devices.h" #include "hw/boards.h" @@ -266,7 +270,7 @@ static int integratorcm_init(SysBusDevice *dev) s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->flash); memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s, @@ -533,7 +537,6 @@ static void integratorcp_init(MachineState *machine) qemu_irq pic[32]; DeviceState *dev, *sic, *icp; int i; - Error *err = NULL; if (!cpu_model) { cpu_model = "arm926"; @@ -552,18 +555,10 @@ static void integratorcp_init(MachineState *machine) * realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); cpu = ARM_CPU(cpuobj); @@ -619,18 +614,13 @@ static void integratorcp_init(MachineState *machine) arm_load_kernel(cpu, &integrator_binfo); } -static QEMUMachine integratorcp_machine = { - .name = "integratorcp", - .desc = "ARM Integrator/CP (ARM926EJ-S)", - .init = integratorcp_init, -}; - -static void integratorcp_machine_init(void) +static void integratorcp_machine_init(MachineClass *mc) { - qemu_register_machine(&integratorcp_machine); + mc->desc = "ARM Integrator/CP (ARM926EJ-S)"; + mc->init = integratorcp_init; } -machine_init(integratorcp_machine_init); +DEFINE_MACHINE("integratorcp", integratorcp_machine_init) static Property core_properties[] = { DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), diff --git a/qemu/hw/arm/kzm.c b/qemu/hw/arm/kzm.c index 5be0369a5..2c96ee33b 100644 --- a/qemu/hw/arm/kzm.c +++ b/qemu/hw/arm/kzm.c @@ -13,141 +13,135 @@ * i.MX31 SoC */ -#include "hw/sysbus.h" +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/fsl-imx31.h" +#include "hw/boards.h" +#include "qemu/error-report.h" #include "exec/address-spaces.h" -#include "hw/hw.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" #include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" +#include "hw/devices.h" #include "hw/char/serial.h" -#include "hw/arm/imx.h" - - /* Memory map for Kzm Emulation Baseboard: - * 0x00000000-0x00003fff 16k secure ROM IGNORED - * 0x00004000-0x00407fff Reserved IGNORED - * 0x00404000-0x00407fff ROM IGNORED - * 0x00408000-0x0fffffff Reserved IGNORED - * 0x10000000-0x1fffbfff RAM aliasing IGNORED - * 0x1fffc000-0x1fffffff RAM EMULATED - * 0x20000000-0x2fffffff Reserved IGNORED - * 0x30000000-0x7fffffff I.MX31 Internal Register Space - * 0x43f00000 IO_AREA0 - * 0x43f90000 UART1 EMULATED - * 0x43f94000 UART2 EMULATED - * 0x68000000 AVIC EMULATED - * 0x53f80000 CCM EMULATED - * 0x53f94000 PIT 1 EMULATED - * 0x53f98000 PIT 2 EMULATED - * 0x53f90000 GPT EMULATED - * 0x80000000-0x87ffffff RAM EMULATED - * 0x88000000-0x8fffffff RAM Aliasing EMULATED - * 0xa0000000-0xafffffff NAND Flash IGNORED - * 0xb0000000-0xb3ffffff Unavailable IGNORED - * 0xb4000000-0xb4000fff 8-bit free space IGNORED - * 0xb4001000-0xb400100f Board control IGNORED - * 0xb4001003 DIP switch - * 0xb4001010-0xb400101f 7-segment LED IGNORED - * 0xb4001020-0xb400102f LED IGNORED - * 0xb4001030-0xb400103f LED IGNORED - * 0xb4001040-0xb400104f FPGA, UART EMULATED - * 0xb4001050-0xb400105f FPGA, UART EMULATED - * 0xb4001060-0xb40fffff FPGA IGNORED - * 0xb6000000-0xb61fffff LAN controller EMULATED - * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED - * 0xb6300000-0xb7ffffff Free IGNORED - * 0xb8000000-0xb8004fff Memory control registers IGNORED - * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED - * 0xc4000000-0xffffffff Reserved IGNORED - */ - -#define KZM_RAMADDRESS (0x80000000) -#define KZM_FPGA (0xb4001040) +#include "sysemu/qtest.h" + +/* Memory map for Kzm Emulation Baseboard: + * 0x00000000-0x7fffffff See i.MX31 SOC for support + * 0x80000000-0x8fffffff RAM EMULATED + * 0x90000000-0x9fffffff RAM EMULATED + * 0xa0000000-0xafffffff Flash IGNORED + * 0xb0000000-0xb3ffffff Unavailable IGNORED + * 0xb4000000-0xb4000fff 8-bit free space IGNORED + * 0xb4001000-0xb400100f Board control IGNORED + * 0xb4001003 DIP switch + * 0xb4001010-0xb400101f 7-segment LED IGNORED + * 0xb4001020-0xb400102f LED IGNORED + * 0xb4001030-0xb400103f LED IGNORED + * 0xb4001040-0xb400104f FPGA, UART EMULATED + * 0xb4001050-0xb400105f FPGA, UART EMULATED + * 0xb4001060-0xb40fffff FPGA IGNORED + * 0xb6000000-0xb61fffff LAN controller EMULATED + * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED + * 0xb6300000-0xb7ffffff Free IGNORED + * 0xb8000000-0xb8004fff Memory control registers IGNORED + * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED + * 0xc4000000-0xffffffff Reserved IGNORED + */ + +typedef struct IMX31KZM { + FslIMX31State soc; + MemoryRegion ram; + MemoryRegion ram_alias; +} IMX31KZM; + +#define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR) +#define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040) +#define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR) static struct arm_boot_info kzm_binfo = { - .loader_start = KZM_RAMADDRESS, + .loader_start = KZM_RAM_ADDR, .board_id = 1722, }; static void kzm_init(MachineState *machine) { - ram_addr_t ram_size = machine->ram_size; - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - DeviceState *dev; - DeviceState *ccm; - - if (!cpu_model) { - cpu_model = "arm1136"; + IMX31KZM *s = g_new0(IMX31KZM, 1); + unsigned int ram_size; + unsigned int alias_offset; + unsigned int i; + + object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), + &error_abort); + + object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + + /* Check the amount of memory is compatible with the SOC */ + if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) { + error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " + "reduced to %x", machine->ram_size, + FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE); + machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE; } - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); + memory_region_allocate_system_memory(&s->ram, NULL, "kzm.ram", + machine->ram_size); + memory_region_add_subregion(get_system_memory(), FSL_IMX31_SDRAM0_ADDR, + &s->ram); + + /* initialize the alias memory if any */ + for (i = 0, ram_size = machine->ram_size, alias_offset = 0; + (i < 2) && ram_size; i++) { + unsigned int size; + static const struct { + hwaddr addr; + unsigned int size; + } ram[2] = { + { FSL_IMX31_SDRAM0_ADDR, FSL_IMX31_SDRAM0_SIZE }, + { FSL_IMX31_SDRAM1_ADDR, FSL_IMX31_SDRAM1_SIZE }, + }; + + size = MIN(ram_size, ram[i].size); + + ram_size -= size; + + if (size < ram[i].size) { + memory_region_init_alias(&s->ram_alias, NULL, "ram.alias", + &s->ram, alias_offset, ram[i].size - size); + memory_region_add_subregion(get_system_memory(), + ram[i].addr + size, &s->ram_alias); + } + + alias_offset += ram[i].size; } - /* On a real system, the first 16k is a `secure boot rom' */ - - memory_region_allocate_system_memory(ram, NULL, "kzm.ram", ram_size); - memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram); - - memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size); - memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias); - - memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort); - memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram); - - dev = sysbus_create_varargs("imx_avic", 0x68000000, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), - NULL); - - imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45)); - imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32)); - - ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL); - - imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm); - imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm); - imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm); - if (nd_table[0].used) { - lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52)); + lan9118_init(&nd_table[0], KZM_LAN9118_ADDR, + qdev_get_gpio_in(DEVICE(&s->soc.avic), 52)); } if (serial_hds[2]) { /* touchscreen */ - serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0, - qdev_get_gpio_in(dev, 52), - 14745600, serial_hds[2], - DEVICE_NATIVE_ENDIAN); + serial_mm_init(get_system_memory(), KZM_FPGA_ADDR+0x10, 0, + qdev_get_gpio_in(DEVICE(&s->soc.avic), 52), + 14745600, serial_hds[2], DEVICE_NATIVE_ENDIAN); } - kzm_binfo.ram_size = ram_size; - kzm_binfo.kernel_filename = kernel_filename; - kzm_binfo.kernel_cmdline = kernel_cmdline; - kzm_binfo.initrd_filename = initrd_filename; + kzm_binfo.ram_size = machine->ram_size; + kzm_binfo.kernel_filename = machine->kernel_filename; + kzm_binfo.kernel_cmdline = machine->kernel_cmdline; + kzm_binfo.initrd_filename = machine->initrd_filename; kzm_binfo.nb_cpus = 1; - arm_load_kernel(cpu, &kzm_binfo); -} -static QEMUMachine kzm_machine = { - .name = "kzm", - .desc = "ARM KZM Emulation Baseboard (ARM1136)", - .init = kzm_init, -}; + if (!qtest_enabled()) { + arm_load_kernel(&s->soc.cpu, &kzm_binfo); + } +} -static void kzm_machine_init(void) +static void kzm_machine_init(MachineClass *mc) { - qemu_register_machine(&kzm_machine); + mc->desc = "ARM KZM Emulation Baseboard (ARM1136)"; + mc->init = kzm_init; } -machine_init(kzm_machine_init) +DEFINE_MACHINE("kzm", kzm_machine_init) diff --git a/qemu/hw/arm/mainstone.c b/qemu/hw/arm/mainstone.c index 0da02a67e..454acc5d2 100644 --- a/qemu/hw/arm/mainstone.c +++ b/qemu/hw/arm/mainstone.c @@ -11,6 +11,8 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/arm/arm.h" @@ -124,7 +126,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, /* Setup CPU & memory */ mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM, - &error_abort); + &error_fatal); vmstate_register_ram_global(rom); memory_region_set_readonly(rom, true); memory_region_add_subregion(address_space_mem, 0, rom); @@ -188,15 +190,10 @@ static void mainstone_init(MachineState *machine) mainstone_common_init(get_system_memory(), machine, mainstone, 0x196); } -static QEMUMachine mainstone2_machine = { - .name = "mainstone", - .desc = "Mainstone II (PXA27x)", - .init = mainstone_init, -}; - -static void mainstone_machine_init(void) +static void mainstone2_machine_init(MachineClass *mc) { - qemu_register_machine(&mainstone2_machine); + mc->desc = "Mainstone II (PXA27x)"; + mc->init = mainstone_init; } -machine_init(mainstone_machine_init); +DEFINE_MACHINE("mainstone", mainstone2_machine_init) diff --git a/qemu/hw/arm/musicpal.c b/qemu/hw/arm/musicpal.c index 42f66b33e..7a4cc07dd 100644 --- a/qemu/hw/arm/musicpal.c +++ b/qemu/hw/arm/musicpal.c @@ -9,6 +9,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/devices.h" @@ -1599,7 +1603,7 @@ static void musicpal_init(MachineState *machine) memory_region_add_subregion(address_space_mem, 0, ram); memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE, - &error_abort); + &error_fatal); vmstate_register_ram_global(sram); memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); @@ -1709,18 +1713,13 @@ static void musicpal_init(MachineState *machine) arm_load_kernel(cpu, &musicpal_binfo); } -static QEMUMachine musicpal_machine = { - .name = "musicpal", - .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)", - .init = musicpal_init, -}; - -static void musicpal_machine_init(void) +static void musicpal_machine_init(MachineClass *mc) { - qemu_register_machine(&musicpal_machine); + mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)"; + mc->init = musicpal_init; } -machine_init(musicpal_machine_init); +DEFINE_MACHINE("musicpal", musicpal_machine_init) static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) { diff --git a/qemu/hw/arm/netduino2.c b/qemu/hw/arm/netduino2.c index 8f26780ef..23d792837 100644 --- a/qemu/hw/arm/netduino2.c +++ b/qemu/hw/arm/netduino2.c @@ -22,6 +22,8 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/boards.h" #include "qemu/error-report.h" #include "hw/arm/stm32f205_soc.h" @@ -29,29 +31,19 @@ static void netduino2_init(MachineState *machine) { DeviceState *dev; - Error *err = NULL; dev = qdev_create(NULL, TYPE_STM32F205_SOC); if (machine->kernel_filename) { qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename); } qdev_prop_set_string(dev, "cpu-model", "cortex-m3"); - object_property_set_bool(OBJECT(dev), true, "realized", &err); - if (err != NULL) { - error_report("%s", error_get_pretty(err)); - exit(1); - } + object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal); } -static QEMUMachine netduino2_machine = { - .name = "netduino2", - .desc = "Netduino 2 Machine", - .init = netduino2_init, -}; - -static void netduino2_machine_init(void) +static void netduino2_machine_init(MachineClass *mc) { - qemu_register_machine(&netduino2_machine); + mc->desc = "Netduino 2 Machine"; + mc->init = netduino2_init; } -machine_init(netduino2_machine_init); +DEFINE_MACHINE("netduino2", netduino2_machine_init) diff --git a/qemu/hw/arm/nseries.c b/qemu/hw/arm/nseries.c index a659e8525..538250555 100644 --- a/qemu/hw/arm/nseries.c +++ b/qemu/hw/arm/nseries.c @@ -18,7 +18,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "qemu-common.h" +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/cutils.h" #include "sysemu/sysemu.h" #include "hw/arm/omap.h" #include "hw/arm/arm.h" @@ -172,8 +174,8 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_int32(s->nand, "shift", 1); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { - qdev_prop_set_drive_nofail(s->nand, "drive", - blk_by_legacy_dinfo(dinfo)); + qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_init_nofail(s->nand); sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, @@ -1275,7 +1277,7 @@ static int n8x0_atag_setup(void *p, int model) strcpy((void *) w, "hw-build"); /* char component[12] */ w += 6; strcpy((void *) w, "QEMU "); - pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */ + pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */ w += 6; tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; @@ -1413,24 +1415,40 @@ static void n810_init(MachineState *machine) n8x0_init(machine, &n810_binfo, 810); } -static QEMUMachine n800_machine = { - .name = "n800", - .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", - .init = n800_init, - .default_boot_order = "", +static void n800_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)"; + mc->init = n800_init; + mc->default_boot_order = ""; +} + +static const TypeInfo n800_type = { + .name = MACHINE_TYPE_NAME("n800"), + .parent = TYPE_MACHINE, + .class_init = n800_class_init, }; -static QEMUMachine n810_machine = { - .name = "n810", - .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", - .init = n810_init, - .default_boot_order = "", +static void n810_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)"; + mc->init = n810_init; + mc->default_boot_order = ""; +} + +static const TypeInfo n810_type = { + .name = MACHINE_TYPE_NAME("n810"), + .parent = TYPE_MACHINE, + .class_init = n810_class_init, }; static void nseries_machine_init(void) { - qemu_register_machine(&n800_machine); - qemu_register_machine(&n810_machine); + type_register_static(&n800_type); + type_register_static(&n810_type); } -machine_init(nseries_machine_init); +type_init(nseries_machine_init) diff --git a/qemu/hw/arm/omap1.c b/qemu/hw/arm/omap1.c index de2b28925..b3cf0ec69 100644 --- a/qemu/hw/arm/omap1.c +++ b/qemu/hw/arm/omap1.c @@ -17,6 +17,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/boards.h" #include "hw/hw.h" #include "hw/arm/arm.h" @@ -27,6 +31,8 @@ #include "sysemu/blockdev.h" #include "qemu/range.h" #include "hw/sysbus.h" +#include "qemu/cutils.h" +#include "qemu/bcd.h" /* Should signal the TCMI/GPMC */ uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) @@ -106,7 +112,7 @@ static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) if (timer->st && timer->enable && timer->rate) return timer->val - muldiv64(distance >> (timer->ptv + 1), - timer->rate, get_ticks_per_sec()); + timer->rate, NANOSECONDS_PER_SECOND); else return timer->val; } @@ -124,7 +130,7 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) if (timer->enable && timer->st && timer->rate) { timer->val = timer->reset_val; /* Should skip this on clk enable */ expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), - get_ticks_per_sec(), timer->rate); + NANOSECONDS_PER_SECOND, timer->rate); /* If timer expiry would be sooner than in about 1 ms and * auto-reload isn't set, then fire immediately. This is a hack @@ -132,10 +138,11 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) * sets the interval to a very low value and polls the status bit * in a busy loop when it wants to sleep just a couple of CPU * ticks. */ - if (expires > (get_ticks_per_sec() >> 10) || timer->ar) + if (expires > (NANOSECONDS_PER_SECOND >> 10) || timer->ar) { timer_mod(timer->timer, timer->time + expires); - else + } else { qemu_bh_schedule(timer->tick); + } } else timer_del(timer->timer); } @@ -258,8 +265,7 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, hwaddr base, qemu_irq irq, omap_clk clk) { - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) - g_malloc0(sizeof(struct omap_mpu_timer_s)); + struct omap_mpu_timer_s *s = g_new0(struct omap_mpu_timer_s, 1); s->irq = irq; s->clk = clk; @@ -388,8 +394,7 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, hwaddr base, qemu_irq irq, omap_clk clk) { - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) - g_malloc0(sizeof(struct omap_watchdog_timer_s)); + struct omap_watchdog_timer_s *s = g_new0(struct omap_watchdog_timer_s, 1); s->timer.irq = irq; s->timer.clk = clk; @@ -495,8 +500,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, hwaddr base, qemu_irq irq, omap_clk clk) { - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) - g_malloc0(sizeof(struct omap_32khz_timer_s)); + struct omap_32khz_timer_s *s = g_new0(struct omap_32khz_timer_s, 1); s->timer.irq = irq; s->timer.clk = clk; @@ -615,14 +619,14 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, now -= s->ulpd_gauge_start; /* 32-kHz ticks */ - ticks = muldiv64(now, 32768, get_ticks_per_sec()); + ticks = muldiv64(now, 32768, NANOSECONDS_PER_SECOND); s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; if (ticks >> 32) /* OVERFLOW_32K */ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; /* High frequency ticks */ - ticks = muldiv64(now, 12000000, get_ticks_per_sec()); + ticks = muldiv64(now, 12000000, NANOSECONDS_PER_SECOND); s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; if (ticks >> 32) /* OVERFLOW_HI_FREQ */ @@ -1236,8 +1240,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init( MemoryRegion *memory, hwaddr base, qemu_irq abort_irq, omap_clk clk) { - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) - g_malloc0(sizeof(struct omap_tipb_bridge_s)); + struct omap_tipb_bridge_s *s = g_new0(struct omap_tipb_bridge_s, 1); s->abort = abort_irq; omap_tipb_bridge_reset(s); @@ -2099,8 +2102,7 @@ static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, omap_clk clk) { - struct omap_mpuio_s *s = (struct omap_mpuio_s *) - g_malloc0(sizeof(struct omap_mpuio_s)); + struct omap_mpuio_s *s = g_new0(struct omap_mpuio_s, 1); s->irq = gpio_int; s->kbd_irq = kbd_int; @@ -2292,8 +2294,7 @@ static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, qemu_irq dma, omap_clk clk) { - struct omap_uwire_s *s = (struct omap_uwire_s *) - g_malloc0(sizeof(struct omap_uwire_s)); + struct omap_uwire_s *s = g_new0(struct omap_uwire_s, 1); s->txirq = txirq; s->rxirq = rxirq; @@ -2932,8 +2933,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, qemu_irq timerirq, qemu_irq alarmirq, omap_clk clk) { - struct omap_rtc_s *s = (struct omap_rtc_s *) - g_malloc0(sizeof(struct omap_rtc_s)); + struct omap_rtc_s *s = g_new0(struct omap_rtc_s, 1); s->irq = timerirq; s->alarm = alarmirq; @@ -3032,7 +3032,7 @@ static void omap_mcbsp_source_tick(void *opaque) omap_mcbsp_rx_newdata(s); timer_mod(s->source_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - get_ticks_per_sec()); + NANOSECONDS_PER_SECOND); } static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) @@ -3078,7 +3078,7 @@ static void omap_mcbsp_sink_tick(void *opaque) omap_mcbsp_tx_newdata(s); timer_mod(s->sink_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - get_ticks_per_sec()); + NANOSECONDS_PER_SECOND); } static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) @@ -3468,8 +3468,7 @@ static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, qemu_irq txirq, qemu_irq rxirq, qemu_irq *dma, omap_clk clk) { - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) - g_malloc0(sizeof(struct omap_mcbsp_s)); + struct omap_mcbsp_s *s = g_new0(struct omap_mcbsp_s, 1); s->txirq = txirq; s->rxirq = rxirq; @@ -3648,8 +3647,7 @@ static void omap_lpg_clk_update(void *opaque, int line, int on) static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, hwaddr base, omap_clk clk) { - struct omap_lpg_s *s = (struct omap_lpg_s *) - g_malloc0(sizeof(struct omap_lpg_s)); + struct omap_lpg_s *s = g_new0(struct omap_lpg_s, 1); s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s); @@ -3853,8 +3851,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, const char *core) { int i; - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) - g_malloc0(sizeof(struct omap_mpu_state_s)); + struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1); qemu_irq dma_irqs[6]; DriveInfo *dinfo; SysBusDevice *busdev; @@ -3882,7 +3879,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, s->sdram_size); memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->imif_ram); memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); diff --git a/qemu/hw/arm/omap2.c b/qemu/hw/arm/omap2.c index e39b31729..3a0d77714 100644 --- a/qemu/hw/arm/omap2.c +++ b/qemu/hw/arm/omap2.c @@ -18,6 +18,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/boards.h" @@ -596,8 +600,7 @@ static const MemoryRegionOps omap_eac_ops = { static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) { - struct omap_eac_s *s = (struct omap_eac_s *) - g_malloc0(sizeof(struct omap_eac_s)); + struct omap_eac_s *s = g_new0(struct omap_eac_s, 1); s->irq = irq; s->codec.rxdrq = *drq ++; @@ -788,8 +791,7 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, hwaddr channel_base, qemu_irq irq, omap_clk clk, CharDriverState *chr) { - struct omap_sti_s *s = (struct omap_sti_s *) - g_malloc0(sizeof(struct omap_sti_s)); + struct omap_sti_s *s = g_new0(struct omap_sti_s, 1); s->irq = irq; omap_sti_reset(s); @@ -1806,8 +1808,7 @@ static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, struct omap_mpu_state_s *mpu) { - struct omap_prcm_s *s = (struct omap_prcm_s *) - g_malloc0(sizeof(struct omap_prcm_s)); + struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1); s->irq[0] = mpu_int; s->irq[1] = dsp_int; @@ -2185,8 +2186,7 @@ static void omap_sysctl_reset(struct omap_sysctl_s *s) static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, omap_clk iclk, struct omap_mpu_state_s *mpu) { - struct omap_sysctl_s *s = (struct omap_sysctl_s *) - g_malloc0(sizeof(struct omap_sysctl_s)); + struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1); s->mpu = mpu; omap_sysctl_reset(s); @@ -2248,8 +2248,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, unsigned long sdram_size, const char *core) { - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) - g_malloc0(sizeof(struct omap_mpu_state_s)); + struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1); qemu_irq dma_irqs[4]; DriveInfo *dinfo; int i; @@ -2276,7 +2275,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->sdram_size); memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram); memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->sram); memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram); diff --git a/qemu/hw/arm/omap_sx1.c b/qemu/hw/arm/omap_sx1.c index 4b0f7f9c4..5d74026cb 100644 --- a/qemu/hw/arm/omap_sx1.c +++ b/qemu/hw/arm/omap_sx1.c @@ -25,6 +25,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/arm/omap.h" @@ -122,7 +124,7 @@ static void sx1_init(MachineState *machine, const int version) /* External Flash (EMIFS) */ memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(flash); memory_region_set_readonly(flash, true); memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash); @@ -166,7 +168,7 @@ static void sx1_init(MachineState *machine, const int version) (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { MemoryRegion *flash_1 = g_new(MemoryRegion, 1); memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(flash_1); memory_region_set_readonly(flash_1, true); memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1); @@ -217,22 +219,38 @@ static void sx1_init_v2(MachineState *machine) sx1_init(machine, 2); } -static QEMUMachine sx1_machine_v2 = { - .name = "sx1", - .desc = "Siemens SX1 (OMAP310) V2", - .init = sx1_init_v2, +static void sx1_machine_v2_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Siemens SX1 (OMAP310) V2"; + mc->init = sx1_init_v2; +} + +static const TypeInfo sx1_machine_v2_type = { + .name = MACHINE_TYPE_NAME("sx1"), + .parent = TYPE_MACHINE, + .class_init = sx1_machine_v2_class_init, }; -static QEMUMachine sx1_machine_v1 = { - .name = "sx1-v1", - .desc = "Siemens SX1 (OMAP310) V1", - .init = sx1_init_v1, +static void sx1_machine_v1_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Siemens SX1 (OMAP310) V1"; + mc->init = sx1_init_v1; +} + +static const TypeInfo sx1_machine_v1_type = { + .name = MACHINE_TYPE_NAME("sx1-v1"), + .parent = TYPE_MACHINE, + .class_init = sx1_machine_v1_class_init, }; static void sx1_machine_init(void) { - qemu_register_machine(&sx1_machine_v2); - qemu_register_machine(&sx1_machine_v1); + type_register_static(&sx1_machine_v1_type); + type_register_static(&sx1_machine_v2_type); } -machine_init(sx1_machine_init); +type_init(sx1_machine_init) diff --git a/qemu/hw/arm/palm.c b/qemu/hw/arm/palm.c index 7f1cfb8f6..7f460732e 100644 --- a/qemu/hw/arm/palm.c +++ b/qemu/hw/arm/palm.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "audio/audio.h" #include "sysemu/sysemu.h" @@ -213,7 +215,7 @@ static void palmte_init(MachineState *machine) /* External Flash (EMIFS) */ memory_region_init_ram(flash, NULL, "palmte.flash", flash_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(flash); memory_region_set_readonly(flash, true); memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash); @@ -269,15 +271,10 @@ static void palmte_init(MachineState *machine) arm_load_kernel(mpu->cpu, &palmte_binfo); } -static QEMUMachine palmte_machine = { - .name = "cheetah", - .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", - .init = palmte_init, -}; - -static void palmte_machine_init(void) +static void palmte_machine_init(MachineClass *mc) { - qemu_register_machine(&palmte_machine); + mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)"; + mc->init = palmte_init; } -machine_init(palmte_machine_init); +DEFINE_MACHINE("cheetah", palmte_machine_init) diff --git a/qemu/hw/arm/palmetto-bmc.c b/qemu/hw/arm/palmetto-bmc.c new file mode 100644 index 000000000..89ebd92b9 --- /dev/null +++ b/qemu/hw/arm/palmetto-bmc.c @@ -0,0 +1,68 @@ +/* + * OpenPOWER Palmetto BMC + * + * Andrew Jeffery <andrew@aj.id.au> + * + * Copyright 2016 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 "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/arm/arm.h" +#include "hw/arm/ast2400.h" +#include "hw/boards.h" + +static struct arm_boot_info palmetto_bmc_binfo = { + .loader_start = AST2400_SDRAM_BASE, + .board_id = 0, + .nb_cpus = 1, +}; + +typedef struct PalmettoBMCState { + AST2400State soc; + MemoryRegion ram; +} PalmettoBMCState; + +static void palmetto_bmc_init(MachineState *machine) +{ + PalmettoBMCState *bmc; + + bmc = g_new0(PalmettoBMCState, 1); + object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), + &error_abort); + + memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); + memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE, + &bmc->ram); + object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), + &error_abort); + object_property_set_bool(OBJECT(&bmc->soc), true, "realized", + &error_abort); + + palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; + palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; + palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; + palmetto_bmc_binfo.ram_size = ram_size; + arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo); +} + +static void palmetto_bmc_machine_init(MachineClass *mc) +{ + mc->desc = "OpenPOWER Palmetto BMC"; + mc->init = palmetto_bmc_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_sdcard = 1; + mc->no_parallel = 1; +} + +DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init); diff --git a/qemu/hw/arm/pxa2xx.c b/qemu/hw/arm/pxa2xx.c index ec353f79c..1a8c36033 100644 --- a/qemu/hw/arm/pxa2xx.c +++ b/qemu/hw/arm/pxa2xx.c @@ -7,15 +7,20 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/pxa.h" #include "sysemu/sysemu.h" #include "hw/char/serial.h" #include "hw/i2c/i2c.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" #include "sysemu/char.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" +#include "qemu/cutils.h" static struct { hwaddr io_base; @@ -1731,8 +1736,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) { - PXA2xxI2SState *s = (PXA2xxI2SState *) - g_malloc0(sizeof(PXA2xxI2SState)); + PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1); s->irq = irq; s->rx_dma = rx_dma; @@ -1959,7 +1963,7 @@ static void pxa2xx_fir_instance_init(Object *obj) PXA2xxFIrState *s = PXA2XX_FIR(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, + memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); @@ -2061,7 +2065,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, PXA2xxState *s; int i; DriveInfo *dinfo; - s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); + s = g_new0(PXA2xxState, 1); if (revision && strncmp(revision, "pxa27", 5)) { fprintf(stderr, "Machine requires a PXA27x processor.\n"); @@ -2079,11 +2083,11 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, /* SDRAM & Internal Memory Storage */ memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->internal); memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); @@ -2157,7 +2161,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); - s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); + s->ssp = g_new0(SSIBus *, i); for (i = 0; pxa27x_ssp[i].io_base; i ++) { DeviceState *dev; dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base, @@ -2202,7 +2206,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) int i; DriveInfo *dinfo; - s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); + s = g_new0(PXA2xxState, 1); s->cpu = cpu_arm_init("pxa255"); if (s->cpu == NULL) { @@ -2213,11 +2217,11 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) /* SDRAM & Internal Memory Storage */ memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); memory_region_init_ram(&s->internal, NULL, "pxa255.internal", - PXA2XX_INTERNAL_SIZE, &error_abort); + PXA2XX_INTERNAL_SIZE, &error_fatal); vmstate_register_ram_global(&s->internal); memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); @@ -2290,7 +2294,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa255_ssp[i].io_base; i ++); - s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i); + s->ssp = g_new0(SSIBus *, i); for (i = 0; pxa255_ssp[i].io_base; i ++) { DeviceState *dev; dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base, diff --git a/qemu/hw/arm/pxa2xx_gpio.c b/qemu/hw/arm/pxa2xx_gpio.c index c89c8045c..67e7e7094 100644 --- a/qemu/hw/arm/pxa2xx_gpio.c +++ b/qemu/hw/arm/pxa2xx_gpio.c @@ -7,6 +7,7 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/arm/pxa.h" diff --git a/qemu/hw/arm/pxa2xx_pic.c b/qemu/hw/arm/pxa2xx_pic.c index d41ac9341..7e51532cd 100644 --- a/qemu/hw/arm/pxa2xx_pic.c +++ b/qemu/hw/arm/pxa2xx_pic.c @@ -8,6 +8,9 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/sysbus.h" diff --git a/qemu/hw/arm/raspi.c b/qemu/hw/arm/raspi.c new file mode 100644 index 000000000..2b295f14c --- /dev/null +++ b/qemu/hw/arm/raspi.c @@ -0,0 +1,172 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous + * + * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft + * Written by Andrew Baumann + * + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/arm/bcm2836.h" +#include "qemu/error-report.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/arm/arm.h" +#include "sysemu/sysemu.h" + +#define SMPBOOT_ADDR 0x300 /* this should leave enough space for ATAGS */ +#define MVBAR_ADDR 0x400 /* secure vectors */ +#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */ +#define FIRMWARE_ADDR 0x8000 /* Pi loads kernel.img here by default */ + +/* Table of Linux board IDs for different Pi versions */ +static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43}; + +typedef struct RasPiState { + BCM2836State soc; + MemoryRegion ram; +} RasPiState; + +static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) +{ + static const uint32_t smpboot[] = { + 0xe1a0e00f, /* mov lr, pc */ + 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */ + 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */ + 0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */ + 0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */ + 0xe320f001, /* 1: yield */ + 0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/ + 0xe3530000, /* cmp r3, #0 ;spin while zero */ + 0x0afffffb, /* beq 1b */ + 0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */ + 0xe12fff13, /* bx r3 ;jump to target */ + 0x400000cc, /* (constant: mailbox 3 read/clear base) */ + }; + + /* check that we don't overrun board setup vectors */ + QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR); + /* check that board setup address is correctly relocated */ + QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0 + || (BOARDSETUP_ADDR >> 4) >= 0x100); + + rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) +{ + arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR); +} + +static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) +{ + CPUState *cs = CPU(cpu); + cpu_set_pc(cs, info->smp_loader_start); +} + +static void setup_boot(MachineState *machine, int version, size_t ram_size) +{ + static struct arm_boot_info binfo; + int r; + + binfo.board_id = raspi_boardid[version]; + binfo.ram_size = ram_size; + binfo.nb_cpus = smp_cpus; + binfo.board_setup_addr = BOARDSETUP_ADDR; + binfo.write_board_setup = write_board_setup; + binfo.secure_board_setup = true; + binfo.secure_boot = true; + + /* Pi2 requires SMP setup */ + if (version == 2) { + binfo.smp_loader_start = SMPBOOT_ADDR; + binfo.write_secondary_boot = write_smpboot; + binfo.secondary_cpu_reset_hook = reset_secondary; + } + + /* If the user specified a "firmware" image (e.g. UEFI), we bypass + * the normal Linux boot process + */ + if (machine->firmware) { + /* load the firmware image (typically kernel.img) */ + r = load_image_targphys(machine->firmware, FIRMWARE_ADDR, + ram_size - FIRMWARE_ADDR); + if (r < 0) { + error_report("Failed to load firmware from %s", machine->firmware); + exit(1); + } + + binfo.entry = FIRMWARE_ADDR; + binfo.firmware_loaded = true; + } else { + binfo.kernel_filename = machine->kernel_filename; + binfo.kernel_cmdline = machine->kernel_cmdline; + binfo.initrd_filename = machine->initrd_filename; + } + + arm_load_kernel(ARM_CPU(first_cpu), &binfo); +} + +static void raspi2_init(MachineState *machine) +{ + RasPiState *s = g_new0(RasPiState, 1); + uint32_t vcram_size; + DriveInfo *di; + BlockBackend *blk; + BusState *bus; + DeviceState *carddev; + + object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), + &error_abort); + + /* Allocate and map RAM */ + memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram", + machine->ram_size); + /* FIXME: Remove when we have custom CPU address space support */ + memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0); + + /* Setup the SOC */ + object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram), + &error_abort); + object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus", + &error_abort); + object_property_set_int(OBJECT(&s->soc), 0xa21041, "board-rev", + &error_abort); + object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); + + /* Create and plug in the SD cards */ + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus"); + if (bus == NULL) { + error_report("No SD bus found in SOC object"); + exit(1); + } + carddev = qdev_create(bus, TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + + vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size", + &error_abort); + setup_boot(machine, 2, machine->ram_size - vcram_size); +} + +static void raspi2_machine_init(MachineClass *mc) +{ + mc->desc = "Raspberry Pi 2"; + mc->init = raspi2_init; + mc->block_default_type = IF_SD; + mc->no_parallel = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->max_cpus = BCM2836_NCPUS; + mc->default_ram_size = 1024 * 1024 * 1024; +}; +DEFINE_MACHINE("raspi2", raspi2_machine_init) diff --git a/qemu/hw/arm/realview.c b/qemu/hw/arm/realview.c index ef2788d3e..3222b360e 100644 --- a/qemu/hw/arm/realview.c +++ b/qemu/hw/arm/realview.c @@ -7,6 +7,10 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/arm/primecell.h" @@ -99,33 +103,21 @@ static void realview_init(MachineState *machine, for (n = 0; n < smp_cpus; n++) { Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - Error *err = NULL; /* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board * does not currently support EL3 so the CPU EL3 property is disabled * before realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } if (is_pb && is_mpcore) { - object_property_set_int(cpuobj, periphbase, "reset-cbar", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_int(cpuobj, periphbase, "reset-cbar", + &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ); } @@ -151,13 +143,13 @@ static void realview_init(MachineState *machine, low_ram_size = ram_size - 0x20000000; ram_size = 0x20000000; memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(ram_lo); memory_region_add_subregion(sysmem, 0x20000000, ram_lo); } memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(ram_hi); low_ram_size = ram_size; if (low_ram_size > 0x10000000) @@ -353,7 +345,7 @@ static void realview_init(MachineState *machine, BootROM happens to be in ROM/flash or in memory that isn't clobbered until after Linux boots the secondary CPUs. */ memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000, - &error_abort); + &error_fatal); vmstate_register_ram_global(ram_hack); memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); @@ -399,41 +391,73 @@ static void realview_pbx_a9_init(MachineState *machine) realview_init(machine, BOARD_PBX_A9); } -static QEMUMachine realview_eb_machine = { - .name = "realview-eb", - .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", - .init = realview_eb_init, - .block_default_type = IF_SCSI, +static void realview_eb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)"; + mc->init = realview_eb_init; + mc->block_default_type = IF_SCSI; +} + +static const TypeInfo realview_eb_type = { + .name = MACHINE_TYPE_NAME("realview-eb"), + .parent = TYPE_MACHINE, + .class_init = realview_eb_class_init, }; -static QEMUMachine realview_eb_mpcore_machine = { - .name = "realview-eb-mpcore", - .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)", - .init = realview_eb_mpcore_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, +static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM RealView Emulation Baseboard (ARM11MPCore)"; + mc->init = realview_eb_mpcore_init; + mc->block_default_type = IF_SCSI; + mc->max_cpus = 4; +} + +static const TypeInfo realview_eb_mpcore_type = { + .name = MACHINE_TYPE_NAME("realview-eb-mpcore"), + .parent = TYPE_MACHINE, + .class_init = realview_eb_mpcore_class_init, }; -static QEMUMachine realview_pb_a8_machine = { - .name = "realview-pb-a8", - .desc = "ARM RealView Platform Baseboard for Cortex-A8", - .init = realview_pb_a8_init, +static void realview_pb_a8_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM RealView Platform Baseboard for Cortex-A8"; + mc->init = realview_pb_a8_init; +} + +static const TypeInfo realview_pb_a8_type = { + .name = MACHINE_TYPE_NAME("realview-pb-a8"), + .parent = TYPE_MACHINE, + .class_init = realview_pb_a8_class_init, }; -static QEMUMachine realview_pbx_a9_machine = { - .name = "realview-pbx-a9", - .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9", - .init = realview_pbx_a9_init, - .block_default_type = IF_SCSI, - .max_cpus = 4, +static void realview_pbx_a9_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9"; + mc->init = realview_pbx_a9_init; + mc->block_default_type = IF_SCSI; + mc->max_cpus = 4; +} + +static const TypeInfo realview_pbx_a9_type = { + .name = MACHINE_TYPE_NAME("realview-pbx-a9"), + .parent = TYPE_MACHINE, + .class_init = realview_pbx_a9_class_init, }; static void realview_machine_init(void) { - qemu_register_machine(&realview_eb_machine); - qemu_register_machine(&realview_eb_mpcore_machine); - qemu_register_machine(&realview_pb_a8_machine); - qemu_register_machine(&realview_pbx_a9_machine); + type_register_static(&realview_eb_type); + type_register_static(&realview_eb_mpcore_type); + type_register_static(&realview_pb_a8_type); + type_register_static(&realview_pbx_a9_type); } -machine_init(realview_machine_init); +type_init(realview_machine_init) diff --git a/qemu/hw/arm/spitz.c b/qemu/hw/arm/spitz.c index 5bf032a63..bf61d63b5 100644 --- a/qemu/hw/arm/spitz.c +++ b/qemu/hw/arm/spitz.c @@ -10,13 +10,15 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/arm/arm.h" #include "sysemu/sysemu.h" #include "hw/pcmcia.h" #include "hw/i2c/i2c.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" #include "hw/block/flash.h" #include "qemu/timer.h" #include "hw/devices.h" @@ -403,7 +405,7 @@ static void spitz_keyboard_tick(void *opaque) } timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - get_ticks_per_sec() / 32); + NANOSECONDS_PER_SECOND / 32); } static void spitz_keyboard_pre_map(SpitzKeyboardState *s) @@ -913,7 +915,7 @@ static void spitz_common_init(MachineState *machine, sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_abort); + memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal); vmstate_register_ram_global(rom); memory_region_set_readonly(rom, true); memory_region_add_subregion(address_space_mem, 0, rom); @@ -972,39 +974,71 @@ static void terrier_init(MachineState *machine) spitz_common_init(machine, terrier, 0x33f); } -static QEMUMachine akitapda_machine = { - .name = "akita", - .desc = "Akita PDA (PXA270)", - .init = akita_init, +static void akitapda_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)"; + mc->init = akita_init; +} + +static const TypeInfo akitapda_type = { + .name = MACHINE_TYPE_NAME("akita"), + .parent = TYPE_MACHINE, + .class_init = akitapda_class_init, }; -static QEMUMachine spitzpda_machine = { - .name = "spitz", - .desc = "Spitz PDA (PXA270)", - .init = spitz_init, +static void spitzpda_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)"; + mc->init = spitz_init; +} + +static const TypeInfo spitzpda_type = { + .name = MACHINE_TYPE_NAME("spitz"), + .parent = TYPE_MACHINE, + .class_init = spitzpda_class_init, }; -static QEMUMachine borzoipda_machine = { - .name = "borzoi", - .desc = "Borzoi PDA (PXA270)", - .init = borzoi_init, +static void borzoipda_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)"; + mc->init = borzoi_init; +} + +static const TypeInfo borzoipda_type = { + .name = MACHINE_TYPE_NAME("borzoi"), + .parent = TYPE_MACHINE, + .class_init = borzoipda_class_init, }; -static QEMUMachine terrierpda_machine = { - .name = "terrier", - .desc = "Terrier PDA (PXA270)", - .init = terrier_init, +static void terrierpda_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)"; + mc->init = terrier_init; +} + +static const TypeInfo terrierpda_type = { + .name = MACHINE_TYPE_NAME("terrier"), + .parent = TYPE_MACHINE, + .class_init = terrierpda_class_init, }; static void spitz_machine_init(void) { - qemu_register_machine(&akitapda_machine); - qemu_register_machine(&spitzpda_machine); - qemu_register_machine(&borzoipda_machine); - qemu_register_machine(&terrierpda_machine); + type_register_static(&akitapda_type); + type_register_static(&spitzpda_type); + type_register_static(&borzoipda_type); + type_register_static(&terrierpda_type); } -machine_init(spitz_machine_init); +type_init(spitz_machine_init) static bool is_version_0(void *opaque, int version_id) { @@ -1060,10 +1094,6 @@ static VMStateDescription vmstate_spitz_kbd = { }, }; -static Property spitz_keyboard_properties[] = { - DEFINE_PROP_END_OF_LIST(), -}; - static void spitz_keyboard_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1071,7 +1101,6 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data) k->init = spitz_keyboard_init; dc->vmsd = &vmstate_spitz_kbd; - dc->props = spitz_keyboard_properties; } static const TypeInfo spitz_keyboard_info = { diff --git a/qemu/hw/arm/stellaris.c b/qemu/hw/arm/stellaris.c index cb515ec76..c1766f856 100644 --- a/qemu/hw/arm/stellaris.c +++ b/qemu/hw/arm/stellaris.c @@ -7,8 +7,10 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/sysbus.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" #include "hw/arm/arm.h" #include "hw/devices.h" #include "qemu/timer.h" @@ -16,6 +18,7 @@ #include "net/net.h" #include "hw/boards.h" #include "exec/address-spaces.h" +#include "sysemu/sysemu.h" #define GPIO_A 0 #define GPIO_B 1 @@ -98,7 +101,7 @@ static void gptm_reload(gptm_state *s, int n, int reset) tick += (int64_t)count * system_clock_scale; } else if (s->config == 1) { /* 32-bit RTC. 1Hz tick. */ - tick += get_ticks_per_sec(); + tick += NANOSECONDS_PER_SECOND; } else if (s->mode[n] == 0xa) { /* PWM mode. Not implemented. */ } else { @@ -675,7 +678,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq, { ssys_state *s; - s = (ssys_state *)g_malloc0(sizeof(ssys_state)); + s = g_new0(ssys_state, 1); s->irq = irq; s->board = board; /* Most devices come preprogrammed with a MAC address in the user data. */ @@ -1176,6 +1179,14 @@ static int stellaris_adc_init(SysBusDevice *sbd) return 0; } +static +void do_sys_reset(void *opaque, int n, int level) +{ + if (level) { + qemu_system_reset_request(); + } +} + /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1210,8 +1221,7 @@ 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}; - qemu_irq *pic; - DeviceState *gpio_dev[7]; + DeviceState *gpio_dev[7], *nvic; qemu_irq gpio_in[7][8]; qemu_irq gpio_out[7][8]; qemu_irq adc; @@ -1231,22 +1241,29 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, /* Flash programming is done via the SCU, so pretend it is ROM. */ memory_region_init_ram(flash, NULL, "stellaris.flash", flash_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(flash); memory_region_set_readonly(flash, true); memory_region_add_subregion(system_memory, 0, flash); memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(sram); memory_region_add_subregion(system_memory, 0x20000000, sram); - pic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES, + nvic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES, kernel_filename, cpu_model); + qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0, + qemu_allocate_irq(&do_sys_reset, NULL, 0)); + if (board->dc1 & (1 << 16)) { dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000, - pic[14], pic[15], pic[16], pic[17], NULL); + qdev_get_gpio_in(nvic, 14), + qdev_get_gpio_in(nvic, 15), + qdev_get_gpio_in(nvic, 16), + qdev_get_gpio_in(nvic, 17), + NULL); adc = qdev_get_gpio_in(dev, 0); } else { adc = NULL; @@ -1255,19 +1272,21 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (0x10000 << i)) { dev = sysbus_create_simple(TYPE_STELLARIS_GPTM, 0x40030000 + i * 0x1000, - pic[timer_irq[i]]); + qdev_get_gpio_in(nvic, timer_irq[i])); /* TODO: This is incorrect, but we get away with it because the ADC output is only ever pulsed. */ qdev_connect_gpio_out(dev, 0, adc); } } - stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a); + stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28), + board, nd_table[0].macaddr.a); for (i = 0; i < 7; i++) { if (board->dc4 & (1 << i)) { gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i], - pic[gpio_irq[i]]); + qdev_get_gpio_in(nvic, + gpio_irq[i])); for (j = 0; j < 8; j++) { gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j); gpio_out[i][j] = NULL; @@ -1276,7 +1295,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } if (board->dc2 & (1 << 12)) { - dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, pic[8]); + dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, + qdev_get_gpio_in(nvic, 8)); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); if (board->peripherals & BP_OLED_I2C) { i2c_create_slave(i2c, "ssd0303", 0x3d); @@ -1286,11 +1306,12 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, for (i = 0; i < 4; i++) { if (board->dc2 & (1 << i)) { sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, - pic[uart_irq[i]]); + qdev_get_gpio_in(nvic, uart_irq[i])); } } if (board->dc2 & (1 << 4)) { - dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); + dev = sysbus_create_simple("pl022", 0x40008000, + qdev_get_gpio_in(nvic, 7)); if (board->peripherals & BP_OLED_SSI) { void *bus; DeviceState *sddev; @@ -1326,7 +1347,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, qdev_set_nic_properties(enet, &nd_table[0]); qdev_init_nofail(enet); sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); - sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]); + sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42)); } if (board->peripherals & BP_GAMEPAD) { qemu_irq gpad_irq[5]; @@ -1366,25 +1387,41 @@ static void lm3s6965evb_init(MachineState *machine) stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); } -static QEMUMachine lm3s811evb_machine = { - .name = "lm3s811evb", - .desc = "Stellaris LM3S811EVB", - .init = lm3s811evb_init, +static void lm3s811evb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Stellaris LM3S811EVB"; + mc->init = lm3s811evb_init; +} + +static const TypeInfo lm3s811evb_type = { + .name = MACHINE_TYPE_NAME("lm3s811evb"), + .parent = TYPE_MACHINE, + .class_init = lm3s811evb_class_init, }; -static QEMUMachine lm3s6965evb_machine = { - .name = "lm3s6965evb", - .desc = "Stellaris LM3S6965EVB", - .init = lm3s6965evb_init, +static void lm3s6965evb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Stellaris LM3S6965EVB"; + mc->init = lm3s6965evb_init; +} + +static const TypeInfo lm3s6965evb_type = { + .name = MACHINE_TYPE_NAME("lm3s6965evb"), + .parent = TYPE_MACHINE, + .class_init = lm3s6965evb_class_init, }; static void stellaris_machine_init(void) { - qemu_register_machine(&lm3s811evb_machine); - qemu_register_machine(&lm3s6965evb_machine); + type_register_static(&lm3s811evb_type); + type_register_static(&lm3s6965evb_type); } -machine_init(stellaris_machine_init); +type_init(stellaris_machine_init) static void stellaris_i2c_class_init(ObjectClass *klass, void *data) { diff --git a/qemu/hw/arm/stm32f205_soc.c b/qemu/hw/arm/stm32f205_soc.c index 0f3bdc77b..a5ea1e237 100644 --- a/qemu/hw/arm/stm32f205_soc.c +++ b/qemu/hw/arm/stm32f205_soc.c @@ -22,6 +22,10 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/arm/arm.h" #include "exec/address-spaces.h" #include "hw/arm/stm32f205_soc.h" @@ -59,9 +63,8 @@ static void stm32f205_soc_initfn(Object *obj) static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) { STM32F205State *s = STM32F205_SOC(dev_soc); - DeviceState *syscfgdev, *usartdev, *timerdev; + DeviceState *syscfgdev, *usartdev, *timerdev, *nvic; SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev; - qemu_irq *pic; Error *err = NULL; int i; @@ -71,7 +74,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) MemoryRegion *flash_alias = g_new(MemoryRegion, 1); memory_region_init_ram(flash, NULL, "STM32F205.flash", FLASH_SIZE, - &error_abort); + &error_fatal); memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias", flash, 0, FLASH_SIZE); @@ -84,12 +87,12 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(system_memory, 0, flash_alias); memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE, - &error_abort); + &error_fatal); vmstate_register_ram_global(sram); memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram); - pic = armv7m_init(get_system_memory(), FLASH_SIZE, 96, - s->kernel_filename, s->cpu_model); + nvic = armv7m_init(get_system_memory(), FLASH_SIZE, 96, + s->kernel_filename, s->cpu_model); /* System configuration controller */ syscfgdev = DEVICE(&s->syscfg); @@ -100,7 +103,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) } syscfgbusdev = SYS_BUS_DEVICE(syscfgdev); sysbus_mmio_map(syscfgbusdev, 0, 0x40013800); - sysbus_connect_irq(syscfgbusdev, 0, pic[71]); + sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71)); /* Attach UART (uses USART registers) and USART controllers */ for (i = 0; i < STM_NUM_USARTS; i++) { @@ -112,7 +115,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) } usartbusdev = SYS_BUS_DEVICE(usartdev); sysbus_mmio_map(usartbusdev, 0, usart_addr[i]); - sysbus_connect_irq(usartbusdev, 0, pic[usart_irq[i]]); + sysbus_connect_irq(usartbusdev, 0, + qdev_get_gpio_in(nvic, usart_irq[i])); } /* Timer 2 to 5 */ @@ -126,7 +130,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) } timerbusdev = SYS_BUS_DEVICE(timerdev); sysbus_mmio_map(timerbusdev, 0, timer_addr[i]); - sysbus_connect_irq(timerbusdev, 0, pic[timer_irq[i]]); + sysbus_connect_irq(timerbusdev, 0, + qdev_get_gpio_in(nvic, timer_irq[i])); } } diff --git a/qemu/hw/arm/strongarm.c b/qemu/hw/arm/strongarm.c index da9fc1d51..1eeb1ab39 100644 --- a/qemu/hw/arm/strongarm.c +++ b/qemu/hw/arm/strongarm.c @@ -27,6 +27,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "cpu.h" #include "hw/boards.h" #include "hw/sysbus.h" #include "strongarm.h" @@ -34,7 +36,8 @@ #include "hw/arm/arm.h" #include "sysemu/char.h" #include "sysemu/sysemu.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" +#include "qemu/cutils.h" //#define DEBUG @@ -1023,7 +1026,7 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s) ssp.parity = parity; ssp.data_bits = data_bits; ssp.stop_bits = stop_bits; - s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; + s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; if (s->chr) { qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); } @@ -1588,7 +1591,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, StrongARMState *s; int i; - s = g_malloc0(sizeof(StrongARMState)); + s = g_new0(StrongARMState, 1); if (!rev) { rev = "sa1110-b5"; diff --git a/qemu/hw/arm/sysbus-fdt.c b/qemu/hw/arm/sysbus-fdt.c index 9d28797c8..5debb3348 100644 --- a/qemu/hw/arm/sysbus-fdt.c +++ b/qemu/hw/arm/sysbus-fdt.c @@ -21,6 +21,13 @@ * */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include <libfdt.h> +#include "qemu-common.h" +#ifdef CONFIG_LINUX +#include <linux/vfio.h> +#endif #include "hw/arm/sysbus-fdt.h" #include "qemu/error-report.h" #include "sysemu/device_tree.h" @@ -28,6 +35,7 @@ #include "sysemu/sysemu.h" #include "hw/vfio/vfio-platform.h" #include "hw/vfio/vfio-calxeda-xgmac.h" +#include "hw/vfio/vfio-amd-xgbe.h" #include "hw/arm/fdt.h" /* @@ -56,6 +64,146 @@ typedef struct NodeCreationPair { int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque); } NodeCreationPair; +/* helpers */ + +typedef struct HostProperty { + const char *name; + bool optional; +} HostProperty; + +#ifdef CONFIG_LINUX + +/** + * copy_properties_from_host + * + * copies properties listed in an array from host device tree to + * guest device tree. If a non optional property is not found, the + * function asserts. An optional property is ignored if not found + * in the host device tree. + * @props: array of HostProperty to copy + * @nb_props: number of properties in the array + * @host_dt: host device tree blob + * @guest_dt: guest device tree blob + * @node_path: host dt node path where the property is supposed to be + found + * @nodename: guest node name the properties should be added to + */ +static void copy_properties_from_host(HostProperty *props, int nb_props, + void *host_fdt, void *guest_fdt, + char *node_path, char *nodename) +{ + int i, prop_len; + const void *r; + Error *err = NULL; + + for (i = 0; i < nb_props; i++) { + r = qemu_fdt_getprop(host_fdt, node_path, + props[i].name, + &prop_len, + props[i].optional ? &err : &error_fatal); + if (r) { + qemu_fdt_setprop(guest_fdt, nodename, + props[i].name, r, prop_len); + } else { + if (prop_len != -FDT_ERR_NOTFOUND) { + /* optional property not returned although property exists */ + error_report_err(err); + } else { + error_free(err); + } + } + } +} + +/* clock properties whose values are copied/pasted from host */ +static HostProperty clock_copied_properties[] = { + {"compatible", false}, + {"#clock-cells", false}, + {"clock-frequency", true}, + {"clock-output-names", true}, +}; + +/** + * fdt_build_clock_node + * + * Build a guest clock node, used as a dependency from a passthrough'ed + * device. Most information are retrieved from the host clock node. + * Also check the host clock is a fixed one. + * + * @host_fdt: host device tree blob from which info are retrieved + * @guest_fdt: guest device tree blob where the clock node is added + * @host_phandle: phandle of the clock in host device tree + * @guest_phandle: phandle to assign to the guest node + */ +static void fdt_build_clock_node(void *host_fdt, void *guest_fdt, + uint32_t host_phandle, + uint32_t guest_phandle) +{ + char *node_path = NULL; + char *nodename; + const void *r; + int ret, node_offset, prop_len, path_len = 16; + + node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle); + if (node_offset <= 0) { + error_setg(&error_fatal, + "not able to locate clock handle %d in host device tree", + host_phandle); + } + node_path = g_malloc(path_len); + while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len)) + == -FDT_ERR_NOSPACE) { + path_len += 16; + node_path = g_realloc(node_path, path_len); + } + if (ret < 0) { + error_setg(&error_fatal, + "not able to retrieve node path for clock handle %d", + host_phandle); + } + + r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len, + &error_fatal); + if (strcmp(r, "fixed-clock")) { + error_setg(&error_fatal, + "clock handle %d is not a fixed clock", host_phandle); + } + + nodename = strrchr(node_path, '/'); + qemu_fdt_add_subnode(guest_fdt, nodename); + + copy_properties_from_host(clock_copied_properties, + ARRAY_SIZE(clock_copied_properties), + host_fdt, guest_fdt, + node_path, nodename); + + qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle); + + g_free(node_path); +} + +/** + * sysfs_to_dt_name: convert the name found in sysfs into the node name + * for instance e0900000.xgmac is converted into xgmac@e0900000 + * @sysfs_name: directory name in sysfs + * + * returns the device tree name upon success or NULL in case the sysfs name + * does not match the expected format + */ +static char *sysfs_to_dt_name(const char *sysfs_name) +{ + gchar **substrings = g_strsplit(sysfs_name, ".", 2); + char *dt_name = NULL; + + if (!substrings || !substrings[0] || !substrings[1]) { + goto out; + } + dt_name = g_strdup_printf("%s@%s", substrings[1], substrings[0]); +out: + g_strfreev(substrings); + return dt_name; +} + /* Device Specific Code */ /** @@ -70,7 +218,7 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) PlatformBusDevice *pbus = data->pbus; void *fdt = data->fdt; const char *parent_node = data->pbus_node_name; - int compat_str_len, i, ret = -1; + int compat_str_len, i; char *nodename; uint32_t *irq_attr, *reg_attr; uint64_t mmio_base, irq_number; @@ -93,14 +241,10 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i); reg_attr[2 * i] = cpu_to_be32(mmio_base); reg_attr[2 * i + 1] = cpu_to_be32( - memory_region_size(&vdev->regions[i]->mem)); - } - ret = qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, - vbasedev->num_regions * 2 * sizeof(uint32_t)); - if (ret) { - error_report("could not set reg property of node %s", nodename); - goto fail_reg; + memory_region_size(vdev->regions[i]->mem)); } + qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, + vbasedev->num_regions * 2 * sizeof(uint32_t)); irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); for (i = 0; i < vbasedev->num_irqs; i++) { @@ -110,22 +254,173 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) irq_attr[3 * i + 1] = cpu_to_be32(irq_number); irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); } - ret = qemu_fdt_setprop(fdt, nodename, "interrupts", + qemu_fdt_setprop(fdt, nodename, "interrupts", irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); - if (ret) { - error_report("could not set interrupts property of node %s", - nodename); + g_free(irq_attr); + g_free(reg_attr); + g_free(nodename); + return 0; +} + +/* AMD xgbe properties whose values are copied/pasted from host */ +static HostProperty amd_xgbe_copied_properties[] = { + {"compatible", false}, + {"dma-coherent", true}, + {"amd,per-channel-interrupt", true}, + {"phy-mode", false}, + {"mac-address", true}, + {"amd,speed-set", false}, + {"amd,serdes-blwc", true}, + {"amd,serdes-cdr-rate", true}, + {"amd,serdes-pq-skew", true}, + {"amd,serdes-tx-amp", true}, + {"amd,serdes-dfe-tap-config", true}, + {"amd,serdes-dfe-tap-enable", true}, + {"clock-names", false}, +}; + +/** + * add_amd_xgbe_fdt_node + * + * Generates the combined xgbe/phy node following kernel >=4.2 + * binding documentation: + * Documentation/devicetree/bindings/net/amd-xgbe.txt: + * Also 2 clock nodes are created (dma and ptp) + * + * Asserts in case of error + */ +static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) +{ + PlatformBusFDTData *data = opaque; + PlatformBusDevice *pbus = data->pbus; + VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); + VFIODevice *vbasedev = &vdev->vbasedev; + VFIOINTp *intp; + const char *parent_node = data->pbus_node_name; + char **node_path, *nodename, *dt_name; + void *guest_fdt = data->fdt, *host_fdt; + const void *r; + int i, prop_len; + uint32_t *irq_attr, *reg_attr, *host_clock_phandles; + uint64_t mmio_base, irq_number; + uint32_t guest_clock_phandles[2]; + + host_fdt = load_device_tree_from_sysfs(); + + dt_name = sysfs_to_dt_name(vbasedev->name); + if (!dt_name) { + error_setg(&error_fatal, "%s incorrect sysfs device name %s", + __func__, vbasedev->name); + } + node_path = qemu_fdt_node_path(host_fdt, dt_name, vdev->compat, + &error_fatal); + if (!node_path || !node_path[0]) { + error_setg(&error_fatal, "%s unable to retrieve node path for %s/%s", + __func__, dt_name, vdev->compat); } + + if (node_path[1]) { + error_setg(&error_fatal, "%s more than one node matching %s/%s!", + __func__, dt_name, vdev->compat); + } + + g_free(dt_name); + + if (vbasedev->num_regions != 5) { + error_setg(&error_fatal, "%s Does the host dt node combine XGBE/PHY?", + __func__); + } + + /* generate nodes for DMA_CLK and PTP_CLK */ + r = qemu_fdt_getprop(host_fdt, node_path[0], "clocks", + &prop_len, &error_fatal); + if (prop_len != 8) { + error_setg(&error_fatal, "%s clocks property should contain 2 handles", + __func__); + } + host_clock_phandles = (uint32_t *)r; + guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt); + guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt); + + /** + * clock handles fetched from host dt are in be32 layout whereas + * rest of the code uses cpu layout. Also guest clock handles are + * in cpu layout. + */ + fdt_build_clock_node(host_fdt, guest_fdt, + be32_to_cpu(host_clock_phandles[0]), + guest_clock_phandles[0]); + + fdt_build_clock_node(host_fdt, guest_fdt, + be32_to_cpu(host_clock_phandles[1]), + guest_clock_phandles[1]); + + /* combined XGBE/PHY node */ + mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); + nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node, + vbasedev->name, mmio_base); + qemu_fdt_add_subnode(guest_fdt, nodename); + + copy_properties_from_host(amd_xgbe_copied_properties, + ARRAY_SIZE(amd_xgbe_copied_properties), + host_fdt, guest_fdt, + node_path[0], nodename); + + qemu_fdt_setprop_cells(guest_fdt, nodename, "clocks", + guest_clock_phandles[0], + guest_clock_phandles[1]); + + reg_attr = g_new(uint32_t, vbasedev->num_regions * 2); + for (i = 0; i < vbasedev->num_regions; i++) { + mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i); + reg_attr[2 * i] = cpu_to_be32(mmio_base); + reg_attr[2 * i + 1] = cpu_to_be32( + memory_region_size(vdev->regions[i]->mem)); + } + qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr, + vbasedev->num_regions * 2 * sizeof(uint32_t)); + + irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); + for (i = 0; i < vbasedev->num_irqs; i++) { + irq_number = platform_bus_get_irqn(pbus, sbdev , i) + + data->irq_start; + irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI); + irq_attr[3 * i + 1] = cpu_to_be32(irq_number); + /* + * General device interrupt and PCS auto-negotiation interrupts are + * level-sensitive while the 4 per-channel interrupts are edge + * sensitive + */ + QLIST_FOREACH(intp, &vdev->intp_list, next) { + if (intp->pin == i) { + break; + } + } + if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) { + irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); + } else { + irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + } + } + qemu_fdt_setprop(guest_fdt, nodename, "interrupts", + irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); + + g_free(host_fdt); + g_strfreev(node_path); g_free(irq_attr); -fail_reg: g_free(reg_attr); g_free(nodename); - return ret; + return 0; } +#endif /* CONFIG_LINUX */ + /* list of supported dynamic sysbus devices */ static const NodeCreationPair add_fdt_node_functions[] = { +#ifdef CONFIG_LINUX {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node}, + {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node}, +#endif {"", NULL}, /* last element */ }; diff --git a/qemu/hw/arm/tosa.c b/qemu/hw/arm/tosa.c index 73572ebe0..4e9494f94 100644 --- a/qemu/hw/arm/tosa.c +++ b/qemu/hw/arm/tosa.c @@ -11,6 +11,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/arm/arm.h" @@ -19,7 +21,7 @@ #include "hw/pcmcia.h" #include "hw/boards.h" #include "hw/i2c/i2c.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" #include "sysemu/block-backend.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" @@ -227,7 +229,7 @@ static void tosa_init(MachineState *machine) mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); - memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_abort); + memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal); vmstate_register_ram_global(rom); memory_region_set_readonly(rom, true); memory_region_add_subregion(address_space_mem, 0, rom); @@ -252,18 +254,13 @@ static void tosa_init(MachineState *machine) sl_bootparam_write(SL_PXA_PARAM_BASE); } -static QEMUMachine tosapda_machine = { - .name = "tosa", - .desc = "Tosa PDA (PXA255)", - .init = tosa_init, -}; - -static void tosapda_machine_init(void) +static void tosapda_machine_init(MachineClass *mc) { - qemu_register_machine(&tosapda_machine); + mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)"; + mc->init = tosa_init; } -machine_init(tosapda_machine_init); +DEFINE_MACHINE("tosa", tosapda_machine_init) static void tosa_dac_class_init(ObjectClass *klass, void *data) { diff --git a/qemu/hw/arm/versatilepb.c b/qemu/hw/arm/versatilepb.c index 6c69f4eaa..e5a80c2d2 100644 --- a/qemu/hw/arm/versatilepb.c +++ b/qemu/hw/arm/versatilepb.c @@ -7,6 +7,10 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/devices.h" @@ -192,7 +196,6 @@ static void versatile_init(MachineState *machine, int board_id) int n; int done_smc = 0; DriveInfo *dinfo; - Error *err = NULL; if (!machine->cpu_model) { machine->cpu_model = "arm926"; @@ -211,18 +214,10 @@ static void versatile_init(MachineState *machine, int board_id) * realization. */ if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); } - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); cpu = ARM_CPU(cpuobj); @@ -391,27 +386,43 @@ static void vab_init(MachineState *machine) versatile_init(machine, 0x25e); } -static QEMUMachine versatilepb_machine = { - .name = "versatilepb", - .desc = "ARM Versatile/PB (ARM926EJ-S)", - .init = vpb_init, - .block_default_type = IF_SCSI, +static void versatilepb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM Versatile/PB (ARM926EJ-S)"; + mc->init = vpb_init; + mc->block_default_type = IF_SCSI; +} + +static const TypeInfo versatilepb_type = { + .name = MACHINE_TYPE_NAME("versatilepb"), + .parent = TYPE_MACHINE, + .class_init = versatilepb_class_init, }; -static QEMUMachine versatileab_machine = { - .name = "versatileab", - .desc = "ARM Versatile/AB (ARM926EJ-S)", - .init = vab_init, - .block_default_type = IF_SCSI, +static void versatileab_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "ARM Versatile/AB (ARM926EJ-S)"; + mc->init = vab_init; + mc->block_default_type = IF_SCSI; +} + +static const TypeInfo versatileab_type = { + .name = MACHINE_TYPE_NAME("versatileab"), + .parent = TYPE_MACHINE, + .class_init = versatileab_class_init, }; static void versatile_machine_init(void) { - qemu_register_machine(&versatilepb_machine); - qemu_register_machine(&versatileab_machine); + type_register_static(&versatilepb_type); + type_register_static(&versatileab_type); } -machine_init(versatile_machine_init); +type_init(versatile_machine_init) static void vpb_sic_class_init(ObjectClass *klass, void *data) { diff --git a/qemu/hw/arm/vexpress.c b/qemu/hw/arm/vexpress.c index da217884e..70b3e701e 100644 --- a/qemu/hw/arm/vexpress.c +++ b/qemu/hw/arm/vexpress.c @@ -21,6 +21,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/arm/primecell.h" @@ -168,8 +172,8 @@ typedef struct { } VexpressMachineState; #define TYPE_VEXPRESS_MACHINE "vexpress" -#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9" -#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15" +#define TYPE_VEXPRESS_A9_MACHINE MACHINE_TYPE_NAME("vexpress-a9") +#define TYPE_VEXPRESS_A15_MACHINE MACHINE_TYPE_NAME("vexpress-a15") #define VEXPRESS_MACHINE(obj) \ OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE) #define VEXPRESS_MACHINE_GET_CLASS(obj) \ @@ -211,7 +215,6 @@ static void init_cpus(const char *cpu_model, const char *privdev, /* Create the actual CPUs */ for (n = 0; n < smp_cpus; n++) { Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - Error *err = NULL; if (!secure) { object_property_set_bool(cpuobj, false, "has_el3", NULL); @@ -221,11 +224,7 @@ static void init_cpus(const char *cpu_model, const char *privdev, object_property_set_int(cpuobj, periphbase, "reset-cbar", &error_abort); } - object_property_set_bool(cpuobj, true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_bool(cpuobj, true, "realized", &error_fatal); } /* Create the private peripheral devices (including the GIC); @@ -391,7 +390,7 @@ static void a15_daughterboard_init(const VexpressMachineState *vms, /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ /* 0x2e000000: system SRAM */ memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000, - &error_abort); + &error_fatal); vmstate_register_ram_global(sram); memory_region_add_subregion(sysmem, 0x2e000000, sram); @@ -482,8 +481,10 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) uint32_t acells, scells, intc; const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", + NULL, &error_fatal); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", + NULL, &error_fatal); intc = find_int_controller(fdt); if (!intc) { /* Not fatal, we just won't provide virtio. This will @@ -541,7 +542,7 @@ static void vexpress_common_init(MachineState *machine) { VexpressMachineState *vms = VEXPRESS_MACHINE(machine); VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine); - VEDBoardInfo *daughterboard = vmc->daughterboard;; + VEDBoardInfo *daughterboard = vmc->daughterboard; DeviceState *dev, *sysctl, *pl041; qemu_irq pic[64]; uint32_t sys_id; @@ -671,13 +672,13 @@ static void vexpress_common_init(MachineState *machine) sram_size = 0x2000000; memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(sram); memory_region_add_subregion(sysmem, map[VE_SRAM], sram); vram_size = 0x800000; memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(vram); memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); @@ -747,7 +748,6 @@ static void vexpress_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->name = TYPE_VEXPRESS_MACHINE; mc->desc = "ARM Versatile Express"; mc->init = vexpress_common_init; mc->block_default_type = IF_SCSI; @@ -759,10 +759,9 @@ static void vexpress_a9_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); - mc->name = TYPE_VEXPRESS_A9_MACHINE; mc->desc = "ARM Versatile Express for Cortex-A9"; - vmc->daughterboard = &a9_daughterboard;; + vmc->daughterboard = &a9_daughterboard; } static void vexpress_a15_class_init(ObjectClass *oc, void *data) @@ -770,7 +769,6 @@ static void vexpress_a15_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); - mc->name = TYPE_VEXPRESS_A15_MACHINE; mc->desc = "ARM Versatile Express for Cortex-A15"; vmc->daughterboard = &a15_daughterboard; @@ -805,4 +803,4 @@ static void vexpress_machine_init(void) type_register_static(&vexpress_a15_info); } -machine_init(vexpress_machine_init); +type_init(vexpress_machine_init); diff --git a/qemu/hw/arm/virt-acpi-build.c b/qemu/hw/arm/virt-acpi-build.c index f36514031..f51fe396c 100644 --- a/qemu/hw/arm/virt-acpi-build.c +++ b/qemu/hw/arm/virt-acpi-build.c @@ -26,6 +26,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu-common.h" #include "hw/arm/virt-acpi-build.h" #include "qemu/bitmap.h" @@ -43,20 +45,7 @@ #include "hw/pci/pci.h" #define ARM_SPI_BASE 32 - -typedef struct VirtAcpiCpuInfo { - DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT); -} VirtAcpiCpuInfo; - -static void virt_acpi_get_cpu_info(VirtAcpiCpuInfo *cpuinfo) -{ - CPUState *cpu; - - memset(cpuinfo->found_cpus, 0, sizeof cpuinfo->found_cpus); - CPU_FOREACH(cpu) { - set_bit(cpu->cpu_index, cpuinfo->found_cpus); - } -} +#define ACPI_POWER_BUTTON_DEVICE "PWRB" static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) { @@ -71,7 +60,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) } static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, - int uart_irq) + uint32_t uart_irq) { Aml *dev = aml_device("COM0"); aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011"))); @@ -82,7 +71,7 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, uart_memmap->size, AML_READ_WRITE)); aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, uart_irq)); + AML_EXCLUSIVE, &uart_irq, 1)); aml_append(dev, aml_name_decl("_CRS", crs)); /* The _ADR entry is used to link this device to the UART described @@ -93,19 +82,16 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_append(scope, dev); } -static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap, - int rtc_irq) +static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) { - Aml *dev = aml_device("RTC0"); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); + Aml *dev = aml_device("FWCF"); + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(rtc_memmap->base, - rtc_memmap->size, AML_READ_WRITE)); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, rtc_irq)); + aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, + fw_cfg_memmap->size, AML_READ_WRITE)); aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); } @@ -114,7 +100,7 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) { Aml *dev, *crs; hwaddr base = flash_memmap->base; - hwaddr size = flash_memmap->size; + hwaddr size = flash_memmap->size / 2; dev = aml_device("FLS0"); aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); @@ -136,14 +122,14 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) static void acpi_dsdt_add_virtio(Aml *scope, const MemMapEntry *virtio_mmio_memmap, - int mmio_irq, int num) + uint32_t mmio_irq, int num) { hwaddr base = virtio_mmio_memmap->base; hwaddr size = virtio_mmio_memmap->size; - int irq = mmio_irq; int i; for (i = 0; i < num; i++) { + uint32_t irq = mmio_irq + i; Aml *dev = aml_device("VR%02u", i); aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); aml_append(dev, aml_name_decl("_UID", aml_int(i))); @@ -152,14 +138,15 @@ static void acpi_dsdt_add_virtio(Aml *scope, aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, irq + i)); + AML_EXCLUSIVE, &irq, 1)); aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); base += size; } } -static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) +static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, + uint32_t irq, bool use_highmem) { Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf; int i, bus_no; @@ -179,6 +166,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) aml_append(dev, aml_name_decl("_ADR", aml_int(0))); aml_append(dev, aml_name_decl("_UID", aml_string("PCI0"))); aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device"))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); /* Declare the PCI Routing Table. */ Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS); @@ -197,29 +185,30 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) /* Create GSI link device */ for (i = 0; i < PCI_NUM_PINS; i++) { + uint32_t irqs = irq + i; Aml *dev_gsi = aml_device("GSI%d", i); aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F"))); aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0))); crs = aml_resource_template(); aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, irq + i)); + AML_EXCLUSIVE, &irqs, 1)); aml_append(dev_gsi, aml_name_decl("_PRS", crs)); crs = aml_resource_template(); aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, irq + i)); + AML_EXCLUSIVE, &irqs, 1)); aml_append(dev_gsi, aml_name_decl("_CRS", crs)); - method = aml_method("_SRS", 1); + method = aml_method("_SRS", 1, AML_NOTSERIALIZED); aml_append(dev_gsi, method); aml_append(dev, dev_gsi); } - method = aml_method("_CBA", 0); + method = aml_method("_CBA", 0, AML_NOTSERIALIZED); aml_append(method, aml_return(aml_int(base_ecam))); aml_append(dev, method); - method = aml_method("_CRS", 0); + method = aml_method("_CRS", 0, AML_NOTSERIALIZED); Aml *rbuf = aml_resource_template(); aml_append(rbuf, aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, @@ -234,6 +223,17 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio, size_pio)); + if (use_highmem) { + hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base; + hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size; + + aml_append(rbuf, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + base_mmio_high, base_mmio_high, 0x0000, + size_mmio_high)); + } + aml_append(method, aml_name_decl("RBUF", rbuf)); aml_append(method, aml_return(rbuf)); aml_append(dev, method); @@ -241,7 +241,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) /* Declare an _OSC (OS Control Handoff) method */ aml_append(dev, aml_name_decl("SUPP", aml_int(0))); aml_append(dev, aml_name_decl("CTRL", aml_int(0))); - method = aml_method("_OSC", 4); + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); @@ -259,16 +259,16 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); - aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D)), + aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL), aml_name("CTRL"))); ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); - aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08)), + aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08), NULL), aml_name("CDW1"))); aml_append(ifctx, ifctx1); ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); - aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10)), + aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10), NULL), aml_name("CDW1"))); aml_append(ifctx, ifctx1); @@ -277,13 +277,13 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) aml_append(method, ifctx); elsectx = aml_else(); - aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4)), + aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4), NULL), aml_name("CDW1"))); aml_append(elsectx, aml_return(aml_arg(3))); aml_append(method, elsectx); aml_append(dev, method); - method = aml_method("_DSM", 4); + method = aml_method("_DSM", 4, AML_NOTSERIALIZED); /* PCI Firmware Specification 3.0 * 4.6.1. _DSM for PCI Express Slot Information @@ -310,6 +310,46 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq) aml_append(scope, dev); } +static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap, + uint32_t gpio_irq) +{ + Aml *dev = aml_device("GPO0"); + aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061"))); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(gpio_memmap->base, gpio_memmap->size, + AML_READ_WRITE)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, &gpio_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + Aml *aei = aml_resource_template(); + /* Pin 3 for power button */ + const uint32_t pin_list[1] = {3}; + aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1, + "GPO0", NULL, 0)); + aml_append(dev, aml_name_decl("_AEI", aei)); + + /* _E03 is handle for power button */ + Aml *method = aml_method("_E03", 0, AML_NOTSERIALIZED); + aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), + aml_int(0x80))); + aml_append(dev, method); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_power_button(Aml *scope) +{ + Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C"))); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + aml_append(scope, dev); +} + /* RSDP */ static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) @@ -334,7 +374,8 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - rsdp, rsdp, sizeof *rsdp, &rsdp->checksum); + rsdp_table, rsdp, sizeof *rsdp, + &rsdp->checksum); return rsdp_table; } @@ -368,7 +409,8 @@ build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ - build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2); + build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2, + NULL, NULL); } static void @@ -387,7 +429,7 @@ build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN) - 1; - build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1); + build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL); } /* GTDT */ @@ -403,7 +445,7 @@ build_gtdt(GArray *table_data, GArray *linker) gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE; gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16; - gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE; + gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON; gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16; gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE; @@ -413,13 +455,12 @@ build_gtdt(GArray *table_data, GArray *linker) build_header(linker, table_data, (void *)(table_data->data + gtdt_start), "GTDT", - table_data->len - gtdt_start, 2); + table_data->len - gtdt_start, 2, NULL, NULL); } /* MADT */ static void -build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, - VirtAcpiCpuInfo *cpuinfo) +build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) { int madt_start = table_data->len; const MemMapEntry *memmap = guest_info->memmap; @@ -431,37 +472,49 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, madt = acpi_data_push(table_data, sizeof *madt); + gicd = acpi_data_push(table_data, sizeof *gicd); + gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; + gicd->length = sizeof(*gicd); + gicd->base_address = memmap[VIRT_GIC_DIST].base; + for (i = 0; i < guest_info->smp_cpus; i++) { AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, sizeof *gicc); + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); + gicc->type = ACPI_APIC_GENERIC_INTERRUPT; gicc->length = sizeof(*gicc); - gicc->base_address = memmap[VIRT_GIC_CPU].base; + if (guest_info->gic_version == 2) { + gicc->base_address = memmap[VIRT_GIC_CPU].base; + } gicc->cpu_interface_number = i; - gicc->arm_mpidr = i; + gicc->arm_mpidr = armcpu->mp_affinity; gicc->uid = i; - if (test_bit(i, cpuinfo->found_cpus)) { - gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); - } + gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); } - gicd = acpi_data_push(table_data, sizeof *gicd); - gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; - gicd->length = sizeof(*gicd); - gicd->base_address = memmap[VIRT_GIC_DIST].base; - - gic_msi = acpi_data_push(table_data, sizeof *gic_msi); - gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; - gic_msi->length = sizeof(*gic_msi); - gic_msi->gic_msi_frame_id = 0; - gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base); - gic_msi->flags = cpu_to_le32(1); - gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS); - gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE); + if (guest_info->gic_version == 3) { + AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, + sizeof *gicr); + + gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR; + gicr->length = sizeof(*gicr); + gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); + gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); + } else { + gic_msi = acpi_data_push(table_data, sizeof *gic_msi); + gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; + gic_msi->length = sizeof(*gic_msi); + gic_msi->gic_msi_frame_id = 0; + gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base); + gic_msi->flags = cpu_to_le32(1); + gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS); + gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE); + } build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 3); + table_data->len - madt_start, 3, NULL, NULL); } /* FADT */ @@ -486,7 +539,7 @@ build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) sizeof fadt->dsdt); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 5); + (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); } /* DSDT */ @@ -501,16 +554,24 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) /* Reserve space for header */ acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); + /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. + * While UEFI can use libfdt to disable the RTC device node in the DTB that + * it passes to the OS, it cannot modify AML. Therefore, we won't generate + * the RTC ACPI device at all when using UEFI. + */ scope = aml_scope("\\_SB"); acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC], - (irqmap[VIRT_RTC] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); - acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE)); + acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), + guest_info->use_highmem); + acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], + (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); + acpi_dsdt_add_power_button(scope); aml_append(dsdt, scope); @@ -518,7 +579,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); build_header(linker, table_data, (void *)(table_data->data + table_data->len - dsdt->buf->len), - "DSDT", dsdt->buf->len, 2); + "DSDT", dsdt->buf->len, 2, NULL, NULL); free_aml_allocator(); } @@ -538,11 +599,8 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; unsigned dsdt, rsdt; - VirtAcpiCpuInfo cpuinfo; GArray *tables_blob = tables->table_data; - virt_acpi_get_cpu_info(&cpuinfo); - table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -569,7 +627,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) build_fadt(tables_blob, tables->linker, dsdt); acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, guest_info, &cpuinfo); + build_madt(tables_blob, tables->linker, guest_info); acpi_add_table(table_offsets, tables_blob); build_gtdt(tables_blob, tables->linker); @@ -582,7 +640,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets); + build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); @@ -603,7 +661,7 @@ static void acpi_ram_update(MemoryRegion *mr, GArray *data) memory_region_set_dirty(mr, 0, size); } -static void virt_acpi_build_update(void *build_opaque, uint32_t offset) +static void virt_acpi_build_update(void *build_opaque) { AcpiBuildState *build_state = build_opaque; AcpiBuildTables tables; diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c index 484689264..56d35c771 100644 --- a/qemu/hw/arm/virt.c +++ b/qemu/hw/arm/virt.c @@ -28,6 +28,8 @@ * This is essentially the same approach kvmtool uses. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "hw/arm/primecell.h" @@ -48,6 +50,11 @@ #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" +#include "hw/intc/arm_gic_common.h" +#include "kvm_arm.h" +#include "hw/smbios/smbios.h" +#include "qapi/visitor.h" +#include "standard-headers/linux/input.h" /* Number of external interrupt lines to configure the GIC with */ #define NUM_IRQS 256 @@ -67,6 +74,7 @@ typedef struct VirtBoardInfo { uint32_t clock_phandle; uint32_t gic_phandle; uint32_t v2m_phandle; + bool using_psci; } VirtBoardInfo; typedef struct { @@ -77,9 +85,11 @@ typedef struct { typedef struct { MachineState parent; bool secure; + bool highmem; + int32_t gic_version; } VirtMachineState; -#define TYPE_VIRT_MACHINE "virt" +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") #define VIRT_MACHINE(obj) \ OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) #define VIRT_MACHINE_GET_CLASS(obj) \ @@ -87,6 +97,23 @@ typedef struct { #define VIRT_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) +/* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means + * RAM can go up to the 256GB mark, leaving 256GB of the physical + * address space unallocated and free for future use between 256G and 512G. + * If we need to provide more RAM to VMs in the future then we need to: + * * allocate a second bank of RAM starting at 2TB and working up + * * fix the DT and ACPI table generation code in QEMU to correctly + * report two split lumps of RAM to the guest + * * fix KVM in the host kernel to allow guests with >40 bit address spaces + * (We don't want to fill all the way up to 512GB with RAM because + * we might want it for non-RAM purposes later. Conversely it seems + * reasonable to assume that anybody configuring a VM with a quarter + * of a terabyte of RAM will be doing it on a host with more than a + * terabyte of physical address space.) + */ +#define RAMLIMIT_GB 255 +#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024) + /* Addresses and sizes of our components. * 0..128MB is space for a flash device so we can run bootrom code such as UEFI. * 128MB..256MB is used for miscellaneous device I/O. @@ -107,22 +134,33 @@ static const MemMapEntry a15memmap[] = { [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, + /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */ + [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 }, + /* This redistributor space allows up to 2*64kB*123 CPUs */ + [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, - [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, + [VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, + [VIRT_GPIO] = { 0x09030000, 0x00001000 }, + [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, + [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 }, [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 }, [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 }, - [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, + [VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES }, + /* Second PCIe window, 512GB wide at the 512GB boundary */ + [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL }, }; static const int a15irqmap[] = { [VIRT_UART] = 1, [VIRT_RTC] = 2, [VIRT_PCIE] = 3, /* ... to 6 */ + [VIRT_GPIO] = 7, + [VIRT_SECURE_UART] = 8, [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ @@ -212,6 +250,10 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) void *fdt = vbi->fdt; ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); + if (!vbi->using_psci) { + return; + } + qemu_fdt_add_subnode(fdt, "/psci"); if (armcpu->psci_version == 2) { const char comp[] = "arm,psci-0.2\0arm,psci"; @@ -249,7 +291,7 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); } -static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) +static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) { /* Note that on A15 h/w these interrupts are level-triggered, * but for the GIC implementation provided by both QEMU and KVM @@ -258,8 +300,11 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) ARMCPU *armcpu; uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; - irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, - GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1); + if (gictype == 2) { + irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, + GIC_FDT_IRQ_PPI_CPU_WIDTH, + (1 << vbi->smp_cpus) - 1); + } qemu_fdt_add_subnode(vbi->fdt, "/timer"); @@ -272,6 +317,7 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", "arm,armv7-timer"); } + qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0); qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, @@ -282,9 +328,32 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) { int cpu; + int addr_cells = 1; + + /* + * From Documentation/devicetree/bindings/arm/cpus.txt + * On ARM v8 64-bit systems value should be set to 2, + * that corresponds to the MPIDR_EL1 register size. + * If MPIDR_EL1[63:32] value is equal to 0 on all CPUs + * in the system, #address-cells can be set to 1, since + * MPIDR_EL1[63:32] bits are not used for CPUs + * identification. + * + * Here we actually don't know whether our system is 32- or 64-bit one. + * The simplest way to go is to examine affinity IDs of all our CPUs. If + * at least one of them has Aff3 populated, we set #address-cells to 2. + */ + for (cpu = 0; cpu < vbi->smp_cpus; cpu++) { + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); + + if (armcpu->mp_affinity & ARM_AFF3_MASK) { + addr_cells = 2; + break; + } + } qemu_fdt_add_subnode(vbi->fdt, "/cpus"); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1); + qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells); qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) { @@ -296,12 +365,19 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", armcpu->dtb_compatible); - if (vbi->smp_cpus > 1) { + if (vbi->using_psci && vbi->smp_cpus > 1) { qemu_fdt_setprop_string(vbi->fdt, nodename, "enable-method", "psci"); } - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity); + if (addr_cells == 2) { + qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg", + armcpu->mp_affinity); + } else { + qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", + armcpu->mp_affinity); + } + g_free(nodename); } } @@ -319,25 +395,36 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle); } -static void fdt_add_gic_node(VirtBoardInfo *vbi) +static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) { vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); qemu_fdt_add_subnode(vbi->fdt, "/intc"); - /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - "arm,cortex-a15-gic"); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); + if (type == 3) { + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,gic-v3"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_GIC_REDIST].base, + 2, vbi->memmap[VIRT_GIC_REDIST].size); + } else { + /* 'cortex-a15-gic' means 'GIC v2' */ + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,cortex-a15-gic"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_GIC_CPU].base, + 2, vbi->memmap[VIRT_GIC_CPU].size); + } + qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); } @@ -360,29 +447,34 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) { - /* We create a standalone GIC v2 */ + /* We create a standalone GIC */ DeviceState *gicdev; SysBusDevice *gicbusdev; - const char *gictype = "arm_gic"; + const char *gictype; int i; - if (kvm_irqchip_in_kernel()) { - gictype = "kvm-arm-gic"; - } + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); gicdev = qdev_create(NULL, gictype); - qdev_prop_set_uint32(gicdev, "revision", 2); + qdev_prop_set_uint32(gicdev, "revision", type); qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); /* Note that the num-irq property counts both internal and external * interrupts; there are always 32 of the former (mandated by GIC spec). */ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); + if (!kvm_irqchip_in_kernel()) { + qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + } qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + if (type == 3) { + sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base); + } else { + sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + } /* Wire the outputs from each CPU's generic timer to the * appropriate GIC PPI inputs, and the GIC's IRQ output to @@ -390,15 +482,23 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); - int ppibase = NUM_IRQS + i * 32; - /* physical timer; we wire it up to the non-secure timer's ID, - * since a real A15 always has TrustZone but QEMU doesn't. + int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; + int irq; + /* Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs we use for the virt board. */ - qdev_connect_gpio_out(cpudev, 0, - qdev_get_gpio_in(gicdev, ppibase + 30)); - /* virtual timer */ - qdev_connect_gpio_out(cpudev, 1, - qdev_get_gpio_in(gicdev, ppibase + 27)); + const int timer_irq[] = { + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, + }; + + for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + qdev_connect_gpio_out(cpudev, irq, + qdev_get_gpio_in(gicdev, + ppibase + timer_irq[irq])); + } sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, @@ -409,21 +509,29 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi); + fdt_add_gic_node(vbi, type); - create_v2m(vbi, pic); + if (type == 2) { + create_v2m(vbi, pic); + } } -static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, + MemoryRegion *mem) { char *nodename; - hwaddr base = vbi->memmap[VIRT_UART].base; - hwaddr size = vbi->memmap[VIRT_UART].size; - int irq = vbi->irqmap[VIRT_UART]; + hwaddr base = vbi->memmap[uart].base; + hwaddr size = vbi->memmap[uart].size; + int irq = vbi->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; + DeviceState *dev = qdev_create(NULL, "pl011"); + SysBusDevice *s = SYS_BUS_DEVICE(dev); - sysbus_create_simple("pl011", base, pic[irq]); + qdev_init_nofail(dev); + memory_region_add_subregion(mem, base, + sysbus_mmio_get_region(s, 0)); + sysbus_connect_irq(s, 0, pic[irq]); nodename = g_strdup_printf("/pl011@%" PRIx64, base); qemu_fdt_add_subnode(vbi->fdt, nodename); @@ -440,7 +548,14 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); - qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); + if (uart == VIRT_UART) { + qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); + } else { + /* Mark as not usable by the normal world */ + qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + } + g_free(nodename); } @@ -467,6 +582,64 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic) g_free(nodename); } +static DeviceState *gpio_key_dev; +static void virt_powerdown_req(Notifier *n, void *opaque) +{ + /* use gpio Pin 3 for power button event */ + qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); +} + +static Notifier virt_system_powerdown_notifier = { + .notify = virt_powerdown_req +}; + +static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) +{ + char *nodename; + DeviceState *pl061_dev; + hwaddr base = vbi->memmap[VIRT_GPIO].base; + hwaddr size = vbi->memmap[VIRT_GPIO].size; + int irq = vbi->irqmap[VIRT_GPIO]; + const char compat[] = "arm,pl061\0arm,primecell"; + + pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); + + uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt); + nodename = g_strdup_printf("/pl061@%" PRIx64, base); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, base, 2, size); + qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2); + qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0); + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, irq, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); + qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle); + + gpio_key_dev = sysbus_create_simple("gpio-key", -1, + qdev_get_gpio_in(pl061_dev, 3)); + qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys"); + qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys"); + qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0); + qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1); + + qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff"); + qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff", + "label", "GPIO Key Poweroff"); + qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code", + KEY_POWER); + qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff", + "gpios", phandle, 3, 0); + + /* connect powerdown request */ + qemu_register_powerdown_notifier(&virt_system_powerdown_notifier); + + g_free(nodename); +} + static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) { int i; @@ -532,13 +705,15 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) } static void create_one_flash(const char *name, hwaddr flashbase, - hwaddr flashsize) + hwaddr flashsize, const char *file, + MemoryRegion *sysmem) { /* Create and map a single flash device. We use the same * parameters as the flash devices on the Versatile Express board. */ DriveInfo *dinfo = drive_get_next(IF_PFLASH); DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); const uint64_t sectorlength = 256 * 1024; if (dinfo) { @@ -558,19 +733,10 @@ static void create_one_flash(const char *name, hwaddr flashbase, qdev_prop_set_string(dev, "name", name); qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, flashbase); -} - -static void create_flash(const VirtBoardInfo *vbi) -{ - /* Create two flash devices to fill the VIRT_FLASH space in the memmap. - * Any file passed via -bios goes in the first of these. - */ - hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; - char *nodename; + memory_region_add_subregion(sysmem, flashbase, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); - if (bios_name) { + if (file) { char *fn; int image_size; @@ -580,39 +746,82 @@ static void create_flash(const VirtBoardInfo *vbi) "but you cannot use both options at once"); exit(1); } - fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file); if (!fn) { - error_report("Could not find ROM image '%s'", bios_name); + error_report("Could not find ROM image '%s'", file); exit(1); } - image_size = load_image_targphys(fn, flashbase, flashsize); + image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0)); g_free(fn); if (image_size < 0) { - error_report("Could not load ROM image '%s'", bios_name); + error_report("Could not load ROM image '%s'", file); exit(1); } } +} + +static void create_flash(const VirtBoardInfo *vbi, + MemoryRegion *sysmem, + MemoryRegion *secure_sysmem) +{ + /* Create two flash devices to fill the VIRT_FLASH space in the memmap. + * Any file passed via -bios goes in the first of these. + * sysmem is the system memory space. secure_sysmem is the secure view + * of the system, and the first flash device should be made visible only + * there. The second flash device is visible to both secure and nonsecure. + * If sysmem == secure_sysmem this means there is no separate Secure + * address space and both flash devices are generally visible. + */ + hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; + char *nodename; - create_one_flash("virt.flash0", flashbase, flashsize); - create_one_flash("virt.flash1", flashbase + flashsize, flashsize); + create_one_flash("virt.flash0", flashbase, flashsize, + bios_name, secure_sysmem); + create_one_flash("virt.flash1", flashbase + flashsize, flashsize, + NULL, sysmem); - nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, flashbase, 2, flashsize, - 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - g_free(nodename); + if (sysmem == secure_sysmem) { + /* Report both flash devices as a single node in the DT */ + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, flashbase, 2, flashsize, + 2, flashbase + flashsize, 2, flashsize); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + g_free(nodename); + } else { + /* Report the devices as separate nodes so we can mark one as + * only visible to the secure world. + */ + nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, flashbase, 2, flashsize); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + g_free(nodename); + + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, flashbase + flashsize, 2, flashsize); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + g_free(nodename); + } } -static void create_fw_cfg(const VirtBoardInfo *vbi) +static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) { hwaddr base = vbi->memmap[VIRT_FW_CFG].base; hwaddr size = vbi->memmap[VIRT_FW_CFG].size; char *nodename; - fw_cfg_init_mem_wide(base + 8, base, 8); + fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, as); nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); qemu_fdt_add_subnode(vbi->fdt, nodename); @@ -658,10 +867,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, 0x7 /* PCI irq */); } -static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, + bool use_highmem) { hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base; hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size; + hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base; + hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size; hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base; hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size; hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base; @@ -676,6 +888,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) DeviceState *dev; char *nodename; int i; + PCIHostState *pci; dev = qdev_create(NULL, TYPE_GPEX_HOST); qdev_init_nofail(dev); @@ -698,6 +911,16 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) mmio_reg, base_mmio, size_mmio); memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); + if (use_highmem) { + /* Map high MMIO space */ + MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1); + + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", + mmio_reg, base_mmio_high, size_mmio_high); + memory_region_add_subregion(get_system_memory(), base_mmio_high, + high_mmio_alias); + } + /* Map IO port space */ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); @@ -705,6 +928,19 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); } + pci = PCI_HOST_BRIDGE(dev); + if (pci->bus) { + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + pci_nic_init_nofail(nd, pci->bus, nd->model, NULL); + } + } + nodename = g_strdup_printf("/pcie@%" PRIx64, base); qemu_fdt_add_subnode(vbi->fdt, nodename); qemu_fdt_setprop_string(vbi->fdt, nodename, @@ -715,15 +951,30 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle); + if (vbi->v2m_phandle) { + qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", + vbi->v2m_phandle); + } qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base_ecam, 2, size_ecam); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", - 1, FDT_PCI_RANGE_IOPORT, 2, 0, - 2, base_pio, 2, size_pio, - 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, - 2, base_mmio, 2, size_mmio); + + if (use_highmem) { + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + 1, FDT_PCI_RANGE_IOPORT, 2, 0, + 2, base_pio, 2, size_pio, + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio, + 1, FDT_PCI_RANGE_MMIO_64BIT, + 2, base_mmio_high, + 2, base_mmio_high, 2, size_mmio_high); + } else { + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + 1, FDT_PCI_RANGE_IOPORT, 2, 0, + 2, base_pio, 2, size_pio, + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio); + } qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename); @@ -772,6 +1023,27 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) sysbus_mmio_get_region(s, 0)); } +static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem) +{ + MemoryRegion *secram = g_new(MemoryRegion, 1); + char *nodename; + hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base; + hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size; + + memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal); + vmstate_register_ram_global(secram); + memory_region_add_subregion(secure_sysmem, base, secram); + + nodename = g_strdup_printf("/secram@%" PRIx64, base); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); + qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + + g_free(nodename); +} + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; @@ -780,12 +1052,42 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) return board->fdt; } +static void virt_build_smbios(VirtGuestInfo *guest_info) +{ + FWCfgState *fw_cfg = guest_info->fw_cfg; + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + + if (!fw_cfg) { + return; + } + + if (kvm_enabled()) { + product = "KVM Virtual Machine"; + } + + smbios_set_defaults("QEMU", product, + "1.0", false, true, SMBIOS_ENTRY_POINT_30); + + smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len); + + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } +} + static void virt_guest_info_machine_done(Notifier *notifier, void *data) { VirtGuestInfoState *guest_info_state = container_of(notifier, VirtGuestInfoState, machine_done); virt_acpi_setup(&guest_info_state->info); + virt_build_smbios(&guest_info_state->info); } static void machvirt_init(MachineState *machine) @@ -793,18 +1095,33 @@ static void machvirt_init(MachineState *machine) VirtMachineState *vms = VIRT_MACHINE(machine); qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); - int n; + MemoryRegion *secure_sysmem = NULL; + int gic_version = vms->gic_version; + int n, virt_max_cpus; MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; VirtBoardInfo *vbi; VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); VirtGuestInfo *guest_info = &guest_info_state->info; char **cpustr; + bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); if (!cpu_model) { cpu_model = "cortex-a15"; } + /* We can probe only here because during property set + * KVM is not available yet + */ + if (!gic_version) { + gic_version = kvm_arm_vgic_probe(); + if (!gic_version) { + error_report("Unable to determine GIC version supported by host"); + error_printf("KVM acceleration is probably not supported\n"); + exit(1); + } + } + /* Separate the actual CPU model name from any appended features */ cpustr = g_strsplit(cpu_model, ",", 2); @@ -815,13 +1132,55 @@ static void machvirt_init(MachineState *machine) exit(1); } + /* If we have an EL3 boot ROM then the assumption is that it will + * implement PSCI itself, so disable QEMU's internal implementation + * so it doesn't get in the way. Instead of starting secondary + * CPUs in PSCI powerdown state we will start them all running and + * let the boot ROM sort them out. + * The usual case is that we do use QEMU's PSCI implementation. + */ + vbi->using_psci = !(vms->secure && firmware_loaded); + + /* The maximum number of CPUs depends on the GIC version, or on how + * many redistributors we can fit into the memory map. + */ + if (gic_version == 3) { + virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; + } else { + virt_max_cpus = GIC_NCPU; + } + + if (max_cpus > virt_max_cpus) { + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " + "supported by machine 'mach-virt' (%d)", + max_cpus, virt_max_cpus); + exit(1); + } + vbi->smp_cpus = smp_cpus; if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { - error_report("mach-virt: cannot model more than 30GB RAM"); + error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB); exit(1); } + if (vms->secure) { + if (kvm_enabled()) { + error_report("mach-virt: KVM does not support Security extensions"); + exit(1); + } + + /* The Secure view of the world is the same as the NonSecure, + * but with a few extra devices. Create it as a container region + * containing the system memory at low priority; any secure-only + * devices go in at higher priority and take precedence. + */ + secure_sysmem = g_new(MemoryRegion, 1); + memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", + UINT64_MAX); + memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); + } + create_fdt(vbi); for (n = 0; n < smp_cpus; n++) { @@ -832,7 +1191,7 @@ static void machvirt_init(MachineState *machine) char *cpuopts = g_strdup(cpustr[1]); if (!oc) { - fprintf(stderr, "Unable to find CPU definition\n"); + error_report("Unable to find CPU definition"); exit(1); } cpuobj = object_new(object_class_get_name(oc)); @@ -849,12 +1208,15 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, false, "has_el3", NULL); } - object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit", - NULL); + if (vbi->using_psci) { + object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, + "psci-conduit", NULL); - /* Secondary CPUs start in PSCI powered-down state */ - if (n > 0) { - object_property_set_bool(cpuobj, true, "start-powered-off", NULL); + /* Secondary CPUs start in PSCI powered-down state */ + if (n > 0) { + object_property_set_bool(cpuobj, true, + "start-powered-off", NULL); + } } if (object_property_find(cpuobj, "reset-cbar", NULL)) { @@ -862,10 +1224,17 @@ static void machvirt_init(MachineState *machine) "reset-cbar", &error_abort); } + object_property_set_link(cpuobj, OBJECT(sysmem), "memory", + &error_abort); + if (vms->secure) { + object_property_set_link(cpuobj, OBJECT(secure_sysmem), + "secure-memory", &error_abort); + } + object_property_set_bool(cpuobj, true, "realized", NULL); } g_strfreev(cpustr); - fdt_add_timer_nodes(vbi); + fdt_add_timer_nodes(vbi, gic_version); fdt_add_cpu_nodes(vbi); fdt_add_psci_node(vbi); @@ -873,15 +1242,22 @@ static void machvirt_init(MachineState *machine) machine->ram_size); memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); - create_flash(vbi); + create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); + + create_gic(vbi, pic, gic_version, vms->secure); - create_gic(vbi, pic); + create_uart(vbi, pic, VIRT_UART, sysmem); - create_uart(vbi, pic); + if (vms->secure) { + create_secure_ram(vbi, secure_sysmem); + create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem); + } create_rtc(vbi, pic); - create_pcie(vbi, pic); + create_pcie(vbi, pic, vms->highmem); + + create_gpio(vbi, pic); /* Create mmio transports, so the user can create virtio backends * (which will be automatically plugged in to the transports). If @@ -889,13 +1265,15 @@ static void machvirt_init(MachineState *machine) */ create_virtio_devices(vbi, pic); - create_fw_cfg(vbi); + create_fw_cfg(vbi, &address_space_memory); rom_set_fw(fw_cfg_find()); guest_info->smp_cpus = smp_cpus; guest_info->fw_cfg = fw_cfg_find(); guest_info->memmap = vbi->memmap; guest_info->irqmap = vbi->irqmap; + guest_info->use_highmem = vms->highmem; + guest_info->gic_version = gic_version; guest_info_state->machine_done.notify = virt_guest_info_machine_done; qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); @@ -907,7 +1285,7 @@ static void machvirt_init(MachineState *machine) vbi->bootinfo.board_id = -1; vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; vbi->bootinfo.get_dtb = machvirt_dtb; - vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); + vbi->bootinfo.firmware_loaded = firmware_loaded; arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo); /* @@ -933,45 +1311,125 @@ static void virt_set_secure(Object *obj, bool value, Error **errp) vms->secure = value; } -static void virt_instance_init(Object *obj) +static bool virt_get_highmem(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem; +} + +static void virt_set_highmem(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem = value; +} + +static char *virt_get_gic_version(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + const char *val = vms->gic_version == 3 ? "3" : "2"; + + return g_strdup(val); +} + +static void virt_set_gic_version(Object *obj, const char *value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + if (!strcmp(value, "3")) { + vms->gic_version = 3; + } else if (!strcmp(value, "2")) { + vms->gic_version = 2; + } else if (!strcmp(value, "host")) { + vms->gic_version = 0; /* Will probe later */ + } else { + error_setg(errp, "Invalid gic-version value"); + error_append_hint(errp, "Valid values are 3, 2, host.\n"); + } +} + +static void virt_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = machvirt_init; + /* Start max_cpus at the maximum QEMU supports. We'll further restrict + * it later in machvirt_init, where we have more information about the + * configuration of the particular instance. + */ + mc->max_cpus = MAX_CPUMASK_BITS; + mc->has_dynamic_sysbus = true; + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; +} + +static const TypeInfo virt_machine_info = { + .name = TYPE_VIRT_MACHINE, + .parent = TYPE_MACHINE, + .abstract = true, + .instance_size = sizeof(VirtMachineState), + .class_size = sizeof(VirtMachineClass), + .class_init = virt_machine_class_init, +}; + +static void virt_2_6_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); - /* EL3 is enabled by default on virt */ - vms->secure = true; + /* EL3 is disabled by default on virt: this makes us consistent + * between KVM and TCG for this board, and it also allows us to + * boot UEFI blobs which assume no TrustZone support. + */ + vms->secure = false; object_property_add_bool(obj, "secure", virt_get_secure, virt_set_secure, NULL); object_property_set_description(obj, "secure", "Set on/off to enable/disable the ARM " "Security Extensions (TrustZone)", NULL); + + /* High memory is enabled by default */ + vms->highmem = true; + object_property_add_bool(obj, "highmem", virt_get_highmem, + virt_set_highmem, NULL); + object_property_set_description(obj, "highmem", + "Set on/off to enable/disable using " + "physical address space above 32 bits", + NULL); + /* Default GIC type is v2 */ + vms->gic_version = 2; + object_property_add_str(obj, "gic-version", virt_get_gic_version, + virt_set_gic_version, NULL); + object_property_set_description(obj, "gic-version", + "Set GIC version. " + "Valid values are 2, 3 and host", NULL); } -static void virt_class_init(ObjectClass *oc, void *data) +static void virt_2_6_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + static GlobalProperty compat_props[] = { + { /* end of list */ } + }; - mc->name = TYPE_VIRT_MACHINE; - mc->desc = "ARM Virtual Machine", - mc->init = machvirt_init; - mc->max_cpus = 8; - mc->has_dynamic_sysbus = true; - mc->block_default_type = IF_VIRTIO; - mc->no_cdrom = 1; + mc->desc = "QEMU 2.6 ARM Virtual Machine"; + mc->alias = "virt"; + mc->compat_props = compat_props; } static const TypeInfo machvirt_info = { - .name = TYPE_VIRT_MACHINE, - .parent = TYPE_MACHINE, - .instance_size = sizeof(VirtMachineState), - .instance_init = virt_instance_init, - .class_size = sizeof(VirtMachineClass), - .class_init = virt_class_init, + .name = MACHINE_TYPE_NAME("virt-2.6"), + .parent = TYPE_VIRT_MACHINE, + .instance_init = virt_2_6_instance_init, + .class_init = virt_2_6_class_init, }; static void machvirt_machine_init(void) { + type_register_static(&virt_machine_info); type_register_static(&machvirt_info); } -machine_init(machvirt_machine_init); +type_init(machvirt_machine_init); diff --git a/qemu/hw/arm/xilinx_zynq.c b/qemu/hw/arm/xilinx_zynq.c index a4e7b5c63..98b17c9ae 100644 --- a/qemu/hw/arm/xilinx_zynq.c +++ b/qemu/hw/arm/xilinx_zynq.c @@ -15,6 +15,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" #include "net/net.h" @@ -24,8 +28,10 @@ #include "hw/block/flash.h" #include "sysemu/block-backend.h" #include "hw/loader.h" -#include "hw/ssi.h" +#include "hw/misc/zynq-xadc.h" +#include "hw/ssi/ssi.h" #include "qemu/error-report.h" +#include "hw/sd/sd.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -43,6 +49,45 @@ static const int dma_irqs[8] = { 46, 47, 48, 49, 72, 73, 74, 75 }; +#define BOARD_SETUP_ADDR 0x100 + +#define SLCR_LOCK_OFFSET 0x004 +#define SLCR_UNLOCK_OFFSET 0x008 +#define SLCR_ARM_PLL_OFFSET 0x100 + +#define SLCR_XILINX_UNLOCK_KEY 0xdf0d +#define SLCR_XILINX_LOCK_KEY 0x767b + +#define ARMV7_IMM16(x) (extract32((x), 0, 12) | \ + extract32((x), 12, 4) << 16) + +/* Write immediate val to address r0 + addr. r0 should contain base offset + * of the SLCR block. Clobbers r1. + */ + +#define SLCR_WRITE(addr, val) \ + 0xe3001000 + ARMV7_IMM16(extract32((val), 0, 16)), /* movw r1 ... */ \ + 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \ + 0xe5801000 + (addr) + +static void zynq_write_board_setup(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + int n; + uint32_t board_setup_blob[] = { + 0xe3a004f8, /* mov r0, #0xf8000000 */ + SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY), + SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008), + SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY), + 0xe12fff1e, /* bx lr */ + }; + for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { + board_setup_blob[n] = tswap32(board_setup_blob[n]); + } + rom_add_blob_fixed("board-setup", board_setup_blob, + sizeof(board_setup_blob), BOARD_SETUP_ADDR); +} + static struct arm_boot_info zynq_binfo = {}; static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) @@ -113,10 +158,11 @@ static void zynq_init(MachineState *machine) MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); - DeviceState *dev; + DeviceState *dev, *carddev; SysBusDevice *busdev; + DriveInfo *di; + BlockBackend *blk; qemu_irq pic[64]; - Error *err = NULL; int n; if (!cpu_model) { @@ -131,29 +177,14 @@ static void zynq_init(MachineState *machine) * realization. */ if (object_property_find(OBJECT(cpu), "has_el3", NULL)) { - object_property_set_bool(OBJECT(cpu), false, "has_el3", &err); - if (err) { - error_report_err(err); - exit(1); - } - } - - object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err); - if (err) { - error_report_err(err); - exit(1); + object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal); } - object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", &err); - if (err) { - error_report_err(err); - exit(1); - } - object_property_set_bool(OBJECT(cpu), true, "realized", &err); - if (err) { - error_report_err(err); - exit(1); - } + object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", + &error_fatal); + object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", + &error_fatal); + object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal); /* max 2GB ram */ if (ram_size > 0x80000000) { @@ -167,7 +198,7 @@ static void zynq_init(MachineState *machine) /* 256K of on-chip memory */ memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10, - &error_abort); + &error_fatal); vmstate_register_ram_global(ocm_ram); memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram); @@ -220,11 +251,28 @@ static void zynq_init(MachineState *machine) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + 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"); 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]); + di = drive_get_next(IF_SD); + blk = di ? blk_by_legacy_dinfo(di) : NULL; + carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); + + dev = qdev_create(NULL, TYPE_ZYNQ_XADC); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]); + dev = qdev_create(NULL, "pl330"); qdev_prop_set_uint8(dev, "num_chnls", 8); qdev_prop_set_uint8(dev, "num_periph_req", 4); @@ -252,21 +300,19 @@ static void zynq_init(MachineState *machine) zynq_binfo.nb_cpus = 1; zynq_binfo.board_id = 0xd32; zynq_binfo.loader_start = 0; + zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR; + zynq_binfo.write_board_setup = zynq_write_board_setup; + arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo); } -static QEMUMachine zynq_machine = { - .name = "xilinx-zynq-a9", - .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9", - .init = zynq_init, - .block_default_type = IF_SCSI, - .max_cpus = 1, - .no_sdcard = 1, -}; - -static void zynq_machine_init(void) +static void zynq_machine_init(MachineClass *mc) { - qemu_register_machine(&zynq_machine); + mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; + mc->init = zynq_init; + mc->block_default_type = IF_SCSI; + mc->max_cpus = 1; + mc->no_sdcard = 1; } -machine_init(zynq_machine_init); +DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init) diff --git a/qemu/hw/arm/xlnx-ep108.c b/qemu/hw/arm/xlnx-ep108.c index f94da86cb..5f480182b 100644 --- a/qemu/hw/arm/xlnx-ep108.c +++ b/qemu/hw/arm/xlnx-ep108.c @@ -15,6 +15,10 @@ * for more details. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/arm/xlnx-zynqmp.h" #include "hw/boards.h" #include "qemu/error-report.h" @@ -25,42 +29,76 @@ typedef struct XlnxEP108 { MemoryRegion ddr_ram; } XlnxEP108; -/* Max 2GB RAM */ -#define EP108_MAX_RAM_SIZE 0x80000000ull - static struct arm_boot_info xlnx_ep108_binfo; static void xlnx_ep108_init(MachineState *machine) { XlnxEP108 *s = g_new0(XlnxEP108, 1); - Error *err = NULL; + int i; + uint64_t ram_size = machine->ram_size; + + /* Create the memory region to pass to the SoC */ + if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) { + error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of " + "0x%llx", ram_size, + XLNX_ZYNQMP_MAX_RAM_SIZE); + exit(1); + } + + if (ram_size < 0x08000000) { + qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108", + ram_size); + } + + memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", + ram_size); object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP); object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); - if (err) { - error_report("%s", error_get_pretty(err)); - exit(1); - } + object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram), + "ddr-ram", &error_abort); - if (machine->ram_size > EP108_MAX_RAM_SIZE) { - error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " - "reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE); - machine->ram_size = EP108_MAX_RAM_SIZE; - } + object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); + + /* Create and plug in the SD cards */ + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + BusState *bus; + DriveInfo *di = drive_get_next(IF_SD); + BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; + DeviceState *carddev; + char *bus_name; - if (machine->ram_size <= 0x08000000) { - qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108", - machine->ram_size); + bus_name = g_strdup_printf("sd-bus%d", i); + bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name); + g_free(bus_name); + if (!bus) { + error_report("No SD bus found for SD card %d", i); + exit(1); + } + carddev = qdev_create(bus, TYPE_SD_CARD); + qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(carddev), true, "realized", + &error_fatal); } - memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", - machine->ram_size); - memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram); + for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { + SSIBus *spi_bus; + DeviceState *flash_dev; + qemu_irq cs_line; + gchar *bus_name = g_strdup_printf("spi%d", i); + + spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); + g_free(bus_name); - xlnx_ep108_binfo.ram_size = machine->ram_size; + flash_dev = ssi_create_slave(spi_bus, "sst25wf080"); + cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line); + } + + xlnx_ep108_binfo.ram_size = ram_size; xlnx_ep108_binfo.kernel_filename = machine->kernel_filename; xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline; xlnx_ep108_binfo.initrd_filename = machine->initrd_filename; @@ -68,15 +106,10 @@ static void xlnx_ep108_init(MachineState *machine) arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_ep108_binfo); } -static QEMUMachine xlnx_ep108_machine = { - .name = "xlnx-ep108", - .desc = "Xilinx ZynqMP EP108 board", - .init = xlnx_ep108_init, -}; - -static void xlnx_ep108_machine_init(void) +static void xlnx_ep108_machine_init(MachineClass *mc) { - qemu_register_machine(&xlnx_ep108_machine); + mc->desc = "Xilinx ZynqMP EP108 board"; + mc->init = xlnx_ep108_init; } -machine_init(xlnx_ep108_machine_init); +DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init) diff --git a/qemu/hw/arm/xlnx-zynqmp.c b/qemu/hw/arm/xlnx-zynqmp.c index 62ef4ceb3..4d504da64 100644 --- a/qemu/hw/arm/xlnx-zynqmp.c +++ b/qemu/hw/arm/xlnx-zynqmp.c @@ -15,6 +15,10 @@ * for more details. */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/arm/xlnx-zynqmp.h" #include "hw/intc/arm_gic_common.h" #include "exec/address-spaces.h" @@ -28,6 +32,10 @@ #define GIC_DIST_ADDR 0xf9010000 #define GIC_CPU_ADDR 0xf9020000 +#define SATA_INTR 133 +#define SATA_ADDR 0xFD0C0000 +#define SATA_NUM_PORTS 2 + static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, }; @@ -44,6 +52,22 @@ static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = { 21, 22, }; +static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = { + 0xFF160000, 0xFF170000, +}; + +static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = { + 48, 49, +}; + +static const uint64_t spi_addr[XLNX_ZYNQMP_NUM_SPIS] = { + 0xFF040000, 0xFF050000, +}; + +static const int spi_intr[XLNX_ZYNQMP_NUM_SPIS] = { + 19, 20, +}; + typedef struct XlnxZynqMPGICRegion { int region_index; uint32_t address; @@ -78,6 +102,11 @@ static void xlnx_zynqmp_init(Object *obj) &error_abort); } + object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION, + (Object **)&s->ddr_ram, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); + object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); @@ -90,6 +119,22 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART); qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); } + + object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI); + qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); + + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]), + TYPE_SYSBUS_SDHCI); + qdev_set_parent_bus(DEVICE(&s->sdhci[i]), + sysbus_get_default()); + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { + object_initialize(&s->spi[i], sizeof(s->spi[i]), + TYPE_XILINX_SPIPS); + qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); + } } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -97,16 +142,63 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) XlnxZynqMPState *s = XLNX_ZYNQMP(dev); MemoryRegion *system_memory = get_system_memory(); uint8_t i; + uint64_t ram_size; const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]"; + ram_addr_t ddr_low_size, ddr_high_size; qemu_irq gic_spi[GIC_NUM_SPI_INTR]; Error *err = NULL; + ram_size = memory_region_size(s->ddr_ram); + + /* Create the DDR Memory Regions. User friendly checks should happen at + * the board level + */ + if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) { + /* The RAM size is above the maximum available for the low DDR. + * Create the high DDR memory region as well. + */ + assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE); + ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE; + ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE; + + memory_region_init_alias(&s->ddr_ram_high, NULL, + "ddr-ram-high", s->ddr_ram, + ddr_low_size, ddr_high_size); + memory_region_add_subregion(get_system_memory(), + XLNX_ZYNQMP_HIGH_RAM_START, + &s->ddr_ram_high); + } else { + /* RAM must be non-zero */ + assert(ram_size); + ddr_low_size = ram_size; + } + + memory_region_init_alias(&s->ddr_ram_low, NULL, + "ddr-ram-low", s->ddr_ram, + 0, ddr_low_size); + memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low); + + /* Create the four OCM banks */ + for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) { + char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i); + + memory_region_init_ram(&s->ocm_ram[i], NULL, ocm_name, + XLNX_ZYNQMP_OCM_RAM_SIZE, &error_fatal); + vmstate_register_ram_global(&s->ocm_ram[i]); + memory_region_add_subregion(get_system_memory(), + XLNX_ZYNQMP_OCM_RAM_0_ADDRESS + + i * XLNX_ZYNQMP_OCM_RAM_SIZE, + &s->ocm_ram[i]); + + g_free(ocm_name); + } + qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS); object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err) { - error_propagate((errp), (err)); + error_propagate(errp, err); return; } assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS); @@ -147,16 +239,11 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(name); object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &err); - if (err) { - error_propagate((errp), (err)); - return; - } - + "reset-cbar", &error_abort); object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", &err); if (err) { - error_propagate((errp), (err)); + error_propagate(errp, err); return; } @@ -185,22 +272,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(name); object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", - &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - + &error_abort); object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", &err); if (err) { - error_propagate((errp), (err)); + error_propagate(errp, err); return; } } if (!s->boot_cpu_ptr) { - error_setg(errp, "ZynqMP Boot cpu %s not found\n", boot_cpu); + error_setg(errp, "ZynqMP Boot cpu %s not found", boot_cpu); return; } @@ -217,7 +299,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); if (err) { - error_propagate((errp), (err)); + error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]); @@ -228,13 +310,62 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); if (err) { - error_propagate((errp), (err)); + error_propagate(errp, err); return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, gic_spi[uart_intr[i]]); } + + object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", + &error_abort); + object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]); + + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + char *bus_name; + + object_property_set_bool(OBJECT(&s->sdhci[i]), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0, + sdhci_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0, + gic_spi[sdhci_intr[i]]); + /* Alias controller SD bus to the SoC itself */ + bus_name = g_strdup_printf("sd-bus%d", i); + object_property_add_alias(OBJECT(s), bus_name, + OBJECT(&s->sdhci[i]), "sd-bus", + &error_abort); + g_free(bus_name); + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { + gchar *bus_name; + + object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, + gic_spi[spi_intr[i]]); + + /* Alias controller SPI bus to the SoC itself */ + bus_name = g_strdup_printf("spi%d", i); + object_property_add_alias(OBJECT(s), bus_name, + OBJECT(&s->spi[i]), "spi0", + &error_abort); + g_free(bus_name); + } } static Property xlnx_zynqmp_props[] = { @@ -248,6 +379,12 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data) dc->props = xlnx_zynqmp_props; dc->realize = xlnx_zynqmp_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo xlnx_zynqmp_type_info = { diff --git a/qemu/hw/arm/z2.c b/qemu/hw/arm/z2.c index 17355479a..aea895a50 100644 --- a/qemu/hw/arm/z2.c +++ b/qemu/hw/arm/z2.c @@ -11,12 +11,13 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/arm/arm.h" #include "hw/devices.h" #include "hw/i2c/i2c.h" -#include "hw/ssi.h" +#include "hw/ssi/ssi.h" #include "hw/boards.h" #include "sysemu/sysemu.h" #include "hw/block/flash.h" @@ -372,15 +373,10 @@ static void z2_init(MachineState *machine) arm_load_kernel(mpu->cpu, &z2_binfo); } -static QEMUMachine z2_machine = { - .name = "z2", - .desc = "Zipit Z2 (PXA27x)", - .init = z2_init, -}; - -static void z2_machine_init(void) +static void z2_machine_init(MachineClass *mc) { - qemu_register_machine(&z2_machine); + mc->desc = "Zipit Z2 (PXA27x)"; + mc->init = z2_init; } -machine_init(z2_machine_init); +DEFINE_MACHINE("z2", z2_machine_init) |