static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu, int rs, ulong addr, bool w, int i) { int emulated = EMULATE_FAIL; int r; u32 tmp[2]; int len = w ? sizeof(u32) : sizeof(u64); kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0]); tmp[1] = vcpu->arch.qpr[rs]; r = kvmppc_st(vcpu, &addr, len, tmp, true); vcpu->arch.paddr_accessed = addr; if (r < 0) { kvmppc_inject_pf(vcpu, addr, true); } else if ((r == EMULATE_DO_MMIO) && w) { emulated = kvmppc_handle_store(run, vcpu, tmp[0], 4, 1); } else if (r == EMULATE_DO_MMIO) { u64 val = ((u64)tmp[0] << 32) | tmp[1]; emulated = kvmppc_handle_store(run, vcpu, val, 8, 1); } else { emulated = EMULATE_DONE; } dprintk(KERN_INFO "KVM: PSQ_ST [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0], tmp[1], addr, len); return emulated; }
static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu, int rs, ulong addr, int ls_type) { int emulated = EMULATE_FAIL; int r; char tmp[8]; u64 val; int len; switch (ls_type) { case FPU_LS_SINGLE: kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp); val = *((u32*)tmp); len = sizeof(u32); break; case FPU_LS_SINGLE_LOW: *((u32*)tmp) = vcpu->arch.fpr[rs]; val = vcpu->arch.fpr[rs] & 0xffffffff; len = sizeof(u32); break; case FPU_LS_DOUBLE: *((u64*)tmp) = vcpu->arch.fpr[rs]; val = vcpu->arch.fpr[rs]; len = sizeof(u64); break; default: val = 0; len = 0; } r = kvmppc_st(vcpu, &addr, len, tmp, true); vcpu->arch.paddr_accessed = addr; if (r < 0) { kvmppc_inject_pf(vcpu, addr, true); } else if (r == EMULATE_DO_MMIO) { emulated = kvmppc_handle_store(run, vcpu, val, len, 1); } else { emulated = EMULATE_DONE; } dprintk(KERN_INFO "KVM: FPR_ST [0x%llx] at 0x%lx (%d)\n", val, addr, len); return emulated; }
static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu, int rs, ulong addr, int ls_type) { int emulated = EMULATE_FAIL; int r; char tmp[8]; int len = sizeof(u32); if (ls_type == FPU_LS_DOUBLE) len = sizeof(u64); /* read from memory */ r = kvmppc_ld(vcpu, &addr, len, tmp, true); vcpu->arch.paddr_accessed = addr; if (r < 0) { kvmppc_inject_pf(vcpu, addr, false); goto done_load; } else if (r == EMULATE_DO_MMIO) { emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs, len, 1); goto done_load; } emulated = EMULATE_DONE; /* put in registers */ switch (ls_type) { case FPU_LS_SINGLE: kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs)); vcpu->arch.qpr[rs] = *((u32*)tmp); break; case FPU_LS_DOUBLE: VCPU_FPR(vcpu, rs) = *((u64*)tmp); break; } dprintk(KERN_INFO "KVM: FPR_LD [0x%llx] at 0x%lx (%d)\n", *(u64*)tmp, addr, len); done_load: return emulated; }
static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu, int rs, ulong addr, bool w, int i) { int emulated = EMULATE_FAIL; int r; float one = 1.0; u32 tmp[2]; /* read from memory */ if (w) { r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true); memcpy(&tmp[1], &one, sizeof(u32)); } else { r = kvmppc_ld(vcpu, &addr, sizeof(u32) * 2, tmp, true); } vcpu->arch.paddr_accessed = addr; if (r < 0) { kvmppc_inject_pf(vcpu, addr, false); goto done_load; } else if ((r == EMULATE_DO_MMIO) && w) { emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs, 4, 1); vcpu->arch.qpr[rs] = tmp[1]; goto done_load; } else if (r == EMULATE_DO_MMIO) { emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs, 8, 1); goto done_load; } emulated = EMULATE_DONE; /* put in registers */ kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs)); vcpu->arch.qpr[rs] = tmp[1]; dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0], tmp[1], addr, w ? 4 : 8); done_load: return emulated; }