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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJYBRruAAoJEDwlJe0UNgzeMw4P/0+3OG+APNCAp9AWNzlR23T6 sjDnk4R3thtHECpsu606Hl1F2tYYxXJiBf6gJbZb2TK8iaqTvJ6WB/i1FqcFrrtw RXUsWDlrezTcEmzs4oW7FYK4bmqUrjHM6LrWgZm5IdxZ3QSwCwuZhHlHfl0ZRPDd qomaF+k2fTSNVV3zxUy5J2jdLhhaM+6Hfi4IIafQV9RDahBOGJfzRxqwL7u3Cbys 3KY7ayKJrnzH8z4HNVmrYO9WM5c+M+5EiHV92ieoDrD2P85vFXdodvWsdYr/HyLb 7g+bLR/4LaSNfgNqGO/zzzxeF7JcipqHRfjPzEJMVnxF/vOusSY/8YYE3ODwf38k 8xbp1WO3rpNFdn3Dt5zsNOqClBxfgTUiQLw3PnaN3HfmhvaShWGBO9d7sN+kBKkw lIV5rc69D74chbdmG7TLRouPHduYmHnAYer6bio9MfIfBj6Vf+ZypKNHwKjnf+3s dVP5GjNZO1doUn9NUKrKfG1jElkEJBnt+u8mN+pEn2SxA+Qya6pYS263PHa7l8Uc E0qN7YN3vaeSxO3tE/vDcvDFGNpwLOM5iW5ljKsf/khbCivElfvmkCEzSgrh514Y tc/MczeWxewxKNnCy3Q3l1JC1eAQuKNjQV+u2bVjfBfVucX3c8n+OOMUNdlImR/T R7t2hbXn+GAkE2oXAUrz =L99V -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
2d02ac10b6
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -33,6 +33,7 @@ typedef struct VirtGuestInfo {
|
||||
const int *irqmap;
|
||||
bool use_highmem;
|
||||
int gic_version;
|
||||
bool no_its;
|
||||
} VirtGuestInfo;
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
10
target-arm/trace-events
Normal file
10
target-arm/trace-events
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
252
tests/m25p80-test.c
Normal file
252
tests/m25p80-test.c
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
5
vl.c
5
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);
|
||||
|
Loading…
Reference in New Issue
Block a user