Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b33cb58 authored by Simon Guo's avatar Simon Guo Committed by Paul Mackerras
Browse files

KVM: PPC: Reimplement LOAD_FP/STORE_FP instruction mmio emulation with analyse_instr() input



This patch reimplements LOAD_FP/STORE_FP instruction MMIO emulation with
analyse_instr() input. It utilizes the FPCONV/UPDATE properties exported by
analyse_instr() and invokes kvmppc_handle_load(s)/kvmppc_handle_store()
accordingly.

For FP store MMIO emulation, the FP regs need to be flushed firstly so
that the right FP reg vals can be read from vcpu->arch.fpr, which will
be stored into MMIO data.

Suggested-by: default avatarPaul Mackerras <paulus@ozlabs.org>
Signed-off-by: default avatarSimon Guo <wei.guo.simon@gmail.com>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent 2e6baa46
Loading
Loading
Loading
Loading
+44 −157
Original line number Original line Diff line number Diff line
@@ -138,6 +138,26 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)


			break;
			break;
		}
		}
#ifdef CONFIG_PPC_FPU
		case LOAD_FP:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;

			if (op.type & FPCONV)
				vcpu->arch.mmio_sp64_extend = 1;

			if (op.type & SIGNEXT)
				emulated = kvmppc_handle_loads(run, vcpu,
					     KVM_MMIO_REG_FPR|op.reg, size, 1);
			else
				emulated = kvmppc_handle_load(run, vcpu,
					     KVM_MMIO_REG_FPR|op.reg, size, 1);

			if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
				kvmppc_set_gpr(vcpu, op.update_reg, op.ea);

			break;
#endif
		case STORE:
		case STORE:
			/* if need byte reverse, op.val has been reversed by
			/* if need byte reverse, op.val has been reversed by
			 * analyse_instr().
			 * analyse_instr().
@@ -149,6 +169,30 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
				kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
				kvmppc_set_gpr(vcpu, op.update_reg, op.ea);


			break;
			break;
#ifdef CONFIG_PPC_FPU
		case STORE_FP:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;

			/* The FP registers need to be flushed so that
			 * kvmppc_handle_store() can read actual FP vals
			 * from vcpu->arch.
			 */
			if (vcpu->kvm->arch.kvm_ops->giveup_ext)
				vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu,
						MSR_FP);

			if (op.type & FPCONV)
				vcpu->arch.mmio_sp64_extend = 1;

			emulated = kvmppc_handle_store(run, vcpu,
					VCPU_FPR(vcpu, op.reg), size, 1);

			if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
				kvmppc_set_gpr(vcpu, op.update_reg, op.ea);

			break;
#endif
		case CACHEOP:
		case CACHEOP:
			/* Do nothing. The guest is performing dcbi because
			/* Do nothing. The guest is performing dcbi because
			 * hardware DMA is not snooped by the dcache, but
			 * hardware DMA is not snooped by the dcache, but
@@ -170,93 +214,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
	switch (get_op(inst)) {
	switch (get_op(inst)) {
	case 31:
	case 31:
		switch (get_xop(inst)) {
		switch (get_xop(inst)) {
#ifdef CONFIG_PPC_FPU
		case OP_31_XOP_LFSX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			vcpu->arch.mmio_sp64_extend = 1;
			emulated = kvmppc_handle_load(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 4, 1);
			break;

		case OP_31_XOP_LFSUX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			vcpu->arch.mmio_sp64_extend = 1;
			emulated = kvmppc_handle_load(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 4, 1);
			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
			break;

		case OP_31_XOP_LFDX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_load(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 8, 1);
			break;

		case OP_31_XOP_LFDUX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_load(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 8, 1);
			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
			break;

		case OP_31_XOP_LFIWAX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_loads(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 4, 1);
			break;

		case OP_31_XOP_LFIWZX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_load(run, vcpu,
				KVM_MMIO_REG_FPR|rt, 4, 1);
			break;

		case OP_31_XOP_STFSX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			vcpu->arch.mmio_sp64_extend = 1;
			emulated = kvmppc_handle_store(run, vcpu,
				VCPU_FPR(vcpu, rs), 4, 1);
			break;

		case OP_31_XOP_STFSUX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			vcpu->arch.mmio_sp64_extend = 1;
			emulated = kvmppc_handle_store(run, vcpu,
				VCPU_FPR(vcpu, rs), 4, 1);
			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
			break;

		case OP_31_XOP_STFDX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_store(run, vcpu,
				VCPU_FPR(vcpu, rs), 8, 1);
			break;

		case OP_31_XOP_STFDUX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_store(run, vcpu,
				VCPU_FPR(vcpu, rs), 8, 1);
			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
			break;

		case OP_31_XOP_STFIWX:
			if (kvmppc_check_fp_disabled(vcpu))
				return EMULATE_DONE;
			emulated = kvmppc_handle_store(run, vcpu,
				VCPU_FPR(vcpu, rs), 4, 1);
			break;
#endif

#ifdef CONFIG_VSX
#ifdef CONFIG_VSX
		case OP_31_XOP_LXSDX:
		case OP_31_XOP_LXSDX:
			if (kvmppc_check_vsx_disabled(vcpu))
			if (kvmppc_check_vsx_disabled(vcpu))
@@ -421,76 +378,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
		}
		}
		break;
		break;


#ifdef CONFIG_PPC_FPU
	case OP_STFS:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		vcpu->arch.mmio_sp64_extend = 1;
		emulated = kvmppc_handle_store(run, vcpu,
			VCPU_FPR(vcpu, rs),
			4, 1);
		break;

	case OP_STFSU:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		vcpu->arch.mmio_sp64_extend = 1;
		emulated = kvmppc_handle_store(run, vcpu,
			VCPU_FPR(vcpu, rs),
			4, 1);
		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
		break;

	case OP_STFD:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		emulated = kvmppc_handle_store(run, vcpu,
			VCPU_FPR(vcpu, rs),
	                               8, 1);
		break;

	case OP_STFDU:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		emulated = kvmppc_handle_store(run, vcpu,
			VCPU_FPR(vcpu, rs),
	                               8, 1);
		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
		break;

	case OP_LFS:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		vcpu->arch.mmio_sp64_extend = 1;
		emulated = kvmppc_handle_load(run, vcpu,
			KVM_MMIO_REG_FPR|rt, 4, 1);
		break;

	case OP_LFSU:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		vcpu->arch.mmio_sp64_extend = 1;
		emulated = kvmppc_handle_load(run, vcpu,
			KVM_MMIO_REG_FPR|rt, 4, 1);
		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
		break;

	case OP_LFD:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		emulated = kvmppc_handle_load(run, vcpu,
			KVM_MMIO_REG_FPR|rt, 8, 1);
		break;

	case OP_LFDU:
		if (kvmppc_check_fp_disabled(vcpu))
			return EMULATE_DONE;
		emulated = kvmppc_handle_load(run, vcpu,
			KVM_MMIO_REG_FPR|rt, 8, 1);
		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
		break;
#endif

	default:
	default:
		emulated = EMULATE_FAIL;
		emulated = EMULATE_FAIL;
		break;
		break;