* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "cpu.h"
-#include "hw/hw.h"
+#include "hw/irq.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "qemu/log.h"
+#include "qemu/main-loop.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
+#include "sysemu/runstate.h"
#include "kvm_ppc.h"
+#include "migration/vmstate.h"
#include "trace.h"
//#define PPC_DEBUG_IRQ
}
if (old_pending != env->pending_interrupts) {
-#ifdef CONFIG_KVM
kvmppc_set_interrupt(cpu, n_IRQ, level);
-#endif
}
static void power7_set_irq(void *opaque, int pin, int level)
{
PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
+ &cpu->env, pin, level);
switch (pin) {
case POWER7_INPUT_INT:
LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
return;
}
- if (level) {
- env->irq_input_state |= 1 << pin;
- } else {
- env->irq_input_state &= ~(1 << pin);
- }
}
void ppcPOWER7_irq_init(PowerPCCPU *cpu)
static void power9_set_irq(void *opaque, int pin, int level)
{
PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
- env, pin, level);
+ &cpu->env, pin, level);
switch (pin) {
case POWER9_INPUT_INT:
LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
return;
}
- if (level) {
- env->irq_input_state |= 1 << pin;
- } else {
- env->irq_input_state &= ~(1 << pin);
- }
}
void ppcPOWER9_irq_init(PowerPCCPU *cpu)
void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
switch ((val >> 28) & 0x3) {
case 0x0:
&tb_env->atb_offset, ((uint64_t)value << 32) | tb);
}
+uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
+{
+ ppc_tb_t *tb_env = env->tb_env;
+
+ return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ tb_env->vtb_offset);
+}
+
+void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
+{
+ ppc_tb_t *tb_env = env->tb_env;
+
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ &tb_env->vtb_offset, value);
+}
+
+void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
+{
+ ppc_tb_t *tb_env = env->tb_env;
+ uint64_t tb;
+
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ tb_env->tb_offset);
+ tb &= 0xFFFFFFUL;
+ tb |= (value & ~0xFFFFFFUL);
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ &tb_env->tb_offset, tb);
+}
+
static void cpu_ppc_tb_stop (CPUPPCState *env)
{
ppc_tb_t *tb_env = env->tb_env;
target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
ppc_tb_t *tb_env = env->tb_env;
uint64_t hdecr;
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
{
ppc_tb_t *tb_env = env->tb_env;
- uint64_t diff;
- diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
-
- return tb_env->purr_load +
- muldiv64(diff, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
+ return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ tb_env->purr_offset);
}
/* When decrementer expires,
void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int nr_bits = 32;
void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value,
cpu_ppc_hdecr_excp(cpu);
}
-static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
+void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
{
- ppc_tb_t *tb_env = cpu->env.tb_env;
+ ppc_tb_t *tb_env = env->tb_env;
- tb_env->purr_load = value;
- tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ &tb_env->purr_offset, value);
}
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
{
CPUPPCState *env = opaque;
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
tb_env->tb_freq = freq;
*/
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
- cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
+ cpu_ppc_store_purr(env, 0x0000000000000000ULL);
}
static void timebase_save(PPCTimebase *tb)
* there is no need to update it from KVM here
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
+
+ tb->runstate_paused = runstate_check(RUN_STATE_PAUSED);
}
static void timebase_load(PPCTimebase *tb)
CPU_FOREACH(cpu) {
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
pcpu->env.tb_env->tb_offset = tb_off_adj;
-#if defined(CONFIG_KVM)
- kvm_set_one_reg(cpu, KVM_REG_PPC_TB_OFFSET,
- &pcpu->env.tb_env->tb_offset);
-#endif
+ kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
}
}
}
/*
- * When migrating, read the clock just before migration,
- * so that the guest clock counts during the events
- * between:
+ * When migrating a running guest, read the clock just
+ * before migration, so that the guest clock counts
+ * during the events between:
*
* * vm_stop()
* *
{
PPCTimebase *tb = opaque;
- timebase_save(tb);
+ /* guest_timebase won't be overridden in case of paused guest */
+ if (!tb->runstate_paused) {
+ timebase_save(tb);
+ }
return 0;
}
/* Set up (once) timebase frequency (in Hz) */
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env;
tb_env = g_malloc0(sizeof(ppc_tb_t));
env->tb_env = tb_env;
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
- if (env->insns_flags & PPC_SEGMENT_64B) {
+ if (is_book3s_arch2x(env)) {
/* All Book3S 64bit CPUs implement level based DEC logic */
tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
}
uint64_t now, next;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ppc40x_timer_t *ppc40x_timer;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
env->spr[SPR_40x_TSR] |= 1 << 27;
uint64_t now, next;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
/*****************************************************************************/
-/* Debug port */
-void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
+
+int ppc_cpu_pir(PowerPCCPU *cpu)
{
- addr &= 0xF;
- switch (addr) {
- case 0:
- printf("%c", val);
- break;
- case 1:
- printf("\n");
- fflush(stdout);
- break;
- case 2:
- printf("Set loglevel to %04" PRIx32 "\n", val);
- qemu_set_log(val | 0x100);
- break;
- }
+ CPUPPCState *env = &cpu->env;
+ return env->spr_cb[SPR_PIR].default_value;
}
PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- if (env->spr_cb[SPR_PIR].default_value == pir) {
+ if (ppc_cpu_pir(cpu) == pir) {
return cpu;
}
}
return NULL;
}
+
+void ppc_irq_reset(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+
+ env->irq_input_state = 0;
+ kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
+}