aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-10-17 19:41:23 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-10-17 19:41:23 +0100
commit2d02ac10b6644d71c88cc7943e74d7ad6674fff1 (patch)
tree28f11b0787b3fd3fb4b85881feead80f9ad76c81
parent0975b8b823a888d474fa33821dfe84e6904db197 (diff)
parent041ac05672993ff33a15f8017c0f729ca6dfad73 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20161017' into staging
target-arm: * target-arm: kvm: use AddressSpace-specific listener * aspeed: add SMC controllers * hw/arm/boot: allow using a command line specified dtb without a kernel * hw/dma/pl080: Fix bad bit mask * hw/intc/arm_gic_kvm: Fix build on aarch64 with some compilers * hw/arm/virt: fix ACPI tables for ITS * tests: add a m25p80 test * tests: cleanup ptimer-test * pxa2xx: Auto-assign name for i2c bus in i2c_init_bus * target-arm: handle tagged addresses in A64 code * target-arm: Fix masking of PC lower bits when doing exception returns * target-arm: Implement dummy MDCCINT_EL1 * target-arm: Add trace events for the generic timers * hw/intc/arm_gicv3: Fix ICC register tracepoints * hw/char/pl011: Add trace events # gpg: Signature made Mon 17 Oct 2016 19:39:42 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20161017: (25 commits) hw/char/pl011: Add trace events hw/intc/arm_gicv3: Fix ICC register tracepoints target-arm: Add trace events for the generic timers target-arm: Implement dummy MDCCINT_EL1 Fix masking of PC lower bits when doing exception returns target-arm: Comments added to identify cases in a switch target-arm: Code changes to implement overwrite of tag field on PC load target-arm: Infrastucture changes to enable handling of tagged address loading into PC pxa2xx: Auto-assign name for i2c bus in i2c_init_bus. tests: cleanup ptimer-test tests: add a m25p80 test hw/arm/virt: no ITS on older machine types hw/arm/virt-acpi-build: fix MADT generation hw/intc/arm_gic_kvm: Fix build on aarch64 hw/dma/pl080: Fix bad bit mask (PL080_CONF_M1 | PL080_CONF_M1) hw/arm/boot: allow using a command line specified dtb without a kernel aspeed: add support for the SMC segment registers aspeed: create mapping regions for the maximum number of slaves aspeed: add support for the AST2500 SoC SMC controllers aspeed: extend the number of host SPI controllers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--Makefile.objs1
-rw-r--r--docs/generic-loader.txt22
-rw-r--r--hw/arm/aspeed.c4
-rw-r--r--hw/arm/aspeed_soc.c74
-rw-r--r--hw/arm/boot.c4
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/arm/virt-acpi-build.c14
-rw-r--r--hw/arm/virt.c15
-rw-r--r--hw/char/pl011.c71
-rw-r--r--hw/char/trace-events9
-rw-r--r--hw/dma/pl080.c2
-rw-r--r--hw/dma/xilinx_axidma.c8
-rw-r--r--hw/intc/arm_gic_kvm.c14
-rw-r--r--hw/intc/arm_gicv3_cpuif.c23
-rw-r--r--hw/intc/trace-events14
-rw-r--r--hw/ssi/aspeed_smc.c194
-rw-r--r--include/hw/arm/aspeed_soc.h10
-rw-r--r--include/hw/arm/virt-acpi-build.h1
-rw-r--r--include/hw/ssi/aspeed_smc.h3
-rw-r--r--stubs/vmstate.c5
-rw-r--r--target-arm/cpu.h52
-rw-r--r--target-arm/helper.c74
-rw-r--r--target-arm/kvm.c3
-rw-r--r--target-arm/op_helper.c7
-rw-r--r--target-arm/trace-events10
-rw-r--r--target-arm/translate-a64.c90
-rw-r--r--target-arm/translate.c29
-rw-r--r--target-arm/translate.h2
-rw-r--r--tests/Makefile.include7
-rw-r--r--tests/m25p80-test.c252
-rw-r--r--tests/ptimer-test-stubs.c7
-rw-r--r--tests/ptimer-test.c22
-rw-r--r--vl.c5
33 files changed, 882 insertions, 168 deletions
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/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=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<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.
- <force-raw> - Forces the file to be treated as a raw image. This can be
- used to specify the load address of ELF files.
+ <force-raw> - 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.
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 6b18c7f172..c7206fda6d 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -128,8 +128,8 @@ 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.spi, "mx25l25635e", &error_abort);
+ aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &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 c0a3102058..e14f5c217e 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -25,25 +25,37 @@
#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
#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, };
#define AST2400_SDRAM_BASE 0x40000000
#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,
+ 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 },
- { "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,
+ "aspeed.smc.fmc", aspeed_soc_ast2400_typenames },
+ { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE,
+ 1, aspeed_soc_ast2400_spi_bases,
+ "aspeed.smc.fmc", aspeed_soc_ast2400_typenames },
+ { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE,
+ 2, aspeed_soc_ast2500_spi_bases,
+ "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames },
};
/*
@@ -75,6 +87,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);
@@ -100,13 +113,16 @@ 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), sc->info->fmc_typename);
+ 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]),
+ 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());
+ }
object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC);
object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL);
@@ -121,6 +137,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 */
@@ -178,29 +195,34 @@ 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,
+ s->fmc.ctrl->flash_window_base);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
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, ASPEED_SOC_SPI_FLASH_BASE);
/* SDMC - SDRAM Memory Controller */
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
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/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);
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index c77525d33a..fa0655a775 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() && !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);
+ 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;
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/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"
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");
}
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);
}
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)
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
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index d319e04a27..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)
@@ -127,18 +127,22 @@
#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
+#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000
+
/*
* 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 },
};
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 },
@@ -149,15 +153,155 @@ 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, 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 },
+ { "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 },
};
+/*
+ * 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)
{
@@ -281,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);
}
@@ -301,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 {
@@ -332,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);
@@ -384,23 +542,33 @@ 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);
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);
+ 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);
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 932704c380..5406b498d7 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;
@@ -31,8 +33,8 @@ typedef struct AspeedSoCState {
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedSCUState scu;
- AspeedSMCState smc;
- AspeedSMCState spi;
+ AspeedSMCState fmc;
+ AspeedSMCState spi[ASPEED_SPIS_NUM];
AspeedSDMCState sdmc;
} AspeedSoCState;
@@ -44,6 +46,10 @@ typedef struct AspeedSoCInfo {
const char *cpu_model;
uint32_t silicon_rev;
hwaddr sdram_base;
+ int spis_num;
+ const hwaddr *spi_bases;
+ const char *fmc_typename;
+ const char **spi_typename;
} AspeedSoCInfo;
typedef struct AspeedSoCClass {
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;
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 {
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/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..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);
}
@@ -4060,6 +4072,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
};
@@ -6720,6 +6740,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/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(&notify);
}
kd = g_new0(KVMDevice, 1);
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/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
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 307e281557..96c222722e 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;
@@ -1596,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;
@@ -1614,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;
@@ -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) {
@@ -11175,6 +11247,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.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);
}
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. */
diff --git a/tests/Makefile.include b/tests/Makefile.include
index a77777cf9c..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
@@ -295,6 +297,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
@@ -306,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
@@ -514,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)
@@ -626,6 +629,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)
@@ -675,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/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;
+}
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);
}
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);