@@ -10,8 +10,10 @@
#define HYPERCALL_CODE(vendor, code) ((vendor << HYPERVISOR_VENDOR_SHIFT) + code)
#define KVM_HC_CODE_SERVICE 0
+#define KVM_HC_CODE_SWDBG 1
#define KVM_HC_SERVICE HYPERCALL_CODE(HYPERVISOR_KVM, KVM_HC_CODE_SERVICE)
#define KVM_HC_FUNC_IPI 1
+#define KVM_HC_SWDBG HYPERCALL_CODE(HYPERVISOR_KVM, KVM_HC_CODE_SWDBG)
/*
* LoongArch hypcall return code
@@ -15,10 +15,13 @@
*/
#define __KVM_HAVE_READONLY_MEM
+#define __KVM_HAVE_GUEST_DEBUG
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
+#define KVM_GUESTDBG_USE_SW_BP 0x00010000
+
/*
* for KVM_GET_REGS and KVM_SET_REGS
*/
@@ -758,23 +758,31 @@ static int kvm_handle_hypcall(struct kvm_vcpu *vcpu)
{
larch_inst inst;
unsigned int code;
+ int ret;
inst.word = vcpu->arch.badi;
code = inst.reg0i15_format.immediate;
- update_pc(&vcpu->arch);
+ ret = RESUME_GUEST;
switch (code) {
case KVM_HC_SERVICE:
vcpu->stat.hvcl_exits++;
kvm_handle_pv_hcall(vcpu);
break;
+ case KVM_HC_SWDBG:
+ vcpu->run->exit_reason = KVM_EXIT_DEBUG;
+ ret = RESUME_HOST;
+ break;
default:
/* Treat it as noop intruction, only set return value */
vcpu->arch.gprs[LOONGARCH_GPR_A0] = KVM_HC_INVALID_CODE;
break;
}
- return RESUME_GUEST;
+ if (ret == RESUME_GUEST)
+ update_pc(&vcpu->arch);
+
+ return ret;
}
/*
@@ -245,10 +245,22 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return ret;
}
+#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
+ KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP)
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
- struct kvm_guest_debug *dbg)
+ 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;
+ /* No hardware breakpoint */
+ } else {
+ vcpu->guest_debug = 0;
+ }
+
+ return 0;
}
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
@@ -77,6 +77,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:
When VM runs in kvm mode, system will not exit to host mode if executing general software breakpoint instruction, one 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 one special hypercall code is used for software breakpoint usage, vm exists to host mode and kvm hypervisor identifies the special hypercall code and set exit_reason with KVM_EXIT_DEBUG, and then let qemu handle it. This patch uses hypercall code and needs hypercall instruction emulation handling, and it is dependent on this patchset: https://lore.kernel.org/all/20240201031950.3225626-1-maobibo@loongson.cn/ Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- arch/loongarch/include/asm/kvm_para.h | 2 ++ arch/loongarch/include/uapi/asm/kvm.h | 3 +++ arch/loongarch/kvm/exit.c | 12 ++++++++++-- arch/loongarch/kvm/vcpu.c | 16 ++++++++++++++-- arch/loongarch/kvm/vm.c | 1 + 5 files changed, 30 insertions(+), 4 deletions(-)