qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64
@ 2015-05-29 15:19 Alex Bennée
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV) Alex Bennée
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: marc.zyngier, Alex Bennée, linux-arm-kernel, kvm, kvmarm

Hi,

You may be wondering what happened to v3 and v4. They do exist but
they didn't change much from the the original patches as I've been
mostly looking the kernel side of the equation. So in summary the
changes are:

  - updates to the kernel ABI
  - don't fall over on kernels without debug support
  - better logging, syncing and use of internals.h
  - debug exception re-injection for guest events*

More detailed changelogs are attached to each patch.

* see
  https://lists.cs.columbia.edu/pipermail/kvmarm/2015-May/014807.html

GIT Repos:

The patch series is based off a recent master and can be found at:

https://github.com/stsquad/qemu
branch: kvm/guest-debug-v5

The kernel patches for this series are based off a v4.1-rc5-v5 and can be
found at:

https://git.linaro.org/people/alex.bennee/linux.git
branch: guest-debug/4.1-rc5-v5

Alex Bennée (6):
  linux-headers: sync from my kernel tree (DEV)
  target-arm: kvm64: introduce kvm_arm_init_debug()
  target-arm: kvm - implement software breakpoints
  target-arm: kvm - support for single step
  target-arm: kvm - add support for HW assisted debug
  target-arm: kvm - re-inject guest debug exceptions

 include/standard-headers/linux/virtio_balloon.h |  28 ++-
 include/standard-headers/linux/virtio_blk.h     |   8 +-
 include/standard-headers/linux/virtio_ids.h     |   1 +
 include/standard-headers/linux/virtio_input.h   |  76 ++++++
 include/standard-headers/linux/virtio_ring.h    |   2 +-
 linux-headers/asm-arm/kvm.h                     |   9 +-
 linux-headers/asm-arm64/kvm.h                   |  29 ++-
 linux-headers/asm-mips/kvm.h                    | 164 +++++++-----
 linux-headers/asm-s390/kvm.h                    |   4 +
 linux-headers/asm-x86/hyperv.h                  |   2 +
 linux-headers/linux/kvm.h                       |  71 +++++-
 linux-headers/linux/vfio.h                      |   2 +
 target-arm/cpu.h                                |   1 +
 target-arm/helper-a64.c                         |  17 +-
 target-arm/internals.h                          |   1 +
 target-arm/kvm.c                                | 137 ++++++++--
 target-arm/kvm64.c                              | 318 ++++++++++++++++++++++++
 target-arm/kvm_arm.h                            |  21 ++
 18 files changed, 790 insertions(+), 101 deletions(-)
 create mode 100644 include/standard-headers/linux/virtio_input.h

-- 
2.4.1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV)
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug() Alex Bennée
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: marc.zyngier, Alex Bennée, linux-arm-kernel, kvm, kvmarm

I assume I'll properly merge the KVM Headers direct from Linux when
the kernel side is upstream. These headers came from:

https://git.linaro.org/people/alex.bennee/linux.git/shortlog/refs/heads/guest-debug/4.1-rc5-v5

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - update ABI to include ->far
v3
  - update with latest 4.1-rc1 headers
v4
  - update to v4 headers
v5
  - update to v5 headers
---
 include/standard-headers/linux/virtio_balloon.h |  28 +++-
 include/standard-headers/linux/virtio_blk.h     |   8 +-
 include/standard-headers/linux/virtio_ids.h     |   1 +
 include/standard-headers/linux/virtio_input.h   |  76 +++++++++++
 include/standard-headers/linux/virtio_ring.h    |   2 +-
 linux-headers/asm-arm/kvm.h                     |   9 +-
 linux-headers/asm-arm64/kvm.h                   |  29 ++++-
 linux-headers/asm-mips/kvm.h                    | 164 +++++++++++++++---------
 linux-headers/asm-s390/kvm.h                    |   4 +
 linux-headers/asm-x86/hyperv.h                  |   2 +
 linux-headers/linux/kvm.h                       |  71 +++++++++-
 linux-headers/linux/vfio.h                      |   2 +
 12 files changed, 325 insertions(+), 71 deletions(-)
 create mode 100644 include/standard-headers/linux/virtio_input.h

diff --git a/include/standard-headers/linux/virtio_balloon.h b/include/standard-headers/linux/virtio_balloon.h
index 799376d..88ada1d 100644
--- a/include/standard-headers/linux/virtio_balloon.h
+++ b/include/standard-headers/linux/virtio_balloon.h
@@ -25,6 +25,7 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE. */
+#include "standard-headers/linux/types.h"
 #include "standard-headers/linux/virtio_ids.h"
 #include "standard-headers/linux/virtio_config.h"
 
@@ -51,9 +52,32 @@ struct virtio_balloon_config {
 #define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
 #define VIRTIO_BALLOON_S_NR       6
 
+/*
+ * Memory statistics structure.
+ * Driver fills an array of these structures and passes to device.
+ *
+ * NOTE: fields are laid out in a way that would make compiler add padding
+ * between and after fields, so we have to use compiler-specific attributes to
+ * pack it, to disable this padding. This also often causes compiler to
+ * generate suboptimal code.
+ *
+ * We maintain this statistics structure format for backwards compatibility,
+ * but don't follow this example.
+ *
+ * If implementing a similar structure, do something like the below instead:
+ *     struct virtio_balloon_stat {
+ *         __virtio16 tag;
+ *         uint8_t reserved[6];
+ *         __virtio64 val;
+ *     };
+ *
+ * In other words, add explicit reserved fields to align field and
+ * structure boundaries at field size, avoiding compiler padding
+ * without the packed attribute.
+ */
 struct virtio_balloon_stat {
-	uint16_t tag;
-	uint64_t val;
+	__virtio16 tag;
+	__virtio64 val;
 } QEMU_PACKED;
 
 #endif /* _LINUX_VIRTIO_BALLOON_H */
diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard-headers/linux/virtio_blk.h
index 12016b4..cd601f4 100644
--- a/include/standard-headers/linux/virtio_blk.h
+++ b/include/standard-headers/linux/virtio_blk.h
@@ -58,7 +58,7 @@ struct virtio_blk_config {
 	uint32_t size_max;
 	/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
 	uint32_t seg_max;
-	/* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+	/* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
 	struct virtio_blk_geometry {
 		uint16_t cylinders;
 		uint8_t heads;
@@ -117,7 +117,11 @@ struct virtio_blk_config {
 #define VIRTIO_BLK_T_BARRIER	0x80000000
 #endif /* !VIRTIO_BLK_NO_LEGACY */
 
-/* This is the first element of the read scatter-gather list. */
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
 struct virtio_blk_outhdr {
 	/* VIRTIO_BLK_T* */
 	__virtio32 type;
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index 284fc3a..5f60aa4 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -39,5 +39,6 @@
 #define VIRTIO_ID_9P		9 /* 9p virtio console */
 #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */
 #define VIRTIO_ID_CAIF	       12 /* Virtio caif */
+#define VIRTIO_ID_INPUT        18 /* virtio input */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/standard-headers/linux/virtio_input.h b/include/standard-headers/linux/virtio_input.h
new file mode 100644
index 0000000..a98a797
--- /dev/null
+++ b/include/standard-headers/linux/virtio_input.h
@@ -0,0 +1,76 @@
+#ifndef _LINUX_VIRTIO_INPUT_H
+#define _LINUX_VIRTIO_INPUT_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "standard-headers/linux/types.h"
+
+enum virtio_input_config_select {
+	VIRTIO_INPUT_CFG_UNSET      = 0x00,
+	VIRTIO_INPUT_CFG_ID_NAME    = 0x01,
+	VIRTIO_INPUT_CFG_ID_SERIAL  = 0x02,
+	VIRTIO_INPUT_CFG_ID_DEVIDS  = 0x03,
+	VIRTIO_INPUT_CFG_PROP_BITS  = 0x10,
+	VIRTIO_INPUT_CFG_EV_BITS    = 0x11,
+	VIRTIO_INPUT_CFG_ABS_INFO   = 0x12,
+};
+
+struct virtio_input_absinfo {
+	uint32_t min;
+	uint32_t max;
+	uint32_t fuzz;
+	uint32_t flat;
+	uint32_t res;
+};
+
+struct virtio_input_devids {
+	uint16_t bustype;
+	uint16_t vendor;
+	uint16_t product;
+	uint16_t version;
+};
+
+struct virtio_input_config {
+	uint8_t    select;
+	uint8_t    subsel;
+	uint8_t    size;
+	uint8_t    reserved[5];
+	union {
+		char string[128];
+		uint8_t bitmap[128];
+		struct virtio_input_absinfo abs;
+		struct virtio_input_devids ids;
+	} u;
+};
+
+struct virtio_input_event {
+	uint16_t type;
+	uint16_t code;
+	uint32_t value;
+};
+
+#endif /* _LINUX_VIRTIO_INPUT_H */
diff --git a/include/standard-headers/linux/virtio_ring.h b/include/standard-headers/linux/virtio_ring.h
index cc647d6..6fe276f 100644
--- a/include/standard-headers/linux/virtio_ring.h
+++ b/include/standard-headers/linux/virtio_ring.h
@@ -155,7 +155,7 @@ static inline unsigned vring_size(unsigned int num, unsigned long align)
 }
 
 /* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
-/* Assuming a given event_idx value from the other size, if
+/* Assuming a given event_idx value from the other side, if
  * we have just incremented index from old to new_idx,
  * should we trigger an event? */
 static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 0db25bc..c98e4dc 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -195,9 +195,16 @@ struct kvm_arch_memory_slot {
 #define KVM_ARM_IRQ_CPU_IRQ		0
 #define KVM_ARM_IRQ_CPU_FIQ		1
 
-/* Highest supported SPI, from VGIC_NR_IRQS */
+/*
+ * This used to hold the highest supported SPI, but it is now obsolete
+ * and only here to provide source code level compatibility with older
+ * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
+ */
 #define KVM_ARM_IRQ_GIC_MAX		127
 
+/* One single KVM irqchip, ie. the VGIC */
+#define KVM_NR_IRQCHIPS          1
+
 /* PSCI interface */
 #define KVM_PSCI_FN_BASE		0x95c1ba5e
 #define KVM_PSCI_FN(n)			(KVM_PSCI_FN_BASE + (n))
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 3ef77a4..62ed4ee 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -100,12 +100,32 @@ struct kvm_sregs {
 struct kvm_fpu {
 };
 
+/*
+ * See v8 ARM ARM D7.3: Debug Registers
+ *
+ * The architectural limit is 16 debug registers of each type although
+ * in practice there are usually less (see ID_AA64DFR0_EL1).
+ */
+#define KVM_ARM_MAX_DBG_REGS 16
 struct kvm_guest_debug_arch {
+	__u32 dbg_bcr[KVM_ARM_MAX_DBG_REGS];
+	__u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS];
+	__u32 dbg_wcr[KVM_ARM_MAX_DBG_REGS];
+	__u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS];
 };
 
 struct kvm_debug_exit_arch {
+	__u32 hsr;
+	__u64 far;	/* used for watchpoints */
 };
 
+/*
+ * Architecture specific defines for kvm_guest_debug->control
+ */
+
+#define KVM_GUESTDBG_USE_SW_BP		(1 << 16)
+#define KVM_GUESTDBG_USE_HW_BP		(1 << 17)
+
 struct kvm_sync_regs {
 };
 
@@ -188,9 +208,16 @@ struct kvm_arch_memory_slot {
 #define KVM_ARM_IRQ_CPU_IRQ		0
 #define KVM_ARM_IRQ_CPU_FIQ		1
 
-/* Highest supported SPI, from VGIC_NR_IRQS */
+/*
+ * This used to hold the highest supported SPI, but it is now obsolete
+ * and only here to provide source code level compatibility with older
+ * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
+ */
 #define KVM_ARM_IRQ_GIC_MAX		127
 
+/* One single KVM irqchip, ie. the VGIC */
+#define KVM_NR_IRQCHIPS          1
+
 /* PSCI interface */
 #define KVM_PSCI_FN_BASE		0x95c1ba5e
 #define KVM_PSCI_FN(n)			(KVM_PSCI_FN_BASE + (n))
diff --git a/linux-headers/asm-mips/kvm.h b/linux-headers/asm-mips/kvm.h
index 2c04b6d..6985eb5 100644
--- a/linux-headers/asm-mips/kvm.h
+++ b/linux-headers/asm-mips/kvm.h
@@ -36,77 +36,85 @@ struct kvm_regs {
 
 /*
  * for KVM_GET_FPU and KVM_SET_FPU
- *
- * If Status[FR] is zero (32-bit FPU), the upper 32-bits of the FPRs
- * are zero filled.
  */
 struct kvm_fpu {
-	__u64 fpr[32];
-	__u32 fir;
-	__u32 fccr;
-	__u32 fexr;
-	__u32 fenr;
-	__u32 fcsr;
-	__u32 pad;
 };
 
 
 /*
- * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access CP0
+ * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
  * registers.  The id field is broken down as follows:
  *
- *  bits[2..0]   - Register 'sel' index.
- *  bits[7..3]   - Register 'rd'  index.
- *  bits[15..8]  - Must be zero.
- *  bits[31..16] - 1 -> CP0 registers.
- *  bits[51..32] - Must be zero.
  *  bits[63..52] - As per linux/kvm.h
+ *  bits[51..32] - Must be zero.
+ *  bits[31..16] - Register set.
+ *
+ * Register set = 0: GP registers from kvm_regs (see definitions below).
+ *
+ * Register set = 1: CP0 registers.
+ *  bits[15..8]  - Must be zero.
+ *  bits[7..3]   - Register 'rd'  index.
+ *  bits[2..0]   - Register 'sel' index.
+ *
+ * Register set = 2: KVM specific registers (see definitions below).
+ *
+ * Register set = 3: FPU / MSA registers (see definitions below).
  *
  * Other sets registers may be added in the future.  Each set would
  * have its own identifier in bits[31..16].
- *
- * The registers defined in struct kvm_regs are also accessible, the
- * id values for these are below.
  */
 
-#define KVM_REG_MIPS_R0 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 0)
-#define KVM_REG_MIPS_R1 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 1)
-#define KVM_REG_MIPS_R2 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 2)
-#define KVM_REG_MIPS_R3 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 3)
-#define KVM_REG_MIPS_R4 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 4)
-#define KVM_REG_MIPS_R5 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 5)
-#define KVM_REG_MIPS_R6 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 6)
-#define KVM_REG_MIPS_R7 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 7)
-#define KVM_REG_MIPS_R8 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 8)
-#define KVM_REG_MIPS_R9 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 9)
-#define KVM_REG_MIPS_R10 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 10)
-#define KVM_REG_MIPS_R11 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 11)
-#define KVM_REG_MIPS_R12 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 12)
-#define KVM_REG_MIPS_R13 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 13)
-#define KVM_REG_MIPS_R14 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 14)
-#define KVM_REG_MIPS_R15 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 15)
-#define KVM_REG_MIPS_R16 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 16)
-#define KVM_REG_MIPS_R17 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 17)
-#define KVM_REG_MIPS_R18 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 18)
-#define KVM_REG_MIPS_R19 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 19)
-#define KVM_REG_MIPS_R20 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 20)
-#define KVM_REG_MIPS_R21 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 21)
-#define KVM_REG_MIPS_R22 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 22)
-#define KVM_REG_MIPS_R23 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 23)
-#define KVM_REG_MIPS_R24 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 24)
-#define KVM_REG_MIPS_R25 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 25)
-#define KVM_REG_MIPS_R26 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 26)
-#define KVM_REG_MIPS_R27 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 27)
-#define KVM_REG_MIPS_R28 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 28)
-#define KVM_REG_MIPS_R29 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 29)
-#define KVM_REG_MIPS_R30 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 30)
-#define KVM_REG_MIPS_R31 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 31)
-
-#define KVM_REG_MIPS_HI (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 32)
-#define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33)
-#define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34)
-
-/* KVM specific control registers */
+#define KVM_REG_MIPS_GP		(KVM_REG_MIPS | 0x0000000000000000ULL)
+#define KVM_REG_MIPS_CP0	(KVM_REG_MIPS | 0x0000000000010000ULL)
+#define KVM_REG_MIPS_KVM	(KVM_REG_MIPS | 0x0000000000020000ULL)
+#define KVM_REG_MIPS_FPU	(KVM_REG_MIPS | 0x0000000000030000ULL)
+
+
+/*
+ * KVM_REG_MIPS_GP - General purpose registers from kvm_regs.
+ */
+
+#define KVM_REG_MIPS_R0		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  0)
+#define KVM_REG_MIPS_R1		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  1)
+#define KVM_REG_MIPS_R2		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  2)
+#define KVM_REG_MIPS_R3		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  3)
+#define KVM_REG_MIPS_R4		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  4)
+#define KVM_REG_MIPS_R5		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  5)
+#define KVM_REG_MIPS_R6		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  6)
+#define KVM_REG_MIPS_R7		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  7)
+#define KVM_REG_MIPS_R8		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  8)
+#define KVM_REG_MIPS_R9		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 |  9)
+#define KVM_REG_MIPS_R10	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 10)
+#define KVM_REG_MIPS_R11	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 11)
+#define KVM_REG_MIPS_R12	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 12)
+#define KVM_REG_MIPS_R13	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 13)
+#define KVM_REG_MIPS_R14	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 14)
+#define KVM_REG_MIPS_R15	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 15)
+#define KVM_REG_MIPS_R16	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 16)
+#define KVM_REG_MIPS_R17	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 17)
+#define KVM_REG_MIPS_R18	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 18)
+#define KVM_REG_MIPS_R19	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 19)
+#define KVM_REG_MIPS_R20	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 20)
+#define KVM_REG_MIPS_R21	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 21)
+#define KVM_REG_MIPS_R22	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 22)
+#define KVM_REG_MIPS_R23	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 23)
+#define KVM_REG_MIPS_R24	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 24)
+#define KVM_REG_MIPS_R25	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 25)
+#define KVM_REG_MIPS_R26	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 26)
+#define KVM_REG_MIPS_R27	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 27)
+#define KVM_REG_MIPS_R28	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 28)
+#define KVM_REG_MIPS_R29	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 29)
+#define KVM_REG_MIPS_R30	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 30)
+#define KVM_REG_MIPS_R31	(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 31)
+
+#define KVM_REG_MIPS_HI		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 32)
+#define KVM_REG_MIPS_LO		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 33)
+#define KVM_REG_MIPS_PC		(KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 34)
+
+
+/*
+ * KVM_REG_MIPS_KVM - KVM specific control registers.
+ */
 
 /*
  * CP0_Count control
@@ -118,8 +126,7 @@ struct kvm_fpu {
  *        safely without losing time or guest timer interrupts.
  * Other: Reserved, do not change.
  */
-#define KVM_REG_MIPS_COUNT_CTL		(KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
-					 0x20000 | 0)
+#define KVM_REG_MIPS_COUNT_CTL	    (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 0)
 #define KVM_REG_MIPS_COUNT_CTL_DC	0x00000001
 
 /*
@@ -131,15 +138,46 @@ struct kvm_fpu {
  * emulated.
  * Modifications to times in the future are rejected.
  */
-#define KVM_REG_MIPS_COUNT_RESUME	(KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
-					 0x20000 | 1)
+#define KVM_REG_MIPS_COUNT_RESUME   (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 1)
 /*
  * CP0_Count rate in Hz
  * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without
  * discontinuities in CP0_Count.
  */
-#define KVM_REG_MIPS_COUNT_HZ		(KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
-					 0x20000 | 2)
+#define KVM_REG_MIPS_COUNT_HZ	    (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 2)
+
+
+/*
+ * KVM_REG_MIPS_FPU - Floating Point and MIPS SIMD Architecture (MSA) registers.
+ *
+ *  bits[15..8]  - Register subset (see definitions below).
+ *  bits[7..5]   - Must be zero.
+ *  bits[4..0]   - Register number within register subset.
+ */
+
+#define KVM_REG_MIPS_FPR	(KVM_REG_MIPS_FPU | 0x0000000000000000ULL)
+#define KVM_REG_MIPS_FCR	(KVM_REG_MIPS_FPU | 0x0000000000000100ULL)
+#define KVM_REG_MIPS_MSACR	(KVM_REG_MIPS_FPU | 0x0000000000000200ULL)
+
+/*
+ * KVM_REG_MIPS_FPR - Floating point / Vector registers.
+ */
+#define KVM_REG_MIPS_FPR_32(n)	(KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32  | (n))
+#define KVM_REG_MIPS_FPR_64(n)	(KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64  | (n))
+#define KVM_REG_MIPS_VEC_128(n)	(KVM_REG_MIPS_FPR | KVM_REG_SIZE_U128 | (n))
+
+/*
+ * KVM_REG_MIPS_FCR - Floating point control registers.
+ */
+#define KVM_REG_MIPS_FCR_IR	(KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 |  0)
+#define KVM_REG_MIPS_FCR_CSR	(KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31)
+
+/*
+ * KVM_REG_MIPS_MSACR - MIPS SIMD Architecture (MSA) control registers.
+ */
+#define KVM_REG_MIPS_MSA_IR	 (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 |  0)
+#define KVM_REG_MIPS_MSA_CSR	 (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 |  1)
+
 
 /*
  * KVM MIPS specific structures and definitions
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index c5a93eb..512d8f1 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -150,6 +150,7 @@ struct kvm_guest_debug_arch {
 #define KVM_SYNC_CRS    (1UL << 3)
 #define KVM_SYNC_ARCH0  (1UL << 4)
 #define KVM_SYNC_PFAULT (1UL << 5)
+#define KVM_SYNC_VRS    (1UL << 6)
 /* definition of registers in kvm_run */
 struct kvm_sync_regs {
 	__u64 prefix;	/* prefix register */
@@ -164,6 +165,9 @@ struct kvm_sync_regs {
 	__u64 pft;	/* pfault token [PFAULT] */
 	__u64 pfs;	/* pfault select [PFAULT] */
 	__u64 pfc;	/* pfault compare [PFAULT] */
+	__u64 vrs[32][2];	/* vector registers */
+	__u8  reserved[512];	/* for future vector expansion */
+	__u32 fpc;	/* only valid with vector registers */
 };
 
 #define KVM_REG_S390_TODPR	(KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index 90c458e..ce6068d 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -225,6 +225,8 @@
 #define HV_STATUS_INVALID_HYPERCALL_CODE	2
 #define HV_STATUS_INVALID_HYPERCALL_INPUT	3
 #define HV_STATUS_INVALID_ALIGNMENT		4
+#define HV_STATUS_INSUFFICIENT_MEMORY		11
+#define HV_STATUS_INVALID_CONNECTION_ID		18
 #define HV_STATUS_INSUFFICIENT_BUFFERS		19
 
 typedef struct _HV_REFERENCE_TSC_PAGE {
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 60a54c8..d9d0a2d 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -147,6 +147,16 @@ struct kvm_pit_config {
 
 #define KVM_PIT_SPEAKER_DUMMY     1
 
+struct kvm_s390_skeys {
+	__u64 start_gfn;
+	__u64 count;
+	__u64 skeydata_addr;
+	__u32 flags;
+	__u32 reserved[9];
+};
+#define KVM_S390_GET_SKEYS_NONE   1
+#define KVM_S390_SKEYS_MAX        1048576
+
 #define KVM_EXIT_UNKNOWN          0
 #define KVM_EXIT_EXCEPTION        1
 #define KVM_EXIT_IO               2
@@ -172,6 +182,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_S390_TSCH        22
 #define KVM_EXIT_EPR              23
 #define KVM_EXIT_SYSTEM_EVENT     24
+#define KVM_EXIT_S390_STSI        25
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -226,6 +237,7 @@ struct kvm_run {
 			__u32 count;
 			__u64 data_offset; /* relative to kvm_run start */
 		} io;
+		/* KVM_EXIT_DEBUG */
 		struct {
 			struct kvm_debug_exit_arch arch;
 		} debug;
@@ -274,6 +286,7 @@ struct kvm_run {
 			__u32 data;
 			__u8  is_write;
 		} dcr;
+		/* KVM_EXIT_INTERNAL_ERROR */
 		struct {
 			__u32 suberror;
 			/* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
@@ -284,6 +297,7 @@ struct kvm_run {
 		struct {
 			__u64 gprs[32];
 		} osi;
+		/* KVM_EXIT_PAPR_HCALL */
 		struct {
 			__u64 nr;
 			__u64 ret;
@@ -309,6 +323,15 @@ struct kvm_run {
 			__u32 type;
 			__u64 flags;
 		} system_event;
+		/* KVM_EXIT_S390_STSI */
+		struct {
+			__u64 addr;
+			__u8 ar;
+			__u8 reserved;
+			__u8 fc;
+			__u8 sel1;
+			__u16 sel2;
+		} s390_stsi;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -324,7 +347,7 @@ struct kvm_run {
 	__u64 kvm_dirty_regs;
 	union {
 		struct kvm_sync_regs regs;
-		char padding[1024];
+		char padding[2048];
 	} s;
 };
 
@@ -365,6 +388,24 @@ struct kvm_translation {
 	__u8  pad[5];
 };
 
+/* for KVM_S390_MEM_OP */
+struct kvm_s390_mem_op {
+	/* in */
+	__u64 gaddr;		/* the guest address */
+	__u64 flags;		/* flags */
+	__u32 size;		/* amount of bytes */
+	__u32 op;		/* type of operation */
+	__u64 buf;		/* buffer in userspace */
+	__u8 ar;		/* the access register number */
+	__u8 reserved[31];	/* should be set to 0 */
+};
+/* types for kvm_s390_mem_op->op */
+#define KVM_S390_MEMOP_LOGICAL_READ	0
+#define KVM_S390_MEMOP_LOGICAL_WRITE	1
+/* flags for kvm_s390_mem_op->flags */
+#define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
+#define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)
+
 /* for KVM_INTERRUPT */
 struct kvm_interrupt {
 	/* in */
@@ -520,6 +561,13 @@ struct kvm_s390_irq {
 	} u;
 };
 
+struct kvm_s390_irq_state {
+	__u64 buf;
+	__u32 flags;
+	__u32 len;
+	__u32 reserved[4];
+};
+
 /* for KVM_SET_GUEST_DEBUG */
 
 #define KVM_GUESTDBG_ENABLE		0x00000001
@@ -760,6 +808,17 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_ENABLE_HCALL 104
 #define KVM_CAP_CHECK_EXTENSION_VM 105
 #define KVM_CAP_S390_USER_SIGP 106
+#define KVM_CAP_S390_VECTOR_REGISTERS 107
+#define KVM_CAP_S390_MEM_OP 108
+#define KVM_CAP_S390_USER_STSI 109
+#define KVM_CAP_S390_SKEYS 110
+#define KVM_CAP_MIPS_FPU 111
+#define KVM_CAP_MIPS_MSA 112
+#define KVM_CAP_S390_INJECT_IRQ 113
+#define KVM_CAP_S390_IRQ_STATE 114
+#define KVM_CAP_PPC_HWRNG 115
+#define KVM_CAP_GUEST_DEBUG_HW_BPS 116
+#define KVM_CAP_GUEST_DEBUG_HW_WPS 117
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1135,6 +1194,16 @@ struct kvm_s390_ucas_mapping {
 #define KVM_ARM_VCPU_INIT	  _IOW(KVMIO,  0xae, struct kvm_vcpu_init)
 #define KVM_ARM_PREFERRED_TARGET  _IOR(KVMIO,  0xaf, struct kvm_vcpu_init)
 #define KVM_GET_REG_LIST	  _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
+/* Available with KVM_CAP_S390_MEM_OP */
+#define KVM_S390_MEM_OP		  _IOW(KVMIO,  0xb1, struct kvm_s390_mem_op)
+/* Available with KVM_CAP_S390_SKEYS */
+#define KVM_S390_GET_SKEYS      _IOW(KVMIO, 0xb2, struct kvm_s390_skeys)
+#define KVM_S390_SET_SKEYS      _IOW(KVMIO, 0xb3, struct kvm_s390_skeys)
+/* Available with KVM_CAP_S390_INJECT_IRQ */
+#define KVM_S390_IRQ              _IOW(KVMIO,  0xb4, struct kvm_s390_irq)
+/* Available with KVM_CAP_S390_IRQ_STATE */
+#define KVM_S390_SET_IRQ_STATE	  _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
+#define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 95ba870..0508d0b 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -160,6 +160,8 @@ struct vfio_device_info {
 	__u32	flags;
 #define VFIO_DEVICE_FLAGS_RESET	(1 << 0)	/* Device supports reset */
 #define VFIO_DEVICE_FLAGS_PCI	(1 << 1)	/* vfio-pci device */
+#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2)	/* vfio-platform device */
+#define VFIO_DEVICE_FLAGS_AMBA  (1 << 3)	/* vfio-amba device */
 	__u32	num_regions;	/* Max region index + 1 */
 	__u32	num_irqs;	/* Max IRQ index + 1 */
 };
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug()
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV) Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-06-04 10:56   ` Peter Maydell
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints Alex Bennée
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: marc.zyngier, Alex Bennée, linux-arm-kernel, kvm, kvmarm

As we haven't always had guest debug support we need to probe for it.
Additionally we don't do this in the start-up capability code so we
don't fall over on old kernels.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target-arm/kvm64.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 93c1ca8..61592d2 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -25,6 +25,22 @@
 #include "internals.h"
 #include "hw/arm/arm.h"
 
+static bool have_guest_debug;
+
+/**
+ * kvm_arm_init_debug()
+ * @cs: CPUState
+ *
+ * Check for guest debug capabilities.
+ *
+ */
+static void kvm_arm_init_debug(CPUState *cs)
+{
+    have_guest_debug = kvm_check_extension(cs->kvm_state,
+                                           KVM_CAP_SET_GUEST_DEBUG);
+    return;
+}
+
 static inline void set_feature(uint64_t *features, int feature)
 {
     *features |= 1ULL << feature;
@@ -107,6 +123,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
         return ret;
     }
 
+    kvm_arm_init_debug(cs);
+
     return kvm_arm_init_cpreg_list(cpu);
 }
 
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV) Alex Bennée
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug() Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-06-04 10:56   ` Peter Maydell
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step Alex Bennée
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: kvm, marc.zyngier, Paolo Bonzini, Alex Bennée, kvmarm,
	linux-arm-kernel

These don't involve messing around with debug registers, just setting
the breakpoint instruction in memory. GDB will not use this mechanism if
it can't access the memory to write the breakpoint.

All the kernel has to do is ensure the hypervisor traps the breakpoint
exceptions and returns to userspace.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

--
v2
  - handle debug exit with new hsr exception info
  - add verbosity to UNIMP message
v3
  - sync with kvm_cpu_synchronize_state() before checking PC.
  - use internals.h defines
  - use env->pc
  - use proper format types
---
 target-arm/kvm.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 76 insertions(+), 12 deletions(-)

diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index fdd9ba3..c3bad6f 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -510,9 +510,60 @@ void kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 {
 }
 
+/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register
+ *
+ * To minimise translating between kernel and user-space the kernel
+ * ABI just provides user-space with the full exception syndrome
+ * register value to be decoded in QEMU.
+ */
+
+static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
+{
+    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+    int hsr_ec = arch_info->hsr >> ARM_EL_EC_SHIFT;
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    /* Ensure PC is synchronised */
+    kvm_cpu_synchronize_state(cs);
+
+    switch (hsr_ec) {
+    case EC_AA64_BKPT:
+        if (kvm_find_sw_breakpoint(cs, env->pc)) {
+            return true;
+        }
+        break;
+    default:
+        error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
+                     __func__, arch_info->hsr, env->pc);
+    }
+
+    /* If we don't handle this it could be it really is for the
+       guest to handle */
+    qemu_log_mask(LOG_UNIMP,
+                  "%s: re-injecting exception not yet implemented"
+                  " (0x%"PRIx32", %"PRIx64")\n",
+                  __func__, hsr_ec, env->pc);
+
+    return false;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
-    return 0;
+    int ret = 0;
+
+    switch (run->exit_reason) {
+    case KVM_EXIT_DEBUG:
+        if (kvm_handle_debug(cs, run)) {
+            ret = EXCP_DEBUG;
+        } /* otherwise return to guest */
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
+                      __func__, run->exit_reason);
+        break;
+    }
+    return ret;
 }
 
 bool kvm_arch_stop_on_emulation_error(CPUState *cs)
@@ -537,14 +588,33 @@ int kvm_arch_on_sigbus(int code, void *addr)
 
 void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
 {
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+    if (kvm_sw_breakpoints_active(cs)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+    }
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs,
-                                  struct kvm_sw_breakpoint *bp)
+/* C6.6.29 BRK instruction */
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-    return -EINVAL;
+    static const uint32_t brk = 0xd4200000;
+
+    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, 4, 1)) {
+        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 != 0xd4200000 ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
+        return -EINVAL;
+    }
+    return 0;
 }
 
 int kvm_arch_insert_hw_breakpoint(target_ulong addr,
@@ -561,12 +631,6 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr,
     return -EINVAL;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs,
-                                  struct kvm_sw_breakpoint *bp)
-{
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-    return -EINVAL;
-}
 
 void kvm_arch_remove_all_hw_breakpoints(void)
 {
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
                   ` (2 preceding siblings ...)
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-06-04 10:59   ` Peter Maydell
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug Alex Bennée
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: kvm, marc.zyngier, Paolo Bonzini, Alex Bennée, kvmarm,
	linux-arm-kernel

This adds support for single-step. There isn't much to do on the QEMU
side as after we set-up the request for single step via the debug ioctl
it is all handled within the kernel.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - convert to using HSR_EC
v3
  - use internals.h definitions
---
 target-arm/kvm.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index c3bad6f..de2865a 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -528,6 +528,13 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
     kvm_cpu_synchronize_state(cs);
 
     switch (hsr_ec) {
+    case EC_SOFTWARESTEP:
+        if (cs->singlestep_enabled) {
+            return true;
+        } else {
+            error_report("Came out of SINGLE STEP when not enabled");
+        }
+        break;
     case EC_AA64_BKPT:
         if (kvm_find_sw_breakpoint(cs, env->pc)) {
             return true;
@@ -588,6 +595,9 @@ int kvm_arch_on_sigbus(int code, void *addr)
 
 void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
 {
+    if (cs->singlestep_enabled) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+    }
     if (kvm_sw_breakpoints_active(cs)) {
         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
     }
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
                   ` (3 preceding siblings ...)
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-06-04 11:10   ` Peter Maydell
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions Alex Bennée
  2015-06-04 11:35 ` [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Peter Maydell
  6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: kvm, marc.zyngier, Paolo Bonzini, Alex Bennée, kvmarm,
	linux-arm-kernel

This adds basic support for HW assisted debug. The ioctl interface to
KVM allows us to pass an implementation defined number of break and
watch point registers. When KVM_GUESTDBG_USE_HW_BP is specified these
debug registers will be installed in place on the world switch into the
guest.

The hardware is actually capable of more advanced matching but it is
unclear if this expressiveness is available via the gdbstub protocol.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - correct setting of PMC/BAS/MASK
  - improved commentary
  - added helper function to check watchpoint in range
  - fix find/deletion of watchpoints
v3
  - use internals.h definitions
---
 target-arm/kvm.c     |  35 +++---
 target-arm/kvm64.c   | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 target-arm/kvm_arm.h |  21 ++++
 3 files changed, 338 insertions(+), 22 deletions(-)

diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index de2865a..e1fccdd 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -17,6 +17,7 @@
 
 #include "qemu-common.h"
 #include "qemu/timer.h"
+#include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
@@ -540,6 +541,16 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
             return true;
         }
         break;
+    case EC_BREAKPOINT:
+        if (kvm_arm_find_hw_breakpoint(cs, env->pc)) {
+            return true;
+        }
+        break;
+    case EC_WATCHPOINT:
+        if (kvm_arm_find_hw_watchpoint(cs, arch_info->far)) {
+            return true;
+        }
+        break;
     default:
         error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
                      __func__, arch_info->hsr, env->pc);
@@ -601,6 +612,10 @@ void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
     if (kvm_sw_breakpoints_active(cs)) {
         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
     }
+    if (kvm_hw_breakpoints_active(cs)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+        kvm_copy_hw_breakpoint_data(&dbg->arch);
+    }
 }
 
 /* C6.6.29 BRK instruction */
@@ -627,26 +642,6 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_insert_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-    return -EINVAL;
-}
-
-int kvm_arch_remove_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-    return -EINVAL;
-}
-
-
-void kvm_arch_remove_all_hw_breakpoints(void)
-{
-    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-}
-
 void kvm_arch_init_irq_routing(KVMState *s)
 {
 }
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 61592d2..06d4e1e 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -2,6 +2,7 @@
  * ARM implementation of KVM hooks, 64 bit specific code
  *
  * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
+ * Copyright Alex Bennée 2014, Linaro
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
@@ -12,12 +13,18 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
 
+#include <linux/elf.h>
 #include <linux/kvm.h>
 
 #include "config-host.h"
 #include "qemu-common.h"
 #include "qemu/timer.h"
+#include "qemu/host-utils.h"
+#include "qemu/error-report.h"
+#include "exec/gdbstub.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
@@ -26,21 +33,314 @@
 #include "hw/arm/arm.h"
 
 static bool have_guest_debug;
+/* Max and current break/watch point counts */
+int max_hw_bp, max_hw_wp;
+int cur_hw_bp, cur_hw_wp;
+struct kvm_guest_debug_arch guest_debug_registers;
 
 /**
- * kvm_arm_init_debug()
+ * kvm_arm_init_debug() - check for guest debug capabilities
  * @cs: CPUState
  *
- * Check for guest debug capabilities.
+ * kvm_check_extension returns 0 if we have no debug registers or the
+ * number we have.
  *
  */
 static void kvm_arm_init_debug(CPUState *cs)
 {
     have_guest_debug = kvm_check_extension(cs->kvm_state,
                                            KVM_CAP_SET_GUEST_DEBUG);
+    max_hw_wp = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
+    max_hw_bp = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
     return;
 }
 
+/**
+ * insert_hw_breakpoint()
+ * @addr: address of breakpoint
+ *
+ * See ARM ARM D2.9.1 for details but here we are only going to create
+ * simple un-linked breakpoints (i.e. we don't chain breakpoints
+ * together to match address and context or vmid). The hardware is
+ * capable of fancier matching but that will require exposing that
+ * fanciness to GDB's interface
+ *
+ * D7.3.2 DBGBCR<n>_EL1, Debug Breakpoint Control Registers
+ *
+ *  31  24 23  20 19   16 15 14  13  12   9 8   5 4    3 2   1  0
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ * | RES0 |  BT  |  LBN  | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ *
+ * BT: Breakpoint type (0 = unlinked address match)
+ * LBN: Linked BP number (0 = unused)
+ * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
+ * BAS: Byte Address Select (RES1 for AArch64)
+ * E: Enable bit
+ */
+static int insert_hw_breakpoint(target_ulong addr)
+{
+    uint32_t bcr = 0x1; /* E=1, enable */
+    if (cur_hw_bp >= max_hw_bp) {
+        return -ENOBUFS;
+    }
+    bcr = deposit32(bcr, 1, 2, 0x3);   /* PMC = 11 */
+    bcr = deposit32(bcr, 5, 4, 0xf);   /* BAS = RES1 */
+    guest_debug_registers.dbg_bcr[cur_hw_bp] = bcr;
+    guest_debug_registers.dbg_bvr[cur_hw_bp] = addr;
+    cur_hw_bp++;
+    return 0;
+}
+
+/**
+ * delete_hw_breakpoint()
+ * @pc: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_breakpoint(target_ulong pc)
+{
+    int i;
+    for (i = 0; i < cur_hw_bp; i++) {
+      if (guest_debug_registers.dbg_bvr[i] == pc) {
+          while (i < cur_hw_bp) {
+              if (i == max_hw_bp) {
+                  guest_debug_registers.dbg_bvr[i] = 0;
+                  guest_debug_registers.dbg_bcr[i] = 0;
+              } else {
+                  guest_debug_registers.dbg_bvr[i] =
+                      guest_debug_registers.dbg_bvr[i + 1];
+                  guest_debug_registers.dbg_bcr[i] =
+                      guest_debug_registers.dbg_bcr[i + 1];
+              }
+              i++;
+          }
+          cur_hw_bp--;
+          return 0;
+      }
+    }
+    return -ENOENT;
+}
+
+/**
+ * insert_hw_watchpoint()
+ * @addr: address of watch point
+ * @len: size of area
+ * @type: type of watch point
+ *
+ * See ARM ARM D2.10. As with the breakpoints we can do some advanced
+ * stuff if we want to. The watch points can be linked with the break
+ * points above to make them context aware. However for simplicity
+ * currently we only deal with simple read/write watch points.
+ *
+ * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
+ *
+ *  31  29 28   24 23  21  20  19 16 15 14  13   12  5 4   3 2   1  0
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ * | RES0 |  MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ *
+ * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
+ * WT: 0 - unlinked, 1 - linked (not currently used)
+ * LBN: Linked BP number (not currently used)
+ * SSC/HMC/PAC: Security, Higher and Priv access control (Table D-12)
+ * BAS: Byte Address Select
+ * LSC: Load/Store control (01: load, 10: store, 11: both)
+ * E: Enable
+ *
+ * The bottom 2 bits of the value register are masked. Therefor to
+ * break on an sizes smaller than unaligned byte you need to set
+ * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
+ * need to ensure you mask the address as required and set BAS=0xff
+ */
+
+static int insert_hw_watchpoint(target_ulong addr,
+                                target_ulong len, int type)
+{
+    uint32_t dbgwcr = 1; /* E=1, enable */
+    uint64_t dbgwvr = addr & (~0x7ULL);
+
+    if (cur_hw_wp >= max_hw_wp) {
+        return -ENOBUFS;
+    }
+
+    /* PAC 00 is reserved, assume EL1 exception */
+    dbgwcr = deposit32(dbgwcr, 1, 2, 1);
+
+    switch (type) {
+    case GDB_WATCHPOINT_READ:
+        dbgwcr = deposit32(dbgwcr, 3, 2, 1);
+        break;
+    case GDB_WATCHPOINT_WRITE:
+        dbgwcr = deposit32(dbgwcr, 3, 2, 2);
+        break;
+    case GDB_WATCHPOINT_ACCESS:
+        dbgwcr = deposit32(dbgwcr, 3, 2, 3);
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+    if (len <= 8) {
+        /* we align the address and set the bits in BAS */
+        int off = addr & 0x7;
+        int bas = (1 << len)-1;
+        dbgwcr = deposit32(dbgwcr, 5+off, 8-off, bas);
+    } else {
+        /* For ranges above 8 bytes we need to be a power of 2 */
+        if (ctpop64(len)==1) {
+            int bits = ctz64(len);
+            dbgwvr &= ~((1 << bits)-1);
+            dbgwcr = deposit32(dbgwcr, 24, 4, bits);
+            dbgwcr = deposit32(dbgwcr, 5, 8, 0xff);
+        } else {
+            return -ENOBUFS;
+        }
+    }
+
+    guest_debug_registers.dbg_wcr[cur_hw_wp] = dbgwcr;
+    guest_debug_registers.dbg_wvr[cur_hw_wp] = dbgwvr;
+    cur_hw_wp++;
+    return 0;
+}
+
+
+static bool check_watchpoint_in_range(int i, target_ulong addr)
+{
+    uint32_t dbgwcr = guest_debug_registers.dbg_wcr[i];
+    uint64_t addr_top, addr_bottom = guest_debug_registers.dbg_wvr[i];
+    int bas = extract32(dbgwcr, 5, 8);
+    int mask = extract32(dbgwcr, 24, 4);
+
+    if (mask) {
+        addr_top = addr_bottom + (1 << mask);
+    } else {
+        /* BAS must be contiguous but can offset against the base
+         * address in DBGWVR */
+        addr_bottom = addr_bottom + ctz32(bas);
+        addr_top = addr_bottom + clo32(bas);
+    }
+
+    if (addr >= addr_bottom && addr <= addr_top ) {
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * delete_hw_watchpoint()
+ * @addr: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_watchpoint(target_ulong addr,
+                                target_ulong len, int type)
+{
+    int i;
+    for (i = 0; i < cur_hw_wp; i++) {
+        if (check_watchpoint_in_range(i, addr)) {
+            while (i < cur_hw_wp) {
+                if (i == max_hw_wp) {
+                    guest_debug_registers.dbg_wvr[i] = 0;
+                    guest_debug_registers.dbg_wcr[i] = 0;
+                } else {
+                    guest_debug_registers.dbg_wvr[i] =
+                        guest_debug_registers.dbg_wvr[i + 1];
+                    guest_debug_registers.dbg_wcr[i] =
+                        guest_debug_registers.dbg_wcr[i + 1];
+                }
+                i++;
+            }
+            cur_hw_wp--;
+            return 0;
+        }
+    }
+    return -ENOENT;
+}
+
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        return insert_hw_breakpoint(addr);
+        break;
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+        return insert_hw_watchpoint(addr, len, type);
+    default:
+        return -ENOSYS;
+    }
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        return delete_hw_breakpoint(addr);
+        break;
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+        return delete_hw_watchpoint(addr, len, type);
+    default:
+        return -ENOSYS;
+    }
+}
+
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    memset((void *)&guest_debug_registers, 0, sizeof(guest_debug_registers));
+    cur_hw_bp = 0;
+    cur_hw_wp = 0;
+}
+
+void kvm_copy_hw_breakpoint_data(struct kvm_guest_debug_arch *ptr)
+{
+    /* Compile time assert? */
+    g_assert(sizeof(struct kvm_guest_debug_arch) == sizeof(guest_debug_registers));
+    memcpy(ptr, &guest_debug_registers, sizeof(guest_debug_registers));
+}
+
+bool kvm_hw_breakpoints_active(CPUState *cs)
+{
+    return ( (cur_hw_bp > 0) || (cur_hw_wp >0) ) ? TRUE:FALSE;
+}
+
+bool kvm_arm_find_hw_breakpoint(CPUState *cpu, target_ulong pc)
+{
+  if (kvm_hw_breakpoints_active(cpu)) {
+    int i;
+    for (i=0; i<cur_hw_bp; i++) {
+      if (guest_debug_registers.dbg_bvr[i] == pc) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool kvm_arm_find_hw_watchpoint(CPUState *cpu, target_ulong addr)
+{
+  if (kvm_hw_breakpoints_active(cpu)) {
+    int i;
+    for (i=0; i<cur_hw_wp; i++) {
+        if (check_watchpoint_in_range(i, addr)) {
+                return true;
+        }
+    }
+  }
+  return false;
+}
+
+
 static inline void set_feature(uint64_t *features, int feature)
 {
     *features |= 1ULL << feature;
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
index 5abd591..9d713bc 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -179,6 +179,27 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu);
  */
 int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
 
+bool kvm_hw_breakpoints_active(CPUState *cs);
+void kvm_copy_hw_breakpoint_data(struct kvm_guest_debug_arch *ptr);
+
+/**
+ * kvm_arm_find_hw_breakpoint:
+ * @cpu: CPUState
+ * @pc: pc of breakpoint
+ *
+ * Return TRUE if the pc matches one of our breakpoints.
+ */
+bool kvm_arm_find_hw_breakpoint(CPUState *cpu, target_ulong pc);
+
+/**
+ * kvm_arm_find_hw_watchpoint:
+ * @cpu: CPUState
+ * @addr: address of watchpoint
+ *
+ * Return TRUE if the addr matches one of our watchpoints.
+ */
+bool kvm_arm_find_hw_watchpoint(CPUState *cpu, target_ulong addr);
+
 #endif
 
 #endif
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
                   ` (4 preceding siblings ...)
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug Alex Bennée
@ 2015-05-29 15:19 ` Alex Bennée
  2015-06-04 11:29   ` Peter Maydell
  2015-06-04 11:35 ` [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Peter Maydell
  6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2015-05-29 15:19 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, christoffer.dall, zhichao.huang
  Cc: Alex Bennée, kvm, marc.zyngier, Paolo Bonzini,
	Alex Bennée, kvmarm, linux-arm-kernel

From: Alex Bennée <alex@bennee.com>

If we can't find details for the debug exception in our debug state
then we can assume the exception is due to debugging inside the guest.
To inject the exception into the guest state we re-use the TCG exception
code (do_interupt).

However while guest debugging is in effect we currently can't handle the
guest using single step which is heavily used by GDB.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v5:
  - new for v5
---
 target-arm/cpu.h        |  1 +
 target-arm/helper-a64.c | 17 ++++++++++++++---
 target-arm/internals.h  |  1 +
 target-arm/kvm.c        | 30 ++++++++++++++++++++++--------
 4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 083211c..95ae3a8 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -56,6 +56,7 @@
 #define EXCP_SMC            13   /* Secure Monitor Call */
 #define EXCP_VIRQ           14
 #define EXCP_VFIQ           15
+#define EXCP_WAPT           16
 
 #define ARMV7M_EXCP_RESET   1
 #define ARMV7M_EXCP_NMI     2
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 861f6fa..32bd27d 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -25,6 +25,7 @@
 #include "qemu/bitops.h"
 #include "internals.h"
 #include "qemu/crc32c.h"
+#include "sysemu/kvm.h"
 #include <zlib.h> /* For crc32 */
 
 /* C2.4.7 Multiply and divide */
@@ -478,10 +479,13 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
     }
 
     arm_log_exception(cs->exception_index);
-    qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_el(env));
+    qemu_log_mask(CPU_LOG_INT, "...from EL%d PC 0x%" PRIx64 "\n",
+                  arm_current_el(env), env->pc);
+
     if (qemu_loglevel_mask(CPU_LOG_INT)
         && !excp_is_internal(cs->exception_index)) {
-        qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
+        qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
+                      env->exception.syndrome >> ARM_EL_EC_SHIFT,
                       env->exception.syndrome);
     }
 
@@ -494,6 +498,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
     switch (cs->exception_index) {
     case EXCP_PREFETCH_ABORT:
     case EXCP_DATA_ABORT:
+    case EXCP_WAPT:
         env->cp15.far_el[new_el] = env->exception.vaddress;
         qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
                       env->cp15.far_el[new_el]);
@@ -539,6 +544,12 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
     aarch64_restore_sp(env, new_el);
 
     env->pc = addr;
-    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+
+    qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
+                  new_el, env->pc, pstate_read(env));
+
+    if (!kvm_enabled()) {
+        cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+    }
 }
 #endif
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 2cc3017..10e8999 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -58,6 +58,7 @@ static const char * const excnames[] = {
     [EXCP_SMC] = "Secure Monitor Call",
     [EXCP_VIRQ] = "Virtual IRQ",
     [EXCP_VFIQ] = "Virtual FIQ",
+    [EXCP_WAPT] = "Watchpoint",
 };
 
 static inline void arm_log_exception(int idx)
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index e1fccdd..6f608d8 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -523,9 +523,11 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
     struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
     int hsr_ec = arch_info->hsr >> ARM_EL_EC_SHIFT;
     ARMCPU *cpu = ARM_CPU(cs);
+    CPUClass *cc = CPU_GET_CLASS(cs);
     CPUARMState *env = &cpu->env;
+    int forward_excp = EXCP_BKPT;
 
-    /* Ensure PC is synchronised */
+    /* Ensure all state is synchronised */
     kvm_cpu_synchronize_state(cs);
 
     switch (hsr_ec) {
@@ -533,7 +535,14 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
         if (cs->singlestep_enabled) {
             return true;
         } else {
-            error_report("Came out of SINGLE STEP when not enabled");
+            /*
+             * The kernel should have supressed the guests ability to
+             * single step at this point so something has gone wrong.
+             */
+            error_report("%s: guest single-step while debugging unsupported"
+                         " (%"PRIx64", %"PRIx32")\n",
+                         __func__, env->pc, arch_info->hsr);
+            return false;
         }
         break;
     case EC_AA64_BKPT:
@@ -549,19 +558,24 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
     case EC_WATCHPOINT:
         if (kvm_arm_find_hw_watchpoint(cs, arch_info->far)) {
             return true;
+        } else {
+            forward_excp = EXCP_WAPT;
         }
         break;
     default:
         error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
                      __func__, arch_info->hsr, env->pc);
+        return false;
     }
 
-    /* If we don't handle this it could be it really is for the
-       guest to handle */
-    qemu_log_mask(LOG_UNIMP,
-                  "%s: re-injecting exception not yet implemented"
-                  " (0x%"PRIx32", %"PRIx64")\n",
-                  __func__, hsr_ec, env->pc);
+    /* If we are not handling the debug exception it must belong to
+     * the guest. Let's re-use the existing TCG interrupt code to set
+     * everything up properly
+     */
+    cs->exception_index = forward_excp;
+    env->exception.syndrome = arch_info->hsr;
+    env->exception.vaddress = arch_info->far;
+    cc->do_interrupt(cs);
 
     return false;
 }
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints Alex Bennée
@ 2015-06-04 10:56   ` Peter Maydell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 10:56 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm-devel, Marc Zyngier, QEMU Developers, Christoffer Dall,
	Zhichao Huang, Paolo Bonzini, kvmarm@lists.cs.columbia.edu,
	arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> These don't involve messing around with debug registers, just setting
> the breakpoint instruction in memory. GDB will not use this mechanism if
> it can't access the memory to write the breakpoint.
>
> All the kernel has to do is ensure the hypervisor traps the breakpoint
> exceptions and returns to userspace.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> --
> v2
>   - handle debug exit with new hsr exception info
>   - add verbosity to UNIMP message
> v3
>   - sync with kvm_cpu_synchronize_state() before checking PC.
>   - use internals.h defines
>   - use env->pc
>   - use proper format types
> ---
>  target-arm/kvm.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 76 insertions(+), 12 deletions(-)
>
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index fdd9ba3..c3bad6f 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -510,9 +510,60 @@ void kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
>  {
>  }
>
> +/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register
> + *
> + * To minimise translating between kernel and user-space the kernel
> + * ABI just provides user-space with the full exception syndrome
> + * register value to be decoded in QEMU.
> + */
> +
> +static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
> +{
> +    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
> +    int hsr_ec = arch_info->hsr >> ARM_EL_EC_SHIFT;
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +
> +    /* Ensure PC is synchronised */
> +    kvm_cpu_synchronize_state(cs);
> +
> +    switch (hsr_ec) {
> +    case EC_AA64_BKPT:
> +        if (kvm_find_sw_breakpoint(cs, env->pc)) {
> +            return true;
> +        }
> +        break;
> +    default:
> +        error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
> +                     __func__, arch_info->hsr, env->pc);
> +    }
> +
> +    /* If we don't handle this it could be it really is for the
> +       guest to handle */
> +    qemu_log_mask(LOG_UNIMP,
> +                  "%s: re-injecting exception not yet implemented"
> +                  " (0x%"PRIx32", %"PRIx64")\n",
> +                  __func__, hsr_ec, env->pc);
> +
> +    return false;
> +}
> +
>  int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
>  {
> -    return 0;
> +    int ret = 0;
> +
> +    switch (run->exit_reason) {
> +    case KVM_EXIT_DEBUG:
> +        if (kvm_handle_debug(cs, run)) {
> +            ret = EXCP_DEBUG;
> +        } /* otherwise return to guest */
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
> +                      __func__, run->exit_reason);
> +        break;
> +    }
> +    return ret;
>  }
>
>  bool kvm_arch_stop_on_emulation_error(CPUState *cs)
> @@ -537,14 +588,33 @@ int kvm_arch_on_sigbus(int code, void *addr)
>
>  void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
>  {
> -    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
> +    if (kvm_sw_breakpoints_active(cs)) {
> +        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
> +    }
>  }
>
> -int kvm_arch_insert_sw_breakpoint(CPUState *cs,
> -                                  struct kvm_sw_breakpoint *bp)
> +/* C6.6.29 BRK instruction */
> +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
>  {
> -    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
> -    return -EINVAL;
> +    static const uint32_t brk = 0xd4200000;

#define, please, since you're using it here and in the remove fn.

> +
> +    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, 4, 1)) {
> +        return -EINVAL;
> +    }
> +    return 0;
> +}

Shouldn't we be testing the "does the kernel implement debug"
flag before we allow gdb to write in bp insns or mess with
dbg->control ?

-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug()
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug() Alex Bennée
@ 2015-06-04 10:56   ` Peter Maydell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 10:56 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm-devel, Marc Zyngier, QEMU Developers, Christoffer Dall,
	Zhichao Huang, kvmarm@lists.cs.columbia.edu, arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> As we haven't always had guest debug support we need to probe for it.
> Additionally we don't do this in the start-up capability code so we
> don't fall over on old kernels.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step Alex Bennée
@ 2015-06-04 10:59   ` Peter Maydell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 10:59 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm-devel, Marc Zyngier, QEMU Developers, Christoffer Dall,
	Zhichao Huang, Paolo Bonzini, kvmarm@lists.cs.columbia.edu,
	arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> This adds support for single-step. There isn't much to do on the QEMU
> side as after we set-up the request for single step via the debug ioctl
> it is all handled within the kernel.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v2
>   - convert to using HSR_EC
> v3
>   - use internals.h definitions
> ---
>  target-arm/kvm.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index c3bad6f..de2865a 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -528,6 +528,13 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
>      kvm_cpu_synchronize_state(cs);
>
>      switch (hsr_ec) {
> +    case EC_SOFTWARESTEP:
> +        if (cs->singlestep_enabled) {
> +            return true;
> +        } else {
> +            error_report("Came out of SINGLE STEP when not enabled");

All-caps there is a bit odd.

> +        }
> +        break;
>      case EC_AA64_BKPT:
>          if (kvm_find_sw_breakpoint(cs, env->pc)) {
>              return true;
> @@ -588,6 +595,9 @@ int kvm_arch_on_sigbus(int code, void *addr)
>
>  void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
>  {
> +    if (cs->singlestep_enabled) {
> +        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
> +    }
>      if (kvm_sw_breakpoints_active(cs)) {
>          dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
>      }

Again, is there a guard somewhere to prevent us trying to enable
singlestep if the kernel doesn't support it?

-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug Alex Bennée
@ 2015-06-04 11:10   ` Peter Maydell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 11:10 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm-devel, Marc Zyngier, QEMU Developers, Christoffer Dall,
	Zhichao Huang, Paolo Bonzini, kvmarm@lists.cs.columbia.edu,
	arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> This adds basic support for HW assisted debug. The ioctl interface to
> KVM allows us to pass an implementation defined number of break and
> watch point registers. When KVM_GUESTDBG_USE_HW_BP is specified these
> debug registers will be installed in place on the world switch into the
> guest.
>
> The hardware is actually capable of more advanced matching but it is
> unclear if this expressiveness is available via the gdbstub protocol.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v2
>   - correct setting of PMC/BAS/MASK
>   - improved commentary
>   - added helper function to check watchpoint in range
>   - fix find/deletion of watchpoints
> v3
>   - use internals.h definitions
> ---
>  target-arm/kvm.c     |  35 +++---
>  target-arm/kvm64.c   | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  target-arm/kvm_arm.h |  21 ++++
>  3 files changed, 338 insertions(+), 22 deletions(-)
>
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index de2865a..e1fccdd 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -17,6 +17,7 @@
>
>  #include "qemu-common.h"
>  #include "qemu/timer.h"
> +#include "qemu/error-report.h"
>  #include "sysemu/sysemu.h"
>  #include "sysemu/kvm.h"
>  #include "kvm_arm.h"
> @@ -540,6 +541,16 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
>              return true;
>          }
>          break;
> +    case EC_BREAKPOINT:
> +        if (kvm_arm_find_hw_breakpoint(cs, env->pc)) {
> +            return true;
> +        }
> +        break;
> +    case EC_WATCHPOINT:
> +        if (kvm_arm_find_hw_watchpoint(cs, arch_info->far)) {
> +            return true;
> +        }

I assume the kernel is giving us the hardware behaviour of
"watchpoint traps happen before load/store execution, not after"?
(This is the correct thing from the POV of the rest of QEMU.)

> +        break;
>      default:
>          error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
>                       __func__, arch_info->hsr, env->pc);
> @@ -601,6 +612,10 @@ void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
>      if (kvm_sw_breakpoints_active(cs)) {
>          dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
>      }
> +    if (kvm_hw_breakpoints_active(cs)) {
> +        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
> +        kvm_copy_hw_breakpoint_data(&dbg->arch);
> +    }
>  }
>
>  /* C6.6.29 BRK instruction */
> @@ -627,26 +642,6 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
>      return 0;
>  }
>
> -int kvm_arch_insert_hw_breakpoint(target_ulong addr,
> -                                  target_ulong len, int type)
> -{
> -    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
> -    return -EINVAL;
> -}
> -
> -int kvm_arch_remove_hw_breakpoint(target_ulong addr,
> -                                  target_ulong len, int type)
> -{
> -    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
> -    return -EINVAL;
> -}
> -
> -
> -void kvm_arch_remove_all_hw_breakpoints(void)
> -{
> -    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
> -}
> -
>  void kvm_arch_init_irq_routing(KVMState *s)
>  {
>  }
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> index 61592d2..06d4e1e 100644
> --- a/target-arm/kvm64.c
> +++ b/target-arm/kvm64.c
> @@ -2,6 +2,7 @@
>   * ARM implementation of KVM hooks, 64 bit specific code
>   *
>   * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
> + * Copyright Alex Bennée 2014, Linaro

Really 2014? :-)

>   *
>   * This work is licensed under the terms of the GNU GPL, version 2 or later.
>   * See the COPYING file in the top-level directory.
> @@ -12,12 +13,18 @@
>  #include <sys/types.h>
>  #include <sys/ioctl.h>
>  #include <sys/mman.h>
> +#include <sys/ptrace.h>
> +#include <asm/ptrace.h>
>
> +#include <linux/elf.h>
>  #include <linux/kvm.h>
>
>  #include "config-host.h"
>  #include "qemu-common.h"
>  #include "qemu/timer.h"
> +#include "qemu/host-utils.h"
> +#include "qemu/error-report.h"
> +#include "exec/gdbstub.h"
>  #include "sysemu/sysemu.h"
>  #include "sysemu/kvm.h"
>  #include "kvm_arm.h"
> @@ -26,21 +33,314 @@
>  #include "hw/arm/arm.h"
>
>  static bool have_guest_debug;
> +/* Max and current break/watch point counts */
> +int max_hw_bp, max_hw_wp;
> +int cur_hw_bp, cur_hw_wp;
> +struct kvm_guest_debug_arch guest_debug_registers;

...did we figure out how this works for SMP?

>
>  /**
> - * kvm_arm_init_debug()
> + * kvm_arm_init_debug() - check for guest debug capabilities
>   * @cs: CPUState
>   *
> - * Check for guest debug capabilities.
> + * kvm_check_extension returns 0 if we have no debug registers or the
> + * number we have.
>   *
>   */
>  static void kvm_arm_init_debug(CPUState *cs)
>  {
>      have_guest_debug = kvm_check_extension(cs->kvm_state,
>                                             KVM_CAP_SET_GUEST_DEBUG);
> +    max_hw_wp = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
> +    max_hw_bp = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
>      return;
>  }
>
> +/**
> + * insert_hw_breakpoint()
> + * @addr: address of breakpoint
> + *
> + * See ARM ARM D2.9.1 for details but here we are only going to create
> + * simple un-linked breakpoints (i.e. we don't chain breakpoints
> + * together to match address and context or vmid). The hardware is
> + * capable of fancier matching but that will require exposing that
> + * fanciness to GDB's interface
> + *
> + * D7.3.2 DBGBCR<n>_EL1, Debug Breakpoint Control Registers
> + *
> + *  31  24 23  20 19   16 15 14  13  12   9 8   5 4    3 2   1  0
> + * +------+------+-------+-----+----+------+-----+------+-----+---+
> + * | RES0 |  BT  |  LBN  | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
> + * +------+------+-------+-----+----+------+-----+------+-----+---+
> + *
> + * BT: Breakpoint type (0 = unlinked address match)
> + * LBN: Linked BP number (0 = unused)
> + * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
> + * BAS: Byte Address Select (RES1 for AArch64)
> + * E: Enable bit
> + */
> +static int insert_hw_breakpoint(target_ulong addr)
> +{
> +    uint32_t bcr = 0x1; /* E=1, enable */
> +    if (cur_hw_bp >= max_hw_bp) {
> +        return -ENOBUFS;
> +    }
> +    bcr = deposit32(bcr, 1, 2, 0x3);   /* PMC = 11 */

"0b11" would make it clearer you didn't mean decimal 11 here.

> +    bcr = deposit32(bcr, 5, 4, 0xf);   /* BAS = RES1 */
> +    guest_debug_registers.dbg_bcr[cur_hw_bp] = bcr;
> +    guest_debug_registers.dbg_bvr[cur_hw_bp] = addr;
> +    cur_hw_bp++;
> +    return 0;
> +}
> +
> +/**
> + * delete_hw_breakpoint()
> + * @pc: address of breakpoint
> + *
> + * Delete a breakpoint and shuffle any above down
> + */
> +
> +static int delete_hw_breakpoint(target_ulong pc)
> +{
> +    int i;
> +    for (i = 0; i < cur_hw_bp; i++) {
> +      if (guest_debug_registers.dbg_bvr[i] == pc) {
> +          while (i < cur_hw_bp) {
> +              if (i == max_hw_bp) {

When can i be less than cur_hw_bp but still equal to max_hw_bp ?

> +                  guest_debug_registers.dbg_bvr[i] = 0;
> +                  guest_debug_registers.dbg_bcr[i] = 0;
> +              } else {
> +                  guest_debug_registers.dbg_bvr[i] =
> +                      guest_debug_registers.dbg_bvr[i + 1];
> +                  guest_debug_registers.dbg_bcr[i] =
> +                      guest_debug_registers.dbg_bcr[i + 1];
> +              }
> +              i++;
> +          }
> +          cur_hw_bp--;
> +          return 0;
> +      }
> +    }
> +    return -ENOENT;
> +}
> +
> +/**
> + * insert_hw_watchpoint()
> + * @addr: address of watch point
> + * @len: size of area
> + * @type: type of watch point
> + *
> + * See ARM ARM D2.10. As with the breakpoints we can do some advanced
> + * stuff if we want to. The watch points can be linked with the break
> + * points above to make them context aware. However for simplicity
> + * currently we only deal with simple read/write watch points.
> + *
> + * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
> + *
> + *  31  29 28   24 23  21  20  19 16 15 14  13   12  5 4   3 2   1  0
> + * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
> + * | RES0 |  MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
> + * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
> + *
> + * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
> + * WT: 0 - unlinked, 1 - linked (not currently used)
> + * LBN: Linked BP number (not currently used)
> + * SSC/HMC/PAC: Security, Higher and Priv access control (Table D-12)
> + * BAS: Byte Address Select
> + * LSC: Load/Store control (01: load, 10: store, 11: both)
> + * E: Enable
> + *
> + * The bottom 2 bits of the value register are masked. Therefor to
> + * break on an sizes smaller than unaligned byte you need to set
> + * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
> + * need to ensure you mask the address as required and set BAS=0xff
> + */
> +
> +static int insert_hw_watchpoint(target_ulong addr,
> +                                target_ulong len, int type)
> +{
> +    uint32_t dbgwcr = 1; /* E=1, enable */
> +    uint64_t dbgwvr = addr & (~0x7ULL);
> +
> +    if (cur_hw_wp >= max_hw_wp) {
> +        return -ENOBUFS;
> +    }
> +
> +    /* PAC 00 is reserved, assume EL1 exception */
> +    dbgwcr = deposit32(dbgwcr, 1, 2, 1);
> +
> +    switch (type) {
> +    case GDB_WATCHPOINT_READ:
> +        dbgwcr = deposit32(dbgwcr, 3, 2, 1);
> +        break;
> +    case GDB_WATCHPOINT_WRITE:
> +        dbgwcr = deposit32(dbgwcr, 3, 2, 2);
> +        break;
> +    case GDB_WATCHPOINT_ACCESS:
> +        dbgwcr = deposit32(dbgwcr, 3, 2, 3);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +        break;
> +    }
> +    if (len <= 8) {
> +        /* we align the address and set the bits in BAS */
> +        int off = addr & 0x7;
> +        int bas = (1 << len)-1;
> +        dbgwcr = deposit32(dbgwcr, 5+off, 8-off, bas);
> +    } else {
> +        /* For ranges above 8 bytes we need to be a power of 2 */
> +        if (ctpop64(len)==1) {
> +            int bits = ctz64(len);
> +            dbgwvr &= ~((1 << bits)-1);
> +            dbgwcr = deposit32(dbgwcr, 24, 4, bits);
> +            dbgwcr = deposit32(dbgwcr, 5, 8, 0xff);
> +        } else {
> +            return -ENOBUFS;
> +        }
> +    }
> +
> +    guest_debug_registers.dbg_wcr[cur_hw_wp] = dbgwcr;
> +    guest_debug_registers.dbg_wvr[cur_hw_wp] = dbgwvr;
> +    cur_hw_wp++;
> +    return 0;
> +}
> +
> +
> +static bool check_watchpoint_in_range(int i, target_ulong addr)
> +{
> +    uint32_t dbgwcr = guest_debug_registers.dbg_wcr[i];
> +    uint64_t addr_top, addr_bottom = guest_debug_registers.dbg_wvr[i];
> +    int bas = extract32(dbgwcr, 5, 8);
> +    int mask = extract32(dbgwcr, 24, 4);
> +
> +    if (mask) {
> +        addr_top = addr_bottom + (1 << mask);
> +    } else {
> +        /* BAS must be contiguous but can offset against the base
> +         * address in DBGWVR */
> +        addr_bottom = addr_bottom + ctz32(bas);
> +        addr_top = addr_bottom + clo32(bas);
> +    }
> +
> +    if (addr >= addr_bottom && addr <= addr_top ) {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
> +/**
> + * delete_hw_watchpoint()
> + * @addr: address of breakpoint
> + *
> + * Delete a breakpoint and shuffle any above down
> + */
> +
> +static int delete_hw_watchpoint(target_ulong addr,
> +                                target_ulong len, int type)
> +{
> +    int i;
> +    for (i = 0; i < cur_hw_wp; i++) {
> +        if (check_watchpoint_in_range(i, addr)) {
> +            while (i < cur_hw_wp) {
> +                if (i == max_hw_wp) {
> +                    guest_debug_registers.dbg_wvr[i] = 0;
> +                    guest_debug_registers.dbg_wcr[i] = 0;
> +                } else {
> +                    guest_debug_registers.dbg_wvr[i] =
> +                        guest_debug_registers.dbg_wvr[i + 1];
> +                    guest_debug_registers.dbg_wcr[i] =
> +                        guest_debug_registers.dbg_wcr[i + 1];
> +                }
> +                i++;
> +            }
> +            cur_hw_wp--;
> +            return 0;
> +        }
> +    }
> +    return -ENOENT;
> +}
> +
> +
> +int kvm_arch_insert_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    switch (type) {
> +    case GDB_BREAKPOINT_HW:
> +        return insert_hw_breakpoint(addr);
> +        break;
> +    case GDB_WATCHPOINT_READ:
> +    case GDB_WATCHPOINT_WRITE:
> +    case GDB_WATCHPOINT_ACCESS:
> +        return insert_hw_watchpoint(addr, len, type);
> +    default:
> +        return -ENOSYS;
> +    }

More missing guards for "no kernel support" ?

> +}
> +
> +int kvm_arch_remove_hw_breakpoint(target_ulong addr,
> +                                  target_ulong len, int type)
> +{
> +    switch (type) {
> +    case GDB_BREAKPOINT_HW:
> +        return delete_hw_breakpoint(addr);
> +        break;
> +    case GDB_WATCHPOINT_READ:
> +    case GDB_WATCHPOINT_WRITE:
> +    case GDB_WATCHPOINT_ACCESS:
> +        return delete_hw_watchpoint(addr, len, type);
> +    default:
> +        return -ENOSYS;
> +    }
> +}
> +
> +
> +void kvm_arch_remove_all_hw_breakpoints(void)
> +{
> +    memset((void *)&guest_debug_registers, 0, sizeof(guest_debug_registers));
> +    cur_hw_bp = 0;
> +    cur_hw_wp = 0;
> +}
> +
> +void kvm_copy_hw_breakpoint_data(struct kvm_guest_debug_arch *ptr)
> +{
> +    /* Compile time assert? */
> +    g_assert(sizeof(struct kvm_guest_debug_arch) == sizeof(guest_debug_registers));

This assert doesn't seem to me to serve any particularly useful purpose.

> +    memcpy(ptr, &guest_debug_registers, sizeof(guest_debug_registers));
> +}
> +
> +bool kvm_hw_breakpoints_active(CPUState *cs)
> +{
> +    return ( (cur_hw_bp > 0) || (cur_hw_wp >0) ) ? TRUE:FALSE;

Weirdo spacing, TRUE/FALSE aren't capitalised, and boolexpr ? true : false
is the same as boolexpr anyway.

> +}
> +
> +bool kvm_arm_find_hw_breakpoint(CPUState *cpu, target_ulong pc)
> +{
> +  if (kvm_hw_breakpoints_active(cpu)) {
> +    int i;
> +    for (i=0; i<cur_hw_bp; i++) {

More spacing oddities.

> +      if (guest_debug_registers.dbg_bvr[i] == pc) {
> +        return true;
> +      }
> +    }
> +  }
> +  return false;
> +}
> +
> +bool kvm_arm_find_hw_watchpoint(CPUState *cpu, target_ulong addr)
> +{
> +  if (kvm_hw_breakpoints_active(cpu)) {
> +    int i;
> +    for (i=0; i<cur_hw_wp; i++) {
> +        if (check_watchpoint_in_range(i, addr)) {
> +                return true;
> +        }
> +    }
> +  }
> +  return false;
> +}
> +
> +
>  static inline void set_feature(uint64_t *features, int feature)
>  {
>      *features |= 1ULL << feature;
> diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
> index 5abd591..9d713bc 100644
> --- a/target-arm/kvm_arm.h
> +++ b/target-arm/kvm_arm.h
> @@ -179,6 +179,27 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu);
>   */
>  int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
>
> +bool kvm_hw_breakpoints_active(CPUState *cs);
> +void kvm_copy_hw_breakpoint_data(struct kvm_guest_debug_arch *ptr);
> +
> +/**
> + * kvm_arm_find_hw_breakpoint:
> + * @cpu: CPUState
> + * @pc: pc of breakpoint
> + *
> + * Return TRUE if the pc matches one of our breakpoints.

'true'.

> + */
> +bool kvm_arm_find_hw_breakpoint(CPUState *cpu, target_ulong pc);
> +
> +/**
> + * kvm_arm_find_hw_watchpoint:
> + * @cpu: CPUState
> + * @addr: address of watchpoint
> + *
> + * Return TRUE if the addr matches one of our watchpoints.
> + */
> +bool kvm_arm_find_hw_watchpoint(CPUState *cpu, target_ulong addr);
> +
>  #endif
>
>  #endif

-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions Alex Bennée
@ 2015-06-04 11:29   ` Peter Maydell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 11:29 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Alex Bennée, kvm-devel, Marc Zyngier, QEMU Developers,
	Christoffer Dall, Zhichao Huang, Paolo Bonzini,
	kvmarm@lists.cs.columbia.edu, arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> From: Alex Bennée <alex@bennee.com>
>
> If we can't find details for the debug exception in our debug state
> then we can assume the exception is due to debugging inside the guest.
> To inject the exception into the guest state we re-use the TCG exception
> code (do_interupt).
>
> However while guest debugging is in effect we currently can't handle the
> guest using single step which is heavily used by GDB.

Is this just the kernel not supporting this, or would QEMU need
to change as well? Worth mentioning either way.

> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v5:
>   - new for v5
> ---
>  target-arm/cpu.h        |  1 +
>  target-arm/helper-a64.c | 17 ++++++++++++++---
>  target-arm/internals.h  |  1 +
>  target-arm/kvm.c        | 30 ++++++++++++++++++++++--------
>  4 files changed, 38 insertions(+), 11 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 083211c..95ae3a8 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -56,6 +56,7 @@
>  #define EXCP_SMC            13   /* Secure Monitor Call */
>  #define EXCP_VIRQ           14
>  #define EXCP_VFIQ           15
> +#define EXCP_WAPT           16

Why do we need a new EXCP value here? In hardware watchpoints
are reported via a particular syndrome value and (for AArch32)
as Data Aborts, so I would expect that we would just do the same.
The code in this patch doesn't seem to treat EXCP_WAPT any
differently from EXCP_DABT...

>  #define ARMV7M_EXCP_RESET   1
>  #define ARMV7M_EXCP_NMI     2
> diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
> index 861f6fa..32bd27d 100644
> --- a/target-arm/helper-a64.c
> +++ b/target-arm/helper-a64.c
> @@ -25,6 +25,7 @@
>  #include "qemu/bitops.h"
>  #include "internals.h"
>  #include "qemu/crc32c.h"
> +#include "sysemu/kvm.h"
>  #include <zlib.h> /* For crc32 */
>
>  /* C2.4.7 Multiply and divide */
> @@ -478,10 +479,13 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
>      }
>
>      arm_log_exception(cs->exception_index);
> -    qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_el(env));
> +    qemu_log_mask(CPU_LOG_INT, "...from EL%d PC 0x%" PRIx64 "\n",
> +                  arm_current_el(env), env->pc);
> +
>      if (qemu_loglevel_mask(CPU_LOG_INT)
>          && !excp_is_internal(cs->exception_index)) {
> -        qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
> +        qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
> +                      env->exception.syndrome >> ARM_EL_EC_SHIFT,
>                        env->exception.syndrome);
>      }

