mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-11-01 09:13:37 +00:00
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>
This commit is contained in:
parent
4d38d0416e
commit
2737dee106
6 changed files with 42 additions and 1 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue