[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 8/8] s390x/kvm: hw debugging support via guest PER f
From: |
Cornelia Huck |
Subject: |
[Qemu-devel] [PATCH 8/8] s390x/kvm: hw debugging support via guest PER facility |
Date: |
Fri, 16 May 2014 14:41:36 +0200 |
From: David Hildenbrand <address@hidden>
This patch makes use of the hw debugging support in kvm (provided by the guest's
PER facility) on s390. It enables the following features, available using the
gdbserver:
- single-stepping
- hw breakpoints
- hw watchpoints
Signed-off-by: David Hildenbrand <address@hidden>
Signed-off-by: Jens Freimann <address@hidden>
Signed-off-by: Cornelia Huck <address@hidden>
---
target-s390x/cpu-qom.h | 1 +
target-s390x/helper.c | 12 ++++
target-s390x/kvm.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 156 insertions(+), 3 deletions(-)
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index ac0460e..f9c96d1 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -86,6 +86,7 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f,
CPUState *cs,
int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 7c76fc1..3d756ca 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -489,6 +489,18 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr
vaddr)
return raddr;
}
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
+{
+ hwaddr phys_addr;
+ target_ulong page;
+
+ page = vaddr & TARGET_PAGE_MASK;
+ phys_addr = cpu_get_phys_page_debug(cs, page);
+ phys_addr += (vaddr & ~TARGET_PAGE_MASK);
+
+ return phys_addr;
+}
+
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
if (mask & PSW_MASK_WAIT) {
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 6d47637..7a07f9d 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -36,6 +36,7 @@
#include "sysemu/device_tree.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
+#include "exec/gdbstub.h"
#include "trace.h"
/* #define DEBUG_KVM */
@@ -86,6 +87,14 @@
#define ICPT_CPU_STOP 0x28
#define ICPT_IO 0x40
+static CPUWatchpoint hw_watchpoint;
+/*
+ * We don't use a list because this structure is also used to transmit the
+ * hardware breakpoints to the kernel.
+ */
+static struct kvm_hw_breakpoint *hw_breakpoints;
+static int nb_hw_breakpoints;
+
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
@@ -351,24 +360,126 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct
kvm_sw_breakpoint *bp)
return 0;
}
+static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
+ int len, int type)
+{
+ int n;
+
+ for (n = 0; n < nb_hw_breakpoints; n++) {
+ if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
+ (hw_breakpoints[n].len == len || len == -1)) {
+ return &hw_breakpoints[n];
+ }
+ }
+
+ return NULL;
+}
+
+static int insert_hw_breakpoint(target_ulong addr, int len, int type)
+{
+ int size;
+
+ if (find_hw_breakpoint(addr, len, type)) {
+ return -EEXIST;
+ }
+
+ size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
+
+ if (!hw_breakpoints) {
+ nb_hw_breakpoints = 0;
+ hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
+ } else {
+ hw_breakpoints =
+ (struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
+ }
+
+ if (!hw_breakpoints) {
+ nb_hw_breakpoints = 0;
+ return -ENOMEM;
+ }
+
+ hw_breakpoints[nb_hw_breakpoints].addr = addr;
+ hw_breakpoints[nb_hw_breakpoints].len = len;
+ hw_breakpoints[nb_hw_breakpoints].type = type;
+
+ nb_hw_breakpoints++;
+
+ return 0;
+}
+
int kvm_arch_insert_hw_breakpoint(target_ulong addr,
target_ulong len, int type)
{
- return -ENOSYS;
+ switch (type) {
+ case GDB_BREAKPOINT_HW:
+ type = KVM_HW_BP;
+ break;
+ case GDB_WATCHPOINT_WRITE:
+ if (len < 1) {
+ return -EINVAL;
+ }
+ type = KVM_HW_WP_WRITE;
+ break;
+ default:
+ return -ENOSYS;
+ }
+ return insert_hw_breakpoint(addr, len, type);
}
int kvm_arch_remove_hw_breakpoint(target_ulong addr,
target_ulong len, int type)
{
- return -ENOSYS;
+ int size;
+ struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
+
+ if (bp == NULL) {
+ return -ENOENT;
+ }
+
+ nb_hw_breakpoints--;
+ if (nb_hw_breakpoints > 0) {
+ /*
+ * In order to trim the array, move the last element to the position to
+ * be removed - if necessary.
+ */
+ if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
+ *bp = hw_breakpoints[nb_hw_breakpoints];
+ }
+ size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
+ hw_breakpoints =
+ (struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
+ } else {
+ g_free(hw_breakpoints);
+ hw_breakpoints = NULL;
+ }
+
+ return 0;
}
void kvm_arch_remove_all_hw_breakpoints(void)
{
+ nb_hw_breakpoints = 0;
+ g_free(hw_breakpoints);
+ hw_breakpoints = NULL;
}
void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
{
+ int i;
+
+ if (nb_hw_breakpoints > 0) {
+ dbg->arch.nr_hw_bp = nb_hw_breakpoints;
+ dbg->arch.hw_bp = hw_breakpoints;
+
+ for (i = 0; i < nb_hw_breakpoints; ++i) {
+ hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
+ hw_breakpoints[i].addr);
+ }
+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+ } else {
+ dbg->arch.nr_hw_bp = 0;
+ dbg->arch.hw_bp = NULL;
+ }
}
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
@@ -853,7 +964,36 @@ static int handle_tsch(S390CPU *cpu)
static int kvm_arch_handle_debug_exit(S390CPU *cpu)
{
- return -ENOSYS;
+ CPUState *cs = CPU(cpu);
+ struct kvm_run *run = cs->kvm_run;
+
+ int ret = 0;
+ struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+
+ switch (arch_info->type) {
+ case KVM_HW_WP_WRITE:
+ if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+ cs->watchpoint_hit = &hw_watchpoint;
+ hw_watchpoint.vaddr = arch_info->addr;
+ hw_watchpoint.flags = BP_MEM_WRITE;
+ ret = EXCP_DEBUG;
+ }
+ break;
+ case KVM_HW_BP:
+ if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+ ret = EXCP_DEBUG;
+ }
+ break;
+ case KVM_SINGLESTEP:
+ if (cs->singlestep_enabled) {
+ ret = EXCP_DEBUG;
+ }
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
}
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
--
1.7.9.5
- [Qemu-devel] [PATCH 0/8] s390: pending patches, Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 1/8] s390x: split flic into kvm and non-kvm parts, Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 2/8] s390x: Add I/O adapter registration., Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 5/8] linux-headers: update, Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 8/8] s390x/kvm: hw debugging support via guest PER facility,
Cornelia Huck <=
- [Qemu-devel] [PATCH 6/8] s390x: remove duplicate definitions of DIAG 501, Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 4/8] s390x/virtio-ccw: Wire up irq routing and irqfds., Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 3/8] s390x/virtio-ccw: reference-counted indicators, Cornelia Huck, 2014/05/16
- [Qemu-devel] [PATCH 7/8] s390x/kvm: software breakpoint support, Cornelia Huck, 2014/05/16
- Re: [Qemu-devel] [PATCH 0/8] s390: pending patches, Andreas Färber, 2014/05/16