diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index d6b929cf8f..7a433d33a7 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -363,6 +363,8 @@ void cpu_put_timer(QEMUFile *f, CPUTimer *s) qemu_put_be32s(f, &s->frequency); qemu_put_be32s(f, &s->disabled); qemu_put_be64s(f, &s->disabled_mask); + qemu_put_be32s(f, &s->npt); + qemu_put_be64s(f, &s->npt_mask); qemu_put_sbe64s(f, &s->clock_offset); timer_put(f, s->qtimer); @@ -373,6 +375,8 @@ void cpu_get_timer(QEMUFile *f, CPUTimer *s) qemu_get_be32s(f, &s->frequency); qemu_get_be32s(f, &s->disabled); qemu_get_be64s(f, &s->disabled_mask); + qemu_get_be32s(f, &s->npt); + qemu_get_be64s(f, &s->npt_mask); qemu_get_sbe64s(f, &s->clock_offset); timer_get(f, s->qtimer); @@ -380,15 +384,17 @@ void cpu_get_timer(QEMUFile *f, CPUTimer *s) static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, QEMUBHFunc *cb, uint32_t frequency, - uint64_t disabled_mask) + uint64_t disabled_mask, uint64_t npt_mask) { CPUTimer *timer = g_malloc0(sizeof (CPUTimer)); timer->name = name; timer->frequency = frequency; timer->disabled_mask = disabled_mask; + timer->npt_mask = npt_mask; timer->disabled = 1; + timer->npt = 1; timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu); @@ -494,17 +500,17 @@ static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) void cpu_tick_set_count(CPUTimer *timer, uint64_t count) { - uint64_t real_count = count & ~timer->disabled_mask; - uint64_t disabled_bit = count & timer->disabled_mask; + uint64_t real_count = count & ~timer->npt_mask; + uint64_t npt_bit = count & timer->npt_mask; int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - cpu_to_timer_ticks(real_count, timer->frequency); - TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", + TIMER_DPRINTF("%s set_count count=0x%016lx (npt %s) p=%p\n", timer->name, real_count, - timer->disabled?"disabled":"enabled", timer); + timer->npt ? "disabled" : "enabled", timer); - timer->disabled = disabled_bit ? 1 : 0; + timer->npt = npt_bit ? 1 : 0; timer->clock_offset = vm_clock_offset; } @@ -514,12 +520,13 @@ uint64_t cpu_tick_get_count(CPUTimer *timer) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset, timer->frequency); - TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", + TIMER_DPRINTF("%s get_count count=0x%016lx (npt %s) p=%p\n", timer->name, real_count, - timer->disabled?"disabled":"enabled", timer); + timer->npt ? "disabled" : "enabled", timer); - if (timer->disabled) - real_count |= timer->disabled_mask; + if (timer->npt) { + real_count |= timer->npt_mask; + } return real_count; } @@ -799,13 +806,16 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) env = &cpu->env; env->tick = cpu_timer_create("tick", cpu, tick_irq, - tick_frequency, TICK_NPT_MASK); + tick_frequency, TICK_INT_DIS, + TICK_NPT_MASK); env->stick = cpu_timer_create("stick", cpu, stick_irq, - stick_frequency, TICK_INT_DIS); + stick_frequency, TICK_INT_DIS, + TICK_NPT_MASK); env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, - hstick_frequency, TICK_INT_DIS); + hstick_frequency, TICK_INT_DIS, + TICK_NPT_MASK); reset_info = g_malloc0(sizeof(ResetData)); reset_info->cpu = cpu; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 9fa770b144..4aa689ed0b 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -366,6 +366,8 @@ struct CPUTimer uint32_t frequency; uint32_t disabled; uint64_t disabled_mask; + uint32_t npt; + uint64_t npt_mask; int64_t clock_offset; QEMUTimer *qtimer; }; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 4850c7cec7..6600834d4a 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -51,10 +51,16 @@ void helper_tick_set_count(void *opaque, uint64_t count) #endif } -uint64_t helper_tick_get_count(void *opaque) +uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx) { #if !defined(CONFIG_USER_ONLY) - return cpu_tick_get_count(opaque); + CPUTimer *timer = opaque; + + if (timer->npt && mem_idx < MMU_KERNEL_IDX) { + helper_raise_exception(env, TT_PRIV_INSN); + } + + return cpu_tick_get_count(timer); #else return 0; #endif diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 1ad23e8dbc..4374f0dd23 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -25,7 +25,7 @@ DEF_HELPER_2(set_softint, void, env, i64) DEF_HELPER_2(clear_softint, void, env, i64) DEF_HELPER_2(write_softint, void, env, i64) DEF_HELPER_2(tick_set_count, void, ptr, i64) -DEF_HELPER_1(tick_get_count, i64, ptr) +DEF_HELPER_3(tick_get_count, i64, env, ptr, int) DEF_HELPER_2(tick_set_limit, void, ptr, i64) #endif #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 63440dd792..f99ceed834 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2708,12 +2708,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x4: /* V9 rdtick */ { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_dst, r_tickptr); + gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); gen_store_gpr(dc, rd, cpu_dst); } break; @@ -2750,12 +2754,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x18: /* System tick */ { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, stick)); - gen_helper_tick_get_count(cpu_dst, r_tickptr); + gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); gen_store_gpr(dc, rd, cpu_dst); } break; @@ -2863,12 +2871,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 4: // tick { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_tmp0, r_tickptr); + gen_helper_tick_get_count(cpu_tmp0, cpu_env, + r_tickptr, r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); } break; case 5: // tba