diff options
-rw-r--r-- | hw/arm/collie.c | 2 | ||||
-rw-r--r-- | hw/arm/imx25_pdk.c | 2 | ||||
-rw-r--r-- | hw/arm/spitz.c | 8 | ||||
-rw-r--r-- | hw/arm/tosa.c | 2 | ||||
-rw-r--r-- | hw/arm/virt.c | 8 | ||||
-rw-r--r-- | hw/misc/zynq_slcr.c | 8 | ||||
-rw-r--r-- | target-arm/cpu.h | 30 | ||||
-rw-r--r-- | target-arm/helper.c | 60 | ||||
-rw-r--r-- | target-arm/helper.h | 2 | ||||
-rw-r--r-- | target-arm/op_helper.c | 35 | ||||
-rw-r--r-- | target-arm/translate-a64.c | 25 | ||||
-rw-r--r-- | target-arm/translate.c | 36 | ||||
-rw-r--r-- | tests/ds1338-test.c | 2 |
13 files changed, 173 insertions, 47 deletions
diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 4e6541e4e1..9991c0c4a0 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -60,7 +60,7 @@ static void collie_init(MachineState *machine) static void collie_machine_init(MachineClass *mc) { - mc->desc = "Collie PDA (SA-1110)"; + mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)"; mc->init = collie_init; } diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 425011475a..59a4c11277 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -151,4 +151,4 @@ static void imx25_pdk_machine_init(MachineClass *mc) mc->init = imx25_pdk_init; } -DEFINE_MACHINE("imx25_pdk", imx25_pdk_machine_init) +DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 2af03be622..8d3cc0b6b2 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -976,7 +976,7 @@ static void akitapda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Akita PDA (PXA270)"; + mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)"; mc->init = akita_init; } @@ -990,7 +990,7 @@ static void spitzpda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Spitz PDA (PXA270)"; + mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)"; mc->init = spitz_init; } @@ -1004,7 +1004,7 @@ static void borzoipda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Borzoi PDA (PXA270)"; + mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)"; mc->init = borzoi_init; } @@ -1018,7 +1018,7 @@ static void terrierpda_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "Terrier PDA (PXA270)"; + mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)"; mc->init = terrier_init; } diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 51d0b89687..02814d7aba 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -254,7 +254,7 @@ static void tosa_init(MachineState *machine) static void tosapda_machine_init(MachineClass *mc) { - mc->desc = "Tosa PDA (PXA255)"; + mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)"; mc->init = tosa_init; } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d25d6cfce7..4e7160ce96 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -884,12 +884,17 @@ static void virt_build_smbios(VirtGuestInfo *guest_info) FWCfgState *fw_cfg = guest_info->fw_cfg; uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; if (!fw_cfg) { return; } - smbios_set_defaults("QEMU", "QEMU Virtual Machine", + if (kvm_enabled()) { + product = "KVM Virtual Machine"; + } + + smbios_set_defaults("QEMU", product, "1.0", false, true, SMBIOS_ENTRY_POINT_30); smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len, @@ -1157,6 +1162,7 @@ static void virt_class_init(ObjectClass *oc, void *data) mc->has_dynamic_sysbus = true; mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; + mc->pci_allow_0_address = true; } static const TypeInfo machvirt_info = { diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 964f2532ff..3d7870850b 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -393,12 +393,12 @@ static void zynq_slcr_write(void *opaque, hwaddr offset, return; } - if (!s->regs[LOCKSTA]) { - s->regs[offset / 4] = val; - } else { - DB_PRINT("SCLR registers are locked. Unlock them first\n"); + if (s->regs[LOCKSTA]) { + qemu_log_mask(LOG_GUEST_ERROR, + "SCLR registers are locked. Unlock them first\n"); return; } + s->regs[offset] = val; switch (offset) { case PSS_RST_CTRL: diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 493f9d02a9..3daa7f58f9 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -379,6 +379,8 @@ typedef struct CPUARMState { uint64_t dbgwvr[16]; /* watchpoint value registers */ uint64_t dbgwcr[16]; /* watchpoint control registers */ uint64_t mdscr_el1; + uint64_t oslsr_el1; /* OS Lock Status */ + uint64_t mdcr_el2; /* If the counter is enabled, this stores the last time the counter * was reset. Otherwise it stores the counter value */ @@ -1016,11 +1018,11 @@ static inline bool access_secure_reg(CPUARMState *env) */ #define A32_BANKED_CURRENT_REG_GET(_env, _regname) \ A32_BANKED_REG_GET((_env), _regname, \ - ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env)))) + (arm_is_secure(_env) && !arm_el_is_aa64((_env), 3))) #define A32_BANKED_CURRENT_REG_SET(_env, _regname, _val) \ A32_BANKED_REG_SET((_env), _regname, \ - ((!arm_el_is_aa64((_env), 3) && arm_is_secure(_env))), \ + (arm_is_secure(_env) && !arm_el_is_aa64((_env), 3)), \ (_val)) void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); @@ -1587,7 +1589,12 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * interrupt. */ if ((target_el > cur_el) && (target_el != 1)) { - if (arm_el_is_aa64(env, 3) || ((scr || hcr) && (!secure))) { + /* ARM_FEATURE_AARCH64 enabled means the highest EL is AArch64. + * This code currently assumes that EL2 is not implemented + * (and so that highest EL will be 3 and the target_el also 3). + */ + if (arm_feature(env, ARM_FEATURE_AARCH64) || + ((scr || hcr) && (!secure))) { unmasked = 1; } } @@ -1695,7 +1702,22 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) */ static inline int arm_debug_target_el(CPUARMState *env) { - return 1; + bool secure = arm_is_secure(env); + bool route_to_el2 = false; + + if (arm_feature(env, ARM_FEATURE_EL2) && !secure) { + route_to_el2 = env->cp15.hcr_el2 & HCR_TGE || + env->cp15.mdcr_el2 & (1 << 8); + } + + if (route_to_el2) { + return 2; + } else if (arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3) && secure) { + return 3; + } else { + return 1; + } } static inline bool aa64_generate_debug_exceptions(CPUARMState *env) diff --git a/target-arm/helper.c b/target-arm/helper.c index 83679970b4..e7fda37466 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -657,8 +657,12 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { { .name = "MVA_prefetch", .cp = 15, .crn = 7, .crm = 13, .opc1 = 0, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NOP }, + /* We need to break the TB after ISB to execute self-modifying code + * correctly and also to take any pending interrupts immediately. + * So use arm_cp_write_ignore() function instead of ARM_CP_NOP flag. + */ { .name = "ISB", .cp = 15, .crn = 7, .crm = 5, .opc1 = 0, .opc2 = 4, - .access = PL0_W, .type = ARM_CP_NOP }, + .access = PL0_W, .type = ARM_CP_NO_RAW, .writefn = arm_cp_write_ignore }, { .name = "DSB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 4, .access = PL0_W, .type = ARM_CP_NOP }, { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5, @@ -3223,6 +3227,9 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -3444,6 +3451,15 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .resetvalue = 0, .writefn = gt_hyp_ctl_write, .raw_writefn = raw_write }, #endif + /* The only field of MDCR_EL2 that has a defined architectural reset value + * is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N; but we + * don't impelment any PMU event counters, so using zero as a reset + * value for MDCR_EL2 is okay + */ + { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, + .access = PL2_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }, REGINFO_SENTINEL }; @@ -3564,6 +3580,23 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri) return CP_ACCESS_OK; } +static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Writes to OSLAR_EL1 may update the OS lock status, which can be + * read via a bit in OSLSR_EL1. + */ + int oslock; + + if (ri->state == ARM_CP_STATE_AA32) { + oslock = (value == 0xC5ACCE55); + } else { + oslock = value & 1; + } + + env->cp15.oslsr_el1 = deposit32(env->cp15.oslsr_el1, 1, 1, oslock); +} + static const ARMCPRegInfo debug_cp_reginfo[] = { /* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped * debug components. The AArch64 version of DBGDRAR is named MDRAR_EL1; @@ -3592,10 +3625,14 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .type = ARM_CP_ALIAS, .access = PL1_R, .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), }, - /* We define a dummy WI OSLAR_EL1, because Linux writes to it. */ { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .type = ARM_CP_NO_RAW, + .writefn = oslar_write }, + { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4, + .access = PL1_R, .resetvalue = 10, + .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) }, /* Dummy OSDLR_EL1: 32-bit Linux will read this */ { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, @@ -5194,7 +5231,7 @@ void switch_mode(CPUARMState *env, int mode) * BIT IRQ IMO Non-secure Secure * EL3 FIQ RW FMO EL0 EL1 EL2 EL3 EL0 EL1 EL2 EL3 */ -const int8_t target_el_table[2][2][2][2][2][4] = { +static const int8_t target_el_table[2][2][2][2][2][4] = { {{{{/* 0 0 0 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, {/* 0 0 0 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},}, {{/* 0 0 1 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, @@ -5220,11 +5257,22 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure) { CPUARMState *env = cs->env_ptr; - int rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); + int rw; int scr; int hcr; int target_el; - int is64 = arm_el_is_aa64(env, 3); + /* Is the highest EL AArch64? */ + int is64 = arm_feature(env, ARM_FEATURE_AARCH64); + + if (arm_feature(env, ARM_FEATURE_EL3)) { + rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); + } else { + /* Either EL2 is the highest EL (and so the EL2 register width + * is given by is64); or there is no EL2 or EL3, in which case + * the value of 'rw' does not affect the table lookup anyway. + */ + rw = is64; + } switch (excp_idx) { case EXCP_IRQ: diff --git a/target-arm/helper.h b/target-arm/helper.h index 827b33dfec..c2a85c722a 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -54,6 +54,8 @@ DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) +DEF_HELPER_1(check_breakpoints, void, env) + DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_1(cpsr_read, i32, env) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 1425a1d4bb..7929c71b43 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -867,6 +867,15 @@ static bool check_breakpoints(ARMCPU *cpu) return false; } +void HELPER(check_breakpoints)(CPUARMState *env) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + + if (check_breakpoints(cpu)) { + HELPER(exception_internal(env, EXCP_DEBUG)); + } +} + void arm_debug_excp_handler(CPUState *cs) { /* Called by core code when a watchpoint or breakpoint fires; @@ -897,18 +906,22 @@ void arm_debug_excp_handler(CPUState *cs) } } } else { - if (check_breakpoints(cpu)) { - bool same_el = (arm_debug_target_el(env) == arm_current_el(env)); - if (extended_addresses_enabled(env)) { - env->exception.fsr = (1 << 9) | 0x22; - } else { - env->exception.fsr = 0x2; - } - /* FAR is UNKNOWN, so doesn't need setting */ - raise_exception(env, EXCP_PREFETCH_ABORT, - syn_breakpoint(same_el), - arm_debug_target_el(env)); + uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; + bool same_el = (arm_debug_target_el(env) == arm_current_el(env)); + + if (cpu_breakpoint_test(cs, pc, BP_GDB)) { + return; + } + + if (extended_addresses_enabled(env)) { + env->exception.fsr = (1 << 9) | 0x22; + } else { + env->exception.fsr = 0x2; } + /* FAR is UNKNOWN, so doesn't need setting */ + raise_exception(env, EXCP_PREFETCH_ABORT, + syn_breakpoint(same_el), + arm_debug_target_el(env)); } } diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index e65e309535..19f9d8d2c8 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1230,9 +1230,15 @@ static void handle_sync(DisasContext *s, uint32_t insn, return; case 4: /* DSB */ case 5: /* DMB */ - case 6: /* ISB */ /* We don't emulate caches so barriers are no-ops */ return; + case 6: /* ISB */ + /* We need to break the TB after this insn to execute + * a self-modified code correctly and also to take + * any pending interrupts immediately. + */ + s->is_jmp = DISAS_UPDATE; + return; default: unallocated_encoding(s); return; @@ -11084,11 +11090,18 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) CPUBreakpoint *bp; QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_internal_insn(dc, 0, EXCP_DEBUG); - /* Advance PC so that clearing the breakpoint will - invalidate this TB. */ - dc->pc += 2; - goto done_generating; + if (bp->flags & BP_CPU) { + gen_helper_check_breakpoints(cpu_env); + /* End the TB early; it likely won't be executed */ + dc->is_jmp = DISAS_UPDATE; + } else { + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 4; + goto done_generating; + } + break; } } } diff --git a/target-arm/translate.c b/target-arm/translate.c index 22c35877e5..9f1d740b4e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7720,10 +7720,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) return; case 4: /* dsb */ case 5: /* dmb */ - case 6: /* isb */ ARCH(7); /* We don't emulate caches so these are a no-op. */ return; + case 6: /* isb */ + /* We need to break the TB after this insn to execute + * self-modifying code correctly and also to take + * any pending interrupts immediately. + */ + gen_lookup_tb(s); + return; default: goto illegal_op; } @@ -10030,9 +10036,16 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw break; case 4: /* dsb */ case 5: /* dmb */ - case 6: /* isb */ /* These execute as NOPs. */ break; + case 6: /* isb */ + /* We need to break the TB after this insn + * to execute self-modifying code correctly + * and also to take any pending interrupts + * immediately. + */ + gen_lookup_tb(s); + break; default: goto illegal_op; } @@ -11329,11 +11342,20 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) CPUBreakpoint *bp; QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_internal_insn(dc, 0, EXCP_DEBUG); - /* Advance PC so that clearing the breakpoint will - invalidate this TB. */ - dc->pc += 2; - goto done_generating; + if (bp->flags & BP_CPU) { + gen_helper_check_breakpoints(cpu_env); + /* End the TB early; it's likely not going to be executed */ + dc->is_jmp = DISAS_UPDATE; + } else { + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + /* TODO: Advance PC by correct instruction length to + * avoid disassembler error messages */ + dc->pc += 2; + goto done_generating; + } + break; } } } diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c index a7fb415353..7d513d8972 100644 --- a/tests/ds1338-test.c +++ b/tests/ds1338-test.c @@ -61,7 +61,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); - s = qtest_start("-display none -machine imx25_pdk"); + s = qtest_start("-display none -machine imx25-pdk"); i2c = imx_i2c_create(IMX25_I2C_0_BASE); addr = DS1338_ADDR; |