hw/ppc: Reset timebase facilities on machine reset
Lower interrupts, delete timers, and set time facility registers back to initial state on machine reset. This is not so important for record-replay since timebase and decrementer are migrated, but it gives a cleaner reset state. Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Cc: BALATON Zoltan <balaton@eik.bme.hu> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [ clg: checkpatch.pl fixes ] Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
parent
578912ad73
commit
30d0647bcf
@ -81,6 +81,7 @@ static void ppc_heathrow_reset(void *opaque)
|
|||||||
{
|
{
|
||||||
PowerPCCPU *cpu = opaque;
|
PowerPCCPU *cpu = opaque;
|
||||||
|
|
||||||
|
cpu_ppc_tb_reset(&cpu->env);
|
||||||
cpu_reset(CPU(cpu));
|
cpu_reset(CPU(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ static void pegasos2_cpu_reset(void *opaque)
|
|||||||
cpu->env.gpr[1] = 2 * VOF_STACK_SIZE - 0x20;
|
cpu->env.gpr[1] = 2 * VOF_STACK_SIZE - 0x20;
|
||||||
cpu->env.nip = 0x100;
|
cpu->env.nip = 0x100;
|
||||||
}
|
}
|
||||||
|
cpu_ppc_tb_reset(&cpu->env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pegasos2_pci_irq(void *opaque, int n, int level)
|
static void pegasos2_pci_irq(void *opaque, int n, int level)
|
||||||
|
@ -61,6 +61,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
|
|||||||
hreg_compute_hflags(env);
|
hreg_compute_hflags(env);
|
||||||
ppc_maybe_interrupt(env);
|
ppc_maybe_interrupt(env);
|
||||||
|
|
||||||
|
cpu_ppc_tb_reset(env);
|
||||||
|
|
||||||
pcc->intc_reset(pc->chip, cpu);
|
pcc->intc_reset(pc->chip, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
hw/ppc/ppc.c
47
hw/ppc/ppc.c
@ -942,23 +942,6 @@ void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
|
|||||||
&tb_env->purr_offset, value);
|
&tb_env->purr_offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
|
||||||
{
|
|
||||||
CPUPPCState *env = opaque;
|
|
||||||
PowerPCCPU *cpu = env_archcpu(env);
|
|
||||||
ppc_tb_t *tb_env = env->tb_env;
|
|
||||||
|
|
||||||
tb_env->tb_freq = freq;
|
|
||||||
tb_env->decr_freq = freq;
|
|
||||||
/* There is a bug in Linux 2.4 kernels:
|
|
||||||
* if a decrementer exception is pending when it enables msr_ee at startup,
|
|
||||||
* it's not ready to handle it...
|
|
||||||
*/
|
|
||||||
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
|
|
||||||
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
|
|
||||||
cpu_ppc_store_purr(env, 0x0000000000000000ULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timebase_save(PPCTimebase *tb)
|
static void timebase_save(PPCTimebase *tb)
|
||||||
{
|
{
|
||||||
uint64_t ticks = cpu_get_host_ticks();
|
uint64_t ticks = cpu_get_host_ticks();
|
||||||
@ -1060,7 +1043,7 @@ const VMStateDescription vmstate_ppc_timebase = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Set up (once) timebase frequency (in Hz) */
|
/* Set up (once) timebase frequency (in Hz) */
|
||||||
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = env_archcpu(env);
|
PowerPCCPU *cpu = env_archcpu(env);
|
||||||
ppc_tb_t *tb_env;
|
ppc_tb_t *tb_env;
|
||||||
@ -1081,9 +1064,33 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
|||||||
} else {
|
} else {
|
||||||
tb_env->hdecr_timer = NULL;
|
tb_env->hdecr_timer = NULL;
|
||||||
}
|
}
|
||||||
cpu_ppc_set_tb_clk(env, freq);
|
|
||||||
|
|
||||||
return &cpu_ppc_set_tb_clk;
|
tb_env->tb_freq = freq;
|
||||||
|
tb_env->decr_freq = freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_ppc_tb_reset(CPUPPCState *env)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = env_archcpu(env);
|
||||||
|
ppc_tb_t *tb_env = env->tb_env;
|
||||||
|
|
||||||
|
timer_del(tb_env->decr_timer);
|
||||||
|
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
|
||||||
|
tb_env->decr_next = 0;
|
||||||
|
if (tb_env->hdecr_timer != NULL) {
|
||||||
|
timer_del(tb_env->hdecr_timer);
|
||||||
|
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
|
||||||
|
tb_env->hdecr_next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is a bug in Linux 2.4 kernels:
|
||||||
|
* if a decrementer exception is pending when it enables msr_ee at startup,
|
||||||
|
* it's not ready to handle it...
|
||||||
|
*/
|
||||||
|
cpu_ppc_store_decr(env, -1);
|
||||||
|
cpu_ppc_store_hdecr(env, -1);
|
||||||
|
cpu_ppc_store_purr(env, 0x0000000000000000ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_ppc_tb_free(CPUPPCState *env)
|
void cpu_ppc_tb_free(CPUPPCState *env)
|
||||||
|
@ -67,6 +67,7 @@ static void ppc_prep_reset(void *opaque)
|
|||||||
PowerPCCPU *cpu = opaque;
|
PowerPCCPU *cpu = opaque;
|
||||||
|
|
||||||
cpu_reset(CPU(cpu));
|
cpu_reset(CPU(cpu));
|
||||||
|
cpu_ppc_tb_reset(&cpu->env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
|
|||||||
|
|
||||||
kvm_check_mmu(cpu, &error_fatal);
|
kvm_check_mmu(cpu, &error_fatal);
|
||||||
|
|
||||||
|
cpu_ppc_tb_reset(env);
|
||||||
|
|
||||||
spapr_irq_cpu_intc_reset(spapr, cpu);
|
spapr_irq_cpu_intc_reset(spapr, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,8 @@ struct ppc_tb_t {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
|
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
|
||||||
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
|
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
|
||||||
|
void cpu_ppc_tb_reset(CPUPPCState *env);
|
||||||
void cpu_ppc_tb_free(CPUPPCState *env);
|
void cpu_ppc_tb_free(CPUPPCState *env);
|
||||||
void cpu_ppc_hdecr_init(CPUPPCState *env);
|
void cpu_ppc_hdecr_init(CPUPPCState *env);
|
||||||
void cpu_ppc_hdecr_exit(CPUPPCState *env);
|
void cpu_ppc_hdecr_exit(CPUPPCState *env);
|
||||||
|
Loading…
Reference in New Issue
Block a user