summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS23
-rw-r--r--hw/arm/armv7m.c9
-rw-r--r--hw/arm/boot.c36
-rw-r--r--hw/arm/stellaris.c41
-rw-r--r--hw/arm/stm32f205_soc.c15
-rw-r--r--hw/arm/virt-acpi-build.c33
-rw-r--r--hw/arm/xilinx_zynq.c42
-rw-r--r--hw/intc/armv7m_nvic.c9
-rw-r--r--include/hw/arm/arm.h12
-rw-r--r--target-arm/helper.c37
-rw-r--r--target-arm/internals.h16
-rw-r--r--target-arm/kvm32.c34
-rw-r--r--target-arm/op_helper.c8
-rw-r--r--target-arm/translate-a64.c17
-rw-r--r--target-arm/translate.c12
15 files changed, 251 insertions, 93 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 3144113..fc8abe8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -81,6 +81,7 @@ F: disas/alpha.c
ARM
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: target-arm/
F: hw/arm/
@@ -216,6 +217,7 @@ F: */kvm.*
ARM
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: target-arm/kvm.c
@@ -287,6 +289,7 @@ ARM Machines
------------
Allwinner-a10
M: Beniamino Galvani <b.galvani@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/allwinner*
F: include/hw/*/allwinner*
@@ -294,6 +297,7 @@ F: hw/arm/cubieboard.c
ARM PrimeCell
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/char/pl011.c
F: hw/display/pl110*
@@ -308,6 +312,7 @@ F: include/hw/arm/primecell.h
ARM cores
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/intc/arm*
F: hw/intc/gic_internal.h
@@ -327,54 +332,64 @@ M: Evgeny Voevodin <e.voevodin@samsung.com>
M: Maksim Kozlov <m.kozlov@samsung.com>
M: Igor Mitsyanko <i.mitsyanko@gmail.com>
M: Dmitry Solodkiy <d.solodkiy@samsung.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/exynos*
Calxeda Highbank
M: Rob Herring <robh@kernel.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/highbank.c
F: hw/net/xgmac.c
Canon DIGIC
M: Antony Pavlov <antonynpavlov@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: include/hw/arm/digic.h
F: hw/*/digic*
Gumstix
L: qemu-devel@nongnu.org
+L: qemu-arm@nongnu.org
S: Orphan
F: hw/arm/gumstix.c
i.MX31
M: Peter Chubb <peter.chubb@nicta.com.au>
+L: qemu-arm@nongnu.org
S: Odd fixes
F: hw/*/imx*
F: hw/arm/kzm.c
Integrator CP
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/integratorcp.c
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/musicpal.c
nSeries
M: Andrzej Zaborowski <balrogg@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/nseries.c
Palm
M: Andrzej Zaborowski <balrogg@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/palm.c
Real View
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/realview*
F: hw/intc/realview_gic.c
@@ -382,6 +397,7 @@ F: include/hw/intc/realview_gic.h
PXA2XX
M: Andrzej Zaborowski <balrogg@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/mainstone.c
F: hw/arm/spitz.c
@@ -391,17 +407,20 @@ F: hw/*/pxa2xx*
Stellaris
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/stellaris*
Versatile PB
M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/versatile*
Xilinx Zynq
M: Alistair Francis <alistair.francis@xilinx.com>
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/xilinx_zynq.c
F: hw/misc/zynq_slcr.c
@@ -411,6 +430,7 @@ F: hw/ssi/xilinx_spips.c
Xilinx ZynqMP
M: Alistair Francis <alistair.francis@xilinx.com>
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/xlnx-zynqmp.c
F: hw/arm/xlnx-ep108.c
@@ -419,6 +439,7 @@ F: include/hw/arm/xlnx-zynqmp.h
ARM ACPI Subsystem
M: Shannon Zhao <zhaoshenglong@huawei.com>
M: Shannon Zhao <shannon.zhao@linaro.org>
+L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/virt-acpi-build.c
F: include/hw/arm/virt-acpi-build.h
@@ -1235,6 +1256,7 @@ AArch64 target
M: Claudio Fontana <claudio.fontana@huawei.com>
M: Claudio Fontana <claudio.fontana@gmail.com>
S: Maintained
+L: qemu-arm@nongnu.org
F: tcg/aarch64/
F: disas/arm-a64.cc
F: disas/libvixl/
@@ -1242,6 +1264,7 @@ F: disas/libvixl/
ARM target
M: Andrzej Zaborowski <balrogg@gmail.com>
S: Maintained
+L: qemu-arm@nongnu.org
F: tcg/arm/
F: disas/arm.c
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index eb214db..a80d2ad 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -166,17 +166,15 @@ static void armv7m_reset(void *opaque)
mem_size is in bytes.
Returns the NVIC array. */
-qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
+DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
const char *kernel_filename, const char *cpu_model)
{
ARMCPU *cpu;
CPUARMState *env;
DeviceState *nvic;
- qemu_irq *pic = g_new(qemu_irq, num_irq);
int image_size;
uint64_t entry;
uint64_t lowaddr;
- int i;
int big_endian;
MemoryRegion *hack = g_new(MemoryRegion, 1);
@@ -198,9 +196,6 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
qdev_init_nofail(nvic);
sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
- for (i = 0; i < num_irq; i++) {
- pic[i] = qdev_get_gpio_in(nvic, i);
- }
#ifdef TARGET_WORDS_BIGENDIAN
big_endian = 1;
@@ -234,7 +229,7 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
memory_region_add_subregion(system_memory, 0xfffff000, hack);
qemu_register_reset(armv7m_reset, cpu);
- return pic;
+ return nvic;
}
static Property bitband_properties[] = {
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index bef451b..b0879a5 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -28,14 +28,15 @@
#define KERNEL64_LOAD_ADDR 0x00080000
typedef enum {
- FIXUP_NONE = 0, /* do nothing */
- FIXUP_TERMINATOR, /* end of insns */
- FIXUP_BOARDID, /* overwrite with board ID number */
- FIXUP_ARGPTR, /* overwrite with pointer to kernel args */
- FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */
- FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
- FIXUP_BOOTREG, /* overwrite with boot register address */
- FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
+ FIXUP_NONE = 0, /* do nothing */
+ FIXUP_TERMINATOR, /* end of insns */
+ FIXUP_BOARDID, /* overwrite with board ID number */
+ FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
+ FIXUP_ARGPTR, /* overwrite with pointer to kernel args */
+ FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */
+ FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
+ FIXUP_BOOTREG, /* overwrite with boot register address */
+ FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
FIXUP_MAX,
} FixupType;
@@ -58,8 +59,17 @@ static const ARMInsnFixup bootloader_aarch64[] = {
{ 0, FIXUP_TERMINATOR }
};
-/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
+/* A very small bootloader: call the board-setup code (if needed),
+ * set r0-r2, then jump to the kernel.
+ * If we're not calling boot setup code then we don't copy across
+ * the first BOOTLOADER_NO_BOARD_SETUP_OFFSET insns in this array.
+ */
+
static const ARMInsnFixup bootloader[] = {
+ { 0xe28fe008 }, /* add lr, pc, #8 */
+ { 0xe51ff004 }, /* ldr pc, [pc, #-4] */
+ { 0, FIXUP_BOARD_SETUP },
+#define BOOTLOADER_NO_BOARD_SETUP_OFFSET 3
{ 0xe3a00000 }, /* mov r0, #0 */
{ 0xe59f1004 }, /* ldr r1, [pc, #4] */
{ 0xe59f2004 }, /* ldr r2, [pc, #4] */
@@ -131,6 +141,7 @@ static void write_bootloader(const char *name, hwaddr addr,
case FIXUP_NONE:
break;
case FIXUP_BOARDID:
+ case FIXUP_BOARD_SETUP:
case FIXUP_ARGPTR:
case FIXUP_ENTRYPOINT:
case FIXUP_GIC_CPU_IF:
@@ -640,6 +651,9 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
elf_machine = EM_AARCH64;
} else {
primary_loader = bootloader;
+ if (!info->write_board_setup) {
+ primary_loader += BOOTLOADER_NO_BOARD_SETUP_OFFSET;
+ }
kernel_load_offset = KERNEL_LOAD_ADDR;
elf_machine = EM_ARM;
}
@@ -745,6 +759,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
info->initrd_size = initrd_size;
fixupcontext[FIXUP_BOARDID] = info->board_id;
+ fixupcontext[FIXUP_BOARD_SETUP] = info->board_setup_addr;
/* for device tree boot, we pass the DTB directly in r2. Otherwise
* we point to the kernel args.
@@ -793,6 +808,9 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
if (info->nb_cpus > 1) {
info->write_secondary_boot(cpu, info);
}
+ if (info->write_board_setup) {
+ info->write_board_setup(cpu, info);
+ }
/* Notify devices which need to fake up firmware initialization
* that we're doing a direct kernel boot.
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 3d6486f..0114e0a 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -16,6 +16,7 @@
#include "net/net.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
#define GPIO_A 0
#define GPIO_B 1
@@ -1176,6 +1177,14 @@ static int stellaris_adc_init(SysBusDevice *sbd)
return 0;
}
+static
+void do_sys_reset(void *opaque, int n, int level)
+{
+ if (level) {
+ qemu_system_reset_request();
+ }
+}
+
/* Board init. */
static stellaris_board_info stellaris_boards[] = {
{ "LM3S811EVB",
@@ -1210,8 +1219,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
0x40024000, 0x40025000, 0x40026000};
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
- qemu_irq *pic;
- DeviceState *gpio_dev[7];
+ DeviceState *gpio_dev[7], *nvic;
qemu_irq gpio_in[7][8];
qemu_irq gpio_out[7][8];
qemu_irq adc;
@@ -1241,12 +1249,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
vmstate_register_ram_global(sram);
memory_region_add_subregion(system_memory, 0x20000000, sram);
- pic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES,
+ nvic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES,
kernel_filename, cpu_model);
+ qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0,
+ qemu_allocate_irq(&do_sys_reset, NULL, 0));
+
if (board->dc1 & (1 << 16)) {
dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
- pic[14], pic[15], pic[16], pic[17], NULL);
+ qdev_get_gpio_in(nvic, 14),
+ qdev_get_gpio_in(nvic, 15),
+ qdev_get_gpio_in(nvic, 16),
+ qdev_get_gpio_in(nvic, 17),
+ NULL);
adc = qdev_get_gpio_in(dev, 0);
} else {
adc = NULL;
@@ -1255,19 +1270,21 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
if (board->dc2 & (0x10000 << i)) {
dev = sysbus_create_simple(TYPE_STELLARIS_GPTM,
0x40030000 + i * 0x1000,
- pic[timer_irq[i]]);
+ qdev_get_gpio_in(nvic, timer_irq[i]));
/* TODO: This is incorrect, but we get away with it because
the ADC output is only ever pulsed. */
qdev_connect_gpio_out(dev, 0, adc);
}
}
- stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
+ stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
+ board, nd_table[0].macaddr.a);
for (i = 0; i < 7; i++) {
if (board->dc4 & (1 << i)) {
gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
- pic[gpio_irq[i]]);
+ qdev_get_gpio_in(nvic,
+ gpio_irq[i]));
for (j = 0; j < 8; j++) {
gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
gpio_out[i][j] = NULL;
@@ -1276,7 +1293,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
}
if (board->dc2 & (1 << 12)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, pic[8]);
+ dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000,
+ qdev_get_gpio_in(nvic, 8));
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
if (board->peripherals & BP_OLED_I2C) {
i2c_create_slave(i2c, "ssd0303", 0x3d);
@@ -1286,11 +1304,12 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
for (i = 0; i < 4; i++) {
if (board->dc2 & (1 << i)) {
sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
- pic[uart_irq[i]]);
+ qdev_get_gpio_in(nvic, uart_irq[i]));
}
}
if (board->dc2 & (1 << 4)) {
- dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
+ dev = sysbus_create_simple("pl022", 0x40008000,
+ qdev_get_gpio_in(nvic, 7));
if (board->peripherals & BP_OLED_SSI) {
void *bus;
DeviceState *sddev;
@@ -1326,7 +1345,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
qdev_set_nic_properties(enet, &nd_table[0]);
qdev_init_nofail(enet);
sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
- sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42));
}
if (board->peripherals & BP_GAMEPAD) {
qemu_irq gpad_irq[5];
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index 4d26a7e..3f99340 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -59,9 +59,8 @@ static void stm32f205_soc_initfn(Object *obj)
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
{
STM32F205State *s = STM32F205_SOC(dev_soc);
- DeviceState *syscfgdev, *usartdev, *timerdev;
+ DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
- qemu_irq *pic;
Error *err = NULL;
int i;
@@ -88,8 +87,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
vmstate_register_ram_global(sram);
memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
- pic = armv7m_init(get_system_memory(), FLASH_SIZE, 96,
- s->kernel_filename, s->cpu_model);
+ nvic = armv7m_init(get_system_memory(), FLASH_SIZE, 96,
+ s->kernel_filename, s->cpu_model);
/* System configuration controller */
syscfgdev = DEVICE(&s->syscfg);
@@ -100,7 +99,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
}
syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
- sysbus_connect_irq(syscfgbusdev, 0, pic[71]);
+ sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71));
/* Attach UART (uses USART registers) and USART controllers */
for (i = 0; i < STM_NUM_USARTS; i++) {
@@ -112,7 +111,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
}
usartbusdev = SYS_BUS_DEVICE(usartdev);
sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
- sysbus_connect_irq(usartbusdev, 0, pic[usart_irq[i]]);
+ sysbus_connect_irq(usartbusdev, 0,
+ qdev_get_gpio_in(nvic, usart_irq[i]));
}
/* Timer 2 to 5 */
@@ -126,7 +126,8 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
}
timerbusdev = SYS_BUS_DEVICE(timerdev);
sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
- sysbus_connect_irq(timerbusdev, 0, pic[timer_irq[i]]);
+ sysbus_connect_irq(timerbusdev, 0,
+ qdev_get_gpio_in(nvic, timer_irq[i]));
}
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1aaff1f..3c2c5d6 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -180,6 +180,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
+ aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
/* Declare the PCI Routing Table. */
Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS);
@@ -448,6 +449,24 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info,
gicd->length = sizeof(*gicd);
gicd->base_address = memmap[VIRT_GIC_DIST].base;
+ for (i = 0; i < guest_info->smp_cpus; i++) {
+ AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
+ sizeof *gicc);
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
+
+ gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
+ gicc->length = sizeof(*gicc);
+ if (guest_info->gic_version == 2) {
+ gicc->base_address = memmap[VIRT_GIC_CPU].base;
+ }
+ gicc->cpu_interface_number = i;
+ gicc->arm_mpidr = armcpu->mp_affinity;
+ gicc->uid = i;
+ if (test_bit(i, cpuinfo->found_cpus)) {
+ gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
+ }
+ }
+
if (guest_info->gic_version == 3) {
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
sizeof *gicr);
@@ -457,20 +476,6 @@ build_madt(GArray *table_data, GArray *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);
} else {
- for (i = 0; i < guest_info->smp_cpus; i++) {
- AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
- sizeof *gicc);
- gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
- gicc->length = sizeof(*gicc);
- gicc->base_address = memmap[VIRT_GIC_CPU].base;
- gicc->cpu_interface_number = i;
- gicc->arm_mpidr = i;
- gicc->uid = i;
- if (test_bit(i, cpuinfo->found_cpus)) {
- gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
- }
- }
-
gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
gic_msi->length = sizeof(*gic_msi);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 9f89483..82a9db8 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -43,6 +43,45 @@ static const int dma_irqs[8] = {
46, 47, 48, 49, 72, 73, 74, 75
};
+#define BOARD_SETUP_ADDR 0x100
+
+#define SLCR_LOCK_OFFSET 0x004
+#define SLCR_UNLOCK_OFFSET 0x008
+#define SLCR_ARM_PLL_OFFSET 0x100
+
+#define SLCR_XILINX_UNLOCK_KEY 0xdf0d
+#define SLCR_XILINX_LOCK_KEY 0x767b
+
+#define ARMV7_IMM16(x) (extract32((x), 0, 12) | \
+ extract32((x), 12, 4) << 16)
+
+/* Write immediate val to address r0 + addr. r0 should contain base offset
+ * of the SLCR block. Clobbers r1.
+ */
+
+#define SLCR_WRITE(addr, val) \
+ 0xe3001000 + ARMV7_IMM16(extract32((val), 0, 16)), /* movw r1 ... */ \
+ 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \
+ 0xe5801000 + (addr)
+
+static void zynq_write_board_setup(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t board_setup_blob[] = {
+ 0xe3a004f8, /* mov r0, #0xf8000000 */
+ SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY),
+ SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008),
+ SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY),
+ 0xe12fff1e, /* bx lr */
+ };
+ for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
+ board_setup_blob[n] = tswap32(board_setup_blob[n]);
+ }
+ rom_add_blob_fixed("board-setup", board_setup_blob,
+ sizeof(board_setup_blob), BOARD_SETUP_ADDR);
+}
+
static struct arm_boot_info zynq_binfo = {};
static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
@@ -252,6 +291,9 @@ static void zynq_init(MachineState *machine)
zynq_binfo.nb_cpus = 1;
zynq_binfo.board_id = 0xd32;
zynq_binfo.loader_start = 0;
+ zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR;
+ zynq_binfo.write_board_setup = zynq_write_board_setup;
+
arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo);
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 3ec8408..6fc167e 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -28,6 +28,7 @@ typedef struct {
MemoryRegion gic_iomem_alias;
MemoryRegion container;
uint32_t num_irq;
+ qemu_irq sysresetreq;
} nvic_state;
#define TYPE_NVIC "armv7m_nvic"
@@ -348,10 +349,13 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
if ((value >> 16) == 0x05fa) {
+ if (value & 4) {
+ qemu_irq_pulse(s->sysresetreq);
+ }
if (value & 2) {
qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
}
- if (value & 5) {
+ if (value & 1) {
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
}
if (value & 0x700) {
@@ -535,11 +539,14 @@ static void armv7m_nvic_instance_init(Object *obj)
* value in the GICState struct.
*/
GICState *s = ARM_GIC_COMMON(obj);
+ DeviceState *dev = DEVICE(obj);
+ nvic_state *nvic = NVIC(obj);
/* The ARM v7m may have anything from 0 to 496 external interrupt
* IRQ lines. We default to 64. Other boards may differ and should
* set the num-irq property appropriately.
*/
s->num_irq = 64;
+ qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
}
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index 4dcd4f9..67ba7db 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -17,7 +17,7 @@
#include "cpu.h"
/* armv7m.c */
-qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
+DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
const char *kernel_filename, const char *cpu_model);
/*
@@ -87,6 +87,16 @@ struct arm_boot_info {
* -pflash. It also implies that fw_cfg_find() will succeed.
*/
bool firmware_loaded;
+
+ /* Address at which board specific loader/setup code exists. If enabled,
+ * this code-blob will run before anything else. It must return to the
+ * caller via the link register. There is no stack set up. Enabled by
+ * defining write_board_setup, which is responsible for loading the blob
+ * to the specified address.
+ */
+ hwaddr board_setup_addr;
+ void (*write_board_setup)(ARMCPU *cpu,
+ const struct arm_boot_info *info);
};
/**
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1966f9c..4ecae61 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3130,7 +3130,8 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
{ .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[1]) },
+ .access = PL1_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
/* We rely on the access checks not allowing the guest to write to the
* state field when SPSel indicates that it's being used as the stack
* pointer.
@@ -3299,23 +3300,28 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
- .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[6]) },
+ .access = PL2_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_HYP]) },
{ .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 0,
- .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[4]) },
+ .access = PL2_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_IRQ]) },
{ .name = "SPSR_ABT", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 1,
- .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[2]) },
+ .access = PL2_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_ABT]) },
{ .name = "SPSR_UND", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 2,
- .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[3]) },
+ .access = PL2_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_UND]) },
{ .name = "SPSR_FIQ", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 3,
- .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[5]) },
+ .access = PL2_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_FIQ]) },
{ .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
.access = PL2_RW, .writefn = vbar_write,
@@ -3552,7 +3558,8 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
{ .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
- .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[7]) },
+ .access = PL3_RW,
+ .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_MON]) },
{ .name = "VBAR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 12, .crm = 0, .opc2 = 0,
.access = PL3_RW, .writefn = vbar_write,
@@ -5183,21 +5190,21 @@ int bank_number(int mode)
switch (mode) {
case ARM_CPU_MODE_USR:
case ARM_CPU_MODE_SYS:
- return 0;
+ return BANK_USRSYS;
case ARM_CPU_MODE_SVC:
- return 1;
+ return BANK_SVC;
case ARM_CPU_MODE_ABT:
- return 2;
+ return BANK_ABT;
case ARM_CPU_MODE_UND:
- return 3;
+ return BANK_UND;
case ARM_CPU_MODE_IRQ:
- return 4;
+ return BANK_IRQ;
case ARM_CPU_MODE_FIQ:
- return 5;
+ return BANK_FIQ;
case ARM_CPU_MODE_HYP:
- return 6;
+ return BANK_HYP;
case ARM_CPU_MODE_MON:
- return 7;
+ return BANK_MON;
}
g_assert_not_reached();
}
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 412827b..347998c 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -25,6 +25,16 @@
#ifndef TARGET_ARM_INTERNALS_H
#define TARGET_ARM_INTERNALS_H
+/* register banks for CPU modes */
+#define BANK_USRSYS 0
+#define BANK_SVC 1
+#define BANK_ABT 2
+#define BANK_UND 3
+#define BANK_IRQ 4
+#define BANK_FIQ 5
+#define BANK_HYP 6
+#define BANK_MON 7
+
static inline bool excp_is_internal(int excp)
{
/* Return true if this exception number represents a QEMU-internal
@@ -91,9 +101,9 @@ static inline void arm_log_exception(int idx)
static inline unsigned int aarch64_banked_spsr_index(unsigned int el)
{
static const unsigned int map[4] = {
- [1] = 1, /* EL1. */
- [2] = 6, /* EL2. */
- [3] = 7, /* EL3. */
+ [1] = BANK_SVC, /* EL1. */
+ [2] = BANK_HYP, /* EL2. */
+ [3] = BANK_MON, /* EL3. */
};
assert(el >= 1 && el <= 3);
return map[el];
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index 3ae57a6..df1e2b0 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -280,30 +280,30 @@ static const Reg regs[] = {
COREREG(usr_regs.uregs[10], usr_regs[2]),
COREREG(usr_regs.uregs[11], usr_regs[3]),
COREREG(usr_regs.uregs[12], usr_regs[4]),
- COREREG(usr_regs.uregs[13], banked_r13[0]),
- COREREG(usr_regs.uregs[14], banked_r14[0]),
+ COREREG(usr_regs.uregs[13], banked_r13[BANK_USRSYS]),
+ COREREG(usr_regs.uregs[14], banked_r14[BANK_USRSYS]),
/* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
- COREREG(svc_regs[0], banked_r13[1]),
- COREREG(svc_regs[1], banked_r14[1]),
- COREREG64(svc_regs[2], banked_spsr[1]),
- COREREG(abt_regs[0], banked_r13[2]),
- COREREG(abt_regs[1], banked_r14[2]),
- COREREG64(abt_regs[2], banked_spsr[2]),
- COREREG(und_regs[0], banked_r13[3]),
- COREREG(und_regs[1], banked_r14[3]),
- COREREG64(und_regs[2], banked_spsr[3]),
- COREREG(irq_regs[0], banked_r13[4]),
- COREREG(irq_regs[1], banked_r14[4]),
- COREREG64(irq_regs[2], banked_spsr[4]),
+ COREREG(svc_regs[0], banked_r13[BANK_SVC]),
+ COREREG(svc_regs[1], banked_r14[BANK_SVC]),
+ COREREG64(svc_regs[2], banked_spsr[BANK_SVC]),
+ COREREG(abt_regs[0], banked_r13[BANK_ABT]),
+ COREREG(abt_regs[1], banked_r14[BANK_ABT]),
+ COREREG64(abt_regs[2], banked_spsr[BANK_ABT]),
+ COREREG(und_regs[0], banked_r13[BANK_UND]),
+ COREREG(und_regs[1], banked_r14[BANK_UND]),
+ COREREG64(und_regs[2], banked_spsr[BANK_UND]),
+ COREREG(irq_regs[0], banked_r13[BANK_IRQ]),
+ COREREG(irq_regs[1], banked_r14[BANK_IRQ]),
+ COREREG64(irq_regs[2], banked_spsr[BANK_IRQ]),
/* R8_fiq .. R14_fiq and SPSR_fiq */
COREREG(fiq_regs[0], fiq_regs[0]),
COREREG(fiq_regs[1], fiq_regs[1]),
COREREG(fiq_regs[2], fiq_regs[2]),
COREREG(fiq_regs[3], fiq_regs[3]),
COREREG(fiq_regs[4], fiq_regs[4]),
- COREREG(fiq_regs[5], banked_r13[5]),
- COREREG(fiq_regs[6], banked_r14[5]),
- COREREG64(fiq_regs[7], banked_spsr[5]),
+ COREREG(fiq_regs[5], banked_r13[BANK_FIQ]),
+ COREREG(fiq_regs[6], banked_r14[BANK_FIQ]),
+ COREREG64(fiq_regs[7], banked_spsr[BANK_FIQ]),
/* R15 */
COREREG(usr_regs.uregs[15], regs[15]),
/* VFP system registers */
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a4c4ebf..b5db345 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -392,9 +392,9 @@ uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
uint32_t val;
if (regno == 13) {
- val = env->banked_r13[0];
+ val = env->banked_r13[BANK_USRSYS];
} else if (regno == 14) {
- val = env->banked_r14[0];
+ val = env->banked_r14[BANK_USRSYS];
} else if (regno >= 8
&& (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
val = env->usr_regs[regno - 8];
@@ -407,9 +407,9 @@ uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
{
if (regno == 13) {
- env->banked_r13[0] = val;
+ env->banked_r13[BANK_USRSYS] = val;
} else if (regno == 14) {
- env->banked_r14[0] = val;
+ env->banked_r14[BANK_USRSYS] = val;
} else if (regno >= 8
&& (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
env->usr_regs[regno - 8] = val;
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 83b8376..d7e0954 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -126,6 +126,8 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
CPUARMState *env = &cpu->env;
uint32_t psr = pstate_read(env);
int i;
+ int el = arm_current_el(env);
+ const char *ns_status;
cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
env->pc, env->xregs[31]);
@@ -137,13 +139,22 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
cpu_fprintf(f, " ");
}
}
- cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
+
+ if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+ } else {
+ ns_status = "";
+ }
+
+ cpu_fprintf(f, "\nPSTATE=%08x %c%c%c%c %sEL%d%c\n",
psr,
psr & PSTATE_N ? 'N' : '-',
psr & PSTATE_Z ? 'Z' : '-',
psr & PSTATE_C ? 'C' : '-',
- psr & PSTATE_V ? 'V' : '-');
- cpu_fprintf(f, "\n");
+ psr & PSTATE_V ? 'V' : '-',
+ ns_status,
+ el,
+ psr & PSTATE_SP ? 'h' : 't');
if (flags & CPU_DUMP_FPU) {
int numvfpregs = 32;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index b10a455..ff262a2 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -11602,6 +11602,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
CPUARMState *env = &cpu->env;
int i;
uint32_t psr;
+ const char *ns_status;
if (is_a64(env)) {
aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
@@ -11616,13 +11617,22 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, " ");
}
psr = cpsr_read(env);
- cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
+
+ if (arm_feature(env, ARM_FEATURE_EL3) &&
+ (psr & CPSR_M) != ARM_CPU_MODE_MON) {
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+ } else {
+ ns_status = "";
+ }
+
+ cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
psr,
psr & (1 << 31) ? 'N' : '-',
psr & (1 << 30) ? 'Z' : '-',
psr & (1 << 29) ? 'C' : '-',
psr & (1 << 28) ? 'V' : '-',
psr & CPSR_T ? 'T' : 'A',
+ ns_status,
cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
if (flags & CPU_DUMP_FPU) {
OpenPOWER on IntegriCloud