blob: af86a27b1bd4554e0f3d76f83b8d8edb3604effc [file] [log] [blame]
/*
* qemu-kvm-power.c
*
* Add KVM PowerPC specific calls for qemu.
*
* Copyright 2007 IBM Corporation.
* Added by & Authors:
* Jerone Young <jyoung5@us.ibm.com>
* Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
*
* This work is licensed under the GNU GPL licence version 2 or later.
*
*/
#include "config.h"
#include "config-host.h"
#include <string.h>
#include "hw/hw.h"
#include "sysemu.h"
#include "cpu.h"
#include "exec-all.h"
#include "helper_regs.h"
#include "qemu-kvm.h"
#include <libkvm.h>
#include <pthread.h>
#include <sys/utsname.h>
extern kvm_context_t kvm_context;
void cpu_reset(CPUState *env)
{
memset(env->breakpoints, 0, sizeof(env->breakpoints));
cpu_ppc_reset(env);
}
int kvm_arch_qemu_create_context(void)
{
return 0;
}
void kvm_arch_load_regs(CPUState *env)
{
struct kvm_regs regs;
int rc,i;
rc = kvm_get_regs(kvm_context, env->cpu_index, &regs);
if (rc == -1)
perror("kvm_get_regs FAILED");
/* cr is untouched in qemu and not existant in CPUState fr ppr */
/* hflags is a morphed to MSR on ppc, no need to sync that down to kvm */
regs.pc = env->nip;
regs.ctr = env->ctr;
regs.lr = env->lr;
regs.xer = env->xer;
regs.msr = env->msr;
regs.srr0 = env->spr[SPR_SRR0];
regs.srr1 = env->spr[SPR_SRR1];
regs.sprg0 = env->spr[SPR_SPRG0];
regs.sprg1 = env->spr[SPR_SPRG1];
regs.sprg2 = env->spr[SPR_SPRG2];
regs.sprg3 = env->spr[SPR_SPRG3];
regs.sprg4 = env->spr[SPR_SPRG4];
regs.sprg5 = env->spr[SPR_SPRG5];
regs.sprg6 = env->spr[SPR_SPRG6];
regs.sprg7 = env->spr[SPR_SPRG7];
for (i = 0;i < 32; i++){
regs.gpr[i] = env->gpr[i];
}
rc = kvm_set_regs(kvm_context, env->cpu_index, &regs);
if (rc == -1)
perror("kvm_set_regs FAILED");
}
void kvm_arch_save_regs(CPUState *env)
{
struct kvm_regs regs;
uint32_t i, rc;
rc = kvm_get_regs(kvm_context, env->cpu_index, &regs);
if (rc == -1)
perror("kvm_get_regs FAILED");
env->ctr =regs.ctr;
env->lr = regs.lr;
env->xer = regs.xer;
env->msr = regs.msr;
/* calculate hflags based on the current msr using the ppc qemu helper */
hreg_compute_hflags(env);
env->nip = regs.pc;
env->spr[SPR_SRR0] = regs.srr0;
env->spr[SPR_SRR1] = regs.srr1;
env->spr[SPR_SPRG0] = regs.sprg0;
env->spr[SPR_SPRG1] = regs.sprg1;
env->spr[SPR_SPRG2] = regs.sprg2;
env->spr[SPR_SPRG3] = regs.sprg3;
env->spr[SPR_SPRG4] = regs.sprg4;
env->spr[SPR_SPRG5] = regs.sprg5;
env->spr[SPR_SPRG6] = regs.sprg6;
env->spr[SPR_SPRG7] = regs.sprg7;
for (i = 0;i < 32; i++){
env->gpr[i] = regs.gpr[i];
}
}
int kvm_arch_qemu_init_env(CPUState *cenv)
{
if (cenv->cpu_index == 0) {
/* load any registers set in env into
kvm for the first guest vcpu */
kvm_load_registers(cenv);
}
return 0;
}
int kvm_arch_halt(void *opaque, int vcpu)
{
CPUState *env = cpu_single_env;
if (!(env->interrupt_request & CPU_INTERRUPT_HARD)
&& (msr_ee))
{
env->halted = 1;
env->exception_index = EXCP_HLT;
}
return 1;
}
void kvm_arch_pre_kvm_run(void *opaque, int vcpu)
{
return;
}
void kvm_arch_post_kvm_run(void *opaque, int vcpu)
{
CPUState *env = qemu_kvm_cpu_env(vcpu);
cpu_single_env = env;
}
int kvm_arch_has_work(CPUState *env)
{
if ((env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT)) &&
(msr_ee))
return 1;
return 0;
}
int kvm_arch_try_push_interrupts(void *opaque)
{
CPUState *env = cpu_single_env;
int r;
unsigned irq;
/* PowerPC Qemu tracks the various core input pins (interrupt, critical
* interrupt, reset, etc) in PPC-specific env->irq_input_state. */
if (kvm_is_ready_for_interrupt_injection(kvm_context, env->cpu_index) &&
(env->irq_input_state & (1<<PPC40x_INPUT_INT)))
{
/* For now KVM disregards the 'irq' argument. However, in the
* future KVM could cache it in-kernel to avoid a heavyweight exit
* when reading the UIC.
*/
irq = -1U;
r = kvm_inject_irq(kvm_context, env->cpu_index, irq);
if (r < 0)
printf("cpu %d fail inject %x\n", env->cpu_index, irq);
}
/* We don't know if there are more interrupts pending after this. However,
* the guest will return to userspace in the course of handling this one
* anyways, so we will get a chance to deliver the rest. */
return 0;
}
int kvm_arch_try_push_nmi(void *opaque)
{
/* no nmi irq, so discard that call for now and return success.
* This might later get mapped to something on powerpc too if we want
* to support the nmi monitor command somwhow */
return 0;
}
void kvm_arch_update_regs_for_sipi(CPUState *env)
{
printf("%s: no kvm-powerpc multi processor support yet!\n", __func__);
}
/* map dcr access to existing qemu dcr emulation */
int handle_powerpc_dcr_read(int vcpu, uint32_t dcrn, uint32_t *data)
{
CPUState *env = cpu_single_env;
if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
return 0; /* XXX ignore failed DCR ops */
}
int handle_powerpc_dcr_write(int vcpu, uint32_t dcrn, uint32_t data)
{
CPUState *env = cpu_single_env;
if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
return 0; /* XXX ignore failed DCR ops */
}
void kvm_arch_cpu_reset(CPUState *env)
{
}