diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 044ad66730364ebb6ec474a2e9959591e5003b68..a64d0714ea2848d419195c9ec72d4516db3a657e 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -123,7 +123,7 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp) static void arm_gic_common_reset(DeviceState *dev) { GICState *s = ARM_GIC_COMMON(dev); - int i; + int i, j; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { if (s->revision == REV_11MPCORE) { @@ -135,15 +135,30 @@ static void arm_gic_common_reset(DeviceState *dev) s->running_irq[i] = 1023; s->running_priority[i] = 0x100; s->cpu_ctlr[i] = 0; + s->bpr[i] = GIC_MIN_BPR; + s->abpr[i] = GIC_MIN_ABPR; + for (j = 0; j < GIC_INTERNAL; j++) { + s->priority1[j][i] = 0; + } + for (j = 0; j < GIC_NR_SGIS; j++) { + s->sgi_pending[j][i] = 0; + } } for (i = 0; i < GIC_NR_SGIS; i++) { GIC_SET_ENABLED(i, ALL_CPU_MASK); GIC_SET_EDGE_TRIGGER(i); } - if (s->num_cpu == 1) { + + for (i = 0; i < ARRAY_SIZE(s->priority2); i++) { + s->priority2[i] = 0; + } + + for (i = 0; i < GIC_MAXIRQ; i++) { /* For uniprocessor GICs all interrupts always target the sole CPU */ - for (i = 0; i < GIC_MAXIRQ; i++) { + if (s->num_cpu == 1) { s->irq_target[i] = 1; + } else { + s->irq_target[i] = 0; } } s->ctlr = 0; diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 8b93b3c1ae670359542fc3104b2ca0f886da3a0e..3e59c2a288a2371fc6b754dbb1b24af2c165ac89 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -38,7 +38,7 @@ static inline int get_current_cpu(ARMMPTimerState *s) static inline void timerblock_update_irq(TimerBlock *tb) { - qemu_set_irq(tb->irq, tb->status); + qemu_set_irq(tb->irq, tb->status && (tb->control & 4)); } /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ @@ -122,11 +122,18 @@ static void timerblock_write(void *opaque, hwaddr addr, case 8: /* Control. */ old = tb->control; tb->control = value; - if (((old & 1) == 0) && (value & 1)) { - if (tb->count == 0 && (tb->control & 2)) { + if (value & 1) { + if ((old & 1) && (tb->count != 0)) { + /* Do nothing if timer is ticking right now. */ + break; + } + if (tb->control & 2) { tb->count = tb->load; } timerblock_reload(tb, 1); + } else if (old & 1) { + /* Shutdown the timer. */ + timer_del(tb->timer); } break; case 12: /* Interrupt status. */ diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index d46db3c0e29e57728c0010658118507b8ef7b409..35bc88033e66e5fb5bff24ec9339898131073587 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -208,15 +208,14 @@ static void cadence_timer_sync(CadenceTimerState *s) s->reg_intr |= (2 << i); } } + if ((x < 0) || (x >= interval)) { + s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ? + COUNTER_INTR_IV : COUNTER_INTR_OV; + } while (x < 0) { x += interval; } s->reg_value = (uint32_t)(x % interval); - - if (s->reg_value != x) { - s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ? - COUNTER_INTR_IV : COUNTER_INTR_OV; - } cadence_timer_update(s); } diff --git a/target-arm/helper.c b/target-arm/helper.c index aa341599cf9ce956040fe645aee4329c5cae1049..b87afe7cdeba73d484291bd2cee5eff9678bc2c5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2441,7 +2441,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, - .writefn = tlbiall_write }, + .writefn = tlbiall_is_write }, { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NO_RAW, diff --git a/target-arm/helper.h b/target-arm/helper.h index fc885dea430e1b3cb3e9ae1773fe6f5527978cda..827b33dfec7e961af407ed58465eca46200e9913 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -50,6 +50,7 @@ DEF_HELPER_2(exception_internal, void, env, i32) DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(wfe, void, env) +DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 7fa32c470752fbc90dab2e22451029e7599f7b1d..663c05d1d2e7e2be37abdec91d93a3c2cb2c014d 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -323,13 +323,25 @@ void HELPER(wfi)(CPUARMState *env) void HELPER(wfe)(CPUARMState *env) { - CPUState *cs = CPU(arm_env_get_cpu(env)); - - /* Don't actually halt the CPU, just yield back to top + /* This is a hint instruction that is semantically different + * from YIELD even though we currently implement it identically. + * Don't actually halt the CPU, just yield back to top * level loop. This is not going into a "low power state" * (ie halting until some event occurs), so we never take * a configurable trap to a different exception level. */ + HELPER(yield)(env); +} + +void HELPER(yield)(CPUARMState *env) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + CPUState *cs = CPU(cpu); + + /* This is a non-trappable hint instruction that generally indicates + * that the guest is currently busy-looping. Yield control back to the + * top level loop so that a more deserving VCPU has a chance to run. + */ cs->exception_index = EXCP_YIELD; cpu_loop_exit(cs); } diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index e077f2dc30f124b8584513054d6ccaceca1bbb55..689f2be89643424640f18b0de325abb4ed3969f9 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1199,6 +1199,8 @@ static void handle_hint(DisasContext *s, uint32_t insn, s->is_jmp = DISAS_WFI; return; case 1: /* YIELD */ + s->is_jmp = DISAS_YIELD; + return; case 2: /* WFE */ s->is_jmp = DISAS_WFE; return; @@ -11107,6 +11109,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, gen_a64_set_pc_im(dc->pc); gen_helper_wfe(cpu_env); break; + case DISAS_YIELD: + gen_a64_set_pc_im(dc->pc); + gen_helper_yield(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. diff --git a/target-arm/translate.c b/target-arm/translate.c index 971b6db0612e01f880c93f63031887945c3e350f..69ac18c10847fa0290b57c61b3ce4d4d51d286f7 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4080,6 +4080,10 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) static void gen_nop_hint(DisasContext *s, int val) { switch (val) { + case 1: /* yield */ + gen_set_pc_im(s, s->pc); + s->is_jmp = DISAS_YIELD; + break; case 3: /* wfi */ gen_set_pc_im(s, s->pc); s->is_jmp = DISAS_WFI; @@ -11459,6 +11463,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, case DISAS_WFE: gen_helper_wfe(cpu_env); break; + case DISAS_YIELD: + gen_helper_yield(cpu_env); + break; case DISAS_SWI: gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), default_exception_el(dc)); diff --git a/target-arm/translate.h b/target-arm/translate.h index bcdcf117184bb8e3d8636d90202892fc2818e060..9ab978fb750ece7d94785b46dd9f041d56529f10 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -103,6 +103,7 @@ static inline int default_exception_el(DisasContext *s) #define DISAS_WFE 7 #define DISAS_HVC 8 #define DISAS_SMC 9 +#define DISAS_YIELD 10 #ifdef TARGET_AARCH64 void a64_translate_init(void);