]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
LoongArch: KVM: Add hypercall service support for usermode VMM
authorBibo Mao <maobibo@loongson.cn>
Mon, 13 Jan 2025 13:37:17 +0000 (21:37 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Mon, 13 Jan 2025 13:37:17 +0000 (21:37 +0800)
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: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/include/asm/kvm_host.h
arch/loongarch/include/asm/kvm_para.h
arch/loongarch/include/asm/kvm_vcpu.h
arch/loongarch/include/uapi/asm/kvm_para.h
arch/loongarch/kvm/exit.c
arch/loongarch/kvm/vcpu.c

index 7b8367c39da85f2328663d44f6cf82457dca7290..590982cd986ec8186ade85df96e252570d2ec444 100644 (file)
@@ -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 {
index c4e84227280dc1ec74a362723972cb3de6830092..3e4b397f423f48f3157bf0efd1bd9d20bbd9d8e1 100644 (file)
@@ -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
  */
index d7e8f7d50ee0ce13360336f6c66ba24c746989ea..2c349f961bfbcf5b2ed5983bc6c272b37957aa2b 100644 (file)
@@ -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);
index b0604aa9b4bbd29dfafedbdf59f571bd445c2c2c..76d802ef01ce3cb426fb8627a7aac7fb41cc6ec6 100644 (file)
@@ -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 */
index a7893bd01e732a85e116762eb10e18edd806450c..c1e8ec5b941b22cc32c0ed63e63d4fb6963c9559 100644 (file)
@@ -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) {
index d18a4a2704150ebdac537fe6348f1c6ae4daaca7..fb72095c8077e8c5b81db7c284f365e426483fd2 100644 (file)
@@ -1732,9 +1732,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                vcpu->mmio_needed = 0;
        }
 
-       if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
+       switch (run->exit_reason) {
+       case KVM_EXIT_HYPERCALL:
+               kvm_complete_user_service(vcpu, run);
+               break;
+       case KVM_EXIT_LOONGARCH_IOCSR:
                if (!run->iocsr_io.is_write)
                        kvm_complete_iocsr_read(vcpu, run);
+               break;
        }
 
        if (!vcpu->wants_to_run)