Commit 55288490 authored by Bibo Mao's avatar Bibo Mao Committed by Xianglai Li
Browse files

LoongArch: KVM: Add software breakpoint support

LoongArch inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9BTWW



------------------------------------------

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 sets exit_reason with KVM_EXIT_DEBUG, and then let qemu handle it.

Signed-off-by: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent d45b2b75
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#define INSN_NOP		0x03400000
#define INSN_BREAK		0x002a0000
#define INSN_HVCL		0x002b8000

#define ADDR_IMMMASK_LU52ID	0xFFF0000000000000
#define ADDR_IMMMASK_LU32ID	0x000FFFFF00000000
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@

#define KVM_HALT_POLL_NS_DEFAULT	500000

#define KVM_GUESTDBG_VALID_MASK		(KVM_GUESTDBG_ENABLE | \
			KVM_GUESTDBG_USE_SW_BP | KVM_GUESTDBG_SINGLESTEP)
struct kvm_vm_stat {
	struct kvm_vm_stat_generic generic;
	u64 pages;
+2 −0
Original line number Diff line number Diff line
@@ -9,8 +9,10 @@
#define HYPERVISOR_VENDOR_SHIFT		8
#define HYPERCALL_CODE(vendor, code)	((vendor << HYPERVISOR_VENDOR_SHIFT) + code)
#define KVM_HCALL_CODE_PV_SERVICE	0
#define KVM_HCALL_CODE_SWDBG		1
#define KVM_HCALL_PV_SERVICE		HYPERCALL_CODE(HYPERVISOR_KVM, KVM_HCALL_CODE_PV_SERVICE)
#define  KVM_HCALL_FUNC_PV_IPI		1
#define KVM_HCALL_SWDBG			HYPERCALL_CODE(HYPERVISOR_KVM, KVM_HCALL_CODE_SWDBG)

/*
 * LoongArch hypercall return code
+4 −0
Original line number Diff line number Diff line
@@ -15,10 +15,12 @@
 */

#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
 */
@@ -74,6 +76,8 @@ struct kvm_fpu {

#define KVM_REG_LOONGARCH_COUNTER	(KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1)
#define KVM_REG_LOONGARCH_VCPU_RESET	(KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2)
/* Debugging: Special instruction for software breakpoint */
#define KVM_REG_LOONGARCH_DEBUG_INST	(KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)

#define LOONGARCH_REG_SHIFT		3
#define LOONGARCH_REG_64(TYPE, REG)	(TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
+14 −2
Original line number Diff line number Diff line
@@ -774,23 +774,35 @@ static int kvm_handle_hypercall(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_HCALL_PV_SERVICE:
		vcpu->stat.hypercall_exits++;
		kvm_handle_pv_service(vcpu);
		break;
	case KVM_HCALL_SWDBG:
		/* KVM_HC_SWDBG only in effective when SW_BP is enabled */
		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
			vcpu->run->exit_reason = KVM_EXIT_DEBUG;
			ret = RESUME_HOST;
		} else
			vcpu->arch.gprs[LOONGARCH_GPR_A0] = KVM_HCALL_INVALID_CODE;
		break;
	default:
		/* Treat it as noop intruction, only set return value */
		vcpu->arch.gprs[LOONGARCH_GPR_A0] = KVM_HCALL_INVALID_CODE;
		break;
	}

	return RESUME_GUEST;
	if (ret == RESUME_GUEST)
		update_pc(&vcpu->arch);

	return ret;
}

/*
Loading