diff mbox series

[v2] LoongArch: KVM: Add hypercall service support for usermode VMM

Message ID 20250103023053.2625226-1-maobibo@loongson.cn (mailing list archive)
State New
Headers show
Series [v2] LoongArch: KVM: Add hypercall service support for usermode VMM | expand

Commit Message

bibo mao Jan. 3, 2025, 2:30 a.m. UTC
Some VMMs provides special hypercall service in usermode, KVM need
not handle the usermode hypercall service and pass it to VMM and
let VMM handle it.

Here new code KVM_HCALL_CODE_USER is added for user-mode hypercall
service, KVM lets all six registers visiable to VMM.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
  v1 ... v2:
  1. Add function kvm_complete_user_service() when finish hypercall
     in user-mode VMM and continue to run.
  2. Add hypercall_exits stat information.
---
 arch/loongarch/include/asm/kvm_host.h      |  1 +
 arch/loongarch/include/asm/kvm_para.h      |  2 ++
 arch/loongarch/include/asm/kvm_vcpu.h      |  1 +
 arch/loongarch/include/uapi/asm/kvm_para.h |  1 +
 arch/loongarch/kvm/exit.c                  | 30 ++++++++++++++++++++++
 arch/loongarch/kvm/vcpu.c                  |  3 ++-
 6 files changed, 37 insertions(+), 1 deletion(-)


base-commit: fc033cf25e612e840e545f8d5ad2edd6ba613ed5

Comments

Huacai Chen Jan. 4, 2025, 2:07 p.m. UTC | #1
On Fri, Jan 3, 2025 at 10:31 AM Bibo Mao <maobibo@loongson.cn> wrote:
>
> Some VMMs provides special hypercall service in usermode, KVM need
> not handle the usermode hypercall service and pass it to VMM and
> let VMM handle it.
>
> Here new code KVM_HCALL_CODE_USER is added for user-mode hypercall
> service, KVM lets all six registers visiable to VMM.
>
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> ---
>   v1 ... v2:
>   1. Add function kvm_complete_user_service() when finish hypercall
>      in user-mode VMM and continue to run.
>   2. Add hypercall_exits stat information.
> ---
>  arch/loongarch/include/asm/kvm_host.h      |  1 +
>  arch/loongarch/include/asm/kvm_para.h      |  2 ++
>  arch/loongarch/include/asm/kvm_vcpu.h      |  1 +
>  arch/loongarch/include/uapi/asm/kvm_para.h |  1 +
>  arch/loongarch/kvm/exit.c                  | 30 ++++++++++++++++++++++
>  arch/loongarch/kvm/vcpu.c                  |  3 ++-
>  6 files changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> index 7b8367c39da8..590982cd986e 100644
> --- a/arch/loongarch/include/asm/kvm_host.h
> +++ b/arch/loongarch/include/asm/kvm_host.h
> @@ -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 {
> diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h
> index c4e84227280d..d3c00de484f6 100644
> --- a/arch/loongarch/include/asm/kvm_para.h
> +++ b/arch/loongarch/include/asm/kvm_para.h
> @@ -13,12 +13,14 @@
>
>  #define KVM_HCALL_CODE_SERVICE         0
>  #define KVM_HCALL_CODE_SWDBG           1
> +#define KVM_HCALL_CODE_USER            2
Queued but rename KVM_HCALL_CODE_USER to KVM_HCALL_CODE_USER_SERVICE
to keep consistency, thanks.

Huacai

>
>  #define KVM_HCALL_SERVICE              HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE)
>  #define  KVM_HCALL_FUNC_IPI            1
>  #define  KVM_HCALL_FUNC_NOTIFY         2
>
>  #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)
>
>  /*
>   * LoongArch hypercall return code
> diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
> index d7e8f7d50ee0..2c349f961bfb 100644
> --- a/arch/loongarch/include/asm/kvm_vcpu.h
> +++ b/arch/loongarch/include/asm/kvm_vcpu.h
> @@ -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);
> diff --git a/arch/loongarch/include/uapi/asm/kvm_para.h b/arch/loongarch/include/uapi/asm/kvm_para.h
> index b0604aa9b4bb..76d802ef01ce 100644
> --- a/arch/loongarch/include/uapi/asm/kvm_para.h
> +++ b/arch/loongarch/include/uapi/asm/kvm_para.h
> @@ -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 */
> diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
> index a7893bd01e73..70b5ed1241c4 100644
> --- a/arch/loongarch/kvm/exit.c
> +++ b/arch/loongarch/kvm/exit.c
> @@ -538,6 +538,13 @@ int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
>         return er;
>  }
>
> +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;
> +}
> +
>  int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
>  {
>         int idx, ret;
> @@ -873,6 +880,29 @@ 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
> +                * Need 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) {
> diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
> index d18a4a270415..888480a5bc25 100644
> --- a/arch/loongarch/kvm/vcpu.c
> +++ b/arch/loongarch/kvm/vcpu.c
> @@ -1735,7 +1735,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>         if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
>                 if (!run->iocsr_io.is_write)
>                         kvm_complete_iocsr_read(vcpu, run);
> -       }
> +       } else if (run->exit_reason == KVM_EXIT_HYPERCALL)
> +               kvm_complete_user_service(vcpu, run);
>
>         if (!vcpu->wants_to_run)
>                 return r;
>
> base-commit: fc033cf25e612e840e545f8d5ad2edd6ba613ed5
> --
> 2.39.3
>
diff mbox series

Patch

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 7b8367c39da8..590982cd986e 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -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 {
diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h
index c4e84227280d..d3c00de484f6 100644
--- a/arch/loongarch/include/asm/kvm_para.h
+++ b/arch/loongarch/include/asm/kvm_para.h
@@ -13,12 +13,14 @@ 
 
 #define KVM_HCALL_CODE_SERVICE		0
 #define KVM_HCALL_CODE_SWDBG		1
+#define KVM_HCALL_CODE_USER		2
 
 #define KVM_HCALL_SERVICE		HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE)
 #define  KVM_HCALL_FUNC_IPI		1
 #define  KVM_HCALL_FUNC_NOTIFY		2
 
 #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)
 
 /*
  * LoongArch hypercall return code
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
index d7e8f7d50ee0..2c349f961bfb 100644
--- a/arch/loongarch/include/asm/kvm_vcpu.h
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -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);
diff --git a/arch/loongarch/include/uapi/asm/kvm_para.h b/arch/loongarch/include/uapi/asm/kvm_para.h
index b0604aa9b4bb..76d802ef01ce 100644
--- a/arch/loongarch/include/uapi/asm/kvm_para.h
+++ b/arch/loongarch/include/uapi/asm/kvm_para.h
@@ -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 */
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index a7893bd01e73..70b5ed1241c4 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -538,6 +538,13 @@  int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return er;
 }
 
+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;
+}
+
 int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
 {
 	int idx, ret;
@@ -873,6 +880,29 @@  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
+		 * Need 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) {
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index d18a4a270415..888480a5bc25 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -1735,7 +1735,8 @@  int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 	if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
 		if (!run->iocsr_io.is_write)
 			kvm_complete_iocsr_read(vcpu, run);
-	}
+	} else if (run->exit_reason == KVM_EXIT_HYPERCALL)
+		kvm_complete_user_service(vcpu, run);
 
 	if (!vcpu->wants_to_run)
 		return r;