If you just want to improve our debug logging that should be
a separate patch.

>
> @@ -494,6 +498,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
>      switch (cs->exception_index) {
>      case EXCP_PREFETCH_ABORT:
>      case EXCP_DATA_ABORT:
> +    case EXCP_WAPT:
>          env->cp15.far_el[new_el] = env->exception.vaddress;
>          qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
>                        env->cp15.far_el[new_el]);
> @@ -539,6 +544,12 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
>      aarch64_restore_sp(env, new_el);
>
>      env->pc = addr;
> -    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> +
> +    qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
> +                  new_el, env->pc, pstate_read(env));
> +
> +    if (!kvm_enabled()) {
> +        cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> +    }

Do we need a similar change in the AArch32 do_interrupt
code, to handle the case of debugging a 32-bit guest?

>  }
>  #endif
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index 2cc3017..10e8999 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -58,6 +58,7 @@ static const char * const excnames[] = {
>      [EXCP_SMC] = "Secure Monitor Call",
>      [EXCP_VIRQ] = "Virtual IRQ",
>      [EXCP_VFIQ] = "Virtual FIQ",
> +    [EXCP_WAPT] = "Watchpoint",
>  };
>
>  static inline void arm_log_exception(int idx)
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index e1fccdd..6f608d8 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -523,9 +523,11 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
>      struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
>      int hsr_ec = arch_info->hsr >> ARM_EL_EC_SHIFT;
>      ARMCPU *cpu = ARM_CPU(cs);
> +    CPUClass *cc = CPU_GET_CLASS(cs);
>      CPUARMState *env = &cpu->env;
> +    int forward_excp = EXCP_BKPT;
>
> -    /* Ensure PC is synchronised */
> +    /* Ensure all state is synchronised */
>      kvm_cpu_synchronize_state(cs);

