Commit 2737dee1 authored by Bibo Mao's avatar Bibo Mao Committed by Huacai Chen
Browse files

LoongArch: KVM: Add hypercall service support for usermode VMM



Some VMMs provides special hypercall service in usermode, KVM should not
handle the usermode hypercall service, thus pass it to usermode, let the
usermode VMM handle it.

Here a new code KVM_HCALL_CODE_USER_SERVICE is added for the user-mode
hypercall service, KVM lets all six registers visible to usermode VMM.

Signed-off-by: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent 4d38d041
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ enum emulation_result {
#define LOONGARCH_PV_FEAT_UPDATED	BIT_ULL(63)
#define LOONGARCH_PV_FEAT_MASK		(BIT(KVM_FEATURE_IPI) |		\
					 BIT(KVM_FEATURE_STEAL_TIME) |	\
					 BIT(KVM_FEATURE_USER_HCALL) |	\
					 BIT(KVM_FEATURE_VIRT_EXTIOI))

struct kvm_vcpu_arch {
+3 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#define KVM_HCALL_CODE_SERVICE		0
#define KVM_HCALL_CODE_SWDBG		1
#define KVM_HCALL_CODE_USER_SERVICE	2

#define KVM_HCALL_SERVICE		HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE)
#define  KVM_HCALL_FUNC_IPI		1
@@ -20,6 +21,8 @@

#define KVM_HCALL_SWDBG			HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SWDBG)

#define KVM_HCALL_USER_SERVICE		HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_USER_SERVICE)

/*
 * LoongArch hypercall return code
 */
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst);
int  kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst);
int  kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
int  kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
int  kvm_complete_user_service(struct kvm_vcpu *vcpu, struct kvm_run *run);
int  kvm_emu_idle(struct kvm_vcpu *vcpu);
int  kvm_pending_timer(struct kvm_vcpu *vcpu);
int  kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
+1 −0
Original line number Diff line number Diff line
@@ -17,5 +17,6 @@
#define  KVM_FEATURE_STEAL_TIME		2
/* BIT 24 - 31 are features configurable by user space vmm */
#define  KVM_FEATURE_VIRT_EXTIOI	24
#define  KVM_FEATURE_USER_HCALL		25

#endif /* _UAPI_ASM_KVM_PARA_H */
+30 −0
Original line number Diff line number Diff line
@@ -709,6 +709,14 @@ static int kvm_handle_write_fault(struct kvm_vcpu *vcpu)
	return kvm_handle_rdwr_fault(vcpu, true);
}

int kvm_complete_user_service(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
	update_pc(&vcpu->arch);
	kvm_write_reg(vcpu, LOONGARCH_GPR_A0, run->hypercall.ret);

	return 0;
}

/**
 * kvm_handle_fpu_disabled() - Guest used fpu however it is disabled at host
 * @vcpu:	Virtual CPU context.
@@ -873,6 +881,28 @@ static int kvm_handle_hypercall(struct kvm_vcpu *vcpu)
		vcpu->stat.hypercall_exits++;
		kvm_handle_service(vcpu);
		break;
	case KVM_HCALL_USER_SERVICE:
		if (!kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_USER_HCALL)) {
			kvm_write_reg(vcpu, LOONGARCH_GPR_A0, KVM_HCALL_INVALID_CODE);
			break;
		}

		vcpu->stat.hypercall_exits++;
		vcpu->run->exit_reason = KVM_EXIT_HYPERCALL;
		vcpu->run->hypercall.nr = KVM_HCALL_USER_SERVICE;
		vcpu->run->hypercall.args[0] = kvm_read_reg(vcpu, LOONGARCH_GPR_A0);
		vcpu->run->hypercall.args[1] = kvm_read_reg(vcpu, LOONGARCH_GPR_A1);
		vcpu->run->hypercall.args[2] = kvm_read_reg(vcpu, LOONGARCH_GPR_A2);
		vcpu->run->hypercall.args[3] = kvm_read_reg(vcpu, LOONGARCH_GPR_A3);
		vcpu->run->hypercall.args[4] = kvm_read_reg(vcpu, LOONGARCH_GPR_A4);
		vcpu->run->hypercall.args[5] = kvm_read_reg(vcpu, LOONGARCH_GPR_A5);
		vcpu->run->hypercall.flags = 0;
		/*
		 * Set invalid return value by default, let user-mode VMM modify it.
		 */
		vcpu->run->hypercall.ret = KVM_HCALL_INVALID_CODE;
		ret = RESUME_HOST;
		break;
	case KVM_HCALL_SWDBG:
		/* KVM_HCALL_SWDBG only in effective when SW_BP is enabled */
		if (vcpu->guest_debug & KVM_GUESTDBG_SW_BP_MASK) {
Loading