Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

authored by

Bibo Mao and committed by
Huacai Chen
2737dee1 4d38d041

+42 -1
+1
arch/loongarch/include/asm/kvm_host.h
··· 162 162 #define LOONGARCH_PV_FEAT_UPDATED BIT_ULL(63) 163 163 #define LOONGARCH_PV_FEAT_MASK (BIT(KVM_FEATURE_IPI) | \ 164 164 BIT(KVM_FEATURE_STEAL_TIME) | \ 165 + BIT(KVM_FEATURE_USER_HCALL) | \ 165 166 BIT(KVM_FEATURE_VIRT_EXTIOI)) 166 167 167 168 struct kvm_vcpu_arch {
+3
arch/loongarch/include/asm/kvm_para.h
··· 13 13 14 14 #define KVM_HCALL_CODE_SERVICE 0 15 15 #define KVM_HCALL_CODE_SWDBG 1 16 + #define KVM_HCALL_CODE_USER_SERVICE 2 16 17 17 18 #define KVM_HCALL_SERVICE HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE) 18 19 #define KVM_HCALL_FUNC_IPI 1 19 20 #define KVM_HCALL_FUNC_NOTIFY 2 20 21 21 22 #define KVM_HCALL_SWDBG HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SWDBG) 23 + 24 + #define KVM_HCALL_USER_SERVICE HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_USER_SERVICE) 22 25 23 26 /* 24 27 * LoongArch hypercall return code
+1
arch/loongarch/include/asm/kvm_vcpu.h
··· 43 43 int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst); 44 44 int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run); 45 45 int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run); 46 + int kvm_complete_user_service(struct kvm_vcpu *vcpu, struct kvm_run *run); 46 47 int kvm_emu_idle(struct kvm_vcpu *vcpu); 47 48 int kvm_pending_timer(struct kvm_vcpu *vcpu); 48 49 int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
+1
arch/loongarch/include/uapi/asm/kvm_para.h
··· 17 17 #define KVM_FEATURE_STEAL_TIME 2 18 18 /* BIT 24 - 31 are features configurable by user space vmm */ 19 19 #define KVM_FEATURE_VIRT_EXTIOI 24 20 + #define KVM_FEATURE_USER_HCALL 25 20 21 21 22 #endif /* _UAPI_ASM_KVM_PARA_H */
+30
arch/loongarch/kvm/exit.c
··· 709 709 return kvm_handle_rdwr_fault(vcpu, true); 710 710 } 711 711 712 + int kvm_complete_user_service(struct kvm_vcpu *vcpu, struct kvm_run *run) 713 + { 714 + update_pc(&vcpu->arch); 715 + kvm_write_reg(vcpu, LOONGARCH_GPR_A0, run->hypercall.ret); 716 + 717 + return 0; 718 + } 719 + 712 720 /** 713 721 * kvm_handle_fpu_disabled() - Guest used fpu however it is disabled at host 714 722 * @vcpu: Virtual CPU context. ··· 880 872 case KVM_HCALL_SERVICE: 881 873 vcpu->stat.hypercall_exits++; 882 874 kvm_handle_service(vcpu); 875 + break; 876 + case KVM_HCALL_USER_SERVICE: 877 + if (!kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_USER_HCALL)) { 878 + kvm_write_reg(vcpu, LOONGARCH_GPR_A0, KVM_HCALL_INVALID_CODE); 879 + break; 880 + } 881 + 882 + vcpu->stat.hypercall_exits++; 883 + vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; 884 + vcpu->run->hypercall.nr = KVM_HCALL_USER_SERVICE; 885 + vcpu->run->hypercall.args[0] = kvm_read_reg(vcpu, LOONGARCH_GPR_A0); 886 + vcpu->run->hypercall.args[1] = kvm_read_reg(vcpu, LOONGARCH_GPR_A1); 887 + vcpu->run->hypercall.args[2] = kvm_read_reg(vcpu, LOONGARCH_GPR_A2); 888 + vcpu->run->hypercall.args[3] = kvm_read_reg(vcpu, LOONGARCH_GPR_A3); 889 + vcpu->run->hypercall.args[4] = kvm_read_reg(vcpu, LOONGARCH_GPR_A4); 890 + vcpu->run->hypercall.args[5] = kvm_read_reg(vcpu, LOONGARCH_GPR_A5); 891 + vcpu->run->hypercall.flags = 0; 892 + /* 893 + * Set invalid return value by default, let user-mode VMM modify it. 894 + */ 895 + vcpu->run->hypercall.ret = KVM_HCALL_INVALID_CODE; 896 + ret = RESUME_HOST; 883 897 break; 884 898 case KVM_HCALL_SWDBG: 885 899 /* KVM_HCALL_SWDBG only in effective when SW_BP is enabled */
+6 -1
arch/loongarch/kvm/vcpu.c
··· 1732 1732 vcpu->mmio_needed = 0; 1733 1733 } 1734 1734 1735 - if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) { 1735 + switch (run->exit_reason) { 1736 + case KVM_EXIT_HYPERCALL: 1737 + kvm_complete_user_service(vcpu, run); 1738 + break; 1739 + case KVM_EXIT_LOONGARCH_IOCSR: 1736 1740 if (!run->iocsr_io.is_write) 1737 1741 kvm_complete_iocsr_read(vcpu, run); 1742 + break; 1738 1743 } 1739 1744 1740 1745 if (!vcpu->wants_to_run)