133 lines
3.5 KiB
Diff
133 lines
3.5 KiB
Diff
|
|
From 6a301af275fd684c197cf7a2e73fc265993478da Mon Sep 17 00:00:00 2001
|
||
|
|
From: Bibo Mao <maobibo@loongson.cn>
|
||
|
|
Date: Sun, 18 Feb 2024 15:00:25 +0800
|
||
|
|
Subject: [PATCH] target/loongarch/kvm: Add software breakpoint support
|
||
|
|
|
||
|
|
With KVM virtualization, debug exception is passthrough to
|
||
|
|
to guest kernel rather than host mode. Here hypercall
|
||
|
|
instruction with special hypercall code is used for sw
|
||
|
|
breakpoint usage.
|
||
|
|
|
||
|
|
Now only software breakpoint is supported, and itt is allowed
|
||
|
|
to insert/remove software breakpoint. Later hardware breakpoint
|
||
|
|
will be added.
|
||
|
|
|
||
|
|
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
|
||
|
|
---
|
||
|
|
target/loongarch/kvm/kvm.c | 77 ++++++++++++++++++++++++++++++++++++++
|
||
|
|
1 file changed, 77 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
|
||
|
|
index c19978a970..49d02076ad 100644
|
||
|
|
--- a/target/loongarch/kvm/kvm.c
|
||
|
|
+++ b/target/loongarch/kvm/kvm.c
|
||
|
|
@@ -29,6 +29,7 @@
|
||
|
|
#include "trace.h"
|
||
|
|
|
||
|
|
static bool cap_has_mp_state;
|
||
|
|
+static unsigned int brk_insn;
|
||
|
|
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
|
||
|
|
KVM_CAP_LAST_INFO
|
||
|
|
};
|
||
|
|
@@ -675,7 +676,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, bool running,
|
||
|
|
|
||
|
|
int kvm_arch_init_vcpu(CPUState *cs)
|
||
|
|
{
|
||
|
|
+ uint64_t val;
|
||
|
|
+
|
||
|
|
qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
|
||
|
|
+
|
||
|
|
+ if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) {
|
||
|
|
+ brk_insn = val;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -755,6 +763,68 @@ bool kvm_arch_cpu_check_are_resettable(void)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
+
|
||
|
|
+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
|
||
|
|
+{
|
||
|
|
+ if (kvm_sw_breakpoints_active(cpu)) {
|
||
|
|
+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||
|
|
+{
|
||
|
|
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
|
||
|
|
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
|
||
|
|
+ error_report("%s failed", __func__);
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||
|
|
+{
|
||
|
|
+ static uint32_t brk;
|
||
|
|
+
|
||
|
|
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
|
||
|
|
+ brk != brk_insn ||
|
||
|
|
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
|
||
|
|
+ error_report("%s failed", __func__);
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
|
||
|
|
+{
|
||
|
|
+ return -ENOSYS;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
|
||
|
|
+{
|
||
|
|
+ return -ENOSYS;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void kvm_arch_remove_all_hw_breakpoints(void)
|
||
|
|
+{
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
|
||
|
|
+{
|
||
|
|
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
|
||
|
|
+ CPULoongArchState *env = &cpu->env;
|
||
|
|
+
|
||
|
|
+ kvm_cpu_synchronize_state(cs);
|
||
|
|
+ if (cs->singlestep_enabled) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (kvm_find_sw_breakpoint(cs, env->pc)) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
@@ -774,6 +844,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
||
|
|
run->iocsr_io.len,
|
||
|
|
run->iocsr_io.is_write);
|
||
|
|
break;
|
||
|
|
+
|
||
|
|
+ case KVM_EXIT_DEBUG:
|
||
|
|
+ if (kvm_loongarch_handle_debug(cs, run)) {
|
||
|
|
+ ret = EXCP_DEBUG;
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
default:
|
||
|
|
ret = -1;
|
||
|
|
warn_report("KVM: unknown exit reason %d", run->exit_reason);
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|