Not sure the comment is providing any useful information now;
it probably should either be more explanatory or just deleted.

>      switch (hsr_ec) {
> @@ -533,7 +535,14 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
>          if (cs->singlestep_enabled) {
>              return true;
>          } else {
> -            error_report("Came out of SINGLE STEP when not enabled");
> +            /*
> +             * The kernel should have supressed the guests ability to

"suppressed"; "guest's".

> +             * single step at this point so something has gone wrong.
> +             */
> +            error_report("%s: guest single-step while debugging unsupported"
> +                         " (%"PRIx64", %"PRIx32")\n",
> +                         __func__, env->pc, arch_info->hsr);
> +            return false;
>          }
>          break;
>      case EC_AA64_BKPT:
> @@ -549,19 +558,24 @@ static int kvm_handle_debug(CPUState *cs, struct kvm_run *run)
>      case EC_WATCHPOINT:
>          if (kvm_arm_find_hw_watchpoint(cs, arch_info->far)) {
>              return true;
> +        } else {
> +            forward_excp = EXCP_WAPT;
>          }
>          break;
>      default:
>          error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
>                       __func__, arch_info->hsr, env->pc);
> +        return false;
>      }
>
> -    /* If we don't handle this it could be it really is for the
> -       guest to handle */
> -    qemu_log_mask(LOG_UNIMP,
> -                  "%s: re-injecting exception not yet implemented"
> -                  " (0x%"PRIx32", %"PRIx64")\n",
> -                  __func__, hsr_ec, env->pc);
> +    /* If we are not handling the debug exception it must belong to
> +     * the guest. Let's re-use the existing TCG interrupt code to set
> +     * everything up properly
> +     */
> +    cs->exception_index = forward_excp;
> +    env->exception.syndrome = arch_info->hsr;

You need to do at least some manipulation of the HSR, surely?
For instance, the EC value for "watchpoint from lower exception
level" and "watchpoint from current exception level" are different,
so if this was a wp from EL1 then it'll be reported to KVM (at EL2)
as the former, but if we reflect it into the EL1 guest it should
become the latter.

> +    env->exception.vaddress = arch_info->far;

Breakpoints and watchpoints need to set env->exception.fsr too.
You need to set env->exception.target_el as well (patches for
that have now hit master).

I also feel it would be better to set all of hsr/exception_index/
vaddress within the switch cases handling each type of exception,
possibly with a fallback for "generic something's wrong". I think
they turn out to be different enough to make it worth doing, and
it's easier to review the code and be clear that every case is
setting a coherent set of values.

> +    cc->do_interrupt(cs);
>
>      return false;
>  }
> --
> 2.4.1
>

thanks
-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64
  2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
                   ` (5 preceding siblings ...)
  2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions Alex Bennée
@ 2015-06-04 11:35 ` Peter Maydell
  6 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2015-06-04 11:35 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm-devel, Marc Zyngier, QEMU Developers, Christoffer Dall,
	Zhichao Huang, kvmarm@lists.cs.columbia.edu, arm-mail-list

On 29 May 2015 at 16:19, Alex Bennée <alex.bennee@linaro.org> wrote:
> You may be wondering what happened to v3 and v4. They do exist but
> they didn't change much from the the original patches as I've been
> mostly looking the kernel side of the equation. So in summary the
> changes are:
>
>   - updates to the kernel ABI
>   - don't fall over on kernels without debug support
>   - better logging, syncing and use of internals.h
>   - debug exception re-injection for guest events*

Some generic remarks (which we've talked about in irc):

 * does this correctly handle single step over emulated MMIO insns?
   how about single step over insns emulated in the kernel
   without trapping out to userspace? (eg some of the sysregs)
   kvm_skip_instr() doesn't seem to update PSTATE.SS...
 * the kernel currently does kvm_skip_instr() before the
   emulated MMIO exit, not afterwards. That feels conceptually
   the wrong way round -- are there any interesting corner cases
   we would get wrong currently but that naturally fall out in
   the wash if it's done afterwards?
 * what about debugging a 32-bit guest which uses the 32-bit
   ARM/Thumb bkpt insns?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2015-06-04 11:35 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-29 15:19 [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Alex Bennée
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV) Alex Bennée
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug() Alex Bennée
2015-06-04 10:56   ` Peter Maydell
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 3/6] target-arm: kvm - implement software breakpoints Alex Bennée
2015-06-04 10:56   ` Peter Maydell
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 4/6] target-arm: kvm - support for single step Alex Bennée
2015-06-04 10:59   ` Peter Maydell
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 5/6] target-arm: kvm - add support for HW assisted debug Alex Bennée
2015-06-04 11:10   ` Peter Maydell
2015-05-29 15:19 ` [Qemu-devel] [PATCH v5 6/6] target-arm: kvm - re-inject guest debug exceptions Alex Bennée
2015-06-04 11:29   ` Peter Maydell
2015-06-04 11:35 ` [Qemu-devel] [PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64 Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).