target-arm queue:
* implement XScale cache lockdown cp15 ops * fix v7M CPUID base register * implement WFE and YIELD as yields for A64 * fix A64 "BLR LR" * support Cortex-A57 in virt machine model * a few other minor AArch64 bugfixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABCAAGBQJTYl1JAAoJEDwlJe0UNgzeAZUP/1OP9OWKdNcBmfyc+rrpCzOn 49m6FSYOw2jtUf1YYItr38tDIq0rFCLB3DYPUD7hWtll8tFUyE4TD3XsTr0nJ7Jq io12W8Gfuua6K57xmLMaLyrP8hu0gHtnZFEgi9vVz+ASXtqw6SUpFuOr7TFjfP2U qZfELHoWFCek7OnqaR+wn5qKRr+zqEAYr7FlnR2dT3GKT72JEuDGQUZlk2m5oOBb mChrc+SvQBJUXTk+HPNrXdA8i+FOmIfmNXN1lHaGatBjLQoGULb2TEBZU4Zvyg1z 74vermgX9EaqZ7lFI4+gQT4+4wclnX4xP2K/+2b2iBZziLUFhc7Odp0jHw1gh5lY /zADi3+FuB7JJEQztjwD0Q30vZSqIu2PH6wvH3Axnl9va3tYHHGtj267X3MN+KIy KJqQS+0KG/UNzOCkY3bgjXIsmDhWJAZAa0HhL5eze7kznH17iGkej0GT1xVHWf54 9GZydWgtaXaLk/ob9Js/3gLcQ7yEFZBtaVsRHBavrurSeTCV4MS00Xcn+YhTSpRS h6i37hDWpH8GyeqjVmbUaHY+Zxgy01QGXgvP5KwX6g+ulhYGIO+taqTJ+6EWoCSS aTNHsCwYQy1pMm3YtjQd1UC8WQJAKpfDFT8imxjXnU5QGSnqlgYDVSgUlyg4iSY2 s0KRAvT26KV0HJ4FqaZ0 =F2C9 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140501' into staging target-arm queue: * implement XScale cache lockdown cp15 ops * fix v7M CPUID base register * implement WFE and YIELD as yields for A64 * fix A64 "BLR LR" * support Cortex-A57 in virt machine model * a few other minor AArch64 bugfixes # gpg: Signature made Thu 01 May 2014 15:42:17 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140501: hw/arm/virt: Add support for Cortex-A57 hw/arm/virt: Put GIC register banks on 64K boundaries hw/arm/virt: Create the GIC ourselves rather than (ab)using a15mpcore_priv target-arm: Correct a comment refering to EL0 target-arm: A64: Fix a typo when declaring TLBI ops target-arm: A64: Handle blr lr target-arm: Make vbar_write 64bit friendly on 32bit hosts target-arm: implement WFE/YIELD as a yield for AArch64 armv7m_nvic: fix CPUID Base Register target-arm: Implement XScale cache lockdown operations as NOPs Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
fdaad4715a
|
@ -75,8 +75,6 @@ typedef struct MemMapEntry {
|
|||
typedef struct VirtBoardInfo {
|
||||
struct arm_boot_info bootinfo;
|
||||
const char *cpu_model;
|
||||
const char *qdevname;
|
||||
const char *gic_compatible;
|
||||
const MemMapEntry *memmap;
|
||||
const int *irqmap;
|
||||
int smp_cpus;
|
||||
|
@ -98,10 +96,10 @@ typedef struct VirtBoardInfo {
|
|||
static const MemMapEntry a15memmap[] = {
|
||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||
[VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
|
||||
[VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
|
||||
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
|
@ -117,16 +115,16 @@ static const int a15irqmap[] = {
|
|||
static VirtBoardInfo machines[] = {
|
||||
{
|
||||
.cpu_model = "cortex-a15",
|
||||
.qdevname = "a15mpcore_priv",
|
||||
.gic_compatible = "arm,cortex-a15-gic",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
{
|
||||
.cpu_model = "cortex-a57",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
{
|
||||
.cpu_model = "host",
|
||||
/* We use the A15 private peripheral model to get a V2 GIC */
|
||||
.qdevname = "a15mpcore_priv",
|
||||
.gic_compatible = "arm,cortex-a15-gic",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
|
@ -251,8 +249,9 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
||||
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
||||
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
||||
vbi->gic_compatible);
|
||||
"arm,cortex-a15-gic");
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
||||
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
||||
|
@ -263,6 +262,56 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
||||
}
|
||||
|
||||
static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
/* We create a standalone GIC v2 */
|
||||
DeviceState *gicdev;
|
||||
SysBusDevice *gicbusdev;
|
||||
const char *gictype = "arm_gic";
|
||||
int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
gictype = "kvm-arm-gic";
|
||||
}
|
||||
|
||||
gicdev = qdev_create(NULL, gictype);
|
||||
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
|
||||
/* Note that the num-irq property counts both internal and external
|
||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||
*/
|
||||
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
|
||||
qdev_init_nofail(gicdev);
|
||||
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
|
||||
sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
|
||||
|
||||
/* Wire the outputs from each CPU's generic timer to the
|
||||
* appropriate GIC PPI inputs, and the GIC's IRQ output to
|
||||
* the CPU's IRQ input.
|
||||
*/
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
int ppibase = NUM_IRQS + i * 32;
|
||||
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||
*/
|
||||
qdev_connect_gpio_out(cpudev, 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||
/* virtual timer */
|
||||
qdev_connect_gpio_out(cpudev, 1,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||
|
||||
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_IRQS; i++) {
|
||||
pic[i] = qdev_get_gpio_in(gicdev, i);
|
||||
}
|
||||
|
||||
fdt_add_gic_node(vbi);
|
||||
}
|
||||
|
||||
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
char *nodename;
|
||||
|
@ -340,8 +389,6 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||
MemoryRegion *sysmem = get_system_memory();
|
||||
int n;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
VirtBoardInfo *vbi;
|
||||
|
||||
|
@ -404,25 +451,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||
vmstate_register_ram_global(ram);
|
||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||
|
||||
dev = qdev_create(NULL, vbi->qdevname);
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
/* Note that the num-irq property counts both internal and external
|
||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||
*/
|
||||
qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
|
||||
fdt_add_gic_node(vbi);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
||||
|
||||
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
}
|
||||
|
||||
for (n = 0; n < NUM_IRQS; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
create_gic(vbi, pic);
|
||||
|
||||
create_uart(vbi, pic);
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
|||
return 10000;
|
||||
case 0xd00: /* CPUID Base. */
|
||||
cpu = ARM_CPU(current_cpu);
|
||||
return cpu->env.cp15.c0_cpuid;
|
||||
return cpu->midr;
|
||||
case 0xd04: /* Interrupt Control State. */
|
||||
/* VECTACTIVE */
|
||||
val = s->gic.running_irq[0];
|
||||
|
|
|
@ -657,7 +657,7 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
* contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
|
||||
* requires the bottom five bits to be RAZ/WI because they're UNK/SBZP.)
|
||||
*/
|
||||
env->cp15.c12_vbar = value & ~0x1Ful;
|
||||
env->cp15.c12_vbar = value & ~0x1FULL;
|
||||
}
|
||||
|
||||
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
|
@ -1578,6 +1578,21 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = {
|
|||
.cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c1_xscaleauxcr),
|
||||
.resetvalue = 0, },
|
||||
/* XScale specific cache-lockdown: since we have no cache we NOP these
|
||||
* and hope the guest does not really rely on cache behaviour.
|
||||
*/
|
||||
{ .name = "XSCALE_LOCK_ICACHE_LINE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_UNLOCK_ICACHE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_DCACHE_LOCK",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_UNLOCK_DCACHE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
|
@ -1893,51 +1908,51 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
|
|||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
/* TLBI operations */
|
||||
{ .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 0,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbiall_write },
|
||||
{ .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 1,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 2,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_asid_write },
|
||||
{ .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 3,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 5,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 7,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 0,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbiall_write },
|
||||
{ .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 1,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 2,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_asid_write },
|
||||
{ .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 3,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 5,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 7,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
|
|
@ -418,7 +418,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
|||
goto illegal_return;
|
||||
}
|
||||
if (new_el == 0 && (spsr & PSTATE_SP)) {
|
||||
/* Return to EL1 with M[0] bit set */
|
||||
/* Return to EL0 with M[0] bit set */
|
||||
goto illegal_return;
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
|
|
|
@ -1151,6 +1151,8 @@ static void handle_hint(DisasContext *s, uint32_t insn,
|
|||
return;
|
||||
case 1: /* YIELD */
|
||||
case 2: /* WFE */
|
||||
s->is_jmp = DISAS_WFE;
|
||||
return;
|
||||
case 4: /* SEV */
|
||||
case 5: /* SEVL */
|
||||
/* we treat all as NOP at least for now */
|
||||
|
@ -1507,8 +1509,10 @@ 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);
|
||||
break;
|
||||
case 4: /* ERET */
|
||||
|
@ -1527,7 +1531,6 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
|||
return;
|
||||
}
|
||||
|
||||
tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
|
@ -10765,6 +10768,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
|||
case DISAS_EXC:
|
||||
case DISAS_SWI:
|
||||
break;
|
||||
case DISAS_WFE:
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
gen_helper_wfe(cpu_env);
|
||||
break;
|
||||
case DISAS_WFI:
|
||||
/* This is a special case because we don't want to just halt the CPU
|
||||
* if trying to debug across a WFI.
|
||||
|
|
Loading…
Reference in New Issue