mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-23 23:03:59 +00:00
KVM: PPC: Book3S: Add MMIO emulation for VMX instructions
This patch provides the MMIO load/store vector indexed X-Form emulation. Instructions implemented: lvx: the quadword in storage addressed by the result of EA & 0xffff_ffff_ffff_fff0 is loaded into VRT. stvx: the contents of VRS are stored into the quadword in storage addressed by the result of EA & 0xffff_ffff_ffff_fff0. Reported-by: Gopesh Kumar Chaudhary <gopchaud@in.ibm.com> Reported-by: Balamuruhan S <bala24@linux.vnet.ibm.com> Signed-off-by: Jose Ricardo Ziviani <joserz@linux.vnet.ibm.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
d20fe50a7b
commit
09f984961c
5 changed files with 198 additions and 0 deletions
|
@ -690,6 +690,7 @@ struct kvm_vcpu_arch {
|
||||||
u8 mmio_vsx_offset;
|
u8 mmio_vsx_offset;
|
||||||
u8 mmio_vsx_copy_type;
|
u8 mmio_vsx_copy_type;
|
||||||
u8 mmio_vsx_tx_sx_enabled;
|
u8 mmio_vsx_tx_sx_enabled;
|
||||||
|
u8 mmio_vmx_copy_nums;
|
||||||
u8 osi_needed;
|
u8 osi_needed;
|
||||||
u8 osi_enabled;
|
u8 osi_enabled;
|
||||||
u8 papr_enabled;
|
u8 papr_enabled;
|
||||||
|
@ -804,6 +805,7 @@ struct kvm_vcpu_arch {
|
||||||
#define KVM_MMIO_REG_QPR 0x0040
|
#define KVM_MMIO_REG_QPR 0x0040
|
||||||
#define KVM_MMIO_REG_FQPR 0x0060
|
#define KVM_MMIO_REG_FQPR 0x0060
|
||||||
#define KVM_MMIO_REG_VSX 0x0080
|
#define KVM_MMIO_REG_VSX 0x0080
|
||||||
|
#define KVM_MMIO_REG_VMX 0x00c0
|
||||||
|
|
||||||
#define __KVM_HAVE_ARCH_WQP
|
#define __KVM_HAVE_ARCH_WQP
|
||||||
#define __KVM_HAVE_CREATE_DEVICE
|
#define __KVM_HAVE_CREATE_DEVICE
|
||||||
|
|
|
@ -81,6 +81,10 @@ extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
extern int kvmppc_handle_vsx_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
extern int kvmppc_handle_vsx_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
unsigned int rt, unsigned int bytes,
|
unsigned int rt, unsigned int bytes,
|
||||||
int is_default_endian, int mmio_sign_extend);
|
int is_default_endian, int mmio_sign_extend);
|
||||||
|
extern int kvmppc_handle_load128_by2x64(struct kvm_run *run,
|
||||||
|
struct kvm_vcpu *vcpu, unsigned int rt, int is_default_endian);
|
||||||
|
extern int kvmppc_handle_store128_by2x64(struct kvm_run *run,
|
||||||
|
struct kvm_vcpu *vcpu, unsigned int rs, int is_default_endian);
|
||||||
extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
u64 val, unsigned int bytes,
|
u64 val, unsigned int bytes,
|
||||||
int is_default_endian);
|
int is_default_endian);
|
||||||
|
|
|
@ -156,6 +156,12 @@
|
||||||
#define OP_31_XOP_LFDX 599
|
#define OP_31_XOP_LFDX 599
|
||||||
#define OP_31_XOP_LFDUX 631
|
#define OP_31_XOP_LFDUX 631
|
||||||
|
|
||||||
|
/* VMX Vector Load Instructions */
|
||||||
|
#define OP_31_XOP_LVX 103
|
||||||
|
|
||||||
|
/* VMX Vector Store Instructions */
|
||||||
|
#define OP_31_XOP_STVX 231
|
||||||
|
|
||||||
#define OP_LWZ 32
|
#define OP_LWZ 32
|
||||||
#define OP_STFS 52
|
#define OP_STFS 52
|
||||||
#define OP_STFSU 53
|
#define OP_STFSU 53
|
||||||
|
|
|
@ -58,6 +58,18 @@ static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_VSX */
|
#endif /* CONFIG_VSX */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu)
|
||||||
|
{
|
||||||
|
if (!(kvmppc_get_msr(vcpu) & MSR_VEC)) {
|
||||||
|
kvmppc_core_queue_vec_unavail(vcpu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ALTIVEC */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX to do:
|
* XXX to do:
|
||||||
* lfiwax, lfiwzx
|
* lfiwax, lfiwzx
|
||||||
|
@ -98,6 +110,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
|
||||||
vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_NONE;
|
vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_NONE;
|
||||||
vcpu->arch.mmio_sp64_extend = 0;
|
vcpu->arch.mmio_sp64_extend = 0;
|
||||||
vcpu->arch.mmio_sign_extend = 0;
|
vcpu->arch.mmio_sign_extend = 0;
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums = 0;
|
||||||
|
|
||||||
switch (get_op(inst)) {
|
switch (get_op(inst)) {
|
||||||
case 31:
|
case 31:
|
||||||
|
@ -459,6 +472,29 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
|
||||||
rs, 4, 1);
|
rs, 4, 1);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_VSX */
|
#endif /* CONFIG_VSX */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
case OP_31_XOP_LVX:
|
||||||
|
if (kvmppc_check_altivec_disabled(vcpu))
|
||||||
|
return EMULATE_DONE;
|
||||||
|
vcpu->arch.vaddr_accessed &= ~0xFULL;
|
||||||
|
vcpu->arch.paddr_accessed &= ~0xFULL;
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums = 2;
|
||||||
|
emulated = kvmppc_handle_load128_by2x64(run, vcpu,
|
||||||
|
KVM_MMIO_REG_VMX|rt, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_31_XOP_STVX:
|
||||||
|
if (kvmppc_check_altivec_disabled(vcpu))
|
||||||
|
return EMULATE_DONE;
|
||||||
|
vcpu->arch.vaddr_accessed &= ~0xFULL;
|
||||||
|
vcpu->arch.paddr_accessed &= ~0xFULL;
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums = 2;
|
||||||
|
emulated = kvmppc_handle_store128_by2x64(run, vcpu,
|
||||||
|
rs, 1);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_ALTIVEC */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
emulated = EMULATE_FAIL;
|
emulated = EMULATE_FAIL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -924,6 +924,34 @@ static inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_VSX */
|
#endif /* CONFIG_VSX */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
static inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu,
|
||||||
|
u64 gpr)
|
||||||
|
{
|
||||||
|
int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
|
||||||
|
u32 hi, lo;
|
||||||
|
u32 di;
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN
|
||||||
|
hi = gpr >> 32;
|
||||||
|
lo = gpr & 0xffffffff;
|
||||||
|
#else
|
||||||
|
lo = gpr >> 32;
|
||||||
|
hi = gpr & 0xffffffff;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
di = 2 - vcpu->arch.mmio_vmx_copy_nums; /* doubleword index */
|
||||||
|
if (di > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vcpu->arch.mmio_host_swabbed)
|
||||||
|
di = 1 - di;
|
||||||
|
|
||||||
|
VCPU_VSX_VR(vcpu, index).u[di * 2] = hi;
|
||||||
|
VCPU_VSX_VR(vcpu, index).u[di * 2 + 1] = lo;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ALTIVEC */
|
||||||
|
|
||||||
#ifdef CONFIG_PPC_FPU
|
#ifdef CONFIG_PPC_FPU
|
||||||
static inline u64 sp_to_dp(u32 fprs)
|
static inline u64 sp_to_dp(u32 fprs)
|
||||||
{
|
{
|
||||||
|
@ -1026,6 +1054,11 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
|
||||||
KVMPPC_VSX_COPY_DWORD_LOAD_DUMP)
|
KVMPPC_VSX_COPY_DWORD_LOAD_DUMP)
|
||||||
kvmppc_set_vsr_dword_dump(vcpu, gpr);
|
kvmppc_set_vsr_dword_dump(vcpu, gpr);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
case KVM_MMIO_REG_VMX:
|
||||||
|
kvmppc_set_vmx_dword(vcpu, gpr);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
|
@ -1302,6 +1335,111 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_VSX */
|
#endif /* CONFIG_VSX */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
/* handle quadword load access in two halves */
|
||||||
|
int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
|
unsigned int rt, int is_default_endian)
|
||||||
|
{
|
||||||
|
enum emulation_result emulated;
|
||||||
|
|
||||||
|
while (vcpu->arch.mmio_vmx_copy_nums) {
|
||||||
|
emulated = __kvmppc_handle_load(run, vcpu, rt, 8,
|
||||||
|
is_default_endian, 0);
|
||||||
|
|
||||||
|
if (emulated != EMULATE_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
vcpu->arch.paddr_accessed += run->mmio.len;
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return emulated;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int kvmppc_get_vmx_data(struct kvm_vcpu *vcpu, int rs, u64 *val)
|
||||||
|
{
|
||||||
|
vector128 vrs = VCPU_VSX_VR(vcpu, rs);
|
||||||
|
u32 di;
|
||||||
|
u64 w0, w1;
|
||||||
|
|
||||||
|
di = 2 - vcpu->arch.mmio_vmx_copy_nums; /* doubleword index */
|
||||||
|
if (di > 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (vcpu->arch.mmio_host_swabbed)
|
||||||
|
di = 1 - di;
|
||||||
|
|
||||||
|
w0 = vrs.u[di * 2];
|
||||||
|
w1 = vrs.u[di * 2 + 1];
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN
|
||||||
|
*val = (w0 << 32) | w1;
|
||||||
|
#else
|
||||||
|
*val = (w1 << 32) | w0;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle quadword store in two halves */
|
||||||
|
int kvmppc_handle_store128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
|
unsigned int rs, int is_default_endian)
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
enum emulation_result emulated = EMULATE_DONE;
|
||||||
|
|
||||||
|
vcpu->arch.io_gpr = rs;
|
||||||
|
|
||||||
|
while (vcpu->arch.mmio_vmx_copy_nums) {
|
||||||
|
if (kvmppc_get_vmx_data(vcpu, rs, &val) == -1)
|
||||||
|
return EMULATE_FAIL;
|
||||||
|
|
||||||
|
emulated = kvmppc_handle_store(run, vcpu, val, 8,
|
||||||
|
is_default_endian);
|
||||||
|
if (emulated != EMULATE_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
vcpu->arch.paddr_accessed += run->mmio.len;
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return emulated;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvmppc_emulate_mmio_vmx_loadstore(struct kvm_vcpu *vcpu,
|
||||||
|
struct kvm_run *run)
|
||||||
|
{
|
||||||
|
enum emulation_result emulated = EMULATE_FAIL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
vcpu->arch.paddr_accessed += run->mmio.len;
|
||||||
|
|
||||||
|
if (!vcpu->mmio_is_write) {
|
||||||
|
emulated = kvmppc_handle_load128_by2x64(run, vcpu,
|
||||||
|
vcpu->arch.io_gpr, 1);
|
||||||
|
} else {
|
||||||
|
emulated = kvmppc_handle_store128_by2x64(run, vcpu,
|
||||||
|
vcpu->arch.io_gpr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (emulated) {
|
||||||
|
case EMULATE_DO_MMIO:
|
||||||
|
run->exit_reason = KVM_EXIT_MMIO;
|
||||||
|
r = RESUME_HOST;
|
||||||
|
break;
|
||||||
|
case EMULATE_FAIL:
|
||||||
|
pr_info("KVM: MMIO emulation failed (VMX repeat)\n");
|
||||||
|
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||||
|
run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
|
||||||
|
r = RESUME_HOST;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = RESUME_GUEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ALTIVEC */
|
||||||
|
|
||||||
int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -1420,6 +1558,18 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
if (vcpu->arch.mmio_vmx_copy_nums > 0)
|
||||||
|
vcpu->arch.mmio_vmx_copy_nums--;
|
||||||
|
|
||||||
|
if (vcpu->arch.mmio_vmx_copy_nums > 0) {
|
||||||
|
r = kvmppc_emulate_mmio_vmx_loadstore(vcpu, run);
|
||||||
|
if (r == RESUME_HOST) {
|
||||||
|
vcpu->mmio_needed = 1;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
} else if (vcpu->arch.osi_needed) {
|
} else if (vcpu->arch.osi_needed) {
|
||||||
u64 *gprs = run->osi.gprs;
|
u64 *gprs = run->osi.gprs;
|
||||||
|
|
Loading…
Add table
Reference in a new issue