From 82c39f6a8898b028515eddcdbc4ae50959d0af5d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 16 Oct 2015 11:14:52 +0100 Subject: [PATCH 01/13] target-arm: Add missing 'static' attribute Signed-off-by: Stefan Weil Message-id: 1443213733-9807-1-git-send-email-sw@weilnetz.de Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 83679970b4..584f6df80d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5194,7 +5194,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 },}, From 6df99dec9e81838423d723996e96236693fa31fe Mon Sep 17 00:00:00 2001 From: Sergey Sorokin Date: Fri, 16 Oct 2015 11:14:52 +0100 Subject: [PATCH 02/13] target-arm: Break the TB after ISB to execute self-modified code correctly If any store instruction writes the code inside the same TB after this store insn, the execution of the TB must be stopped to execute new code correctly. As described in ARMv8 manual D3.4.6 self-modifying code must do an IC invalidation to be valid, and an ISB after it. So it's enough to end the TB after ISB instruction on the code translation. Also this TB break is necessary to take any pending interrupts immediately after an ISB (as required by ARMv8 ARM D1.14.4). Signed-off-by: Sergey Sorokin [PMM: tweaked commit message and comments slightly] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 6 +++++- target-arm/translate-a64.c | 8 +++++++- target-arm/translate.c | 17 +++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 584f6df80d..b4986705c4 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, diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index e65e309535..a4580c07a6 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; diff --git a/target-arm/translate.c b/target-arm/translate.c index 22c35877e5..127300007f 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; } From 2cde031f5a34996bab32571a26b1a6bcf3e5b5d9 Mon Sep 17 00:00:00 2001 From: Sergey Sorokin Date: Fri, 16 Oct 2015 11:14:52 +0100 Subject: [PATCH 03/13] target-arm: Avoid calling arm_el_is_aa64() function for unimplemented EL It is incorrect to call arm_el_is_aa64() function for unimplemented EL. This patch fixes several attempts to do so. Signed-off-by: Sergey Sorokin [PMM: Reworked several of the comments to be more verbose.] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.h | 11 ++++++++--- target-arm/helper.c | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 493f9d02a9..5fb0479b2a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1016,11 +1016,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 +1587,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; } } diff --git a/target-arm/helper.c b/target-arm/helper.c index b4986705c4..b2d78b0192 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5224,11 +5224,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: From bab27ea2e3855b6495a743f19b9d28cb013443ea Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 16 Oct 2015 11:14:53 +0100 Subject: [PATCH 04/13] hw/arm/virt: smbios: inform guest of kvm ARM/AArch64 KVM guests don't have any way to identify themselves as KVM guests (x86 guests use a CPUID leaf). Now, we could discuss all sorts of reasons why guests shouldn't need to know that, but then there's always some case where it'd be nice... Anyway, now that we have SMBIOS tables in ARM guests, it's easy for the guest to know that it's a QEMU instance. This patch takes that one step further, also identifying KVM, when appropriate. Again, we could debate why generally nothing should care whether it's of type QEMU or QEMU/KVM, but again, sometimes it's nice to know... Signed-off-by: Andrew Jones Reviewed-by: Wei Huang Message-id: 1443017892-15567-1-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d25d6cfce7..5ac5178b71 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, From 1424ca8d4320427c3e93722b65e19077969808a2 Mon Sep 17 00:00:00 2001 From: Davorin Mista Date: Fri, 16 Oct 2015 11:14:53 +0100 Subject: [PATCH 05/13] target-arm: Implement AArch64 OSLAR/OSLSR_EL1 sysregs Added oslar_write function to OSLAR_EL1 sysreg, using a status variable in ARMCPUState.cp15 struct (oslsr_el1). This variable is also linked to the newly added read-only OSLSR_EL1 register. Linux reads from this register during its suspend/resume procedure. Signed-off-by: Davorin Mista [PMM: folded a long line and tweaked a comment] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 5fb0479b2a..d1b5bc1a6f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -379,6 +379,7 @@ 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 */ /* If the counter is enabled, this stores the last time the counter * was reset. Otherwise it stores the counter value */ diff --git a/target-arm/helper.c b/target-arm/helper.c index b2d78b0192..403a30e800 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3568,6 +3568,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; @@ -3596,10 +3613,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, From ad1e8db894fa055ffa9447a5d86520ef1cbac6e9 Mon Sep 17 00:00:00 2001 From: Ryo ONODERA Date: Fri, 16 Oct 2015 11:14:53 +0100 Subject: [PATCH 06/13] target-arm: Provide model numbers for Sharp PDAs * For Collie, Akita, Spitz, Borzoi, Terrier and Tosa PDAs, provide model numbers and manufacturer (Sharp) information. Signed-off-by: Ryo ONODERA Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/collie.c | 2 +- hw/arm/spitz.c | 8 ++++---- hw/arm/tosa.c | 2 +- 3 files changed, 6 insertions(+), 6 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/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; } From b64d64de1a5b88de88146e3ad36e7b09b97837eb Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 16 Oct 2015 11:14:53 +0100 Subject: [PATCH 07/13] arm: imx25-pdk: Fix machine name ARM uses dashes instead of underscores for machine names. Fix imx25_pdk which has not seen a release yet (so there is no legacy yet). Cc: Jean-Christophe Dubois Signed-off-by: Peter Crosthwaite Message-id: 1444445785-3648-1-git-send-email-crosthwaite.peter@gmail.com Reviewed-by: Peter Maydell [PMM: Added change to tests/ds1338-test.c to use new machine name] Signed-off-by: Peter Maydell --- hw/arm/imx25_pdk.c | 2 +- tests/ds1338-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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; From c209b0537203c58a051e5d837320335cea23e494 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 16 Oct 2015 11:14:53 +0100 Subject: [PATCH 08/13] misc: zynq_slcr: Fix MMIO writes The /4 for offset calculation in MMIO writes was happening twice giving wrong write offsets. Fix. While touching the code, change the if-else to be a short returning if and convert the debug message to a GUEST_ERROR, which is more accurate for this condition. Cc: qemu-stable@nongnu.org Cc: Guenter Roeck Signed-off-by: Peter Crosthwaite Reviewed-by: Alistair Francis Signed-off-by: Peter Maydell --- hw/misc/zynq_slcr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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: From 14cc7b54372995a6ba72c7719372e4f710fc9b5a Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 16 Oct 2015 11:14:54 +0100 Subject: [PATCH 09/13] target-arm: Add MDCR_EL2 Add the MDCR_EL2 register. We don't implement any of the debug-related traps this register controls yet, so currently it simply reads back as written. Signed-off-by: Sergey Fedorov Message-id: 1444383794-16767-1-git-send-email-serge.fdrv@gmail.com Reviewed-by: Peter Maydell [PMM: tweaked commit message; moved non-dummy definition from debug_cp_reginfo to el2_cp_reginfo.] Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index d1b5bc1a6f..e555122d17 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -380,6 +380,7 @@ typedef struct CPUARMState { 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 */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 403a30e800..e7fda37466 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3227,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 }; @@ -3448,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 }; From 74de8c356844080fcabc3a44b08b9d22feda691f Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Fri, 16 Oct 2015 11:14:54 +0100 Subject: [PATCH 10/13] hw/arm/virt: Allow zero address for PCI IO space Currently PCI IO address 0 is not allowed even though the IO space starts from 0. This update makes PCI IO address 0 usable. CC: Peter Maydell CC: Andrew Jones Signed-off-by: Alexander Gordeev Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 5ac5178b71..4e7160ce96 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1162,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 = { From 81669b8b81eb450d7b89ee5fdd57bdb73d87022d Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 14 Sep 2015 13:53:48 +0300 Subject: [PATCH 11/13] target-arm: implement arm_debug_target_el() Implement debug exception routing according to ARM ARM D2.3.1 Pseudocode description of routing debug exceptions. Signed-off-by: Sergey Fedorov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index e555122d17..3daa7f58f9 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1702,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) From e63a2d4d9ed73e33a0b7483085808048be8bbcb1 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 13 Oct 2015 12:56:27 +0300 Subject: [PATCH 12/13] target-arm: Fix GDB breakpoint handling GDB breakpoints have higher priority so they have to be checked first. Should GDB breakpoint match, just return from the debug exception handler. Signed-off-by: Sergey Fedorov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/op_helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 1425a1d4bb..67b18c09c3 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -897,6 +897,12 @@ void arm_debug_excp_handler(CPUState *cs) } } } else { + uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; + + if (cpu_breakpoint_test(cs, pc, BP_GDB)) { + return; + } + if (check_breakpoints(cpu)) { bool same_el = (arm_debug_target_el(env) == arm_current_el(env)); if (extended_addresses_enabled(env)) { From 5d98bf8f38c17a348ab6e8af196088cd4953acd0 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 13 Oct 2015 12:56:28 +0300 Subject: [PATCH 13/13] target-arm: Fix CPU breakpoint handling A QEMU breakpoint match is not definitely an architectural breakpoint match. If an exception is generated unconditionally during translation, it is hardly possible to ignore it in the debug exception handler. Generate a call to a helper to check CPU breakpoints and raise an exception only if any breakpoint matches architecturally. Signed-off-by: Sergey Fedorov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.h | 2 ++ target-arm/op_helper.c | 29 ++++++++++++++++++----------- target-arm/translate-a64.c | 17 ++++++++++++----- target-arm/translate.c | 19 ++++++++++++++----- 4 files changed, 46 insertions(+), 21 deletions(-) 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 67b18c09c3..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; @@ -898,23 +907,21 @@ void arm_debug_excp_handler(CPUState *cs) } } else { 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 (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)); + 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 a4580c07a6..19f9d8d2c8 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -11090,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 127300007f..9f1d740b4e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -11342,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; } } }