summaryrefslogtreecommitdiffstats
path: root/arch/loongarch/kvm
diff options
context:
space:
mode:
authorBibo Mao <maobibo@loongson.cn>2024-05-06 22:00:47 +0800
committerHuacai Chen <chenhuacai@loongson.cn>2024-05-06 22:00:47 +0800
commit163e9fc6957fc24d1d6c0a30a3febfd2ecade039 (patch)
tree00967c144a87dd2512a823725a2c60be600695e1 /arch/loongarch/kvm
parent74c16b2e2b0c3b193324f47300fd30cf03a606b7 (diff)
downloadlinux-163e9fc6957fc24d1d6c0a30a3febfd2ecade039.tar.gz
linux-163e9fc6957fc24d1d6c0a30a3febfd2ecade039.tar.bz2
linux-163e9fc6957fc24d1d6c0a30a3febfd2ecade039.zip
LoongArch: KVM: Add software breakpoint support
When VM runs in kvm mode, system will not exit to host mode when executing a general software breakpoint instruction such as INSN_BREAK, trap exception happens in guest mode rather than host mode. In order to debug guest kernel on host side, one mechanism should be used to let VM exit to host mode. Here a hypercall instruction with a special code is used for software breakpoint usage. VM exits to host mode and kvm hypervisor identifies the special hypercall code and sets exit_reason with KVM_EXIT_DEBUG. And then let qemu handle it. Idea comes from ppc kvm, one api KVM_REG_LOONGARCH_DEBUG_INST is added to get the hypercall code. VMM needs get sw breakpoint instruction with this api and set the corresponding sw break point for guest kernel. Signed-off-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Diffstat (limited to 'arch/loongarch/kvm')
-rw-r--r--arch/loongarch/kvm/exit.c16
-rw-r--r--arch/loongarch/kvm/vcpu.c13
-rw-r--r--arch/loongarch/kvm/vm.c1
3 files changed, 27 insertions, 3 deletions
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index 5ace3e8b4e80..43cf34f31c10 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -760,25 +760,37 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu)
static int kvm_handle_hypercall(struct kvm_vcpu *vcpu)
{
+ int ret;
larch_inst inst;
unsigned int code;
inst.word = vcpu->arch.badi;
code = inst.reg0i15_format.immediate;
- update_pc(&vcpu->arch);
+ ret = RESUME_GUEST;
switch (code) {
case KVM_HCALL_SERVICE:
vcpu->stat.hypercall_exits++;
kvm_handle_service(vcpu);
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) {
+ vcpu->run->exit_reason = KVM_EXIT_DEBUG;
+ ret = RESUME_HOST;
+ break;
+ }
+ fallthrough;
default:
/* Treat it as noop intruction, only set return value */
kvm_write_reg(vcpu, LOONGARCH_GPR_A0, KVM_HCALL_INVALID_CODE);
break;
}
- return RESUME_GUEST;
+ if (ret == RESUME_GUEST)
+ update_pc(&vcpu->arch);
+
+ return ret;
}
/*
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 97a7aa508e96..9e8030d45129 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -248,7 +248,15 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
- return -EINVAL;
+ if (dbg->control & ~KVM_GUESTDBG_VALID_MASK)
+ return -EINVAL;
+
+ if (dbg->control & KVM_GUESTDBG_ENABLE)
+ vcpu->guest_debug = dbg->control;
+ else
+ vcpu->guest_debug = 0;
+
+ return 0;
}
static inline int kvm_set_cpuid(struct kvm_vcpu *vcpu, u64 val)
@@ -499,6 +507,9 @@ static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
case KVM_REG_LOONGARCH_COUNTER:
*v = drdtime() + vcpu->kvm->arch.time_offset;
break;
+ case KVM_REG_LOONGARCH_DEBUG_INST:
+ *v = INSN_HVCL | KVM_HCALL_SWDBG;
+ break;
default:
ret = -EINVAL;
break;
diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
index 191d82309a1e..6b2e4f66ad26 100644
--- a/arch/loongarch/kvm/vm.c
+++ b/arch/loongarch/kvm/vm.c
@@ -76,6 +76,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_IOEVENTFD:
case KVM_CAP_MP_STATE:
+ case KVM_CAP_SET_GUEST_DEBUG:
r = 1;
break;
case KVM_CAP_NR_VCPUS: