Skip to content

Commit 163e9fc

Browse files
bibo-maochenhuacai
authored andcommitted
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 <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 74c16b2 commit 163e9fc

File tree

7 files changed

+40
-3
lines changed

7 files changed

+40
-3
lines changed

arch/loongarch/include/asm/inst.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define INSN_NOP 0x03400000
1414
#define INSN_BREAK 0x002a0000
15+
#define INSN_HVCL 0x002b8000
1516

1617
#define ADDR_IMMMASK_LU52ID 0xFFF0000000000000
1718
#define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000

arch/loongarch/include/asm/kvm_host.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131

3232
#define KVM_HALT_POLL_NS_DEFAULT 500000
3333

34+
#define KVM_GUESTDBG_SW_BP_MASK \
35+
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)
36+
#define KVM_GUESTDBG_VALID_MASK \
37+
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP)
38+
3439
struct kvm_vm_stat {
3540
struct kvm_vm_stat_generic generic;
3641
u64 pages;

arch/loongarch/include/asm/kvm_para.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
#define HYPERCALL_ENCODE(vendor, code) ((vendor << HYPERVISOR_VENDOR_SHIFT) + code)
1111

1212
#define KVM_HCALL_CODE_SERVICE 0
13+
#define KVM_HCALL_CODE_SWDBG 1
1314

1415
#define KVM_HCALL_SERVICE HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SERVICE)
1516
#define KVM_HCALL_FUNC_IPI 1
1617

18+
#define KVM_HCALL_SWDBG HYPERCALL_ENCODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SWDBG)
19+
1720
/*
1821
* LoongArch hypercall return code
1922
*/

arch/loongarch/include/uapi/asm/kvm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
1818
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
1919

20+
#define KVM_GUESTDBG_USE_SW_BP 0x00010000
21+
2022
/*
2123
* for KVM_GET_REGS and KVM_SET_REGS
2224
*/
@@ -72,6 +74,8 @@ struct kvm_fpu {
7274

7375
#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1)
7476
#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2)
77+
/* Debugging: Special instruction for software breakpoint */
78+
#define KVM_REG_LOONGARCH_DEBUG_INST (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
7579

7680
#define LOONGARCH_REG_SHIFT 3
7781
#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))

arch/loongarch/kvm/exit.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,25 +760,37 @@ static void kvm_handle_service(struct kvm_vcpu *vcpu)
760760

761761
static int kvm_handle_hypercall(struct kvm_vcpu *vcpu)
762762
{
763+
int ret;
763764
larch_inst inst;
764765
unsigned int code;
765766

766767
inst.word = vcpu->arch.badi;
767768
code = inst.reg0i15_format.immediate;
768-
update_pc(&vcpu->arch);
769+
ret = RESUME_GUEST;
769770

770771
switch (code) {
771772
case KVM_HCALL_SERVICE:
772773
vcpu->stat.hypercall_exits++;
773774
kvm_handle_service(vcpu);
774775
break;
776+
case KVM_HCALL_SWDBG:
777+
/* KVM_HCALL_SWDBG only in effective when SW_BP is enabled */
778+
if (vcpu->guest_debug & KVM_GUESTDBG_SW_BP_MASK) {
779+
vcpu->run->exit_reason = KVM_EXIT_DEBUG;
780+
ret = RESUME_HOST;
781+
break;
782+
}
783+
fallthrough;
775784
default:
776785
/* Treat it as noop intruction, only set return value */
777786
kvm_write_reg(vcpu, LOONGARCH_GPR_A0, KVM_HCALL_INVALID_CODE);
778787
break;
779788
}
780789

781-
return RESUME_GUEST;
790+
if (ret == RESUME_GUEST)
791+
update_pc(&vcpu->arch);
792+
793+
return ret;
782794
}
783795

784796
/*

arch/loongarch/kvm/vcpu.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,15 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
248248
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
249249
struct kvm_guest_debug *dbg)
250250
{
251-
return -EINVAL;
251+
if (dbg->control & ~KVM_GUESTDBG_VALID_MASK)
252+
return -EINVAL;
253+
254+
if (dbg->control & KVM_GUESTDBG_ENABLE)
255+
vcpu->guest_debug = dbg->control;
256+
else
257+
vcpu->guest_debug = 0;
258+
259+
return 0;
252260
}
253261

254262
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,
499507
case KVM_REG_LOONGARCH_COUNTER:
500508
*v = drdtime() + vcpu->kvm->arch.time_offset;
501509
break;
510+
case KVM_REG_LOONGARCH_DEBUG_INST:
511+
*v = INSN_HVCL | KVM_HCALL_SWDBG;
512+
break;
502513
default:
503514
ret = -EINVAL;
504515
break;

arch/loongarch/kvm/vm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
7676
case KVM_CAP_IMMEDIATE_EXIT:
7777
case KVM_CAP_IOEVENTFD:
7878
case KVM_CAP_MP_STATE:
79+
case KVM_CAP_SET_GUEST_DEBUG:
7980
r = 1;
8081
break;
8182
case KVM_CAP_NR_VCPUS:

0 commit comments

Comments
 (0)