target-ppc: Synchronize FPU state with KVM
Currently qemu does not get and put the state of the floating point and vector registers to KVM. This is obviously a problem for savevm, as well as possibly being problematic for debugging of FP-using guests. This patch fixes this by using new extensions to the ONE_REG interface to synchronize the qemu floating point state with KVM. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
d67d40ea07
commit
70b79849b8
130
target-ppc/kvm.c
130
target-ppc/kvm.c
@ -521,6 +521,132 @@ static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr)
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_put_fp(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
struct kvm_one_reg reg;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (env->insns_flags & PPC_FLOAT) {
|
||||
uint64_t fpscr = env->fpscr;
|
||||
bool vsx = !!(env->insns_flags2 & PPC2_VSX);
|
||||
|
||||
reg.id = KVM_REG_PPC_FPSCR;
|
||||
reg.addr = (uintptr_t)&fpscr;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to set FPSCR to KVM: %s\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
uint64_t vsr[2];
|
||||
|
||||
vsr[0] = float64_val(env->fpr[i]);
|
||||
vsr[1] = env->vsr[i];
|
||||
reg.addr = (uintptr_t) &vsr;
|
||||
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
|
||||
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to set %s%d to KVM: %s\n", vsx ? "VSR" : "FPR",
|
||||
i, strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (env->insns_flags & PPC_ALTIVEC) {
|
||||
reg.id = KVM_REG_PPC_VSCR;
|
||||
reg.addr = (uintptr_t)&env->vscr;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to set VSCR to KVM: %s\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg.id = KVM_REG_PPC_VR(i);
|
||||
reg.addr = (uintptr_t)&env->avr[i];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to set VR%d to KVM: %s\n", i, strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_get_fp(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
struct kvm_one_reg reg;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (env->insns_flags & PPC_FLOAT) {
|
||||
uint64_t fpscr;
|
||||
bool vsx = !!(env->insns_flags2 & PPC2_VSX);
|
||||
|
||||
reg.id = KVM_REG_PPC_FPSCR;
|
||||
reg.addr = (uintptr_t)&fpscr;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to get FPSCR from KVM: %s\n", strerror(errno));
|
||||
return ret;
|
||||
} else {
|
||||
env->fpscr = fpscr;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
uint64_t vsr[2];
|
||||
|
||||
reg.addr = (uintptr_t) &vsr;
|
||||
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
|
||||
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to get %s%d from KVM: %s\n",
|
||||
vsx ? "VSR" : "FPR", i, strerror(errno));
|
||||
return ret;
|
||||
} else {
|
||||
env->fpr[i] = vsr[0];
|
||||
if (vsx) {
|
||||
env->vsr[i] = vsr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (env->insns_flags & PPC_ALTIVEC) {
|
||||
reg.id = KVM_REG_PPC_VSCR;
|
||||
reg.addr = (uintptr_t)&env->vscr;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to get VSCR from KVM: %s\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg.id = KVM_REG_PPC_VR(i);
|
||||
reg.addr = (uintptr_t)&env->avr[i];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret < 0) {
|
||||
dprintf("Unable to get VR%d from KVM: %s\n",
|
||||
i, strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
@ -561,6 +687,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
kvm_put_fp(cs);
|
||||
|
||||
if (env->tlb_dirty) {
|
||||
kvm_sw_tlb_put(cpu);
|
||||
env->tlb_dirty = false;
|
||||
@ -666,6 +794,8 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
for (i = 0;i < 32; i++)
|
||||
env->gpr[i] = regs.gpr[i];
|
||||
|
||||
kvm_get_fp(cs);
|
||||
|
||||
if (cap_booke_sregs) {
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
|
||||
if (ret < 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user