From bcf48274ba6fbe6158beccd9d4be4c22931f33b9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 01/25] docs/generic-loader: Update the document This patch does three things: - It adds a list of restrictions and ToDos - It corrects the header --- lines to match the length of the header - It clarifies the force-raw option Signed-off-by: Alistair Francis Reviewed-by: Markus Armbruster Message-id: e75d1d285cf8f45037c41ebe1bc3f68120f09cb9.1475702918.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- docs/generic-loader.txt | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/generic-loader.txt b/docs/generic-loader.txt index 8fcb550414..31bbcd42f6 100644 --- a/docs/generic-loader.txt +++ b/docs/generic-loader.txt @@ -8,7 +8,7 @@ The 'loader' device allows the user to load multiple images or values into QEMU at startup. Loading Data into Memory Values ---------------------- +------------------------------- The loader device allows memory values to be set from the command line. This can be done by following the syntax below: @@ -36,7 +36,7 @@ An example of loading value 0x8000000e to address 0xfd1a0104 is: -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 Setting a CPU's Program Counter ---------------------- +------------------------------- The loader device allows the CPU's PC to be set from the command line. This can be done by following the syntax below: @@ -55,9 +55,10 @@ An example of setting CPU 0's PC to 0x8000 is: -device loader,addr=0x8000,cpu-num=0 Loading Files ---------------------- -The loader device also allows files to be loaded into memory. This can be done -similarly to setting memory values. The syntax is shown below: +------------- +The loader device also allows files to be loaded into memory. It can load raw +files and ELF executable files. Raw files are loaded verbatim. ELF executable +files are loaded by an ELF loader. The syntax is shown below: -device loader,file=[,addr=][,cpu-num=][,force-raw=] @@ -72,8 +73,8 @@ similarly to setting memory values. The syntax is shown below: for the boot image. This will also cause the image to be written to the specified CPU's address space. If not specified, the default is CPU 0. - - Forces the file to be treated as a raw image. This can be - used to specify the load address of ELF files. + - Setting force-raw=on forces the file to be treated as a raw + image. This can be used to load ELF files as if they were raw. All values are parsed using the standard QemuOps parsing. This allows the user to specify any values in any format supported. By default the values @@ -82,3 +83,10 @@ with a '0x'. An example of loading an ELF file which CPU0 will boot is shown below: -device loader,file=./images/boot.elf,cpu-num=0 + +Restrictions and ToDos +---------------------- + - At the moment it is just assumed that if you specify a cpu-num then you + want to set the PC as well. This might not always be the case. In future + the internal state 'set_pc' (which exists in the generic loader now) should + be exposed to the user so that they can choose if the PC is set or not. From cabbcca0375a96f2e0ccae660ca9dc1510adafbd Mon Sep 17 00:00:00 2001 From: Rutuja Shah Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 02/25] Reducing stack frame size in stream_process_mem2s() This patch allocates memory for txbuf in struct Stream rather than the stack. As a result, the stack frame size is reduced of stream_process_mem2s(). Signed-off-by: Rutuja Shah Reviewed-by: Edgar E. Iglesias Reviewed-by: Stefan Hajnoczi Reviewed-by: Alistair Francis Signed-off-by: Peter Maydell --- hw/dma/xilinx_axidma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index b135a5ff12..6065689ad1 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -111,6 +111,7 @@ struct Stream { unsigned int complete_cnt; uint32_t regs[R_MAX]; uint8_t app[20]; + unsigned char txbuf[16 * 1024]; }; struct XilinxAXIDMAStreamSlave { @@ -256,7 +257,6 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, StreamSlave *tx_control_dev) { uint32_t prev_d; - unsigned char txbuf[16 * 1024]; unsigned int txlen; if (!stream_running(s) || stream_idle(s)) { @@ -277,17 +277,17 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, } txlen = s->desc.control & SDESC_CTRL_LEN_MASK; - if ((txlen + s->pos) > sizeof txbuf) { + if ((txlen + s->pos) > sizeof s->txbuf) { hw_error("%s: too small internal txbuf! %d\n", __func__, txlen + s->pos); } cpu_physical_memory_read(s->desc.buffer_address, - txbuf + s->pos, txlen); + s->txbuf + s->pos, txlen); s->pos += txlen; if (stream_desc_eof(&s->desc)) { - stream_push(tx_data_dev, txbuf, s->pos); + stream_push(tx_data_dev, s->txbuf, s->pos); s->pos = 0; stream_complete(s); } From 4344af65e7448b3d03b060d0844d92e0cc6bcc2b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 03/25] target-arm: kvm: use AddressSpace-specific listener The only address space where the GIC devices are added is address_space_memory. There is no need to use a global MemoryListener. This removes the only user of global MemoryListeners. Signed-off-by: Paolo Bonzini [PMM: added missing #include "exec/address-spaces.h"] Reviewed-by: Peter Maydell Message-id: 1475219846-32609-1-git-send-email-pbonzini@redhat.com Signed-off-by: Peter Maydell --- target-arm/kvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index dbe393c109..c00b94e42a 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -23,6 +23,7 @@ #include "internals.h" #include "hw/arm/arm.h" #include "exec/memattrs.h" +#include "exec/address-spaces.h" #include "hw/boards.h" #include "qemu/log.h" @@ -283,7 +284,7 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, } if (QSLIST_EMPTY(&kvm_devices_head)) { - memory_listener_register(&devlistener, NULL); + memory_listener_register(&devlistener, &address_space_memory); qemu_add_machine_init_done_notifier(¬ify); } kd = g_new0(KVMDevice, 1); From 0e5803dfbce6cf056fe15b3b5cb31fe8519a6f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 04/25] aspeed: rename the smc object to fmc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Aspeed SoC has three different types of SMC (Static Memory Controller) controllers: the SMC (legacy), the FMC (the new one) and the SPI for the host PNOR. The FMC and the SPI models are now converging on the AST2500 SoC and the SMC, which was still available on the AST2400 SoC, was removed. The Aspeed SoC does not provide support for the legacy SMC controller. So, let's rename the 'smc' object to 'fmc' to clarify its nature. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-2-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 2 +- hw/arm/aspeed_soc.c | 18 +++++++++--------- include/hw/arm/aspeed_soc.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 6b18c7f172..4bb33cbb5e 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -128,7 +128,7 @@ static void aspeed_board_init(MachineState *machine, object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); + aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort); aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); aspeed_board_binfo.kernel_filename = machine->kernel_filename; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index c0a3102058..479c0d2039 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -100,9 +100,9 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2", &error_abort); - object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc"); - object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL); - qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default()); + object_initialize(&s->fmc, sizeof(s->fmc), "aspeed.smc.fmc"); + object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); + qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi"); object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL); @@ -178,17 +178,17 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); - /* SMC */ - object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err); + /* FMC */ + object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err); + object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SOC_FMC_FLASH_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, qdev_get_gpio_in(DEVICE(&s->vic), 19)); /* SPI */ diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 932704c380..7359e25fce 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -31,7 +31,7 @@ typedef struct AspeedSoCState { AspeedTimerCtrlState timerctrl; AspeedI2CState i2c; AspeedSCUState scu; - AspeedSMCState smc; + AspeedSMCState fmc; AspeedSMCState spi; AspeedSDMCState sdmc; } AspeedSoCState; From dcb834447f7b22b08a918e2266e5751035fbfc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 05/25] aspeed: move the flash module mapping address under the controller definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will ease the definition of the new controllers for the AST2500 SoC and also ease the support of the segment registers, which provide a way to reconfigure the mapping window of each slave. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-3-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 9 ++++----- hw/ssi/aspeed_smc.c | 15 +++++++++++---- include/hw/ssi/aspeed_smc.h | 3 ++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 479c0d2039..80ad7322bd 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -31,9 +31,6 @@ #define ASPEED_SOC_TIMER_BASE 0x1E782000 #define ASPEED_SOC_I2C_BASE 0x1E78A000 -#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 - static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; @@ -187,7 +184,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SOC_FMC_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, + s->fmc.ctrl->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, qdev_get_gpio_in(DEVICE(&s->vic), 19)); @@ -200,7 +198,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, + s->spi.ctrl->flash_window_base); /* SDMC - SDRAM Memory Controller */ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index d319e04a27..84c18299de 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -127,6 +127,10 @@ #define R_SPI_MISC_CTRL (0x10 / 4) #define R_SPI_TIMINGS (0x14 / 4) +#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 +#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 +#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 + /* * Default segments mapping addresses and size for each slave per * controller. These can be changed when board is initialized with the @@ -151,11 +155,14 @@ static const AspeedSegments aspeed_segments_spi[] = { static const AspeedSMCController controllers[] = { { "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_legacy, 0x6000000 }, + CONF_ENABLE_W0, 5, aspeed_segments_legacy, + ASPEED_SOC_SMC_FLASH_BASE, 0x6000000 }, { "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_fmc, 0x10000000 }, + CONF_ENABLE_W0, 5, aspeed_segments_fmc, + ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 }, { "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS, - SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, 0x10000000 }, + SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, + ASPEED_SOC_SPI_FLASH_BASE, 0x10000000 }, }; static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, @@ -395,7 +402,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->mmio_flash, OBJECT(s), &aspeed_smc_flash_default_ops, s, name, - s->ctrl->mapping_window_size); + s->ctrl->flash_window_size); sysbus_init_mmio(sbd, &s->mmio_flash); s->flashes = g_new0(AspeedSMCFlash, s->num_cs); diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index def3b4507e..bdfbcc0ffa 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -42,7 +42,8 @@ typedef struct AspeedSMCController { uint8_t conf_enable_w0; uint8_t max_slaves; const AspeedSegments *segments; - uint32_t mapping_window_size; + hwaddr flash_window_base; + uint32_t flash_window_size; } AspeedSMCController; typedef struct AspeedSMCFlash { From dbcabeeb54e9101307cf6225b9311a3ceaab7d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 06/25] aspeed: extend the number of host SPI controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2500 SoC has two. Let's prepare ground for the next changes which will add the required definitions for the second host SPI controller. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-4-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 2 +- hw/arm/aspeed_soc.c | 44 ++++++++++++++++++++++++------------- include/hw/arm/aspeed_soc.h | 6 ++++- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 4bb33cbb5e..c7206fda6d 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -129,7 +129,7 @@ static void aspeed_board_init(MachineState *machine, &error_abort); aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort); - aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi[0], "mx25l25635e", &error_abort); aspeed_board_binfo.kernel_filename = machine->kernel_filename; aspeed_board_binfo.initrd_filename = machine->initrd_filename; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 80ad7322bd..b3103f3373 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -37,10 +37,17 @@ static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; #define AST2400_SDRAM_BASE 0x40000000 #define AST2500_SDRAM_BASE 0x80000000 +static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE }; + +static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE }; + static const AspeedSoCInfo aspeed_socs[] = { - { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, - { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, - { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE }, + { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, + 1, aspeed_soc_ast2400_spi_bases }, + { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, + 1, aspeed_soc_ast2400_spi_bases }, + { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, + 1, aspeed_soc_ast2500_spi_bases }, }; /* @@ -72,6 +79,7 @@ static void aspeed_soc_init(Object *obj) { AspeedSoCState *s = ASPEED_SOC(obj); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i; s->cpu = cpu_arm_init(sc->info->cpu_model); @@ -101,9 +109,11 @@ static void aspeed_soc_init(Object *obj) object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); - object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi"); - object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL); - qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default()); + for (i = 0; i < sc->info->spis_num; i++) { + object_initialize(&s->spi[i], sizeof(s->spi[i]), "aspeed.smc.spi"); + object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); + qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); + } object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); @@ -118,6 +128,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) { int i; AspeedSoCState *s = ASPEED_SOC(dev); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); Error *err = NULL, *local_err = NULL; /* IO space */ @@ -190,16 +201,19 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->vic), 19)); /* SPI */ - object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err); - error_propagate(&err, local_err); - if (err) { - error_propagate(errp, err); - return; + for (i = 0; i < sc->info->spis_num; i++) { + object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); + object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", + &local_err); + error_propagate(&err, local_err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, + s->spi[i].ctrl->flash_window_base); } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, - s->spi.ctrl->flash_window_base); /* SDMC - SDRAM Memory Controller */ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 7359e25fce..f26a9f0439 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -20,6 +20,8 @@ #include "hw/i2c/aspeed_i2c.h" #include "hw/ssi/aspeed_smc.h" +#define ASPEED_SPIS_NUM 2 + typedef struct AspeedSoCState { /*< private >*/ DeviceState parent; @@ -32,7 +34,7 @@ typedef struct AspeedSoCState { AspeedI2CState i2c; AspeedSCUState scu; AspeedSMCState fmc; - AspeedSMCState spi; + AspeedSMCState spi[ASPEED_SPIS_NUM]; AspeedSDMCState sdmc; } AspeedSoCState; @@ -44,6 +46,8 @@ typedef struct AspeedSoCInfo { const char *cpu_model; uint32_t silicon_rev; hwaddr sdram_base; + int spis_num; + const hwaddr *spi_bases; } AspeedSoCInfo; typedef struct AspeedSoCClass { From 6dc52326ccbb826c3b61aa1429001a79d34be1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:16 +0100 Subject: [PATCH 07/25] aspeed: add support for the AST2500 SoC SMC controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SMC controllers on the Aspeed AST2500 SoC are very similar to the ones found on the AST2400. The differences are on the number of supported flash modules and their default mappings in the SoC address space. The Aspeed AST2500 has one SPI controller for the BMC firmware and two for the host firmware. All controllers have now the same set of registers compatible with the AST2400 FMC controller and the legacy 'SMC' controller is fully gone. We keep the FMC object to act as the BMC SPI controller and add a new SPI controller for the host. We also have to introduce new type names to handle the differences in the flash modules memory mappping. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-5-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 21 +++++++++++++++------ hw/ssi/aspeed_smc.c | 28 +++++++++++++++++++++++++++- include/hw/arm/aspeed_soc.h | 2 ++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index b3103f3373..e14f5c217e 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -25,6 +25,7 @@ #define ASPEED_SOC_IOMEM_BASE 0x1E600000 #define ASPEED_SOC_FMC_BASE 0x1E620000 #define ASPEED_SOC_SPI_BASE 0x1E630000 +#define ASPEED_SOC_SPI2_BASE 0x1E631000 #define ASPEED_SOC_VIC_BASE 0x1E6C0000 #define ASPEED_SOC_SDMC_BASE 0x1E6E0000 #define ASPEED_SOC_SCU_BASE 0x1E6E2000 @@ -38,16 +39,23 @@ static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; #define AST2500_SDRAM_BASE 0x80000000 static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE }; +static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" }; -static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE }; +static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE, + ASPEED_SOC_SPI2_BASE}; +static const char *aspeed_soc_ast2500_typenames[] = { + "aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" }; static const AspeedSoCInfo aspeed_socs[] = { { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases }, + 1, aspeed_soc_ast2400_spi_bases, + "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases }, + 1, aspeed_soc_ast2400_spi_bases, + "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, - 1, aspeed_soc_ast2500_spi_bases }, + 2, aspeed_soc_ast2500_spi_bases, + "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames }, }; /* @@ -105,12 +113,13 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2", &error_abort); - object_initialize(&s->fmc, sizeof(s->fmc), "aspeed.smc.fmc"); + object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); for (i = 0; i < sc->info->spis_num; i++) { - object_initialize(&s->spi[i], sizeof(s->spi[i]), "aspeed.smc.spi"); + object_initialize(&s->spi[i], sizeof(s->spi[i]), + sc->info->spi_typename[i]); object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); } diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 84c18299de..21943f4e5d 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -130,6 +130,7 @@ #define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 #define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 #define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 +#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000 /* * Default segments mapping addresses and size for each slave per @@ -142,7 +143,7 @@ static const AspeedSegments aspeed_segments_legacy[] = { }; static const AspeedSegments aspeed_segments_fmc[] = { - { 0x20000000, 64 * 1024 * 1024 }, + { 0x20000000, 64 * 1024 * 1024 }, /* start address is readonly */ { 0x24000000, 32 * 1024 * 1024 }, { 0x26000000, 32 * 1024 * 1024 }, { 0x28000000, 32 * 1024 * 1024 }, @@ -153,6 +154,22 @@ static const AspeedSegments aspeed_segments_spi[] = { { 0x30000000, 64 * 1024 * 1024 }, }; +static const AspeedSegments aspeed_segments_ast2500_fmc[] = { + { 0x20000000, 128 * 1024 * 1024 }, /* start address is readonly */ + { 0x28000000, 32 * 1024 * 1024 }, + { 0x2A000000, 32 * 1024 * 1024 }, +}; + +static const AspeedSegments aspeed_segments_ast2500_spi1[] = { + { 0x30000000, 32 * 1024 * 1024 }, /* start address is readonly */ + { 0x32000000, 96 * 1024 * 1024 }, /* end address is readonly */ +}; + +static const AspeedSegments aspeed_segments_ast2500_spi2[] = { + { 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */ + { 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */ +}; + static const AspeedSMCController controllers[] = { { "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, CONF_ENABLE_W0, 5, aspeed_segments_legacy, @@ -163,6 +180,15 @@ static const AspeedSMCController controllers[] = { { "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS, SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, ASPEED_SOC_SPI_FLASH_BASE, 0x10000000 }, + { "aspeed.smc.ast2500-fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 3, aspeed_segments_ast2500_fmc, + ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 }, + { "aspeed.smc.ast2500-spi1", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi1, + ASPEED_SOC_SPI_FLASH_BASE, 0x8000000 }, + { "aspeed.smc.ast2500-spi2", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi2, + ASPEED_SOC_SPI2_FLASH_BASE, 0x8000000 }, }; static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index f26a9f0439..5406b498d7 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -48,6 +48,8 @@ typedef struct AspeedSoCInfo { hwaddr sdram_base; int spis_num; const hwaddr *spi_bases; + const char *fmc_typename; + const char **spi_typename; } AspeedSoCInfo; typedef struct AspeedSoCClass { From 2da95fd88b87bd90e39caeaf94943023b85dbe93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 08/25] aspeed: create mapping regions for the maximum number of slaves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SMC controller on the Aspeed SoC has a set of registers to configure the mapping of each flash module in the SoC address space. These mapping windows are configurable even though no SPI slave is attached to the controller. Also rewrite a bit the comments in the code on this topic. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-6-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/ssi/aspeed_smc.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 21943f4e5d..ecf39ccfde 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -417,12 +417,15 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) aspeed_smc_reset(dev); + /* The memory region for the controller registers */ memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, s->ctrl->name, ASPEED_SMC_R_MAX * 4); sysbus_init_mmio(sbd, &s->mmio); /* - * Memory region where flash modules are remapped + * The container memory region representing the address space + * window in which the flash modules are mapped. The size and + * address depends on the SoC model and controller type. */ snprintf(name, sizeof(name), "%s.flash", s->ctrl->name); @@ -431,9 +434,16 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) s->ctrl->flash_window_size); sysbus_init_mmio(sbd, &s->mmio_flash); - s->flashes = g_new0(AspeedSMCFlash, s->num_cs); + s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_slaves); - for (i = 0; i < s->num_cs; ++i) { + /* + * Let's create a sub memory region for each possible slave. All + * have a configurable memory segment in the overall flash mapping + * window of the controller but, there is not necessarily a flash + * module behind to handle the memory accesses. This depends on + * the board configuration. + */ + for (i = 0; i < s->ctrl->max_slaves; ++i) { AspeedSMCFlash *fl = &s->flashes[i]; snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i); From a03cb1daf1a4e6ccce8632e13373eef8c4f9cba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 09/25] aspeed: add support for the SMC segment registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SMC controller on the Aspeed SoC has a set of registers to configure the mapping of each flash module in the SoC address space. Writing to these registers triggers a remap of the memory region and the spec requires a certain number of checks before doing so. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1474977462-28032-7-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/ssi/aspeed_smc.c | 135 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index ecf39ccfde..6e8403ebc2 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -79,10 +79,10 @@ /* CEx Segment Address Register */ #define R_SEG_ADDR0 (0x30 / 4) -#define SEG_SIZE_SHIFT 24 /* 8MB units */ -#define SEG_SIZE_MASK 0x7f +#define SEG_END_SHIFT 24 /* 8MB units */ +#define SEG_END_MASK 0xff #define SEG_START_SHIFT 16 /* address bit [A29-A23] */ -#define SEG_START_MASK 0x7f +#define SEG_START_MASK 0xff #define R_SEG_ADDR1 (0x34 / 4) #define R_SEG_ADDR2 (0x38 / 4) #define R_SEG_ADDR3 (0x3C / 4) @@ -135,8 +135,7 @@ /* * Default segments mapping addresses and size for each slave per * controller. These can be changed when board is initialized with the - * Segment Address Registers but they don't seem do be used on the - * field. + * Segment Address Registers. */ static const AspeedSegments aspeed_segments_legacy[] = { { 0x10000000, 32 * 1024 * 1024 }, @@ -191,6 +190,118 @@ static const AspeedSMCController controllers[] = { ASPEED_SOC_SPI2_FLASH_BASE, 0x8000000 }, }; +/* + * The Segment Register uses a 8MB unit to encode the start address + * and the end address of the mapping window of a flash SPI slave : + * + * | byte 1 | byte 2 | byte 3 | byte 4 | + * +--------+--------+--------+--------+ + * | end | start | 0 | 0 | + * + */ +static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg) +{ + uint32_t reg = 0; + reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; + reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; + return reg; +} + +static inline void aspeed_smc_reg_to_segment(uint32_t reg, AspeedSegments *seg) +{ + seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; + seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; +} + +static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, + const AspeedSegments *new, + int cs) +{ + AspeedSegments seg; + int i; + + for (i = 0; i < s->ctrl->max_slaves; i++) { + if (i == cs) { + continue; + } + + aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + i], &seg); + + if (new->addr + new->size > seg.addr && + new->addr < seg.addr + seg.size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment CS%d [ 0x%" + HWADDR_PRIx" - 0x%"HWADDR_PRIx" ] overlaps with " + "CS%d [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, new->addr, new->addr + new->size, + i, seg.addr, seg.addr + seg.size); + return true; + } + } + return false; +} + +static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, + uint64_t new) +{ + AspeedSMCFlash *fl = &s->flashes[cs]; + AspeedSegments seg; + + aspeed_smc_reg_to_segment(new, &seg); + + /* The start address of CS0 is read-only */ + if (cs == 0 && seg.addr != s->ctrl->flash_window_base) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Tried to change CS0 start address to 0x%" + HWADDR_PRIx "\n", s->ctrl->name, seg.addr); + return; + } + + /* + * The end address of the AST2500 spi controllers is also + * read-only. + */ + if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 || + s->ctrl->segments == aspeed_segments_ast2500_spi2) && + cs == s->ctrl->max_slaves && + seg.addr + seg.size != s->ctrl->segments[cs].addr + + s->ctrl->segments[cs].size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Tried to change CS%d end address to 0x%" + HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr); + return; + } + + /* Keep the segment in the overall flash window */ + if (seg.addr + seg.size <= s->ctrl->flash_window_base || + seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : " + "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + return; + } + + /* Check start address vs. alignment */ + if (seg.addr % seg.size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not " + "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + } + + /* And segments should not overlap */ + if (aspeed_smc_flash_overlap(s, &seg, cs)) { + return; + } + + /* All should be fine now to move the region */ + memory_region_transaction_begin(); + memory_region_set_size(&fl->mmio, seg.size); + memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base); + memory_region_set_enabled(&fl->mmio, true); + memory_region_transaction_commit(); + + s->regs[R_SEG_ADDR0 + cs] = new; +} + static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, unsigned size) { @@ -314,6 +425,12 @@ static void aspeed_smc_reset(DeviceState *d) s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; } + /* setup default segment register values for all */ + for (i = 0; i < s->ctrl->max_slaves; ++i) { + s->regs[R_SEG_ADDR0 + i] = + aspeed_smc_segment_to_reg(&s->ctrl->segments[i]); + } + aspeed_smc_update_cs(s); } @@ -334,6 +451,7 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) addr == s->r_timings || addr == s->r_ce_ctrl || addr == R_INTR_CTRL || + (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_slaves) || (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs)) { return s->regs[addr]; } else { @@ -365,6 +483,13 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { s->regs[addr] = value; aspeed_smc_update_cs(s); + } else if (addr >= R_SEG_ADDR0 && + addr < R_SEG_ADDR0 + s->ctrl->max_slaves) { + int cs = addr - R_SEG_ADDR0; + + if (value != s->regs[R_SEG_ADDR0 + cs]) { + aspeed_smc_flash_set_segment(s, cs, value); + } } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); From 4c8afda7d2864023047d466eddd1e8f73a6b072c Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 10/25] hw/arm/boot: allow using a command line specified dtb without a kernel When kernel and device tree are specified in the QEMU commandline, then this device tree may be modified e.g. to add virtio_mmio devices. With a bootloader e.g. on a flash device these extra devices are not available. With this change, the device tree can be specified at the QEMU commandline. The modified device tree made available to the bootloader with the same mechanism already supported by device trees fully generated by QEMU. Signed-off-by: Michael Olbrich Message-id: 1473520054-402-1-git-send-email-m.olbrich@pengutronix.de Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/boot.c | 4 ++-- vl.c | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 1b913a43ca..942416d95a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -773,6 +773,8 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) */ assert(!(info->secure_board_setup && kvm_enabled())); + info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); + /* Load the kernel. */ if (!info->kernel_filename || info->firmware_loaded) { @@ -833,8 +835,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) elf_machine = EM_ARM; } - info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); - if (!info->secondary_cpu_reset_hook) { info->secondary_cpu_reset_hook = default_reset_secondary; } diff --git a/vl.c b/vl.c index c657acdd3c..2569ec24f8 100644 --- a/vl.c +++ b/vl.c @@ -4389,11 +4389,6 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (!linux_boot && qemu_opt_get(machine_opts, "dtb")) { - error_report("-dtb only allowed with -kernel option"); - exit(1); - } - if (semihosting_enabled() && !semihosting_get_argc() && kernel_filename) { /* fall back to the -kernel/-append */ semihosting_arg_fallback(kernel_filename, kernel_cmdline); From 04bb79d1f519ae190acf836ff9e07bef5086fad0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 11/25] hw/dma/pl080: Fix bad bit mask (PL080_CONF_M1 | PL080_CONF_M1) The M1 and M2 bits are both used for configuring the endianness of the AHB master interfaces, so the second PL080_CONF_M1 should be PL080_CONF_M2 instead. Buglink: https://bugs.launchpad.net/qemu/+bug/1631773 Signed-off-by: Thomas Huth Message-id: 1476274451-26567-1-git-send-email-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/dma/pl080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 3bed5c3390..7724c93b8f 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -351,7 +351,7 @@ static void pl080_write(void *opaque, hwaddr offset, break; case 12: /* Configuration */ s->conf = value; - if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { + if (s->conf & (PL080_CONF_M1 | PL080_CONF_M2)) { qemu_log_mask(LOG_UNIMP, "pl080_write: Big-endian DMA not implemented\n"); } From bad07da21c5da7ab3c64817d163c4e9b7b7fa5f2 Mon Sep 17 00:00:00 2001 From: Christopher Covington Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 12/25] hw/intc/arm_gic_kvm: Fix build on aarch64 Remove unused debugging code to fix native building on aarch64. Without this change, the following -Werr output inhibits make from completing. qemu/hw/intc/arm_gic_kvm.c:38:18: error: debug_gic_kvm defined but not used [-Werror=unused-const-variable=] static const int debug_gic_kvm = 0; ^~~~~~~~~~~~~ cc1: all warnings being treated as errors qemu/rules.mak:60: recipe for target 'hw/intc/arm_gic_kvm.o' failed make[1]: *** [hw/intc/arm_gic_kvm.o] Error 1 Makefile:205: recipe for target 'subdir-aarch64-softmmu' failed Signed-off-by: Christopher Covington Reviewed-by: Peter Maydell Message-id: 20161011163202.19720-1-cov@codeaurora.org Signed-off-by: Peter Maydell --- hw/intc/arm_gic_kvm.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index ae7ac58ffd..11729ee902 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -30,20 +30,6 @@ #include "gic_internal.h" #include "vgic_common.h" -//#define DEBUG_GIC_KVM - -#ifdef DEBUG_GIC_KVM -static const int debug_gic_kvm = 1; -#else -static const int debug_gic_kvm = 0; -#endif - -#define DPRINTF(fmt, ...) do { \ - if (debug_gic_kvm) { \ - printf("arm_gic: " fmt , ## __VA_ARGS__); \ - } \ - } while (0) - #define TYPE_KVM_ARM_GIC "kvm-arm-gic" #define KVM_ARM_GIC(obj) \ OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) From 13cda487126fd2079fc67473bee3d2d119052ff1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 13/25] hw/arm/virt-acpi-build: fix MADT generation We can't return early from build_* functions, as build_header is only called at the end. Signed-off-by: Andrew Jones Reviewed-by: Eric Auger Message-id: 1476117341-32690-2-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c77525d33a..779d83d836 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -554,15 +554,13 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - if (!its_class_name()) { - return; + if (its_class_name()) { + gic_its = acpi_data_push(table_data, sizeof *gic_its); + gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; + gic_its->length = sizeof(*gic_its); + gic_its->translation_id = 0; + gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base); } - - gic_its = acpi_data_push(table_data, sizeof *gic_its); - gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; - gic_its->length = sizeof(*gic_its); - gic_its->translation_id = 0; - gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base); } else { gic_msi = acpi_data_push(table_data, sizeof *gic_msi); gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; From 2231f69b4e4523c43aa459cab18ab77c0e29b4d1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 14/25] hw/arm/virt: no ITS on older machine types We should avoid exposing new hardware (through DT and ACPI) on older machine types. This patch keeps 2.7 and older from changing, despite the introduction of ITS support for 2.8. Signed-off-by: Andrew Jones Reviewed-by: Eric Auger Message-id: 1476117341-32690-3-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 2 +- hw/arm/virt.c | 15 +++++++++++---- include/hw/arm/virt-acpi-build.h | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 779d83d836..fa0655a775 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -554,7 +554,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - if (its_class_name()) { + if (its_class_name() && !guest_info->no_its) { gic_its = acpi_data_push(table_data, sizeof *gic_its); gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; gic_its->length = sizeof(*gic_its); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 795740d9bf..895446f17c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -84,6 +84,7 @@ typedef struct { MachineClass parent; VirtBoardInfo *daughterboard; bool disallow_affinity_adjustment; + bool no_its; } VirtMachineClass; typedef struct { @@ -551,7 +552,8 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, + bool secure, bool no_its) { /* We create a standalone GIC */ DeviceState *gicdev; @@ -615,9 +617,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) fdt_add_gic_node(vbi, type); - if (type == 3) { + if (type == 3 && !no_its) { create_its(vbi, gicdev); - } else { + } else if (type == 2) { create_v2m(vbi, pic); } } @@ -1375,7 +1377,7 @@ static void machvirt_init(MachineState *machine) create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); - create_gic(vbi, pic, gic_version, vms->secure); + create_gic(vbi, pic, gic_version, vms->secure, vmc->no_its); fdt_add_pmu_nodes(vbi, gic_version); @@ -1407,6 +1409,7 @@ static void machvirt_init(MachineState *machine) guest_info->irqmap = vbi->irqmap; guest_info->use_highmem = vms->highmem; guest_info->gic_version = gic_version; + guest_info->no_its = vmc->no_its; guest_info_state->machine_done.notify = virt_guest_info_machine_done; qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); @@ -1561,8 +1564,12 @@ static void virt_2_7_instance_init(Object *obj) static void virt_machine_2_7_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + virt_machine_2_8_options(mc); SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7); + /* ITS was introduced with 2.8 */ + vmc->no_its = true; } DEFINE_VIRT_MACHINE(2, 7) diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h index e43330ad65..f5ec749b8f 100644 --- a/include/hw/arm/virt-acpi-build.h +++ b/include/hw/arm/virt-acpi-build.h @@ -33,6 +33,7 @@ typedef struct VirtGuestInfo { const int *irqmap; bool use_highmem; int gic_version; + bool no_its; } VirtGuestInfo; From 7a2334f7205ca7604dc09b77e74511e96d35686a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 15/25] tests: add a m25p80 test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test uses the palmetto platform and the Aspeed SPI controller to test the m25p80 flash module device model. The flash model is defined by the platform (n25q256a) and it would be nice to find way to control it, using a property probably. Signed-off-by: Cédric Le Goater Reviewed-by: Peter Maydell Message-id: 1475787271-28794-1-git-send-email-clg@kaod.org Brainstormed-with: Greg Kurz Signed-off-by: Peter Maydell --- tests/Makefile.include | 2 + tests/m25p80-test.c | 252 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 tests/m25p80-test.c diff --git a/tests/Makefile.include b/tests/Makefile.include index a77777cf9c..33ea83e499 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -295,6 +295,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF) check-qtest-arm-y = tests/tmp105-test$(EXESUF) check-qtest-arm-y += tests/ds1338-test$(EXESUF) +check-qtest-arm-y += tests/m25p80-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c @@ -626,6 +627,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) +tests/m25p80-test$(EXESUF): tests/m25p80-test.o tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y) tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c new file mode 100644 index 0000000000..cb7ec81f1a --- /dev/null +++ b/tests/m25p80-test.c @@ -0,0 +1,252 @@ +/* + * QTest testcase for the M25P80 Flash (Using the Aspeed SPI + * Controller) + * + * Copyright (C) 2016 IBM Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/bswap.h" +#include "libqtest.h" + +/* + * ASPEED SPI Controller registers + */ +#define R_CONF 0x00 +#define CONF_ENABLE_W0 (1 << 16) +#define R_CE_CTRL 0x04 +#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */ +#define R_CTRL0 0x10 +#define CTRL_CE_STOP_ACTIVE (1 << 2) +#define CTRL_USERMODE 0x3 + +#define ASPEED_FMC_BASE 0x1E620000 +#define ASPEED_FLASH_BASE 0x20000000 + +/* + * Flash commands + */ +enum { + JEDEC_READ = 0x9f, + BULK_ERASE = 0xc7, + READ = 0x03, + PP = 0x02, + WREN = 0x6, + EN_4BYTE_ADDR = 0xB7, + ERASE_SECTOR = 0xd8, +}; + +#define FLASH_JEDEC 0x20ba19 /* n25q256a */ +#define FLASH_SIZE (32 * 1024 * 1024) + +#define PAGE_SIZE 256 + +/* + * Use an explicit bswap for the values read/wrote to the flash region + * as they are BE and the Aspeed CPU is LE. + */ +static inline uint32_t make_be32(uint32_t data) +{ + return bswap32(data); +} + +static void spi_conf(uint32_t value) +{ + uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); + + conf |= value; + writel(ASPEED_FMC_BASE + R_CONF, conf); +} + +static void spi_ctrl_start_user(void) +{ + uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); + + ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; + writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); + + ctrl &= ~CTRL_CE_STOP_ACTIVE; + writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); +} + +static void spi_ctrl_stop_user(void) +{ + uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); + + ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; + writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); +} + +static void test_read_jedec(void) +{ + uint32_t jedec = 0x0; + + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, JEDEC_READ); + jedec |= readb(ASPEED_FLASH_BASE) << 16; + jedec |= readb(ASPEED_FLASH_BASE) << 8; + jedec |= readb(ASPEED_FLASH_BASE); + spi_ctrl_stop_user(); + + g_assert_cmphex(jedec, ==, FLASH_JEDEC); +} + +static void read_page(uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_start_user(); + + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, READ); + writel(ASPEED_FLASH_BASE, make_be32(addr)); + + /* Continuous read are supported */ + for (i = 0; i < PAGE_SIZE / 4; i++) { + page[i] = make_be32(readl(ASPEED_FLASH_BASE)); + } + spi_ctrl_stop_user(); +} + +static void test_erase_sector(void) +{ + uint32_t some_page_addr = 0x600 * PAGE_SIZE; + uint32_t page[PAGE_SIZE / 4]; + int i; + + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, ERASE_SECTOR); + writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); + spi_ctrl_stop_user(); + + /* Previous page should be full of zeroes as backend is not + * initialized */ + read_page(some_page_addr - PAGE_SIZE, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0x0); + } + + /* But this one was erased */ + read_page(some_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } +} + +static void test_erase_all(void) +{ + uint32_t some_page_addr = 0x15000 * PAGE_SIZE; + uint32_t page[PAGE_SIZE / 4]; + int i; + + spi_conf(CONF_ENABLE_W0); + + /* Check some random page. Should be full of zeroes as backend is + * not initialized */ + read_page(some_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0x0); + } + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, WREN); + writeb(ASPEED_FLASH_BASE, BULK_ERASE); + spi_ctrl_stop_user(); + + /* Recheck that some random page */ + read_page(some_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } +} + +static void test_write_page(void) +{ + uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */ + uint32_t some_page_addr = 0x15000 * PAGE_SIZE; + uint32_t page[PAGE_SIZE / 4]; + int i; + + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, PP); + writel(ASPEED_FLASH_BASE, make_be32(my_page_addr)); + + /* Fill the page with its own addresses */ + for (i = 0; i < PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4)); + } + spi_ctrl_stop_user(); + + /* Check what was written */ + read_page(my_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, my_page_addr + i * 4); + } + + /* Check some other page. It should be full of 0xff */ + read_page(some_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } +} + +static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; + +int main(int argc, char **argv) +{ + int ret; + int fd; + char *args; + + g_test_init(&argc, &argv, NULL); + + fd = mkstemp(tmp_path); + g_assert(fd >= 0); + ret = ftruncate(fd, FLASH_SIZE); + g_assert(ret == 0); + close(fd); + + args = g_strdup_printf("-m 256 -machine palmetto-bmc " + "-drive file=%s,format=raw,if=mtd", + tmp_path); + qtest_start(args); + + qtest_add_func("/m25p80/read_jedec", test_read_jedec); + qtest_add_func("/m25p80/erase_sector", test_erase_sector); + qtest_add_func("/m25p80/erase_all", test_erase_all); + qtest_add_func("/m25p80/write_page", test_write_page); + + ret = g_test_run(); + + qtest_quit(global_qtest); + unlink(tmp_path); + g_free(args); + return ret; +} From 24b9462544eeb64e1f10feb460b0c704e972ad4e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Oct 2016 19:22:17 +0100 Subject: [PATCH 16/25] tests: cleanup ptimer-test 1) ptimer-test is not a qtest---it runs the ptimer.c code directly in the ptimer-test process 2) ptimer-test has its own stubs file, so there is no need to add more stubs to stubs/vmstate.c Signed-off-by: Paolo Bonzini Reviewed-by: Dmitry Osipenko Signed-off-by: Peter Maydell --- stubs/vmstate.c | 5 ----- tests/Makefile.include | 5 +++-- tests/ptimer-test-stubs.c | 7 +++++++ tests/ptimer-test.c | 22 +++++++++++----------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 94b831e219..65906271d2 100644 --- a/stubs/vmstate.c +++ b/stubs/vmstate.c @@ -3,11 +3,6 @@ #include "migration/vmstate.h" const VMStateDescription vmstate_dummy = {}; -const VMStateInfo vmstate_info_uint8; -const VMStateInfo vmstate_info_uint32; -const VMStateInfo vmstate_info_uint64; -const VMStateInfo vmstate_info_int64; -const VMStateInfo vmstate_info_timer; int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, diff --git a/tests/Makefile.include b/tests/Makefile.include index 33ea83e499..cbe38adc32 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -116,6 +116,8 @@ check-unit-$(CONFIG_REPLICATION) += tests/test-replication$(EXESUF) check-unit-y += tests/test-bufferiszero$(EXESUF) gcov-files-check-bufferiszero-y = util/bufferiszero.c check-unit-y += tests/test-uuid$(EXESUF) +check-unit-y += tests/ptimer-test$(EXESUF) +gcov-files-ptimer-test-y = hw/core/ptimer.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -307,7 +309,6 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) check-qtest-s390x-y = tests/boot-serial-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) -check-qtest-generic-y += tests/ptimer-test$(EXESUF) qapi-schema += alternate-any.json qapi-schema += alternate-array.json @@ -515,6 +516,7 @@ tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \ $(test-util-obj-y) tests/test-base64$(EXESUF): tests/test-base64.o \ libqemuutil.a libqemustub.a +tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o libqemustub.a tests/test-logging$(EXESUF): tests/test-logging.o $(test-util-obj-y) @@ -677,7 +679,6 @@ tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-ob tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o -tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c index 92a22fbb09..e028a81a29 100644 --- a/tests/ptimer-test-stubs.c +++ b/tests/ptimer-test-stubs.c @@ -11,9 +11,16 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "sysemu/replay.h" +#include "migration/vmstate.h" #include "ptimer-test.h" +const VMStateInfo vmstate_info_uint8; +const VMStateInfo vmstate_info_uint32; +const VMStateInfo vmstate_info_uint64; +const VMStateInfo vmstate_info_int64; +const VMStateInfo vmstate_info_timer; + struct QEMUBH { QEMUBHFunc *cb; void *opaque; diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c index f207eeb0eb..7b0ddf64e0 100644 --- a/tests/ptimer-test.c +++ b/tests/ptimer-test.c @@ -505,47 +505,47 @@ static void add_ptimer_tests(uint8_t policy) g_sprintf(policy_name, "default"); } - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/set_count policy=%s", policy_name), ppolicy, check_set_count); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/set_limit policy=%s", policy_name), ppolicy, check_set_limit); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/oneshot policy=%s", policy_name), ppolicy, check_oneshot); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/periodic policy=%s", policy_name), ppolicy, check_periodic); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/on_the_fly_mode_change policy=%s", policy_name), ppolicy, check_on_the_fly_mode_change); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/on_the_fly_period_change policy=%s", policy_name), ppolicy, check_on_the_fly_period_change); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/on_the_fly_freq_change policy=%s", policy_name), ppolicy, check_on_the_fly_freq_change); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/run_with_period_0 policy=%s", policy_name), ppolicy, check_run_with_period_0); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/run_with_delta_0 policy=%s", policy_name), ppolicy, check_run_with_delta_0); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/periodic_with_load_0 policy=%s", policy_name), ppolicy, check_periodic_with_load_0); - qtest_add_data_func( + g_test_add_data_func( g_strdup_printf("/ptimer/oneshot_with_load_0 policy=%s", policy_name), ppolicy, check_oneshot_with_load_0); } From 08426da7dd0a63835dcf3003e9a022c0d5678be7 Mon Sep 17 00:00:00 2001 From: Vijay Kumar B Date: Mon, 17 Oct 2016 19:22:18 +0100 Subject: [PATCH 17/25] pxa2xx: Auto-assign name for i2c bus in i2c_init_bus. If a name is provided, the same name is assigned to both the I2C controllers. Leaving it NULL, causes names to be automatically assigned with an ID suffix, giving unique names to each controller. This helps us to uniquely identify each controller in the device tree, for example when adding an I2C device. Signed-off-by: Vijay Kumar B. Reviewed-by: Deepak S. Message-id: 1476351885-8905-1-git-send-email-vijaykumar@zilogic.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 0241e07d84..98982872d7 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1505,7 +1505,7 @@ static void pxa2xx_i2c_initfn(Object *obj) PXA2xxI2CState *s = PXA2XX_I2C(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - s->bus = i2c_init_bus(dev, "i2c"); + s->bus = i2c_init_bus(dev, NULL); memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s, "pxa2xx-i2c", s->region_size); From 86fb3fa4ed5873b021a362ea26a021f4aeab1bb4 Mon Sep 17 00:00:00 2001 From: Thomas Hanson Date: Mon, 17 Oct 2016 19:22:18 +0100 Subject: [PATCH 18/25] target-arm: Infrastucture changes to enable handling of tagged address loading into PC When capturing the current CPU state for the TB, extract the TBI0 and TBI1 values from the correct TCR for the current EL and then add them to the TB flags field. Then, at the start of code generation for the block, copy the TBI fields into the DisasContext structure. Signed-off-by: Thomas Hanson Message-id: 1476301853-15774-2-git-send-email-thomas.hanson@linaro.org [PMM: drop useless 'extern' keyword on function prototypes; provide CONFIG_USER_ONLY trivial versions of arm_regime_tbi[01]()] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.h | 52 ++++++++++++++++++++++++++++++++++++-- target-arm/helper.c | 46 +++++++++++++++++++++++++++++++++ target-arm/translate-a64.c | 2 ++ target-arm/translate.h | 2 ++ 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 76d824d315..2218c00dad 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -2191,7 +2191,11 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) #define ARM_TBFLAG_BE_DATA_SHIFT 20 #define ARM_TBFLAG_BE_DATA_MASK (1 << ARM_TBFLAG_BE_DATA_SHIFT) -/* Bit usage when in AArch64 state: currently we have no A64 specific bits */ +/* Bit usage when in AArch64 state */ +#define ARM_TBFLAG_TBI0_SHIFT 0 /* TBI0 for EL0/1 or TBI for EL2/3 */ +#define ARM_TBFLAG_TBI0_MASK (0x1ull << ARM_TBFLAG_TBI0_SHIFT) +#define ARM_TBFLAG_TBI1_SHIFT 1 /* TBI1 for EL0/1 */ +#define ARM_TBFLAG_TBI1_MASK (0x1ull << ARM_TBFLAG_TBI1_SHIFT) /* some convenience accessor macros */ #define ARM_TBFLAG_AARCH64_STATE(F) \ @@ -2222,6 +2226,10 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT) #define ARM_TBFLAG_BE_DATA(F) \ (((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT) +#define ARM_TBFLAG_TBI0(F) \ + (((F) & ARM_TBFLAG_TBI0_MASK) >> ARM_TBFLAG_TBI0_SHIFT) +#define ARM_TBFLAG_TBI1(F) \ + (((F) & ARM_TBFLAG_TBI1_MASK) >> ARM_TBFLAG_TBI1_SHIFT) static inline bool bswap_code(bool sctlr_b) { @@ -2319,12 +2327,51 @@ static inline bool arm_cpu_bswap_data(CPUARMState *env) } #endif +#ifndef CONFIG_USER_ONLY +/** + * arm_regime_tbi0: + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * + * Extracts the TBI0 value from the appropriate TCR for the current EL + * + * Returns: the TBI0 value. + */ +uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx); + +/** + * arm_regime_tbi1: + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * + * Extracts the TBI1 value from the appropriate TCR for the current EL + * + * Returns: the TBI1 value. + */ +uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx); +#else +/* We can't handle tagged addresses properly in user-only mode */ +static inline uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return 0; +} + +static inline uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return 0; +} +#endif + static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { + ARMMMUIdx mmu_idx = cpu_mmu_index(env, false); if (is_a64(env)) { *pc = env->pc; *flags = ARM_TBFLAG_AARCH64_STATE_MASK; + /* Get control bits for tagged addresses */ + *flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT); + *flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT); } else { *pc = env->regs[15]; *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT) @@ -2343,7 +2390,8 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, << ARM_TBFLAG_XSCALE_CPAR_SHIFT); } - *flags |= (cpu_mmu_index(env, false) << ARM_TBFLAG_MMUIDX_SHIFT); + *flags |= (mmu_idx << ARM_TBFLAG_MMUIDX_SHIFT); + /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine * states defined in the ARM ARM for software singlestep: * SS_ACTIVE PSTATE.SS State diff --git a/target-arm/helper.c b/target-arm/helper.c index 25f612d493..70e274221c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6720,6 +6720,52 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } +/* Returns TBI0 value for current regime el */ +uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return extract64(tcr->raw_tcr, 20, 1); + } else { + return extract64(tcr->raw_tcr, 37, 1); + } +} + +/* Returns TBI1 value for current regime el */ +uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return 0; + } else { + return extract64(tcr->raw_tcr, 38, 1); + } +} + /* Return the TTBR associated with this translation regime */ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 307e281557..3b15d2cf7f 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -11175,6 +11175,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) dc->condexec_mask = 0; dc->condexec_cond = 0; dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags); + dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags); + dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); diff --git a/target-arm/translate.h b/target-arm/translate.h index dbd7ac83d5..a53f25a407 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -22,6 +22,8 @@ typedef struct DisasContext { int user; #endif ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ + bool tbi0; /* TBI0 for EL0/1 or TBI for EL2/3 */ + bool tbi1; /* TBI1 for EL0/1, not used for EL2/3 */ bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ /* Flag indicating that exceptions from secure mode are routed to EL3. */ From 6feecb8b941f2d21e5645d0b6e0cdb776998121b Mon Sep 17 00:00:00 2001 From: Thomas Hanson Date: Mon, 17 Oct 2016 19:22:18 +0100 Subject: [PATCH 19/25] target-arm: Code changes to implement overwrite of tag field on PC load For BR, BLR and RET instructions, if tagged addresses are enabled, the tag field in the address must be cleared out prior to loading the address into the PC. Depending on the current EL, it will be set to either all 0's or all 1's. Signed-off-by: Thomas Hanson Message-id: 1476301853-15774-3-git-send-email-thomas.hanson@linaro.org [PMM: remove unnecessary gen_a64_set_pc_reg() wrapper, rename gen_a64_set_pc_var() to gen_a64_set_pc(), fix stray misindentation] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/translate-a64.c | 82 +++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 3b15d2cf7f..16716a2c1f 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -41,6 +41,7 @@ static TCGv_i64 cpu_pc; /* Load/store exclusive handling */ static TCGv_i64 cpu_exclusive_high; +static TCGv_i64 cpu_reg(DisasContext *s, int reg); static const char *regnames[] = { "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", @@ -176,6 +177,76 @@ void gen_a64_set_pc_im(uint64_t val) tcg_gen_movi_i64(cpu_pc, val); } +/* Load the PC from a generic TCG variable. + * + * If address tagging is enabled via the TCR TBI bits, then loading + * an address into the PC will clear out any tag in the it: + * + for EL2 and EL3 there is only one TBI bit, and if it is set + * then the address is zero-extended, clearing bits [63:56] + * + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0 + * and TBI1 controls addressses with bit 55 == 1. + * If the appropriate TBI bit is set for the address then + * the address is sign-extended from bit 55 into bits [63:56] + * + * We can avoid doing this for relative-branches, because the + * PC + offset can never overflow into the tag bits (assuming + * that virtual addresses are less than 56 bits wide, as they + * are currently), but we must handle it for branch-to-register. + */ +static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src) +{ + + if (s->current_el <= 1) { + /* Test if NEITHER or BOTH TBI values are set. If so, no need to + * examine bit 55 of address, can just generate code. + * If mixed, then test via generated code + */ + if (s->tbi0 && s->tbi1) { + TCGv_i64 tmp_reg = tcg_temp_new_i64(); + /* Both bits set, sign extension from bit 55 into [63:56] will + * cover both cases + */ + tcg_gen_shli_i64(tmp_reg, src, 8); + tcg_gen_sari_i64(cpu_pc, tmp_reg, 8); + tcg_temp_free_i64(tmp_reg); + } else if (!s->tbi0 && !s->tbi1) { + /* Neither bit set, just load it as-is */ + tcg_gen_mov_i64(cpu_pc, src); + } else { + TCGv_i64 tcg_tmpval = tcg_temp_new_i64(); + TCGv_i64 tcg_bit55 = tcg_temp_new_i64(); + TCGv_i64 tcg_zero = tcg_const_i64(0); + + tcg_gen_andi_i64(tcg_bit55, src, (1ull << 55)); + + if (s->tbi0) { + /* tbi0==1, tbi1==0, so 0-fill upper byte if bit 55 = 0 */ + tcg_gen_andi_i64(tcg_tmpval, src, + 0x00FFFFFFFFFFFFFFull); + tcg_gen_movcond_i64(TCG_COND_EQ, cpu_pc, tcg_bit55, tcg_zero, + tcg_tmpval, src); + } else { + /* tbi0==0, tbi1==1, so 1-fill upper byte if bit 55 = 1 */ + tcg_gen_ori_i64(tcg_tmpval, src, + 0xFF00000000000000ull); + tcg_gen_movcond_i64(TCG_COND_NE, cpu_pc, tcg_bit55, tcg_zero, + tcg_tmpval, src); + } + tcg_temp_free_i64(tcg_zero); + tcg_temp_free_i64(tcg_bit55); + tcg_temp_free_i64(tcg_tmpval); + } + } else { /* EL > 1 */ + if (s->tbi0) { + /* Force tag byte to all zero */ + tcg_gen_andi_i64(cpu_pc, src, 0x00FFFFFFFFFFFFFFull); + } else { + /* Load unmodified address */ + tcg_gen_mov_i64(cpu_pc, src); + } + } +} + typedef struct DisasCompare64 { TCGCond cond; TCGv_i64 value; @@ -1704,12 +1775,13 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) switch (opc) { case 0: /* BR */ - case 2: /* RET */ - tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); - break; case 1: /* BLR */ - tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn)); - tcg_gen_movi_i64(cpu_reg(s, 30), s->pc); + case 2: /* RET */ + gen_a64_set_pc(s, cpu_reg(s, rn)); + /* BLR also needs to load return address */ + if (opc == 1) { + tcg_gen_movi_i64(cpu_reg(s, 30), s->pc); + } break; case 4: /* ERET */ if (s->current_el == 0) { From 957956b3013c8122a749dfe61a41aef8b4100e31 Mon Sep 17 00:00:00 2001 From: Thomas Hanson Date: Mon, 17 Oct 2016 19:22:18 +0100 Subject: [PATCH 20/25] target-arm: Comments added to identify cases in a switch 3 cases in a switch in disas_exc() require reference to the ARM ARM spec in order to determine what case they're handling. Signed-off-by: Thomas Hanson Message-id: 1476301853-15774-5-git-send-email-thomas.hanson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/translate-a64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 16716a2c1f..96c222722e 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1667,12 +1667,12 @@ static void disas_exc(DisasContext *s, uint32_t insn) * instruction works properly. */ switch (op2_ll) { - case 1: + case 1: /* SVC */ gen_ss_advance(s); gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16), default_exception_el(s)); break; - case 2: + case 2: /* HVC */ if (s->current_el == 0) { unallocated_encoding(s); break; @@ -1685,7 +1685,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) gen_ss_advance(s); gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16), 2); break; - case 3: + case 3: /* SMC */ if (s->current_el == 0) { unallocated_encoding(s); break; From fb0e8e79a9d77ee240dbca036fa8698ce654e5d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 10 Oct 2016 16:26:03 +0100 Subject: [PATCH 21/25] Fix masking of PC lower bits when doing exception returns In commit 9b6a3ea7a699594 store_reg() was changed to mask both bits 0 and 1 of the new PC value when in ARM mode. Unfortunately this broke the exception return code paths when doing a return from ARM mode to Thumb mode: in some of these we write a new CPSR including new Thumb mode bit via gen_helper_cpsr_write_eret(), and then use store_reg() to write the new PC. In this case if the new CPSR specified Thumb mode then masking bit 1 of the PC is incorrect (these code paths correspond to the v8 ARM ARM pseudocode function AArch32.ExceptionReturn(), which always aligns the new PC appropriately for the new instruction set state). Instead of using store_reg() in exception-return code paths, call a new store_pc_exc_ret() which stores the raw new PC value to env->regs[15], and then mask it appropriately in the subsequent helper_cpsr_write_eret() where the new env->thumb state is available. This fixes a bug introduced by 9b6a3ea7a699594 which caused crashes/hangs or otherwise bad behaviour for Linux when userspace was using Thumb. Reported-by: Jerome Forissier Signed-off-by: Peter Maydell Message-id: 1476113163-24578-1-git-send-email-peter.maydell@linaro.org --- target-arm/op_helper.c | 7 +++++++ target-arm/translate.c | 29 ++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index be27b21d52..cd94216591 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -479,6 +479,13 @@ void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val) { cpsr_write(env, val, CPSR_ERET_MASK, CPSRWriteExceptionReturn); + /* Generated code has already stored the new PC value, but + * without masking out its low bits, because which bits need + * masking depends on whether we're returning to Thumb or ARM + * state. Do the masking now. + */ + env->regs[15] &= (env->thumb ? ~1 : ~3); + arm_call_el_change_hook(arm_env_get_cpu(env)); } diff --git a/target-arm/translate.c b/target-arm/translate.c index 8df24bf35a..164b52a0d0 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4363,26 +4363,35 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn) s->is_jmp = DISAS_UPDATE; } -/* Generate an old-style exception return. Marks pc as dead. */ -static void gen_exception_return(DisasContext *s, TCGv_i32 pc) +/* Store value to PC as for an exception return (ie don't + * mask bits). The subsequent call to gen_helper_cpsr_write_eret() + * will do the masking based on the new value of the Thumb bit. + */ +static void store_pc_exc_ret(DisasContext *s, TCGv_i32 pc) { - TCGv_i32 tmp; - store_reg(s, 15, pc); - tmp = load_cpu_field(spsr); - gen_helper_cpsr_write_eret(cpu_env, tmp); - tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_JUMP; + tcg_gen_mov_i32(cpu_R[15], pc); + tcg_temp_free_i32(pc); } /* Generate a v6 exception return. Marks both values as dead. */ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) { + store_pc_exc_ret(s, pc); + /* The cpsr_write_eret helper will mask the low bits of PC + * appropriately depending on the new Thumb bit, so it must + * be called after storing the new PC. + */ gen_helper_cpsr_write_eret(cpu_env, cpsr); tcg_temp_free_i32(cpsr); - store_reg(s, 15, pc); s->is_jmp = DISAS_JUMP; } +/* Generate an old-style exception return. Marks pc as dead. */ +static void gen_exception_return(DisasContext *s, TCGv_i32 pc) +{ + gen_rfe(s, pc, load_cpu_field(spsr)); +} + static void gen_nop_hint(DisasContext *s, int val) { switch (val) { @@ -9366,6 +9375,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } else if (i == rn) { loaded_var = tmp; loaded_base = 1; + } else if (rn == 15 && exc_return) { + store_pc_exc_ret(s, tmp); } else { store_reg_from_load(s, i, tmp); } From 5dbdc4342f479d799a1970dd5fd22e64c9dcd50d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 12 Oct 2016 18:54:33 +0100 Subject: [PATCH 22/25] target-arm: Implement dummy MDCCINT_EL1 MDCCINT_EL1 is part of the DCC debugger communication channel between the CPU and an attached external debugger. QEMU doesn't implement this, but since Linux may try to access this register we need to provide at least a dummy implementation. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Message-id: 1476294876-12340-2-git-send-email-peter.maydell@linaro.org --- target-arm/helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index 70e274221c..a65f4f2f1f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4060,6 +4060,14 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, .access = PL1_RW, .accessfn = access_tda, .type = ARM_CP_NOP }, + /* Dummy MDCCINT_EL1, since we don't implement the Debug Communications + * Channel but Linux may try to access this register. The 32-bit + * alias is DBGDCCINT. + */ + { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_NOP }, REGINFO_SENTINEL }; From 194cbc492bcc8f3f1868ec97a35146bc99c3c71c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 12 Oct 2016 18:54:34 +0100 Subject: [PATCH 23/25] target-arm: Add trace events for the generic timers Add some useful trace events for the ARM generic timers (notably the various register writes and the resulting IRQ line state). Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Message-id: 1476294876-12340-3-git-send-email-peter.maydell@linaro.org --- Makefile.objs | 1 + target-arm/helper.c | 20 ++++++++++++++++---- target-arm/trace-events | 10 ++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 target-arm/trace-events diff --git a/Makefile.objs b/Makefile.objs index 02fb8e76b8..69fdd48679 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -155,6 +155,7 @@ trace-events-y += hw/alpha/trace-events trace-events-y += ui/trace-events trace-events-y += audio/trace-events trace-events-y += net/trace-events +trace-events-y += target-arm/trace-events trace-events-y += target-i386/trace-events trace-events-y += target-sparc/trace-events trace-events-y += target-s390x/trace-events diff --git a/target-arm/helper.c b/target-arm/helper.c index a65f4f2f1f..cb83ee2008 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "trace.h" #include "cpu.h" #include "internals.h" #include "exec/gdbstub.h" @@ -1560,10 +1561,13 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) /* Note that this must be unsigned 64 bit arithmetic: */ int istatus = count - offset >= gt->cval; uint64_t nexttick; + int irqstate; gt->ctl = deposit32(gt->ctl, 2, 1, istatus); - qemu_set_irq(cpu->gt_timer_outputs[timeridx], - (istatus && !(gt->ctl & 2))); + + irqstate = (istatus && !(gt->ctl & 2)); + qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate); + if (istatus) { /* Next transition is when count rolls back over to zero */ nexttick = UINT64_MAX; @@ -1580,11 +1584,13 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) nexttick = INT64_MAX / GTIMER_SCALE; } timer_mod(cpu->gt_timer[timeridx], nexttick); + trace_arm_gt_recalc(timeridx, irqstate, nexttick); } else { /* Timer disabled: ISTATUS and timer output always clear */ gt->ctl &= ~4; qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0); timer_del(cpu->gt_timer[timeridx]); + trace_arm_gt_recalc_disabled(timeridx); } } @@ -1610,6 +1616,7 @@ static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, int timeridx, uint64_t value) { + trace_arm_gt_cval_write(timeridx, value); env->cp15.c14_timer[timeridx].cval = value; gt_recalc_timer(arm_env_get_cpu(env), timeridx); } @@ -1629,6 +1636,7 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, { uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0; + trace_arm_gt_tval_write(timeridx, value); env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset + sextract64(value, 0, 32); gt_recalc_timer(arm_env_get_cpu(env), timeridx); @@ -1641,6 +1649,7 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMCPU *cpu = arm_env_get_cpu(env); uint32_t oldval = env->cp15.c14_timer[timeridx].ctl; + trace_arm_gt_ctl_write(timeridx, value); env->cp15.c14_timer[timeridx].ctl = deposit64(oldval, 0, 2, value); if ((oldval ^ value) & 1) { /* Enable toggled */ @@ -1649,8 +1658,10 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, /* IMASK toggled: don't need to recalculate, * just set the interrupt line based on ISTATUS */ - qemu_set_irq(cpu->gt_timer_outputs[timeridx], - (oldval & 4) && !(value & 2)); + int irqstate = (oldval & 4) && !(value & 2); + + trace_arm_gt_imask_toggle(timeridx, irqstate); + qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate); } } @@ -1715,6 +1726,7 @@ static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = arm_env_get_cpu(env); + trace_arm_gt_cntvoff_write(value); raw_write(env, ri, value); gt_recalc_timer(cpu, GTIMER_VIRT); } diff --git a/target-arm/trace-events b/target-arm/trace-events new file mode 100644 index 0000000000..9f726bdae3 --- /dev/null +++ b/target-arm/trace-events @@ -0,0 +1,10 @@ +# See docs/tracing.txt for syntax documentation. + +# target-arm/helper.c +arm_gt_recalc(int timer, int irqstate, uint64_t nexttick) "gt recalc: timer %d irqstate %d next tick %" PRIx64 +arm_gt_recalc_disabled(int timer) "gt recalc: timer %d irqstate 0 timer disabled" +arm_gt_cval_write(int timer, uint64_t value) "gt_cval_write: timer %d value %" PRIx64 +arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write: timer %d value %" PRIx64 +arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value %" PRIx64 +arm_gt_imask_toggle(int timer, int irqstate) "gt_ctl_write: timer %d IMASK toggle, new irqstate %d" +arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value %" PRIx64 From 081b1b98b7ca8734b4582942024a70ae3268238e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 12 Oct 2016 18:54:35 +0100 Subject: [PATCH 24/25] hw/intc/arm_gicv3: Fix ICC register tracepoints Fix some problems with the tracepoints for ICC register reads and writes: * tracepoints for ICC_BPR, ICC_APR, ICC_IGRPEN, ICC_EIOR were not printing the that indicated whether the access was to the group 0 or 1 register * the ICC_IGREPEN1_EL3 read function was not actually calling the associated tracepoint * the ICC_BPR write function was incorrectly calling the tracepoint for ICC_PMR writes Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias Message-id: 1476294876-12340-4-git-send-email-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 23 +++++++++++++++-------- hw/intc/trace-events | 14 +++++++------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 4633172bec..bca30c49da 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -454,7 +454,8 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, int irq = value & 0xffffff; int grp; - trace_gicv3_icc_eoir_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_eoir_write(ri->crm == 8 ? 0 : 1, + gicv3_redist_affid(cs), value); if (ri->crm == 8) { /* EOIR0 */ @@ -542,7 +543,7 @@ static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri) bpr = MIN(bpr, 7); } - trace_gicv3_icc_bpr_read(gicv3_redist_affid(cs), bpr); + trace_gicv3_icc_bpr_read(ri->crm == 8 ? 0 : 1, gicv3_redist_affid(cs), bpr); return bpr; } @@ -553,7 +554,8 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, GICv3CPUState *cs = icc_cs_from_env(env); int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1; - trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_bpr_write(ri->crm == 8 ? 0 : 1, + gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -591,7 +593,7 @@ static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) value = cs->icc_apr[grp][regno]; - trace_gicv3_icc_ap_read(regno, gicv3_redist_affid(cs), value); + trace_gicv3_icc_ap_read(ri->crm & 1, regno, gicv3_redist_affid(cs), value); return value; } @@ -603,7 +605,7 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, int regno = ri->opc2 & 3; int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1; - trace_gicv3_icc_ap_write(regno, gicv3_redist_affid(cs), value); + trace_gicv3_icc_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -820,7 +822,8 @@ static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri) } value = cs->icc_igrpen[grp]; - trace_gicv3_icc_igrpen_read(gicv3_redist_affid(cs), value); + trace_gicv3_icc_igrpen_read(ri->opc2 & 1 ? 1 : 0, + gicv3_redist_affid(cs), value); return value; } @@ -830,7 +833,8 @@ static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri, GICv3CPUState *cs = icc_cs_from_env(env); int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0; - trace_gicv3_icc_igrpen_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_igrpen_write(ri->opc2 & 1 ? 1 : 0, + gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -843,9 +847,12 @@ static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t icc_igrpen1_el3_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); + uint64_t value; /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */ - return cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1); + value = cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1); + trace_gicv3_icc_igrpen1_el3_read(gicv3_redist_affid(cs), value); + return value; } static void icc_igrpen1_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/hw/intc/trace-events b/hw/intc/trace-events index a367b46b1c..340f617761 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -85,12 +85,12 @@ gic_acknowledge_irq(int cpu, int irq) "cpu %d acknowledged irq %d" # hw/intc/arm_gicv3_cpuif.c gicv3_icc_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR read cpu %x value 0x%" PRIx64 gicv3_icc_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR write cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR read cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR write cpu %x value 0x%" PRIx64 -gicv3_icc_ap_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR read cpu %x value 0x%" PRIx64 -gicv3_icc_ap_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR write cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN read cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN write cpu %x value 0x%" PRIx64 +gicv3_icc_bpr_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_BPR%d read cpu %x value 0x%" PRIx64 +gicv3_icc_bpr_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_BPR%d write cpu %x value 0x%" PRIx64 +gicv3_icc_ap_read(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR%d read cpu %x value 0x%" PRIx64 +gicv3_icc_ap_write(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR%d write cpu %x value 0x%" PRIx64 +gicv3_icc_igrpen_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN%d read cpu %x value 0x%" PRIx64 +gicv3_icc_igrpen_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN%d write cpu %x value 0x%" PRIx64 gicv3_icc_igrpen1_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 read cpu %x value 0x%" PRIx64 gicv3_icc_igrpen1_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 write cpu %x value 0x%" PRIx64 gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x value 0x%" PRIx64 @@ -102,7 +102,7 @@ gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x" gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu %x value 0x%" PRIx64 gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu %x value 0x%" PRIx64 -gicv3_icc_eoir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR write cpu %x value 0x%" PRIx64 +gicv3_icc_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR%d write cpu %x value 0x%" PRIx64 gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x value 0x%" PRIx64 gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64 gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64 From 041ac05672993ff33a15f8017c0f729ca6dfad73 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 12 Oct 2016 18:54:36 +0100 Subject: [PATCH 25/25] hw/char/pl011: Add trace events Add some trace events for the pl011 UART model. Signed-off-by: Peter Maydell Message-id: 1476294876-12340-5-git-send-email-peter.maydell@linaro.org --- hw/char/pl011.c | 71 +++++++++++++++++++++++++++++++------------- hw/char/trace-events | 9 ++++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 786e605fdd..1a7911f81f 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -11,6 +11,7 @@ #include "hw/sysbus.h" #include "sysemu/char.h" #include "qemu/log.h" +#include "trace.h" #define TYPE_PL011 "pl011" #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) @@ -58,6 +59,7 @@ static void pl011_update(PL011State *s) uint32_t flags; flags = s->int_level & s->int_enabled; + trace_pl011_irq_state(flags != 0); qemu_set_irq(s->irq, flags != 0); } @@ -66,10 +68,8 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, { PL011State *s = (PL011State *)opaque; uint32_t c; + uint64_t r; - if (offset >= 0xfe0 && offset < 0x1000) { - return s->id[(offset - 0xfe0) >> 2]; - } switch (offset >> 2) { case 0: /* UARTDR */ s->flags &= ~PL011_FLAG_RXFF; @@ -84,41 +84,62 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, } if (s->read_count == s->read_trigger - 1) s->int_level &= ~ PL011_INT_RX; + trace_pl011_read_fifo(s->read_count); s->rsr = c >> 8; pl011_update(s); if (s->chr) { qemu_chr_accept_input(s->chr); } - return c; + r = c; + break; case 1: /* UARTRSR */ - return s->rsr; + r = s->rsr; + break; case 6: /* UARTFR */ - return s->flags; + r = s->flags; + break; case 8: /* UARTILPR */ - return s->ilpr; + r = s->ilpr; + break; case 9: /* UARTIBRD */ - return s->ibrd; + r = s->ibrd; + break; case 10: /* UARTFBRD */ - return s->fbrd; + r = s->fbrd; + break; case 11: /* UARTLCR_H */ - return s->lcr; + r = s->lcr; + break; case 12: /* UARTCR */ - return s->cr; + r = s->cr; + break; case 13: /* UARTIFLS */ - return s->ifl; + r = s->ifl; + break; case 14: /* UARTIMSC */ - return s->int_enabled; + r = s->int_enabled; + break; case 15: /* UARTRIS */ - return s->int_level; + r = s->int_level; + break; case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; + r = s->int_level & s->int_enabled; + break; case 18: /* UARTDMACR */ - return s->dmacr; + r = s->dmacr; + break; + case 0x3f8 ... 0x400: + r = s->id[(offset - 0xfe0) >> 2]; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset %x\n", (int)offset); - return 0; + r = 0; + break; } + + trace_pl011_read(offset, r); + return r; } static void pl011_set_read_trigger(PL011State *s) @@ -141,6 +162,8 @@ static void pl011_write(void *opaque, hwaddr offset, PL011State *s = (PL011State *)opaque; unsigned char ch; + trace_pl011_write(offset, value); + switch (offset >> 2) { case 0: /* UARTDR */ /* ??? Check if transmitter is enabled. */ @@ -207,11 +230,15 @@ static void pl011_write(void *opaque, hwaddr offset, static int pl011_can_receive(void *opaque) { PL011State *s = (PL011State *)opaque; + int r; - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; + if (s->lcr & 0x10) { + r = s->read_count < 16; + } else { + r = s->read_count < 1; + } + trace_pl011_can_receive(s->lcr, s->read_count, r); + return r; } static void pl011_put_fifo(void *opaque, uint32_t value) @@ -225,7 +252,9 @@ static void pl011_put_fifo(void *opaque, uint32_t value) s->read_fifo[slot] = value; s->read_count++; s->flags &= ~PL011_FLAG_RXFE; + trace_pl011_put_fifo(value, s->read_count); if (!(s->lcr & 0x10) || s->read_count == 16) { + trace_pl011_put_fifo_full(); s->flags |= PL011_FLAG_RXFF; } if (s->read_count == s->read_trigger) { diff --git a/hw/char/trace-events b/hw/char/trace-events index d53577c99d..7fd48bb80d 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -47,3 +47,12 @@ escc_sunkbd_event_in(int ch, const char *name, int down) "QKeyCode 0x%2.2x [%s], escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x" escc_kbd_command(int val) "Command %d" escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x" + +# hw/char/pl011.c +pl011_irq_state(int level) "irq state %d" +pl011_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_read_fifo(int read_count) "FIFO read, read_count now %d" +pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR %08x read_count %d returning %d" +pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d" +pl011_put_fifo_full(void) "FIFO now full, RXFF set"