diff options
-rw-r--r-- | hw/arm/virt.c | 93 | ||||
-rw-r--r-- | hw/intc/armv7m_nvic.c | 2 | ||||
-rw-r--r-- | target-arm/helper.c | 41 | ||||
-rw-r--r-- | target-arm/op_helper.c | 2 | ||||
-rw-r--r-- | target-arm/translate-a64.c | 9 |
5 files changed, 99 insertions, 48 deletions
diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 2bbc9313d2..ea4f02d32e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -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); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 6066fa6838..f5b0c3be6f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -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]; diff --git a/target-arm/helper.c b/target-arm/helper.c index 43c1b4f01d..3be917c22e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -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 diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 57e7d9c480..fb90676bd5 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -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; diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index d86b8ffa55..b62db4d566 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -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. |