All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] KVM :PPC: Userspace Debug support
@ 2013-05-07  9:52 ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen; +Cc: Bharat Bhushan

From: Bharat Bhushan <bharat.bhushan@freescale.com>

This patchset adds the userspace debug support for booke/bookehv.
this is tested on powerpc e500v2/e500mc devices.

We are now assuming that debug resource will not be used by kernel for
its own debugging. It will be used for only kernel user process debugging.
So the kernel debug load interface during context_to is used to load
debug conext for that selected process.

v3->v4
 - 4 out of 7 patches of initial patchset were applied.
   This patchset is on and above those 4 patches
 - KVM local "struct kvmppc_booke_debug_reg" is replaced by
   powerpc global "struct debug_reg"
 - use switch_booke_debug_regs() for debug register context switch.
 - Save DBSR before kernel pre-emption is enabled.
 - Some more cleanup

v2->v3
 - We are now assuming that debug resource will not be used by
   kernel for its own debugging.
   It will be used for only kernel user process debugging.
   So the kernel debug load interface during context_to is
   used to load debug conext for that selected process.

v1->v2
 - Debug registers are save/restore in vcpu_put/vcpu_get.
   Earlier the debug registers are saved/restored in guest entry/exit

Bharat Bhushan (6):
  powerpc: remove unnecessary line continuations
  powerpc: move debug registers in a structure
  powerpc: export debug register save function for KVM
  KVM: PPC: exit to user space on "ehpriv" instruction
  KVM: PPC: Using "struct debug_reg"
  KVM: PPC: Add userspace debug stub support

 arch/powerpc/include/asm/disassemble.h |    4 +
 arch/powerpc/include/asm/kvm_host.h    |   16 +--
 arch/powerpc/include/asm/processor.h   |   38 +++--
 arch/powerpc/include/asm/reg_booke.h   |    8 +-
 arch/powerpc/include/asm/switch_to.h   |    4 +
 arch/powerpc/include/uapi/asm/kvm.h    |   22 ++-
 arch/powerpc/kernel/asm-offsets.c      |    2 +-
 arch/powerpc/kernel/process.c          |   45 +++---
 arch/powerpc/kernel/ptrace.c           |  154 +++++++++---------
 arch/powerpc/kernel/signal_32.c        |    6 +-
 arch/powerpc/kernel/traps.c            |   35 ++--
 arch/powerpc/kvm/booke.c               |  276 ++++++++++++++++++++++++++++----
 arch/powerpc/kvm/booke.h               |    5 +
 arch/powerpc/kvm/e500_emulate.c        |   27 +++
 14 files changed, 458 insertions(+), 184 deletions(-)

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

* [PATCH] powerpc: remove unnecessary line continuations
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/kernel/process.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 59dd545..8779234 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -325,7 +325,7 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
 	/*
 	 * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
 	 */
-	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |	\
+	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
 			DBCR1_IAC3US | DBCR1_IAC4US;
 	/*
 	 * Force Data Address Compare User/Supervisor bits to be User-only
-- 
1.5.6.5

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

* [PATCH] powerpc: move debug registers in a structure
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

This way we can use same data type struct with KVM and
also help in using other debug related function.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/processor.h |   38 +++++----
 arch/powerpc/include/asm/reg_booke.h |    8 +-
 arch/powerpc/kernel/asm-offsets.c    |    2 +-
 arch/powerpc/kernel/process.c        |   42 +++++-----
 arch/powerpc/kernel/ptrace.c         |  154 +++++++++++++++++-----------------
 arch/powerpc/kernel/signal_32.c      |    6 +-
 arch/powerpc/kernel/traps.c          |   35 ++++----
 7 files changed, 146 insertions(+), 139 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 7ff9eaa..1494ac3 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -154,22 +154,7 @@ typedef struct {
 #define TS_FPR(i) fpr[i][TS_FPROFFSET]
 #define TS_TRANS_FPR(i) transact_fpr[i][TS_FPROFFSET]
 
-struct thread_struct {
-	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
-
-#ifdef CONFIG_PPC64
-	unsigned long	ksp_vsid;
-#endif
-	struct pt_regs	*regs;		/* Pointer to saved register state */
-	mm_segment_t	fs;		/* for get_fs() validation */
-#ifdef CONFIG_BOOKE
-	/* BookE base exception scratch space; align on cacheline */
-	unsigned long	normsave[8] ____cacheline_aligned;
-#endif
-#ifdef CONFIG_PPC32
-	void		*pgdir;		/* root of page-table tree */
-#endif
+struct debug_reg {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 	/*
 	 * The following help to manage the use of Debug Control Registers
@@ -206,6 +191,27 @@ struct thread_struct {
 	unsigned long	dvc2;
 #endif
 #endif
+};
+
+struct thread_struct {
+	unsigned long	ksp;		/* Kernel stack pointer */
+	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
+
+#ifdef CONFIG_PPC64
+	unsigned long	ksp_vsid;
+#endif
+	struct pt_regs	*regs;		/* Pointer to saved register state */
+	mm_segment_t	fs;		/* for get_fs() validation */
+#ifdef CONFIG_BOOKE
+	/* BookE base exception scratch space; align on cacheline */
+	unsigned long	normsave[8] ____cacheline_aligned;
+#endif
+#ifdef CONFIG_PPC32
+	void		*pgdir;		/* root of page-table tree */
+#endif
+	/* Debug Registers */
+	struct debug_reg debug;
+
 	/* FP and VSX 0-31 register set */
 	double		fpr[32][TS_FPRWIDTH];
 	struct {
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index b417de3..455dc89 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -381,7 +381,7 @@
 #define DBCR0_IA34T	0x00004000	/* Instr Addr 3-4 range Toggle */
 #define DBCR0_FT	0x00000001	/* Freeze Timers on debug event */
 
-#define dbcr_iac_range(task)	((task)->thread.dbcr0)
+#define dbcr_iac_range(task)	((task)->thread.debug.dbcr0)
 #define DBCR_IAC12I	DBCR0_IA12			/* Range Inclusive */
 #define DBCR_IAC12X	(DBCR0_IA12 | DBCR0_IA12X)	/* Range Exclusive */
 #define DBCR_IAC12MODE	(DBCR0_IA12 | DBCR0_IA12X)	/* IAC 1-2 Mode Bits */
@@ -395,7 +395,7 @@
 #define DBCR1_DAC1W	0x20000000	/* DAC1 Write Debug Event */
 #define DBCR1_DAC2W	0x10000000	/* DAC2 Write Debug Event */
 
-#define dbcr_dac(task)	((task)->thread.dbcr1)
+#define dbcr_dac(task)	((task)->thread.debug.dbcr1)
 #define DBCR_DAC1R	DBCR1_DAC1R
 #define DBCR_DAC1W	DBCR1_DAC1W
 #define DBCR_DAC2R	DBCR1_DAC2R
@@ -441,7 +441,7 @@
 #define DBCR0_CRET	0x00000020	/* Critical Return Debug Event */
 #define DBCR0_FT	0x00000001	/* Freeze Timers on debug event */
 
-#define dbcr_dac(task)	((task)->thread.dbcr0)
+#define dbcr_dac(task)	((task)->thread.debug.dbcr0)
 #define DBCR_DAC1R	DBCR0_DAC1R
 #define DBCR_DAC1W	DBCR0_DAC1W
 #define DBCR_DAC2R	DBCR0_DAC2R
@@ -475,7 +475,7 @@
 #define DBCR1_IAC34MX	0x000000C0	/* Instr Addr 3-4 range eXclusive */
 #define DBCR1_IAC34AT	0x00000001	/* Instr Addr 3-4 range Toggle */
 
-#define dbcr_iac_range(task)	((task)->thread.dbcr1)
+#define dbcr_iac_range(task)	((task)->thread.debug.dbcr1)
 #define DBCR_IAC12I	DBCR1_IAC12M	/* Range Inclusive */
 #define DBCR_IAC12X	DBCR1_IAC12MX	/* Range Exclusive */
 #define DBCR_IAC12MODE	DBCR1_IAC12MX	/* IAC 1-2 Mode Bits */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index a791229..83e870d 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -106,7 +106,7 @@ int main(void)
 #else /* CONFIG_PPC64 */
 	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
+	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, debug.dbcr0));
 #endif
 #ifdef CONFIG_SPE
 	DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0]));
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8779234..ca89375 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -312,49 +312,49 @@ static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
  */
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
-	thread->iac1 = thread->iac2 = 0;
+	thread->debug.iac1 = thread->debug.iac2 = 0;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
-	thread->iac3 = thread->iac4 = 0;
+	thread->debug.iac3 = thread->debug.iac4 = 0;
 #endif
-	thread->dac1 = thread->dac2 = 0;
+	thread->debug.dac1 = thread->debug.dac2 = 0;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-	thread->dvc1 = thread->dvc2 = 0;
+	thread->debug.dvc1 = thread->debug.dvc2 = 0;
 #endif
-	thread->dbcr0 = 0;
+	thread->debug.dbcr0 = 0;
 #ifdef CONFIG_BOOKE
 	/*
 	 * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
 	 */
-	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
+	thread->debug.dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
 			DBCR1_IAC3US | DBCR1_IAC4US;
 	/*
 	 * Force Data Address Compare User/Supervisor bits to be User-only
 	 * (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0.
 	 */
-	thread->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+	thread->debug.dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
 #else
-	thread->dbcr1 = 0;
+	thread->debug.dbcr1 = 0;
 #endif
 }
 
 static void prime_debug_regs(struct thread_struct *thread)
 {
-	mtspr(SPRN_IAC1, thread->iac1);
-	mtspr(SPRN_IAC2, thread->iac2);
+	mtspr(SPRN_IAC1, thread->debug.iac1);
+	mtspr(SPRN_IAC2, thread->debug.iac2);
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
-	mtspr(SPRN_IAC3, thread->iac3);
-	mtspr(SPRN_IAC4, thread->iac4);
+	mtspr(SPRN_IAC3, thread->debug.iac3);
+	mtspr(SPRN_IAC4, thread->debug.iac4);
 #endif
-	mtspr(SPRN_DAC1, thread->dac1);
-	mtspr(SPRN_DAC2, thread->dac2);
+	mtspr(SPRN_DAC1, thread->debug.dac1);
+	mtspr(SPRN_DAC2, thread->debug.dac2);
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-	mtspr(SPRN_DVC1, thread->dvc1);
-	mtspr(SPRN_DVC2, thread->dvc2);
+	mtspr(SPRN_DVC1, thread->debug.dvc1);
+	mtspr(SPRN_DVC2, thread->debug.dvc2);
 #endif
-	mtspr(SPRN_DBCR0, thread->dbcr0);
-	mtspr(SPRN_DBCR1, thread->dbcr1);
+	mtspr(SPRN_DBCR0, thread->debug.dbcr0);
+	mtspr(SPRN_DBCR1, thread->debug.dbcr1);
 #ifdef CONFIG_BOOKE
-	mtspr(SPRN_DBCR2, thread->dbcr2);
+	mtspr(SPRN_DBCR2, thread->debug.dbcr2);
 #endif
 }
 /*
@@ -364,8 +364,8 @@ static void prime_debug_regs(struct thread_struct *thread)
  */
 static void switch_booke_debug_regs(struct thread_struct *new_thread)
 {
-	if ((current->thread.dbcr0 & DBCR0_IDM)
-		|| (new_thread->dbcr0 & DBCR0_IDM))
+	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
+		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
 			prime_debug_regs(new_thread);
 }
 #else	/* !CONFIG_PPC_ADV_DEBUG_REGS */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index f9b30c6..c870505 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -848,8 +848,8 @@ void user_enable_single_step(struct task_struct *task)
 
 	if (regs != NULL) {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		task->thread.dbcr0 &= ~DBCR0_BT;
-		task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+		task->thread.debug.dbcr0 &= ~DBCR0_BT;
+		task->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
 		regs->msr |= MSR_DE;
 #else
 		regs->msr &= ~MSR_BE;
@@ -865,8 +865,8 @@ void user_enable_block_step(struct task_struct *task)
 
 	if (regs != NULL) {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		task->thread.dbcr0 &= ~DBCR0_IC;
-		task->thread.dbcr0 = DBCR0_IDM | DBCR0_BT;
+		task->thread.debug.dbcr0 &= ~DBCR0_IC;
+		task->thread.debug.dbcr0 = DBCR0_IDM | DBCR0_BT;
 		regs->msr |= MSR_DE;
 #else
 		regs->msr &= ~MSR_SE;
@@ -888,16 +888,16 @@ void user_disable_single_step(struct task_struct *task)
 		 * And, after doing so, if all debug flags are off, turn
 		 * off DBCR0(IDM) and MSR(DE) .... Torez
 		 */
-		task->thread.dbcr0 &= ~DBCR0_IC;
+		task->thread.debug.dbcr0 &= ~DBCR0_IC;
 		/*
 		 * Test to see if any of the DBCR_ACTIVE_EVENTS bits are set.
 		 */
-		if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
-					task->thread.dbcr1)) {
+		if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
+					task->thread.debug.dbcr1)) {
 			/*
 			 * All debug events were off.....
 			 */
-			task->thread.dbcr0 &= ~DBCR0_IDM;
+			task->thread.debug.dbcr0 &= ~DBCR0_IDM;
 			regs->msr &= ~MSR_DE;
 		}
 #else
@@ -1025,14 +1025,14 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 	 */
 
 	/* DAC's hold the whole address without any mode flags */
-	task->thread.dac1 = data & ~0x3UL;
+	task->thread.debug.dac1 = data & ~0x3UL;
 
-	if (task->thread.dac1 == 0) {
+	if (task->thread.debug.dac1 == 0) {
 		dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
-		if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
-					task->thread.dbcr1)) {
+		if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
+					task->thread.debug.dbcr1)) {
 			task->thread.regs->msr &= ~MSR_DE;
-			task->thread.dbcr0 &= ~DBCR0_IDM;
+			task->thread.debug.dbcr0 &= ~DBCR0_IDM;
 		}
 		return 0;
 	}
@@ -1044,7 +1044,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 
 	/* Set the Internal Debugging flag (IDM bit 1) for the DBCR0
 	   register */
-	task->thread.dbcr0 |= DBCR0_IDM;
+	task->thread.debug.dbcr0 |= DBCR0_IDM;
 
 	/* Check for write and read flags and set DBCR0
 	   accordingly */
@@ -1074,10 +1074,10 @@ static long set_instruction_bp(struct task_struct *child,
 			      struct ppc_hw_breakpoint *bp_info)
 {
 	int slot;
-	int slot1_in_use = ((child->thread.dbcr0 & DBCR0_IAC1) != 0);
-	int slot2_in_use = ((child->thread.dbcr0 & DBCR0_IAC2) != 0);
-	int slot3_in_use = ((child->thread.dbcr0 & DBCR0_IAC3) != 0);
-	int slot4_in_use = ((child->thread.dbcr0 & DBCR0_IAC4) != 0);
+	int slot1_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC1) != 0);
+	int slot2_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC2) != 0);
+	int slot3_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC3) != 0);
+	int slot4_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC4) != 0);
 
 	if (dbcr_iac_range(child) & DBCR_IAC12MODE)
 		slot2_in_use = 1;
@@ -1096,9 +1096,9 @@ static long set_instruction_bp(struct task_struct *child,
 		/* We need a pair of IAC regsisters */
 		if ((!slot1_in_use) && (!slot2_in_use)) {
 			slot = 1;
-			child->thread.iac1 = bp_info->addr;
-			child->thread.iac2 = bp_info->addr2;
-			child->thread.dbcr0 |= DBCR0_IAC1;
+			child->thread.debug.iac1 = bp_info->addr;
+			child->thread.debug.iac2 = bp_info->addr2;
+			child->thread.debug.dbcr0 |= DBCR0_IAC1;
 			if (bp_info->addr_mode ==
 					PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
 				dbcr_iac_range(child) |= DBCR_IAC12X;
@@ -1107,9 +1107,9 @@ static long set_instruction_bp(struct task_struct *child,
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 		} else if ((!slot3_in_use) && (!slot4_in_use)) {
 			slot = 3;
-			child->thread.iac3 = bp_info->addr;
-			child->thread.iac4 = bp_info->addr2;
-			child->thread.dbcr0 |= DBCR0_IAC3;
+			child->thread.debug.iac3 = bp_info->addr;
+			child->thread.debug.iac4 = bp_info->addr2;
+			child->thread.debug.dbcr0 |= DBCR0_IAC3;
 			if (bp_info->addr_mode ==
 					PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
 				dbcr_iac_range(child) |= DBCR_IAC34X;
@@ -1129,30 +1129,30 @@ static long set_instruction_bp(struct task_struct *child,
 			 */
 			if (slot2_in_use || (slot3_in_use == slot4_in_use)) {
 				slot = 1;
-				child->thread.iac1 = bp_info->addr;
-				child->thread.dbcr0 |= DBCR0_IAC1;
+				child->thread.debug.iac1 = bp_info->addr;
+				child->thread.debug.dbcr0 |= DBCR0_IAC1;
 				goto out;
 			}
 		}
 		if (!slot2_in_use) {
 			slot = 2;
-			child->thread.iac2 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC2;
+			child->thread.debug.iac2 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC2;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 		} else if (!slot3_in_use) {
 			slot = 3;
-			child->thread.iac3 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC3;
+			child->thread.debug.iac3 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC3;
 		} else if (!slot4_in_use) {
 			slot = 4;
-			child->thread.iac4 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC4;
+			child->thread.debug.iac4 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC4;
 #endif
 		} else
 			return -ENOSPC;
 	}
 out:
-	child->thread.dbcr0 |= DBCR0_IDM;
+	child->thread.debug.dbcr0 |= DBCR0_IDM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return slot;
@@ -1162,49 +1162,49 @@ static int del_instruction_bp(struct task_struct *child, int slot)
 {
 	switch (slot) {
 	case 1:
-		if ((child->thread.dbcr0 & DBCR0_IAC1) == 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC1) == 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC12MODE) {
 			/* address range - clear slots 1 & 2 */
-			child->thread.iac2 = 0;
+			child->thread.debug.iac2 = 0;
 			dbcr_iac_range(child) &= ~DBCR_IAC12MODE;
 		}
-		child->thread.iac1 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC1;
+		child->thread.debug.iac1 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC1;
 		break;
 	case 2:
-		if ((child->thread.dbcr0 & DBCR0_IAC2) == 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC2) == 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC12MODE)
 			/* used in a range */
 			return -EINVAL;
-		child->thread.iac2 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC2;
+		child->thread.debug.iac2 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC2;
 		break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case 3:
-		if ((child->thread.dbcr0 & DBCR0_IAC3) == 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC3) == 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC34MODE) {
 			/* address range - clear slots 3 & 4 */
-			child->thread.iac4 = 0;
+			child->thread.debug.iac4 = 0;
 			dbcr_iac_range(child) &= ~DBCR_IAC34MODE;
 		}
-		child->thread.iac3 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC3;
+		child->thread.debug.iac3 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC3;
 		break;
 	case 4:
-		if ((child->thread.dbcr0 & DBCR0_IAC4) == 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC4) == 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC34MODE)
 			/* Used in a range */
 			return -EINVAL;
-		child->thread.iac4 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC4;
+		child->thread.debug.iac4 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC4;
 		break;
 #endif
 	default:
@@ -1234,18 +1234,18 @@ static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
 			dbcr_dac(child) |= DBCR_DAC1R;
 		if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
 			dbcr_dac(child) |= DBCR_DAC1W;
-		child->thread.dac1 = (unsigned long)bp_info->addr;
+		child->thread.debug.dac1 = (unsigned long)bp_info->addr;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
 		if (byte_enable) {
-			child->thread.dvc1 =
+			child->thread.debug.dvc1 =
 				(unsigned long)bp_info->condition_value;
-			child->thread.dbcr2 |=
+			child->thread.debug.dbcr2 |=
 				((byte_enable << DBCR2_DVC1BE_SHIFT) |
 				 (condition_mode << DBCR2_DVC1M_SHIFT));
 		}
 #endif
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-	} else if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
+	} else if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
 		/* Both dac1 and dac2 are part of a range */
 		return -ENOSPC;
 #endif
@@ -1255,19 +1255,19 @@ static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
 			dbcr_dac(child) |= DBCR_DAC2R;
 		if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
 			dbcr_dac(child) |= DBCR_DAC2W;
-		child->thread.dac2 = (unsigned long)bp_info->addr;
+		child->thread.debug.dac2 = (unsigned long)bp_info->addr;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
 		if (byte_enable) {
-			child->thread.dvc2 =
+			child->thread.debug.dvc2 =
 				(unsigned long)bp_info->condition_value;
-			child->thread.dbcr2 |=
+			child->thread.debug.dbcr2 |=
 				((byte_enable << DBCR2_DVC2BE_SHIFT) |
 				 (condition_mode << DBCR2_DVC2M_SHIFT));
 		}
 #endif
 	} else
 		return -ENOSPC;
-	child->thread.dbcr0 |= DBCR0_IDM;
+	child->thread.debug.dbcr0 |= DBCR0_IDM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return slot + 4;
@@ -1279,32 +1279,32 @@ static int del_dac(struct task_struct *child, int slot)
 		if ((dbcr_dac(child) & (DBCR_DAC1R | DBCR_DAC1W)) == 0)
 			return -ENOENT;
 
-		child->thread.dac1 = 0;
+		child->thread.debug.dac1 = 0;
 		dbcr_dac(child) &= ~(DBCR_DAC1R | DBCR_DAC1W);
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
-			child->thread.dac2 = 0;
-			child->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+		if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
+			child->thread.debug.dac2 = 0;
+			child->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
 		}
-		child->thread.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
+		child->thread.debug.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
 #endif
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-		child->thread.dvc1 = 0;
+		child->thread.debug.dvc1 = 0;
 #endif
 	} else if (slot == 2) {
 		if ((dbcr_dac(child) & (DBCR_DAC2R | DBCR_DAC2W)) == 0)
 			return -ENOENT;
 
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		if (child->thread.dbcr2 & DBCR2_DAC12MODE)
+		if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE)
 			/* Part of a range */
 			return -EINVAL;
-		child->thread.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
+		child->thread.debug.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
 #endif
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-		child->thread.dvc2 = 0;
+		child->thread.debug.dvc2 = 0;
 #endif
-		child->thread.dac2 = 0;
+		child->thread.debug.dac2 = 0;
 		dbcr_dac(child) &= ~(DBCR_DAC2R | DBCR_DAC2W);
 	} else
 		return -EINVAL;
@@ -1346,22 +1346,22 @@ static int set_dac_range(struct task_struct *child,
 			return -EIO;
 	}
 
-	if (child->thread.dbcr0 &
+	if (child->thread.debug.dbcr0 &
 	    (DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W))
 		return -ENOSPC;
 
 	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
-		child->thread.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
+		child->thread.debug.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
 	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
-		child->thread.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
-	child->thread.dac1 = bp_info->addr;
-	child->thread.dac2 = bp_info->addr2;
+		child->thread.debug.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
+	child->thread.debug.dac1 = bp_info->addr;
+	child->thread.debug.dac2 = bp_info->addr2;
 	if (mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
-		child->thread.dbcr2  |= DBCR2_DAC12M;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12M;
 	else if (mode == PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
-		child->thread.dbcr2  |= DBCR2_DAC12MX;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12MX;
 	else	/* PPC_BREAKPOINT_MODE_MASK */
-		child->thread.dbcr2  |= DBCR2_DAC12MM;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12MM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return 5;
@@ -1499,9 +1499,9 @@ static long ppc_del_hwdebug(struct task_struct *child, long data)
 		rc = del_dac(child, (int)data - 4);
 
 	if (!rc) {
-		if (!DBCR_ACTIVE_EVENTS(child->thread.dbcr0,
-					child->thread.dbcr1)) {
-			child->thread.dbcr0 &= ~DBCR0_IDM;
+		if (!DBCR_ACTIVE_EVENTS(child->thread.debug.dbcr0,
+					child->thread.debug.dbcr1)) {
+			child->thread.debug.dbcr0 &= ~DBCR0_IDM;
 			child->thread.regs->msr &= ~MSR_DE;
 		}
 	}
@@ -1679,7 +1679,7 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (addr > 0)
 			break;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		ret = put_user(child->thread.dac1, datalp);
+		ret = put_user(child->thread.debug.dac1, datalp);
 #else
 		dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
 			     (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3acb28e..bc857c2 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1292,7 +1292,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 	unsigned char tmp;
 	unsigned long new_msr = regs->msr;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-	unsigned long new_dbcr0 = current->thread.dbcr0;
+	unsigned long new_dbcr0 = current->thread.debug.dbcr0;
 #endif
 
 	for (i=0; i<ndbg; i++) {
@@ -1307,7 +1307,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 			} else {
 				new_dbcr0 &= ~DBCR0_IC;
 				if (!DBCR_ACTIVE_EVENTS(new_dbcr0,
-						current->thread.dbcr1)) {
+						current->thread.debug.dbcr1)) {
 					new_msr &= ~MSR_DE;
 					new_dbcr0 &= ~DBCR0_IDM;
 				}
@@ -1342,7 +1342,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 	   the user is really doing something wrong. */
 	regs->msr = new_msr;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-	current->thread.dbcr0 = new_dbcr0;
+	current->thread.debug.dbcr0 = new_dbcr0;
 #endif
 
 	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 37cc40e..cd77d74 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -350,8 +350,8 @@ static inline int check_io_access(struct pt_regs *regs)
 #define REASON_TRAP		ESR_PTR
 
 /* single-step stuff */
-#define single_stepping(regs)	(current->thread.dbcr0 & DBCR0_IC)
-#define clear_single_step(regs)	(current->thread.dbcr0 &= ~DBCR0_IC)
+#define single_stepping(regs)	(current->thread.debug.dbcr0 & DBCR0_IC)
+#define clear_single_step(regs)	(current->thread.debug.dbcr0 &= ~DBCR0_IC)
 
 #else
 /* On non-4xx, the reason for the machine check or program
@@ -1383,7 +1383,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 	if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {
 		dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W);
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		current->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+		current->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
 #endif
 		do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT,
 			     5);
@@ -1394,24 +1394,24 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 			     6);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC1) {
-		current->thread.dbcr0 &= ~DBCR0_IAC1;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC1;
 		dbcr_iac_range(current) &= ~DBCR_IAC12MODE;
 		do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT,
 			     1);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC2) {
-		current->thread.dbcr0 &= ~DBCR0_IAC2;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC2;
 		do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT,
 			     2);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC3) {
-		current->thread.dbcr0 &= ~DBCR0_IAC3;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC3;
 		dbcr_iac_range(current) &= ~DBCR_IAC34MODE;
 		do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT,
 			     3);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC4) {
-		current->thread.dbcr0 &= ~DBCR0_IAC4;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC4;
 		do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT,
 			     4);
 		changed |= 0x01;
@@ -1421,19 +1421,20 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 	 * Check all other debug flags and see if that bit needs to be turned
 	 * back on or not.
 	 */
-	if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1))
+	if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0,
+			       current->thread.debug.dbcr1))
 		regs->msr |= MSR_DE;
 	else
 		/* Make sure the IDM flag is off */
-		current->thread.dbcr0 &= ~DBCR0_IDM;
+		current->thread.debug.dbcr0 &= ~DBCR0_IDM;
 
 	if (changed & 0x01)
-		mtspr(SPRN_DBCR0, current->thread.dbcr0);
+		mtspr(SPRN_DBCR0, current->thread.debug.dbcr0);
 }
 
 void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
-	current->thread.dbsr = debug_status;
+	current->thread.debug.dbsr = debug_status;
 
 	/* Hack alert: On BookE, Branch Taken stops on the branch itself, while
 	 * on server, it stops on the target of the branch. In order to simulate
@@ -1450,8 +1451,8 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 
 		/* Do the single step trick only when coming from userspace */
 		if (user_mode(regs)) {
-			current->thread.dbcr0 &= ~DBCR0_BT;
-			current->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+			current->thread.debug.dbcr0 &= ~DBCR0_BT;
+			current->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
 			regs->msr |= MSR_DE;
 			return;
 		}
@@ -1479,13 +1480,13 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 			return;
 
 		if (user_mode(regs)) {
-			current->thread.dbcr0 &= ~DBCR0_IC;
-			if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0,
-					       current->thread.dbcr1))
+			current->thread.debug.dbcr0 &= ~DBCR0_IC;
+			if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0,
+					       current->thread.debug.dbcr1))
 				regs->msr |= MSR_DE;
 			else
 				/* Make sure the IDM bit is off */
-				current->thread.dbcr0 &= ~DBCR0_IDM;
+				current->thread.debug.dbcr0 &= ~DBCR0_IDM;
 		}
 
 		_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
-- 
1.5.6.5

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

* [PATCH] powerpc: export debug register save function for KVM
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

KVM need this function when switching from vcpu to user-space
thread. My subsequent patch will use this function.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/switch_to.h |    4 ++++
 arch/powerpc/kernel/process.c        |    3 ++-
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 200d763..50b357f 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -30,6 +30,10 @@ extern void enable_kernel_spe(void);
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+extern void switch_booke_debug_regs(struct thread_struct *new_thread);
+#endif
+
 #ifndef CONFIG_SMP
 extern void discard_lazy_cpu_state(void);
 #else
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index ca89375..a938138 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -362,12 +362,13 @@ static void prime_debug_regs(struct thread_struct *thread)
  * debug registers, set the debug registers from the values
  * stored in the new thread.
  */
-static void switch_booke_debug_regs(struct thread_struct *new_thread)
+void switch_booke_debug_regs(struct thread_struct *new_thread)
 {
 	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
 		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
 			prime_debug_regs(new_thread);
 }
+EXPORT_SYMBOL(switch_booke_debug_regs);
 #else	/* !CONFIG_PPC_ADV_DEBUG_REGS */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
 static void set_debug_reg_defaults(struct thread_struct *thread)
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: exit to user space on "ehpriv" instruction
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

"ehpriv" instruction is used for setting software breakpoints
by user space. This patch adds support to exit to user space
with "run->debug" have relevant information.

As this is the first point we are using run->debug, also defined
the run->debug structure.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/disassemble.h |    4 ++++
 arch/powerpc/include/uapi/asm/kvm.h    |   21 +++++++++++++++++----
 arch/powerpc/kvm/e500_emulate.c        |   27 +++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/disassemble.h b/arch/powerpc/include/asm/disassemble.h
index 9b198d1..856f8de 100644
--- a/arch/powerpc/include/asm/disassemble.h
+++ b/arch/powerpc/include/asm/disassemble.h
@@ -77,4 +77,8 @@ static inline unsigned int get_d(u32 inst)
 	return inst & 0xffff;
 }
 
+static inline unsigned int get_oc(u32 inst)
+{
+	return (inst >> 11) & 0x7fff;
+}
 #endif /* __ASM_PPC_DISASSEMBLE_H__ */
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 0fb1a6e..ded0607 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -269,7 +269,24 @@ struct kvm_fpu {
 	__u64 fpr[32];
 };
 
+/*
+ * Defines for h/w breakpoint, watchpoint (read, write or both) and
+ * software breakpoint.
+ * These are used as "type" in KVM_SET_GUEST_DEBUG ioctl and "status"
+ * for KVM_DEBUG_EXIT.
+ */
+#define KVMPPC_DEBUG_NONE		0x0
+#define KVMPPC_DEBUG_BREAKPOINT		(1UL << 1)
+#define KVMPPC_DEBUG_WATCH_WRITE	(1UL << 2)
+#define KVMPPC_DEBUG_WATCH_READ		(1UL << 3)
 struct kvm_debug_exit_arch {
+	__u64 address;
+	/*
+	 * exiting to userspace because of h/w breakpoint, watchpoint
+	 * (read, write or both) and software breakpoint.
+	 */
+	__u32 status;
+	__u32 reserved;
 };
 
 /* for KVM_SET_GUEST_DEBUG */
@@ -281,10 +298,6 @@ struct kvm_guest_debug_arch {
 		 * Type denotes h/w breakpoint, read watchpoint, write
 		 * watchpoint or watchpoint (both read and write).
 		 */
-#define KVMPPC_DEBUG_NONE		0x0
-#define KVMPPC_DEBUG_BREAKPOINT		(1UL << 1)
-#define KVMPPC_DEBUG_WATCH_WRITE	(1UL << 2)
-#define KVMPPC_DEBUG_WATCH_READ		(1UL << 3)
 		__u32 type;
 		__u32 reserved;
 	} bp[16];
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index b10a012..dab9d07 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -26,6 +26,8 @@
 #define XOP_TLBRE   946
 #define XOP_TLBWE   978
 #define XOP_TLBILX  18
+#define XOP_EHPRIV  270
+#define EHPRIV_OC_DEBUG 0
 
 #ifdef CONFIG_KVM_E500MC
 static int dbell2prio(ulong param)
@@ -82,6 +84,26 @@ static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
 }
 #endif
 
+static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
+				   unsigned int inst, int *advance)
+{
+	int emulated = EMULATE_DONE;
+
+	switch (get_oc(inst)) {
+	case EHPRIV_OC_DEBUG:
+		run->exit_reason = KVM_EXIT_DEBUG;
+		run->debug.arch.address = vcpu->arch.pc;
+		run->debug.arch.status = 0;
+		kvmppc_account_exit(vcpu, DEBUG_EXITS);
+		emulated = EMULATE_EXIT_USER;
+		*advance = 0;
+		break;
+	default:
+		emulated = EMULATE_FAIL;
+	}
+	return emulated;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -130,6 +152,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
 			break;
 
+		case XOP_EHPRIV:
+			emulated = kvmppc_e500_emul_ehpriv(run, vcpu, inst,
+							   advance);
+			break;
+
 		default:
 			emulated = EMULATE_FAIL;
 		}
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: Using "struct debug_reg"
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

For KVM also use the "struct debug_reg" defined in asm/processor.h

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/kvm_host.h |   13 +------------
 arch/powerpc/kvm/booke.c            |   34 ++++++++++++++++++++++++----------
 2 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index af326cd..838a577 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -381,17 +381,6 @@ struct kvmppc_slb {
 #define KVMPPC_EPR_USER		1 /* exit to userspace to fill EPR */
 #define KVMPPC_EPR_KERNEL	2 /* in-kernel irqchip */
 
-struct kvmppc_booke_debug_reg {
-	u32 dbcr0;
-	u32 dbcr1;
-	u32 dbcr2;
-#ifdef CONFIG_KVM_E500MC
-	u32 dbcr4;
-#endif
-	u64 iac[KVMPPC_BOOKE_MAX_IAC];
-	u64 dac[KVMPPC_BOOKE_MAX_DAC];
-};
-
 #define KVMPPC_IRQ_DEFAULT	0
 #define KVMPPC_IRQ_MPIC		1
 #define KVMPPC_IRQ_XICS		2
@@ -535,7 +524,7 @@ struct kvm_vcpu_arch {
 	u32 eptcfg;
 	u32 epr;
 	u32 crit_save;
-	struct kvmppc_booke_debug_reg dbg_reg;
+	struct debug_reg dbg_reg;
 #endif
 	gpa_t paddr_accessed;
 	gva_t vaddr_accessed;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 1020119..ef99536 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1424,7 +1424,6 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	int r = 0;
 	union kvmppc_one_reg val;
 	int size;
-	long int i;
 
 	size = one_reg_size(reg->id);
 	if (size > sizeof(val))
@@ -1432,16 +1431,24 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 
 	switch (reg->id) {
 	case KVM_REG_PPC_IAC1:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac1);
+		break;
 	case KVM_REG_PPC_IAC2:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac2);
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac3);
+		break;
 	case KVM_REG_PPC_IAC4:
-		i = reg->id - KVM_REG_PPC_IAC1;
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac[i]);
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac4);
 		break;
+#endif
 	case KVM_REG_PPC_DAC1:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac1);
+		break;
 	case KVM_REG_PPC_DAC2:
-		i = reg->id - KVM_REG_PPC_DAC1;
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac[i]);
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac2);
 		break;
 	case KVM_REG_PPC_EPR: {
 		u32 epr = get_guest_epr(vcpu);
@@ -1481,7 +1488,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	int r = 0;
 	union kvmppc_one_reg val;
 	int size;
-	long int i;
 
 	size = one_reg_size(reg->id);
 	if (size > sizeof(val))
@@ -1492,16 +1498,24 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 
 	switch (reg->id) {
 	case KVM_REG_PPC_IAC1:
+		vcpu->arch.dbg_reg.iac1 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_IAC2:
+		vcpu->arch.dbg_reg.iac2 = set_reg_val(reg->id, val);
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
+		vcpu->arch.dbg_reg.iac3 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_IAC4:
-		i = reg->id - KVM_REG_PPC_IAC1;
-		vcpu->arch.dbg_reg.iac[i] = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac4 = set_reg_val(reg->id, val);
 		break;
+#endif
 	case KVM_REG_PPC_DAC1:
+		vcpu->arch.dbg_reg.dac1 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_DAC2:
-		i = reg->id - KVM_REG_PPC_DAC1;
-		vcpu->arch.dbg_reg.dac[i] = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.dac2 = set_reg_val(reg->id, val);
 		break;
 	case KVM_REG_PPC_EPR: {
 		u32 new_epr = set_reg_val(reg->id, val);
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-07  9:52 ` Bharat Bhushan
@ 2013-05-07  9:52   ` Bharat Bhushan
  -1 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:40 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

This patch adds the debug stub support on booke/bookehv.
Now QEMU debug stub can use hw breakpoint, watchpoint and
software breakpoint to debug guest.

This is how we save/restore debug register context when switching
between guest, userspace and kernel user-process:

When QEMU is running
 -> thread->debug_reg == QEMU debug register context.
 -> Kernel will handle switching the debug register on context switch.
 -> no vcpu_load() called

QEMU makes ioctls (except RUN)
 -> This will call vcpu_load()
 -> should not change context.
 -> Some ioctls can change vcpu debug register, context saved in vcpu->debug_regs

QEMU Makes RUN ioctl
 -> Save thread->debug_reg on STACK
 -> Store thread->debug_reg == vcpu->debug_reg 
 -> load thread->debug_reg
 -> RUN VCPU ( So thread points to vcpu context )

Context switch happens When VCPU running 
 -> makes vcpu_load() should not load any context
 -> kernel loads the vcpu context as thread->debug_regs points to vcpu context.

On heavyweight_exit
 -> Load the context saved on stack in thread->debug_reg

Currently we do not support debug resource emulation to guest,
On debug exception, always exit to user space irrespective of
user space is expecting the debug exception or not. If this is
unexpected exception (breakpoint/watchpoint event not set by
userspace) then let us leave the action on user space. This
is similar to what it was before, only thing is that now we
have proper exit state available to user space.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/kvm_host.h |    3 +
 arch/powerpc/include/uapi/asm/kvm.h |    1 +
 arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
 arch/powerpc/kvm/booke.h            |    5 +
 4 files changed, 233 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 838a577..1b29945 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
 	u32 eptcfg;
 	u32 epr;
 	u32 crit_save;
+	/* guest debug registers*/
 	struct debug_reg dbg_reg;
+	/* shadow debug registers */
+	struct debug_reg shadow_dbg_reg;
 #endif
 	gpa_t paddr_accessed;
 	gva_t vaddr_accessed;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index ded0607..f5077c2 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -27,6 +27,7 @@
 #define __KVM_HAVE_PPC_SMT
 #define __KVM_HAVE_IRQCHIP
 #define __KVM_HAVE_IRQ_LINE
+#define __KVM_HAVE_GUEST_DEBUG
 
 struct kvm_regs {
 	__u64 pc;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ef99536..6a44ad4 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
 #endif
 }
 
+static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
+{
+	/* Synchronize guest's desire to get debug interrupts into shadow MSR */
+#ifndef CONFIG_KVM_BOOKE_HV
+	vcpu->arch.shadow_msr &= ~MSR_DE;
+	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE;
+#endif
+
+	/* Force enable debug interrupts when user space wants to debug */
+	if (vcpu->guest_debug) {
+#ifdef CONFIG_KVM_BOOKE_HV
+		/*
+		 * Since there is no shadow MSR, sync MSR_DE into the guest
+		 * visible MSR.
+		 */
+		vcpu->arch.shared->msr |= MSR_DE;
+#else
+		vcpu->arch.shadow_msr |= MSR_DE;
+		vcpu->arch.shared->msr &= ~MSR_DE;
+#endif
+	}
+}
+
 /*
  * Helper function for "full" MSR writes.  No need to call this if only
  * EE/CE/ME/DE/RI are changing.
@@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
 	kvmppc_mmu_msr_notify(vcpu, old_msr);
 	kvmppc_vcpu_sync_spe(vcpu);
 	kvmppc_vcpu_sync_fpu(vcpu);
+	kvmppc_vcpu_sync_debug(vcpu);
 }
 
 static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
@@ -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
 	int ret, s;
+	struct debug_reg debug;
 #ifdef CONFIG_PPC_FPU
 	unsigned int fpscr;
 	int fpexc_mode;
@@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 	kvmppc_load_guest_fp(vcpu);
 #endif
 
+	/*
+	 * Clear current->thread.dbcr0 so that kernel does not
+	 * restore h/w registers on context switch in vcpu running state.
+	 */
+	/* Save thread->debug context on stack */
+	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
+	/* Load vcpu debug context in thread->debug */
+	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
+	       sizeof(struct debug_reg));
+
+	switch_booke_debug_regs(&current->thread);
+
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
 	/* No need for kvm_guest_exit. It's done in handle_exit.
 	   We also get here with interrupts enabled. */
 
+	/* Restore userspace context in thread->dbcr0 from stack*/
+	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
+	switch_booke_debug_regs(&current->thread);
+
 #ifdef CONFIG_PPC_FPU
 	kvmppc_save_guest_fp(vcpu);
 
@@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 	}
 }
 
+/*
+ * Currently we do not support debug resource emulation to guest,
+ * so always exit to user space irrespective of user space is
+ * expecting the debug exception or not. This is unexpected event
+ * and let us leave the action on user space.
+ */
+static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+	u32 dbsr = vcpu->arch.dbsr;
+
+	run->debug.arch.status = 0;
+	run->debug.arch.address = vcpu->arch.pc;
+
+	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
+		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
+	} else {
+		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
+			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
+		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
+			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
+		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
+			run->debug.arch.address = dbg_reg->dac1;
+		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
+			run->debug.arch.address = dbg_reg->dac2;
+	}
+
+	return RESUME_HOST;
+}
+
 static void kvmppc_fill_pt_regs(struct pt_regs *regs)
 {
 	ulong r1, ip, msr, lr;
@@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
 	case BOOKE_INTERRUPT_CRITICAL:
 		unknown_exception(&regs);
 		break;
+	case BOOKE_INTERRUPT_DEBUG:
+		/* Save DBSR before preemption is enabled */
+		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
+		kvmppc_clear_dbsr();
+		break;
 	}
 }
 
@@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	}
 
 	case BOOKE_INTERRUPT_DEBUG: {
-		u32 dbsr;
-
-		vcpu->arch.pc = mfspr(SPRN_CSRR0);
-
-		/* clear IAC events in DBSR register */
-		dbsr = mfspr(SPRN_DBSR);
-		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
-		mtspr(SPRN_DBSR, dbsr);
-
-		run->exit_reason = KVM_EXIT_DEBUG;
+		r = kvmppc_handle_debug(run, vcpu);
+		if (r == RESUME_HOST)
+			run->exit_reason = KVM_EXIT_DEBUG;
 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
-		r = RESUME_HOST;
 		break;
 	}
 
@@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	kvmppc_set_msr(vcpu, 0);
 
 #ifndef CONFIG_KVM_BOOKE_HV
-	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
+	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
 	vcpu->arch.shadow_pid = 1;
 	vcpu->arch.shared->msr = 0;
 #endif
@@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	return r;
 }
 
-int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
-					 struct kvm_guest_debug *dbg)
-{
-	return -EINVAL;
-}
-
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	return -ENOTSUPP;
@@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
 }
 
+static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu, uint64_t addr,
+				       int index)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	switch (index) {
+	case 0:
+		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
+		dbg_reg->iac1 = addr;
+		break;
+	case 1:
+		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
+		dbg_reg->iac2 = addr;
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+	case 2:
+		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
+		dbg_reg->iac3 = addr;
+		break;
+	case 3:
+		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
+		dbg_reg->iac4 = addr;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu, uint64_t addr,
+				       int type, int index)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	switch (index) {
+	case 0:
+		if (type & KVMPPC_DEBUG_WATCH_READ)
+			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
+		if (type & KVMPPC_DEBUG_WATCH_WRITE)
+			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
+		dbg_reg->dac1 = addr;
+		break;
+	case 1:
+		if (type & KVMPPC_DEBUG_WATCH_READ)
+			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
+		if (type & KVMPPC_DEBUG_WATCH_WRITE)
+			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
+		dbg_reg->dac2 = addr;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					 struct kvm_guest_debug *dbg)
+{
+	struct debug_reg *dbg_reg;
+	int n, b = 0, w = 0;
+
+	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
+		/* Clear All debug events */
+		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+		vcpu->guest_debug = 0;
+#ifdef CONFIG_KVM_BOOKE_HV
+		/*
+		 * When user space is not using the debug resources
+		 * then allow guest to change the MSR.DE.
+		 */
+		vcpu->arch.shadow_msrp &= ~MSRP_DEP;
+#endif
+		return 0;
+	}
+
+#ifdef CONFIG_KVM_BOOKE_HV
+	/*
+	 * When user space is using the debug resource then
+	 * do not allow guest to change the MSR.DE.
+	 */
+	vcpu->arch.shadow_msrp |= MSRP_DEP;
+#endif
+	vcpu->guest_debug = dbg->control;
+	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+	/* Set DBCR0_EDM in guest visible DBCR0 register. */
+	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
+
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+
+	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
+		return 0;
+
+	/* Code below handles only HW breakpoints */
+	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	/*
+	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
+	 * to occur when MSR.PR is set.
+	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
+	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
+	 * that debug events will not come in hypervisor (GS = 0).
+	 */
+#ifdef CONFIG_KVM_BOOKE_HV
+	dbg_reg->dbcr1 = 0;
+	dbg_reg->dbcr2 = 0;
+#else
+	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
+			  DBCR1_IAC4US;
+	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+#endif
+
+	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
+		uint64_t addr = dbg->arch.bp[n].addr;
+		uint32_t type = dbg->arch.bp[n].type;
+
+		if (type == KVMPPC_DEBUG_NONE)
+			continue;
+
+		if (type & !(KVMPPC_DEBUG_WATCH_READ |
+			     KVMPPC_DEBUG_WATCH_WRITE |
+			     KVMPPC_DEBUG_BREAKPOINT))
+			return -EINVAL;
+
+		if (type & KVMPPC_DEBUG_BREAKPOINT) {
+			/* Setting H/W breakpoint */
+			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
+				return -EINVAL;
+		} else {
+			/* Setting H/W watchpoint */
+			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	vcpu->cpu = smp_processor_id();
@@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	current->thread.kvm_vcpu = NULL;
 	vcpu->cpu = -1;
+
+	/* Disable all debug events */
+	mtspr(SPRN_DBCR0, 0x0);
+	/* Clear pending debug event in DBSR */
+	kvmppc_clear_dbsr();
 }
 
 int __init kvmppc_booke_init(void)
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index 5fd1ba6..a1ff67d 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
 		giveup_fpu(current);
 #endif
 }
+
+static inline void kvmppc_clear_dbsr(void)
+{
+	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
+}
 #endif /* __KVM_BOOKE_H__ */
-- 
1.5.6.5

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

* [PATCH v4] KVM :PPC: Userspace Debug support
@ 2013-05-07  9:52 ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen; +Cc: Bharat Bhushan

From: Bharat Bhushan <bharat.bhushan@freescale.com>

This patchset adds the userspace debug support for booke/bookehv.
this is tested on powerpc e500v2/e500mc devices.

We are now assuming that debug resource will not be used by kernel for
its own debugging. It will be used for only kernel user process debugging.
So the kernel debug load interface during context_to is used to load
debug conext for that selected process.

v3->v4
 - 4 out of 7 patches of initial patchset were applied.
   This patchset is on and above those 4 patches
 - KVM local "struct kvmppc_booke_debug_reg" is replaced by
   powerpc global "struct debug_reg"
 - use switch_booke_debug_regs() for debug register context switch.
 - Save DBSR before kernel pre-emption is enabled.
 - Some more cleanup

v2->v3
 - We are now assuming that debug resource will not be used by
   kernel for its own debugging.
   It will be used for only kernel user process debugging.
   So the kernel debug load interface during context_to is
   used to load debug conext for that selected process.

v1->v2
 - Debug registers are save/restore in vcpu_put/vcpu_get.
   Earlier the debug registers are saved/restored in guest entry/exit

Bharat Bhushan (6):
  powerpc: remove unnecessary line continuations
  powerpc: move debug registers in a structure
  powerpc: export debug register save function for KVM
  KVM: PPC: exit to user space on "ehpriv" instruction
  KVM: PPC: Using "struct debug_reg"
  KVM: PPC: Add userspace debug stub support

 arch/powerpc/include/asm/disassemble.h |    4 +
 arch/powerpc/include/asm/kvm_host.h    |   16 +--
 arch/powerpc/include/asm/processor.h   |   38 +++--
 arch/powerpc/include/asm/reg_booke.h   |    8 +-
 arch/powerpc/include/asm/switch_to.h   |    4 +
 arch/powerpc/include/uapi/asm/kvm.h    |   22 ++-
 arch/powerpc/kernel/asm-offsets.c      |    2 +-
 arch/powerpc/kernel/process.c          |   45 +++---
 arch/powerpc/kernel/ptrace.c           |  154 +++++++++---------
 arch/powerpc/kernel/signal_32.c        |    6 +-
 arch/powerpc/kernel/traps.c            |   35 ++--
 arch/powerpc/kvm/booke.c               |  276 ++++++++++++++++++++++++++++----
 arch/powerpc/kvm/booke.h               |    5 +
 arch/powerpc/kvm/e500_emulate.c        |   27 +++
 14 files changed, 458 insertions(+), 184 deletions(-)



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

* [PATCH] powerpc: remove unnecessary line continuations
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/kernel/process.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 59dd545..8779234 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -325,7 +325,7 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
 	/*
 	 * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
 	 */
-	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |	\
+	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
 			DBCR1_IAC3US | DBCR1_IAC4US;
 	/*
 	 * Force Data Address Compare User/Supervisor bits to be User-only
-- 
1.5.6.5



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

* [PATCH] powerpc: move debug registers in a structure
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

This way we can use same data type struct with KVM and
also help in using other debug related function.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/processor.h |   38 +++++----
 arch/powerpc/include/asm/reg_booke.h |    8 +-
 arch/powerpc/kernel/asm-offsets.c    |    2 +-
 arch/powerpc/kernel/process.c        |   42 +++++-----
 arch/powerpc/kernel/ptrace.c         |  154 +++++++++++++++++-----------------
 arch/powerpc/kernel/signal_32.c      |    6 +-
 arch/powerpc/kernel/traps.c          |   35 ++++----
 7 files changed, 146 insertions(+), 139 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 7ff9eaa..1494ac3 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -154,22 +154,7 @@ typedef struct {
 #define TS_FPR(i) fpr[i][TS_FPROFFSET]
 #define TS_TRANS_FPR(i) transact_fpr[i][TS_FPROFFSET]
 
-struct thread_struct {
-	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
-
-#ifdef CONFIG_PPC64
-	unsigned long	ksp_vsid;
-#endif
-	struct pt_regs	*regs;		/* Pointer to saved register state */
-	mm_segment_t	fs;		/* for get_fs() validation */
-#ifdef CONFIG_BOOKE
-	/* BookE base exception scratch space; align on cacheline */
-	unsigned long	normsave[8] ____cacheline_aligned;
-#endif
-#ifdef CONFIG_PPC32
-	void		*pgdir;		/* root of page-table tree */
-#endif
+struct debug_reg {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 	/*
 	 * The following help to manage the use of Debug Control Registers
@@ -206,6 +191,27 @@ struct thread_struct {
 	unsigned long	dvc2;
 #endif
 #endif
+};
+
+struct thread_struct {
+	unsigned long	ksp;		/* Kernel stack pointer */
+	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
+
+#ifdef CONFIG_PPC64
+	unsigned long	ksp_vsid;
+#endif
+	struct pt_regs	*regs;		/* Pointer to saved register state */
+	mm_segment_t	fs;		/* for get_fs() validation */
+#ifdef CONFIG_BOOKE
+	/* BookE base exception scratch space; align on cacheline */
+	unsigned long	normsave[8] ____cacheline_aligned;
+#endif
+#ifdef CONFIG_PPC32
+	void		*pgdir;		/* root of page-table tree */
+#endif
+	/* Debug Registers */
+	struct debug_reg debug;
+
 	/* FP and VSX 0-31 register set */
 	double		fpr[32][TS_FPRWIDTH];
 	struct {
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index b417de3..455dc89 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -381,7 +381,7 @@
 #define DBCR0_IA34T	0x00004000	/* Instr Addr 3-4 range Toggle */
 #define DBCR0_FT	0x00000001	/* Freeze Timers on debug event */
 
-#define dbcr_iac_range(task)	((task)->thread.dbcr0)
+#define dbcr_iac_range(task)	((task)->thread.debug.dbcr0)
 #define DBCR_IAC12I	DBCR0_IA12			/* Range Inclusive */
 #define DBCR_IAC12X	(DBCR0_IA12 | DBCR0_IA12X)	/* Range Exclusive */
 #define DBCR_IAC12MODE	(DBCR0_IA12 | DBCR0_IA12X)	/* IAC 1-2 Mode Bits */
@@ -395,7 +395,7 @@
 #define DBCR1_DAC1W	0x20000000	/* DAC1 Write Debug Event */
 #define DBCR1_DAC2W	0x10000000	/* DAC2 Write Debug Event */
 
-#define dbcr_dac(task)	((task)->thread.dbcr1)
+#define dbcr_dac(task)	((task)->thread.debug.dbcr1)
 #define DBCR_DAC1R	DBCR1_DAC1R
 #define DBCR_DAC1W	DBCR1_DAC1W
 #define DBCR_DAC2R	DBCR1_DAC2R
@@ -441,7 +441,7 @@
 #define DBCR0_CRET	0x00000020	/* Critical Return Debug Event */
 #define DBCR0_FT	0x00000001	/* Freeze Timers on debug event */
 
-#define dbcr_dac(task)	((task)->thread.dbcr0)
+#define dbcr_dac(task)	((task)->thread.debug.dbcr0)
 #define DBCR_DAC1R	DBCR0_DAC1R
 #define DBCR_DAC1W	DBCR0_DAC1W
 #define DBCR_DAC2R	DBCR0_DAC2R
@@ -475,7 +475,7 @@
 #define DBCR1_IAC34MX	0x000000C0	/* Instr Addr 3-4 range eXclusive */
 #define DBCR1_IAC34AT	0x00000001	/* Instr Addr 3-4 range Toggle */
 
-#define dbcr_iac_range(task)	((task)->thread.dbcr1)
+#define dbcr_iac_range(task)	((task)->thread.debug.dbcr1)
 #define DBCR_IAC12I	DBCR1_IAC12M	/* Range Inclusive */
 #define DBCR_IAC12X	DBCR1_IAC12MX	/* Range Exclusive */
 #define DBCR_IAC12MODE	DBCR1_IAC12MX	/* IAC 1-2 Mode Bits */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index a791229..83e870d 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -106,7 +106,7 @@ int main(void)
 #else /* CONFIG_PPC64 */
 	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
+	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, debug.dbcr0));
 #endif
 #ifdef CONFIG_SPE
 	DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0]));
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8779234..ca89375 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -312,49 +312,49 @@ static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
  */
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
-	thread->iac1 = thread->iac2 = 0;
+	thread->debug.iac1 = thread->debug.iac2 = 0;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
-	thread->iac3 = thread->iac4 = 0;
+	thread->debug.iac3 = thread->debug.iac4 = 0;
 #endif
-	thread->dac1 = thread->dac2 = 0;
+	thread->debug.dac1 = thread->debug.dac2 = 0;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-	thread->dvc1 = thread->dvc2 = 0;
+	thread->debug.dvc1 = thread->debug.dvc2 = 0;
 #endif
-	thread->dbcr0 = 0;
+	thread->debug.dbcr0 = 0;
 #ifdef CONFIG_BOOKE
 	/*
 	 * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
 	 */
-	thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
+	thread->debug.dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
 			DBCR1_IAC3US | DBCR1_IAC4US;
 	/*
 	 * Force Data Address Compare User/Supervisor bits to be User-only
 	 * (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0.
 	 */
-	thread->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+	thread->debug.dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
 #else
-	thread->dbcr1 = 0;
+	thread->debug.dbcr1 = 0;
 #endif
 }
 
 static void prime_debug_regs(struct thread_struct *thread)
 {
-	mtspr(SPRN_IAC1, thread->iac1);
-	mtspr(SPRN_IAC2, thread->iac2);
+	mtspr(SPRN_IAC1, thread->debug.iac1);
+	mtspr(SPRN_IAC2, thread->debug.iac2);
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
-	mtspr(SPRN_IAC3, thread->iac3);
-	mtspr(SPRN_IAC4, thread->iac4);
+	mtspr(SPRN_IAC3, thread->debug.iac3);
+	mtspr(SPRN_IAC4, thread->debug.iac4);
 #endif
-	mtspr(SPRN_DAC1, thread->dac1);
-	mtspr(SPRN_DAC2, thread->dac2);
+	mtspr(SPRN_DAC1, thread->debug.dac1);
+	mtspr(SPRN_DAC2, thread->debug.dac2);
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-	mtspr(SPRN_DVC1, thread->dvc1);
-	mtspr(SPRN_DVC2, thread->dvc2);
+	mtspr(SPRN_DVC1, thread->debug.dvc1);
+	mtspr(SPRN_DVC2, thread->debug.dvc2);
 #endif
-	mtspr(SPRN_DBCR0, thread->dbcr0);
-	mtspr(SPRN_DBCR1, thread->dbcr1);
+	mtspr(SPRN_DBCR0, thread->debug.dbcr0);
+	mtspr(SPRN_DBCR1, thread->debug.dbcr1);
 #ifdef CONFIG_BOOKE
-	mtspr(SPRN_DBCR2, thread->dbcr2);
+	mtspr(SPRN_DBCR2, thread->debug.dbcr2);
 #endif
 }
 /*
@@ -364,8 +364,8 @@ static void prime_debug_regs(struct thread_struct *thread)
  */
 static void switch_booke_debug_regs(struct thread_struct *new_thread)
 {
-	if ((current->thread.dbcr0 & DBCR0_IDM)
-		|| (new_thread->dbcr0 & DBCR0_IDM))
+	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
+		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
 			prime_debug_regs(new_thread);
 }
 #else	/* !CONFIG_PPC_ADV_DEBUG_REGS */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index f9b30c6..c870505 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -848,8 +848,8 @@ void user_enable_single_step(struct task_struct *task)
 
 	if (regs != NULL) {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		task->thread.dbcr0 &= ~DBCR0_BT;
-		task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+		task->thread.debug.dbcr0 &= ~DBCR0_BT;
+		task->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
 		regs->msr |= MSR_DE;
 #else
 		regs->msr &= ~MSR_BE;
@@ -865,8 +865,8 @@ void user_enable_block_step(struct task_struct *task)
 
 	if (regs != NULL) {
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		task->thread.dbcr0 &= ~DBCR0_IC;
-		task->thread.dbcr0 = DBCR0_IDM | DBCR0_BT;
+		task->thread.debug.dbcr0 &= ~DBCR0_IC;
+		task->thread.debug.dbcr0 = DBCR0_IDM | DBCR0_BT;
 		regs->msr |= MSR_DE;
 #else
 		regs->msr &= ~MSR_SE;
@@ -888,16 +888,16 @@ void user_disable_single_step(struct task_struct *task)
 		 * And, after doing so, if all debug flags are off, turn
 		 * off DBCR0(IDM) and MSR(DE) .... Torez
 		 */
-		task->thread.dbcr0 &= ~DBCR0_IC;
+		task->thread.debug.dbcr0 &= ~DBCR0_IC;
 		/*
 		 * Test to see if any of the DBCR_ACTIVE_EVENTS bits are set.
 		 */
-		if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
-					task->thread.dbcr1)) {
+		if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
+					task->thread.debug.dbcr1)) {
 			/*
 			 * All debug events were off.....
 			 */
-			task->thread.dbcr0 &= ~DBCR0_IDM;
+			task->thread.debug.dbcr0 &= ~DBCR0_IDM;
 			regs->msr &= ~MSR_DE;
 		}
 #else
@@ -1025,14 +1025,14 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 	 */
 
 	/* DAC's hold the whole address without any mode flags */
-	task->thread.dac1 = data & ~0x3UL;
+	task->thread.debug.dac1 = data & ~0x3UL;
 
-	if (task->thread.dac1 = 0) {
+	if (task->thread.debug.dac1 = 0) {
 		dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
-		if (!DBCR_ACTIVE_EVENTS(task->thread.dbcr0,
-					task->thread.dbcr1)) {
+		if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
+					task->thread.debug.dbcr1)) {
 			task->thread.regs->msr &= ~MSR_DE;
-			task->thread.dbcr0 &= ~DBCR0_IDM;
+			task->thread.debug.dbcr0 &= ~DBCR0_IDM;
 		}
 		return 0;
 	}
@@ -1044,7 +1044,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 
 	/* Set the Internal Debugging flag (IDM bit 1) for the DBCR0
 	   register */
-	task->thread.dbcr0 |= DBCR0_IDM;
+	task->thread.debug.dbcr0 |= DBCR0_IDM;
 
 	/* Check for write and read flags and set DBCR0
 	   accordingly */
@@ -1074,10 +1074,10 @@ static long set_instruction_bp(struct task_struct *child,
 			      struct ppc_hw_breakpoint *bp_info)
 {
 	int slot;
-	int slot1_in_use = ((child->thread.dbcr0 & DBCR0_IAC1) != 0);
-	int slot2_in_use = ((child->thread.dbcr0 & DBCR0_IAC2) != 0);
-	int slot3_in_use = ((child->thread.dbcr0 & DBCR0_IAC3) != 0);
-	int slot4_in_use = ((child->thread.dbcr0 & DBCR0_IAC4) != 0);
+	int slot1_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC1) != 0);
+	int slot2_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC2) != 0);
+	int slot3_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC3) != 0);
+	int slot4_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC4) != 0);
 
 	if (dbcr_iac_range(child) & DBCR_IAC12MODE)
 		slot2_in_use = 1;
@@ -1096,9 +1096,9 @@ static long set_instruction_bp(struct task_struct *child,
 		/* We need a pair of IAC regsisters */
 		if ((!slot1_in_use) && (!slot2_in_use)) {
 			slot = 1;
-			child->thread.iac1 = bp_info->addr;
-			child->thread.iac2 = bp_info->addr2;
-			child->thread.dbcr0 |= DBCR0_IAC1;
+			child->thread.debug.iac1 = bp_info->addr;
+			child->thread.debug.iac2 = bp_info->addr2;
+			child->thread.debug.dbcr0 |= DBCR0_IAC1;
 			if (bp_info->addr_mode =
 					PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
 				dbcr_iac_range(child) |= DBCR_IAC12X;
@@ -1107,9 +1107,9 @@ static long set_instruction_bp(struct task_struct *child,
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 		} else if ((!slot3_in_use) && (!slot4_in_use)) {
 			slot = 3;
-			child->thread.iac3 = bp_info->addr;
-			child->thread.iac4 = bp_info->addr2;
-			child->thread.dbcr0 |= DBCR0_IAC3;
+			child->thread.debug.iac3 = bp_info->addr;
+			child->thread.debug.iac4 = bp_info->addr2;
+			child->thread.debug.dbcr0 |= DBCR0_IAC3;
 			if (bp_info->addr_mode =
 					PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
 				dbcr_iac_range(child) |= DBCR_IAC34X;
@@ -1129,30 +1129,30 @@ static long set_instruction_bp(struct task_struct *child,
 			 */
 			if (slot2_in_use || (slot3_in_use = slot4_in_use)) {
 				slot = 1;
-				child->thread.iac1 = bp_info->addr;
-				child->thread.dbcr0 |= DBCR0_IAC1;
+				child->thread.debug.iac1 = bp_info->addr;
+				child->thread.debug.dbcr0 |= DBCR0_IAC1;
 				goto out;
 			}
 		}
 		if (!slot2_in_use) {
 			slot = 2;
-			child->thread.iac2 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC2;
+			child->thread.debug.iac2 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC2;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 		} else if (!slot3_in_use) {
 			slot = 3;
-			child->thread.iac3 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC3;
+			child->thread.debug.iac3 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC3;
 		} else if (!slot4_in_use) {
 			slot = 4;
-			child->thread.iac4 = bp_info->addr;
-			child->thread.dbcr0 |= DBCR0_IAC4;
+			child->thread.debug.iac4 = bp_info->addr;
+			child->thread.debug.dbcr0 |= DBCR0_IAC4;
 #endif
 		} else
 			return -ENOSPC;
 	}
 out:
-	child->thread.dbcr0 |= DBCR0_IDM;
+	child->thread.debug.dbcr0 |= DBCR0_IDM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return slot;
@@ -1162,49 +1162,49 @@ static int del_instruction_bp(struct task_struct *child, int slot)
 {
 	switch (slot) {
 	case 1:
-		if ((child->thread.dbcr0 & DBCR0_IAC1) = 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC1) = 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC12MODE) {
 			/* address range - clear slots 1 & 2 */
-			child->thread.iac2 = 0;
+			child->thread.debug.iac2 = 0;
 			dbcr_iac_range(child) &= ~DBCR_IAC12MODE;
 		}
-		child->thread.iac1 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC1;
+		child->thread.debug.iac1 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC1;
 		break;
 	case 2:
-		if ((child->thread.dbcr0 & DBCR0_IAC2) = 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC2) = 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC12MODE)
 			/* used in a range */
 			return -EINVAL;
-		child->thread.iac2 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC2;
+		child->thread.debug.iac2 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC2;
 		break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case 3:
-		if ((child->thread.dbcr0 & DBCR0_IAC3) = 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC3) = 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC34MODE) {
 			/* address range - clear slots 3 & 4 */
-			child->thread.iac4 = 0;
+			child->thread.debug.iac4 = 0;
 			dbcr_iac_range(child) &= ~DBCR_IAC34MODE;
 		}
-		child->thread.iac3 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC3;
+		child->thread.debug.iac3 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC3;
 		break;
 	case 4:
-		if ((child->thread.dbcr0 & DBCR0_IAC4) = 0)
+		if ((child->thread.debug.dbcr0 & DBCR0_IAC4) = 0)
 			return -ENOENT;
 
 		if (dbcr_iac_range(child) & DBCR_IAC34MODE)
 			/* Used in a range */
 			return -EINVAL;
-		child->thread.iac4 = 0;
-		child->thread.dbcr0 &= ~DBCR0_IAC4;
+		child->thread.debug.iac4 = 0;
+		child->thread.debug.dbcr0 &= ~DBCR0_IAC4;
 		break;
 #endif
 	default:
@@ -1234,18 +1234,18 @@ static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
 			dbcr_dac(child) |= DBCR_DAC1R;
 		if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
 			dbcr_dac(child) |= DBCR_DAC1W;
-		child->thread.dac1 = (unsigned long)bp_info->addr;
+		child->thread.debug.dac1 = (unsigned long)bp_info->addr;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
 		if (byte_enable) {
-			child->thread.dvc1 +			child->thread.debug.dvc1  				(unsigned long)bp_info->condition_value;
-			child->thread.dbcr2 |+			child->thread.debug.dbcr2 | 				((byte_enable << DBCR2_DVC1BE_SHIFT) |
 				 (condition_mode << DBCR2_DVC1M_SHIFT));
 		}
 #endif
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-	} else if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
+	} else if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
 		/* Both dac1 and dac2 are part of a range */
 		return -ENOSPC;
 #endif
@@ -1255,19 +1255,19 @@ static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
 			dbcr_dac(child) |= DBCR_DAC2R;
 		if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
 			dbcr_dac(child) |= DBCR_DAC2W;
-		child->thread.dac2 = (unsigned long)bp_info->addr;
+		child->thread.debug.dac2 = (unsigned long)bp_info->addr;
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
 		if (byte_enable) {
-			child->thread.dvc2 +			child->thread.debug.dvc2  				(unsigned long)bp_info->condition_value;
-			child->thread.dbcr2 |+			child->thread.debug.dbcr2 | 				((byte_enable << DBCR2_DVC2BE_SHIFT) |
 				 (condition_mode << DBCR2_DVC2M_SHIFT));
 		}
 #endif
 	} else
 		return -ENOSPC;
-	child->thread.dbcr0 |= DBCR0_IDM;
+	child->thread.debug.dbcr0 |= DBCR0_IDM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return slot + 4;
@@ -1279,32 +1279,32 @@ static int del_dac(struct task_struct *child, int slot)
 		if ((dbcr_dac(child) & (DBCR_DAC1R | DBCR_DAC1W)) = 0)
 			return -ENOENT;
 
-		child->thread.dac1 = 0;
+		child->thread.debug.dac1 = 0;
 		dbcr_dac(child) &= ~(DBCR_DAC1R | DBCR_DAC1W);
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		if (child->thread.dbcr2 & DBCR2_DAC12MODE) {
-			child->thread.dac2 = 0;
-			child->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+		if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
+			child->thread.debug.dac2 = 0;
+			child->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
 		}
-		child->thread.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
+		child->thread.debug.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
 #endif
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-		child->thread.dvc1 = 0;
+		child->thread.debug.dvc1 = 0;
 #endif
 	} else if (slot = 2) {
 		if ((dbcr_dac(child) & (DBCR_DAC2R | DBCR_DAC2W)) = 0)
 			return -ENOENT;
 
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		if (child->thread.dbcr2 & DBCR2_DAC12MODE)
+		if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE)
 			/* Part of a range */
 			return -EINVAL;
-		child->thread.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
+		child->thread.debug.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
 #endif
 #if CONFIG_PPC_ADV_DEBUG_DVCS > 0
-		child->thread.dvc2 = 0;
+		child->thread.debug.dvc2 = 0;
 #endif
-		child->thread.dac2 = 0;
+		child->thread.debug.dac2 = 0;
 		dbcr_dac(child) &= ~(DBCR_DAC2R | DBCR_DAC2W);
 	} else
 		return -EINVAL;
@@ -1346,22 +1346,22 @@ static int set_dac_range(struct task_struct *child,
 			return -EIO;
 	}
 
-	if (child->thread.dbcr0 &
+	if (child->thread.debug.dbcr0 &
 	    (DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W))
 		return -ENOSPC;
 
 	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
-		child->thread.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
+		child->thread.debug.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
 	if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
-		child->thread.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
-	child->thread.dac1 = bp_info->addr;
-	child->thread.dac2 = bp_info->addr2;
+		child->thread.debug.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
+	child->thread.debug.dac1 = bp_info->addr;
+	child->thread.debug.dac2 = bp_info->addr2;
 	if (mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
-		child->thread.dbcr2  |= DBCR2_DAC12M;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12M;
 	else if (mode = PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
-		child->thread.dbcr2  |= DBCR2_DAC12MX;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12MX;
 	else	/* PPC_BREAKPOINT_MODE_MASK */
-		child->thread.dbcr2  |= DBCR2_DAC12MM;
+		child->thread.debug.dbcr2  |= DBCR2_DAC12MM;
 	child->thread.regs->msr |= MSR_DE;
 
 	return 5;
@@ -1499,9 +1499,9 @@ static long ppc_del_hwdebug(struct task_struct *child, long data)
 		rc = del_dac(child, (int)data - 4);
 
 	if (!rc) {
-		if (!DBCR_ACTIVE_EVENTS(child->thread.dbcr0,
-					child->thread.dbcr1)) {
-			child->thread.dbcr0 &= ~DBCR0_IDM;
+		if (!DBCR_ACTIVE_EVENTS(child->thread.debug.dbcr0,
+					child->thread.debug.dbcr1)) {
+			child->thread.debug.dbcr0 &= ~DBCR0_IDM;
 			child->thread.regs->msr &= ~MSR_DE;
 		}
 	}
@@ -1679,7 +1679,7 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (addr > 0)
 			break;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		ret = put_user(child->thread.dac1, datalp);
+		ret = put_user(child->thread.debug.dac1, datalp);
 #else
 		dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
 			     (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3acb28e..bc857c2 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1292,7 +1292,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 	unsigned char tmp;
 	unsigned long new_msr = regs->msr;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-	unsigned long new_dbcr0 = current->thread.dbcr0;
+	unsigned long new_dbcr0 = current->thread.debug.dbcr0;
 #endif
 
 	for (i=0; i<ndbg; i++) {
@@ -1307,7 +1307,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 			} else {
 				new_dbcr0 &= ~DBCR0_IC;
 				if (!DBCR_ACTIVE_EVENTS(new_dbcr0,
-						current->thread.dbcr1)) {
+						current->thread.debug.dbcr1)) {
 					new_msr &= ~MSR_DE;
 					new_dbcr0 &= ~DBCR0_IDM;
 				}
@@ -1342,7 +1342,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
 	   the user is really doing something wrong. */
 	regs->msr = new_msr;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-	current->thread.dbcr0 = new_dbcr0;
+	current->thread.debug.dbcr0 = new_dbcr0;
 #endif
 
 	if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 37cc40e..cd77d74 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -350,8 +350,8 @@ static inline int check_io_access(struct pt_regs *regs)
 #define REASON_TRAP		ESR_PTR
 
 /* single-step stuff */
-#define single_stepping(regs)	(current->thread.dbcr0 & DBCR0_IC)
-#define clear_single_step(regs)	(current->thread.dbcr0 &= ~DBCR0_IC)
+#define single_stepping(regs)	(current->thread.debug.dbcr0 & DBCR0_IC)
+#define clear_single_step(regs)	(current->thread.debug.dbcr0 &= ~DBCR0_IC)
 
 #else
 /* On non-4xx, the reason for the machine check or program
@@ -1383,7 +1383,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 	if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {
 		dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W);
 #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
-		current->thread.dbcr2 &= ~DBCR2_DAC12MODE;
+		current->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
 #endif
 		do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT,
 			     5);
@@ -1394,24 +1394,24 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 			     6);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC1) {
-		current->thread.dbcr0 &= ~DBCR0_IAC1;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC1;
 		dbcr_iac_range(current) &= ~DBCR_IAC12MODE;
 		do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT,
 			     1);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC2) {
-		current->thread.dbcr0 &= ~DBCR0_IAC2;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC2;
 		do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT,
 			     2);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC3) {
-		current->thread.dbcr0 &= ~DBCR0_IAC3;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC3;
 		dbcr_iac_range(current) &= ~DBCR_IAC34MODE;
 		do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT,
 			     3);
 		changed |= 0x01;
 	}  else if (debug_status & DBSR_IAC4) {
-		current->thread.dbcr0 &= ~DBCR0_IAC4;
+		current->thread.debug.dbcr0 &= ~DBCR0_IAC4;
 		do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT,
 			     4);
 		changed |= 0x01;
@@ -1421,19 +1421,20 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
 	 * Check all other debug flags and see if that bit needs to be turned
 	 * back on or not.
 	 */
-	if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1))
+	if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0,
+			       current->thread.debug.dbcr1))
 		regs->msr |= MSR_DE;
 	else
 		/* Make sure the IDM flag is off */
-		current->thread.dbcr0 &= ~DBCR0_IDM;
+		current->thread.debug.dbcr0 &= ~DBCR0_IDM;
 
 	if (changed & 0x01)
-		mtspr(SPRN_DBCR0, current->thread.dbcr0);
+		mtspr(SPRN_DBCR0, current->thread.debug.dbcr0);
 }
 
 void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
-	current->thread.dbsr = debug_status;
+	current->thread.debug.dbsr = debug_status;
 
 	/* Hack alert: On BookE, Branch Taken stops on the branch itself, while
 	 * on server, it stops on the target of the branch. In order to simulate
@@ -1450,8 +1451,8 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 
 		/* Do the single step trick only when coming from userspace */
 		if (user_mode(regs)) {
-			current->thread.dbcr0 &= ~DBCR0_BT;
-			current->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+			current->thread.debug.dbcr0 &= ~DBCR0_BT;
+			current->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
 			regs->msr |= MSR_DE;
 			return;
 		}
@@ -1479,13 +1480,13 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
 			return;
 
 		if (user_mode(regs)) {
-			current->thread.dbcr0 &= ~DBCR0_IC;
-			if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0,
-					       current->thread.dbcr1))
+			current->thread.debug.dbcr0 &= ~DBCR0_IC;
+			if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0,
+					       current->thread.debug.dbcr1))
 				regs->msr |= MSR_DE;
 			else
 				/* Make sure the IDM bit is off */
-				current->thread.dbcr0 &= ~DBCR0_IDM;
+				current->thread.debug.dbcr0 &= ~DBCR0_IDM;
 		}
 
 		_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
-- 
1.5.6.5



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

* [PATCH] powerpc: export debug register save function for KVM
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

KVM need this function when switching from vcpu to user-space
thread. My subsequent patch will use this function.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/switch_to.h |    4 ++++
 arch/powerpc/kernel/process.c        |    3 ++-
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 200d763..50b357f 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -30,6 +30,10 @@ extern void enable_kernel_spe(void);
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+extern void switch_booke_debug_regs(struct thread_struct *new_thread);
+#endif
+
 #ifndef CONFIG_SMP
 extern void discard_lazy_cpu_state(void);
 #else
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index ca89375..a938138 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -362,12 +362,13 @@ static void prime_debug_regs(struct thread_struct *thread)
  * debug registers, set the debug registers from the values
  * stored in the new thread.
  */
-static void switch_booke_debug_regs(struct thread_struct *new_thread)
+void switch_booke_debug_regs(struct thread_struct *new_thread)
 {
 	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
 		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
 			prime_debug_regs(new_thread);
 }
+EXPORT_SYMBOL(switch_booke_debug_regs);
 #else	/* !CONFIG_PPC_ADV_DEBUG_REGS */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
 static void set_debug_reg_defaults(struct thread_struct *thread)
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: exit to user space on "ehpriv" instruction
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

"ehpriv" instruction is used for setting software breakpoints
by user space. This patch adds support to exit to user space
with "run->debug" have relevant information.

As this is the first point we are using run->debug, also defined
the run->debug structure.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/disassemble.h |    4 ++++
 arch/powerpc/include/uapi/asm/kvm.h    |   21 +++++++++++++++++----
 arch/powerpc/kvm/e500_emulate.c        |   27 +++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/disassemble.h b/arch/powerpc/include/asm/disassemble.h
index 9b198d1..856f8de 100644
--- a/arch/powerpc/include/asm/disassemble.h
+++ b/arch/powerpc/include/asm/disassemble.h
@@ -77,4 +77,8 @@ static inline unsigned int get_d(u32 inst)
 	return inst & 0xffff;
 }
 
+static inline unsigned int get_oc(u32 inst)
+{
+	return (inst >> 11) & 0x7fff;
+}
 #endif /* __ASM_PPC_DISASSEMBLE_H__ */
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 0fb1a6e..ded0607 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -269,7 +269,24 @@ struct kvm_fpu {
 	__u64 fpr[32];
 };
 
+/*
+ * Defines for h/w breakpoint, watchpoint (read, write or both) and
+ * software breakpoint.
+ * These are used as "type" in KVM_SET_GUEST_DEBUG ioctl and "status"
+ * for KVM_DEBUG_EXIT.
+ */
+#define KVMPPC_DEBUG_NONE		0x0
+#define KVMPPC_DEBUG_BREAKPOINT		(1UL << 1)
+#define KVMPPC_DEBUG_WATCH_WRITE	(1UL << 2)
+#define KVMPPC_DEBUG_WATCH_READ		(1UL << 3)
 struct kvm_debug_exit_arch {
+	__u64 address;
+	/*
+	 * exiting to userspace because of h/w breakpoint, watchpoint
+	 * (read, write or both) and software breakpoint.
+	 */
+	__u32 status;
+	__u32 reserved;
 };
 
 /* for KVM_SET_GUEST_DEBUG */
@@ -281,10 +298,6 @@ struct kvm_guest_debug_arch {
 		 * Type denotes h/w breakpoint, read watchpoint, write
 		 * watchpoint or watchpoint (both read and write).
 		 */
-#define KVMPPC_DEBUG_NONE		0x0
-#define KVMPPC_DEBUG_BREAKPOINT		(1UL << 1)
-#define KVMPPC_DEBUG_WATCH_WRITE	(1UL << 2)
-#define KVMPPC_DEBUG_WATCH_READ		(1UL << 3)
 		__u32 type;
 		__u32 reserved;
 	} bp[16];
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index b10a012..dab9d07 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -26,6 +26,8 @@
 #define XOP_TLBRE   946
 #define XOP_TLBWE   978
 #define XOP_TLBILX  18
+#define XOP_EHPRIV  270
+#define EHPRIV_OC_DEBUG 0
 
 #ifdef CONFIG_KVM_E500MC
 static int dbell2prio(ulong param)
@@ -82,6 +84,26 @@ static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
 }
 #endif
 
+static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
+				   unsigned int inst, int *advance)
+{
+	int emulated = EMULATE_DONE;
+
+	switch (get_oc(inst)) {
+	case EHPRIV_OC_DEBUG:
+		run->exit_reason = KVM_EXIT_DEBUG;
+		run->debug.arch.address = vcpu->arch.pc;
+		run->debug.arch.status = 0;
+		kvmppc_account_exit(vcpu, DEBUG_EXITS);
+		emulated = EMULATE_EXIT_USER;
+		*advance = 0;
+		break;
+	default:
+		emulated = EMULATE_FAIL;
+	}
+	return emulated;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -130,6 +152,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
 			break;
 
+		case XOP_EHPRIV:
+			emulated = kvmppc_e500_emul_ehpriv(run, vcpu, inst,
+							   advance);
+			break;
+
 		default:
 			emulated = EMULATE_FAIL;
 		}
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: Using "struct debug_reg"
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

For KVM also use the "struct debug_reg" defined in asm/processor.h

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/kvm_host.h |   13 +------------
 arch/powerpc/kvm/booke.c            |   34 ++++++++++++++++++++++++----------
 2 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index af326cd..838a577 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -381,17 +381,6 @@ struct kvmppc_slb {
 #define KVMPPC_EPR_USER		1 /* exit to userspace to fill EPR */
 #define KVMPPC_EPR_KERNEL	2 /* in-kernel irqchip */
 
-struct kvmppc_booke_debug_reg {
-	u32 dbcr0;
-	u32 dbcr1;
-	u32 dbcr2;
-#ifdef CONFIG_KVM_E500MC
-	u32 dbcr4;
-#endif
-	u64 iac[KVMPPC_BOOKE_MAX_IAC];
-	u64 dac[KVMPPC_BOOKE_MAX_DAC];
-};
-
 #define KVMPPC_IRQ_DEFAULT	0
 #define KVMPPC_IRQ_MPIC		1
 #define KVMPPC_IRQ_XICS		2
@@ -535,7 +524,7 @@ struct kvm_vcpu_arch {
 	u32 eptcfg;
 	u32 epr;
 	u32 crit_save;
-	struct kvmppc_booke_debug_reg dbg_reg;
+	struct debug_reg dbg_reg;
 #endif
 	gpa_t paddr_accessed;
 	gva_t vaddr_accessed;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 1020119..ef99536 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1424,7 +1424,6 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	int r = 0;
 	union kvmppc_one_reg val;
 	int size;
-	long int i;
 
 	size = one_reg_size(reg->id);
 	if (size > sizeof(val))
@@ -1432,16 +1431,24 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 
 	switch (reg->id) {
 	case KVM_REG_PPC_IAC1:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac1);
+		break;
 	case KVM_REG_PPC_IAC2:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac2);
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac3);
+		break;
 	case KVM_REG_PPC_IAC4:
-		i = reg->id - KVM_REG_PPC_IAC1;
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac[i]);
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac4);
 		break;
+#endif
 	case KVM_REG_PPC_DAC1:
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac1);
+		break;
 	case KVM_REG_PPC_DAC2:
-		i = reg->id - KVM_REG_PPC_DAC1;
-		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac[i]);
+		val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac2);
 		break;
 	case KVM_REG_PPC_EPR: {
 		u32 epr = get_guest_epr(vcpu);
@@ -1481,7 +1488,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	int r = 0;
 	union kvmppc_one_reg val;
 	int size;
-	long int i;
 
 	size = one_reg_size(reg->id);
 	if (size > sizeof(val))
@@ -1492,16 +1498,24 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 
 	switch (reg->id) {
 	case KVM_REG_PPC_IAC1:
+		vcpu->arch.dbg_reg.iac1 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_IAC2:
+		vcpu->arch.dbg_reg.iac2 = set_reg_val(reg->id, val);
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
 	case KVM_REG_PPC_IAC3:
+		vcpu->arch.dbg_reg.iac3 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_IAC4:
-		i = reg->id - KVM_REG_PPC_IAC1;
-		vcpu->arch.dbg_reg.iac[i] = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.iac4 = set_reg_val(reg->id, val);
 		break;
+#endif
 	case KVM_REG_PPC_DAC1:
+		vcpu->arch.dbg_reg.dac1 = set_reg_val(reg->id, val);
+		break;
 	case KVM_REG_PPC_DAC2:
-		i = reg->id - KVM_REG_PPC_DAC1;
-		vcpu->arch.dbg_reg.dac[i] = set_reg_val(reg->id, val);
+		vcpu->arch.dbg_reg.dac2 = set_reg_val(reg->id, val);
 		break;
 	case KVM_REG_PPC_EPR: {
 		u32 new_epr = set_reg_val(reg->id, val);
-- 
1.5.6.5



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

* [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-07  9:52   ` Bharat Bhushan
  0 siblings, 0 replies; 28+ messages in thread
From: Bharat Bhushan @ 2013-05-07  9:52 UTC (permalink / raw)
  To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen
  Cc: Bharat Bhushan, Bharat Bhushan

This patch adds the debug stub support on booke/bookehv.
Now QEMU debug stub can use hw breakpoint, watchpoint and
software breakpoint to debug guest.

This is how we save/restore debug register context when switching
between guest, userspace and kernel user-process:

When QEMU is running
 -> thread->debug_reg = QEMU debug register context.
 -> Kernel will handle switching the debug register on context switch.
 -> no vcpu_load() called

QEMU makes ioctls (except RUN)
 -> This will call vcpu_load()
 -> should not change context.
 -> Some ioctls can change vcpu debug register, context saved in vcpu->debug_regs

QEMU Makes RUN ioctl
 -> Save thread->debug_reg on STACK
 -> Store thread->debug_reg = vcpu->debug_reg 
 -> load thread->debug_reg
 -> RUN VCPU ( So thread points to vcpu context )

Context switch happens When VCPU running 
 -> makes vcpu_load() should not load any context
 -> kernel loads the vcpu context as thread->debug_regs points to vcpu context.

On heavyweight_exit
 -> Load the context saved on stack in thread->debug_reg

Currently we do not support debug resource emulation to guest,
On debug exception, always exit to user space irrespective of
user space is expecting the debug exception or not. If this is
unexpected exception (breakpoint/watchpoint event not set by
userspace) then let us leave the action on user space. This
is similar to what it was before, only thing is that now we
have proper exit state available to user space.

Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
 arch/powerpc/include/asm/kvm_host.h |    3 +
 arch/powerpc/include/uapi/asm/kvm.h |    1 +
 arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
 arch/powerpc/kvm/booke.h            |    5 +
 4 files changed, 233 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 838a577..1b29945 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
 	u32 eptcfg;
 	u32 epr;
 	u32 crit_save;
+	/* guest debug registers*/
 	struct debug_reg dbg_reg;
+	/* shadow debug registers */
+	struct debug_reg shadow_dbg_reg;
 #endif
 	gpa_t paddr_accessed;
 	gva_t vaddr_accessed;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index ded0607..f5077c2 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -27,6 +27,7 @@
 #define __KVM_HAVE_PPC_SMT
 #define __KVM_HAVE_IRQCHIP
 #define __KVM_HAVE_IRQ_LINE
+#define __KVM_HAVE_GUEST_DEBUG
 
 struct kvm_regs {
 	__u64 pc;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ef99536..6a44ad4 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
 #endif
 }
 
+static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
+{
+	/* Synchronize guest's desire to get debug interrupts into shadow MSR */
+#ifndef CONFIG_KVM_BOOKE_HV
+	vcpu->arch.shadow_msr &= ~MSR_DE;
+	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE;
+#endif
+
+	/* Force enable debug interrupts when user space wants to debug */
+	if (vcpu->guest_debug) {
+#ifdef CONFIG_KVM_BOOKE_HV
+		/*
+		 * Since there is no shadow MSR, sync MSR_DE into the guest
+		 * visible MSR.
+		 */
+		vcpu->arch.shared->msr |= MSR_DE;
+#else
+		vcpu->arch.shadow_msr |= MSR_DE;
+		vcpu->arch.shared->msr &= ~MSR_DE;
+#endif
+	}
+}
+
 /*
  * Helper function for "full" MSR writes.  No need to call this if only
  * EE/CE/ME/DE/RI are changing.
@@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
 	kvmppc_mmu_msr_notify(vcpu, old_msr);
 	kvmppc_vcpu_sync_spe(vcpu);
 	kvmppc_vcpu_sync_fpu(vcpu);
+	kvmppc_vcpu_sync_debug(vcpu);
 }
 
 static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
@@ -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
 	int ret, s;
+	struct debug_reg debug;
 #ifdef CONFIG_PPC_FPU
 	unsigned int fpscr;
 	int fpexc_mode;
@@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 	kvmppc_load_guest_fp(vcpu);
 #endif
 
+	/*
+	 * Clear current->thread.dbcr0 so that kernel does not
+	 * restore h/w registers on context switch in vcpu running state.
+	 */
+	/* Save thread->debug context on stack */
+	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
+	/* Load vcpu debug context in thread->debug */
+	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
+	       sizeof(struct debug_reg));
+
+	switch_booke_debug_regs(&current->thread);
+
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
 	/* No need for kvm_guest_exit. It's done in handle_exit.
 	   We also get here with interrupts enabled. */
 
+	/* Restore userspace context in thread->dbcr0 from stack*/
+	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
+	switch_booke_debug_regs(&current->thread);
+
 #ifdef CONFIG_PPC_FPU
 	kvmppc_save_guest_fp(vcpu);
 
@@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 	}
 }
 
+/*
+ * Currently we do not support debug resource emulation to guest,
+ * so always exit to user space irrespective of user space is
+ * expecting the debug exception or not. This is unexpected event
+ * and let us leave the action on user space.
+ */
+static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+	u32 dbsr = vcpu->arch.dbsr;
+
+	run->debug.arch.status = 0;
+	run->debug.arch.address = vcpu->arch.pc;
+
+	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
+		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
+	} else {
+		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
+			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
+		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
+			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
+		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
+			run->debug.arch.address = dbg_reg->dac1;
+		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
+			run->debug.arch.address = dbg_reg->dac2;
+	}
+
+	return RESUME_HOST;
+}
+
 static void kvmppc_fill_pt_regs(struct pt_regs *regs)
 {
 	ulong r1, ip, msr, lr;
@@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
 	case BOOKE_INTERRUPT_CRITICAL:
 		unknown_exception(&regs);
 		break;
+	case BOOKE_INTERRUPT_DEBUG:
+		/* Save DBSR before preemption is enabled */
+		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
+		kvmppc_clear_dbsr();
+		break;
 	}
 }
 
@@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	}
 
 	case BOOKE_INTERRUPT_DEBUG: {
-		u32 dbsr;
-
-		vcpu->arch.pc = mfspr(SPRN_CSRR0);
-
-		/* clear IAC events in DBSR register */
-		dbsr = mfspr(SPRN_DBSR);
-		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
-		mtspr(SPRN_DBSR, dbsr);
-
-		run->exit_reason = KVM_EXIT_DEBUG;
+		r = kvmppc_handle_debug(run, vcpu);
+		if (r = RESUME_HOST)
+			run->exit_reason = KVM_EXIT_DEBUG;
 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
-		r = RESUME_HOST;
 		break;
 	}
 
@@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	kvmppc_set_msr(vcpu, 0);
 
 #ifndef CONFIG_KVM_BOOKE_HV
-	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
+	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
 	vcpu->arch.shadow_pid = 1;
 	vcpu->arch.shared->msr = 0;
 #endif
@@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 	return r;
 }
 
-int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
-					 struct kvm_guest_debug *dbg)
-{
-	return -EINVAL;
-}
-
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	return -ENOTSUPP;
@@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
 }
 
+static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu, uint64_t addr,
+				       int index)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	switch (index) {
+	case 0:
+		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
+		dbg_reg->iac1 = addr;
+		break;
+	case 1:
+		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
+		dbg_reg->iac2 = addr;
+		break;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+	case 2:
+		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
+		dbg_reg->iac3 = addr;
+		break;
+	case 3:
+		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
+		dbg_reg->iac4 = addr;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu, uint64_t addr,
+				       int type, int index)
+{
+	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	switch (index) {
+	case 0:
+		if (type & KVMPPC_DEBUG_WATCH_READ)
+			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
+		if (type & KVMPPC_DEBUG_WATCH_WRITE)
+			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
+		dbg_reg->dac1 = addr;
+		break;
+	case 1:
+		if (type & KVMPPC_DEBUG_WATCH_READ)
+			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
+		if (type & KVMPPC_DEBUG_WATCH_WRITE)
+			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
+		dbg_reg->dac2 = addr;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+					 struct kvm_guest_debug *dbg)
+{
+	struct debug_reg *dbg_reg;
+	int n, b = 0, w = 0;
+
+	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
+		/* Clear All debug events */
+		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+		vcpu->guest_debug = 0;
+#ifdef CONFIG_KVM_BOOKE_HV
+		/*
+		 * When user space is not using the debug resources
+		 * then allow guest to change the MSR.DE.
+		 */
+		vcpu->arch.shadow_msrp &= ~MSRP_DEP;
+#endif
+		return 0;
+	}
+
+#ifdef CONFIG_KVM_BOOKE_HV
+	/*
+	 * When user space is using the debug resource then
+	 * do not allow guest to change the MSR.DE.
+	 */
+	vcpu->arch.shadow_msrp |= MSRP_DEP;
+#endif
+	vcpu->guest_debug = dbg->control;
+	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+	/* Set DBCR0_EDM in guest visible DBCR0 register. */
+	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
+
+	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+
+	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
+		return 0;
+
+	/* Code below handles only HW breakpoints */
+	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+
+	/*
+	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
+	 * to occur when MSR.PR is set.
+	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
+	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
+	 * that debug events will not come in hypervisor (GS = 0).
+	 */
+#ifdef CONFIG_KVM_BOOKE_HV
+	dbg_reg->dbcr1 = 0;
+	dbg_reg->dbcr2 = 0;
+#else
+	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
+			  DBCR1_IAC4US;
+	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+#endif
+
+	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
+		uint64_t addr = dbg->arch.bp[n].addr;
+		uint32_t type = dbg->arch.bp[n].type;
+
+		if (type = KVMPPC_DEBUG_NONE)
+			continue;
+
+		if (type & !(KVMPPC_DEBUG_WATCH_READ |
+			     KVMPPC_DEBUG_WATCH_WRITE |
+			     KVMPPC_DEBUG_BREAKPOINT))
+			return -EINVAL;
+
+		if (type & KVMPPC_DEBUG_BREAKPOINT) {
+			/* Setting H/W breakpoint */
+			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
+				return -EINVAL;
+		} else {
+			/* Setting H/W watchpoint */
+			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	vcpu->cpu = smp_processor_id();
@@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	current->thread.kvm_vcpu = NULL;
 	vcpu->cpu = -1;
+
+	/* Disable all debug events */
+	mtspr(SPRN_DBCR0, 0x0);
+	/* Clear pending debug event in DBSR */
+	kvmppc_clear_dbsr();
 }
 
 int __init kvmppc_booke_init(void)
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index 5fd1ba6..a1ff67d 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
 		giveup_fpu(current);
 #endif
 }
+
+static inline void kvmppc_clear_dbsr(void)
+{
+	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
+}
 #endif /* __KVM_BOOKE_H__ */
-- 
1.5.6.5



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

* Re: [PATCH] powerpc: export debug register save function for KVM
  2013-05-07  9:52   ` Bharat Bhushan
@ 2013-05-10  9:15     ` Alexander Graf
  -1 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10  9:15 UTC (permalink / raw)
  To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan


On 07.05.2013, at 11:40, Bharat Bhushan wrote:

> KVM need this function when switching from vcpu to user-space
> thread. My subsequent patch will use this function.
> 
> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> ---
> arch/powerpc/include/asm/switch_to.h |    4 ++++
> arch/powerpc/kernel/process.c        |    3 ++-
> 2 files changed, 6 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
> index 200d763..50b357f 100644
> --- a/arch/powerpc/include/asm/switch_to.h
> +++ b/arch/powerpc/include/asm/switch_to.h
> @@ -30,6 +30,10 @@ extern void enable_kernel_spe(void);
> extern void giveup_spe(struct task_struct *);
> extern void load_up_spe(struct task_struct *);
> 
> +#ifdef CONFIG_PPC_ADV_DEBUG_REGS
> +extern void switch_booke_debug_regs(struct thread_struct *new_thread);
> +#endif
> +
> #ifndef CONFIG_SMP
> extern void discard_lazy_cpu_state(void);
> #else
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index ca89375..a938138 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -362,12 +362,13 @@ static void prime_debug_regs(struct thread_struct *thread)
>  * debug registers, set the debug registers from the values
>  * stored in the new thread.
>  */
> -static void switch_booke_debug_regs(struct thread_struct *new_thread)
> +void switch_booke_debug_regs(struct thread_struct *new_thread)
> {
> 	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
> 		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
> 			prime_debug_regs(new_thread);
> }
> +EXPORT_SYMBOL(switch_booke_debug_regs);

EXPORT_SYMBOL_GPL


Alex

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

* Re: [PATCH] powerpc: export debug register save function for KVM
@ 2013-05-10  9:15     ` Alexander Graf
  0 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10  9:15 UTC (permalink / raw)
  To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan


On 07.05.2013, at 11:40, Bharat Bhushan wrote:

> KVM need this function when switching from vcpu to user-space
> thread. My subsequent patch will use this function.
> 
> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> ---
> arch/powerpc/include/asm/switch_to.h |    4 ++++
> arch/powerpc/kernel/process.c        |    3 ++-
> 2 files changed, 6 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
> index 200d763..50b357f 100644
> --- a/arch/powerpc/include/asm/switch_to.h
> +++ b/arch/powerpc/include/asm/switch_to.h
> @@ -30,6 +30,10 @@ extern void enable_kernel_spe(void);
> extern void giveup_spe(struct task_struct *);
> extern void load_up_spe(struct task_struct *);
> 
> +#ifdef CONFIG_PPC_ADV_DEBUG_REGS
> +extern void switch_booke_debug_regs(struct thread_struct *new_thread);
> +#endif
> +
> #ifndef CONFIG_SMP
> extern void discard_lazy_cpu_state(void);
> #else
> diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
> index ca89375..a938138 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -362,12 +362,13 @@ static void prime_debug_regs(struct thread_struct *thread)
>  * debug registers, set the debug registers from the values
>  * stored in the new thread.
>  */
> -static void switch_booke_debug_regs(struct thread_struct *new_thread)
> +void switch_booke_debug_regs(struct thread_struct *new_thread)
> {
> 	if ((current->thread.debug.dbcr0 & DBCR0_IDM)
> 		|| (new_thread->debug.dbcr0 & DBCR0_IDM))
> 			prime_debug_regs(new_thread);
> }
> +EXPORT_SYMBOL(switch_booke_debug_regs);

EXPORT_SYMBOL_GPL


Alex


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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-07  9:52   ` Bharat Bhushan
@ 2013-05-10 10:18     ` Alexander Graf
  -1 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10 10:18 UTC (permalink / raw)
  To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan


On 07.05.2013, at 11:40, Bharat Bhushan wrote:

> This patch adds the debug stub support on booke/bookehv.
> Now QEMU debug stub can use hw breakpoint, watchpoint and
> software breakpoint to debug guest.
> 
> This is how we save/restore debug register context when switching
> between guest, userspace and kernel user-process:
> 
> When QEMU is running
> -> thread->debug_reg == QEMU debug register context.
> -> Kernel will handle switching the debug register on context switch.
> -> no vcpu_load() called
> 
> QEMU makes ioctls (except RUN)
> -> This will call vcpu_load()
> -> should not change context.
> -> Some ioctls can change vcpu debug register, context saved in vcpu->debug_regs
> 
> QEMU Makes RUN ioctl
> -> Save thread->debug_reg on STACK
> -> Store thread->debug_reg == vcpu->debug_reg 
> -> load thread->debug_reg
> -> RUN VCPU ( So thread points to vcpu context )
> 
> Context switch happens When VCPU running 
> -> makes vcpu_load() should not load any context
> -> kernel loads the vcpu context as thread->debug_regs points to vcpu context.
> 
> On heavyweight_exit
> -> Load the context saved on stack in thread->debug_reg
> 
> Currently we do not support debug resource emulation to guest,
> On debug exception, always exit to user space irrespective of
> user space is expecting the debug exception or not. If this is
> unexpected exception (breakpoint/watchpoint event not set by
> userspace) then let us leave the action on user space. This
> is similar to what it was before, only thing is that now we
> have proper exit state available to user space.
> 
> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> ---
> arch/powerpc/include/asm/kvm_host.h |    3 +
> arch/powerpc/include/uapi/asm/kvm.h |    1 +
> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
> arch/powerpc/kvm/booke.h            |    5 +
> 4 files changed, 233 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index 838a577..1b29945 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> 	u32 eptcfg;
> 	u32 epr;
> 	u32 crit_save;
> +	/* guest debug registers*/
> 	struct debug_reg dbg_reg;
> +	/* shadow debug registers */

Please be more verbose here. What exactly does this contain? Why do we need shadow and non-shadow registers? The comment as it is reads like

  /* Add one plus one */
  x = 1 + 1;

> +	struct debug_reg shadow_dbg_reg;
> #endif
> 	gpa_t paddr_accessed;
> 	gva_t vaddr_accessed;
> diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
> index ded0607..f5077c2 100644
> --- a/arch/powerpc/include/uapi/asm/kvm.h
> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> @@ -27,6 +27,7 @@
> #define __KVM_HAVE_PPC_SMT
> #define __KVM_HAVE_IRQCHIP
> #define __KVM_HAVE_IRQ_LINE
> +#define __KVM_HAVE_GUEST_DEBUG
> 
> struct kvm_regs {
> 	__u64 pc;
> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> index ef99536..6a44ad4 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
> #endif
> }
> 
> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
> +{
> +	/* Synchronize guest's desire to get debug interrupts into shadow MSR */
> +#ifndef CONFIG_KVM_BOOKE_HV
> +	vcpu->arch.shadow_msr &= ~MSR_DE;
> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE;
> +#endif
> +
> +	/* Force enable debug interrupts when user space wants to debug */
> +	if (vcpu->guest_debug) {
> +#ifdef CONFIG_KVM_BOOKE_HV
> +		/*
> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> +		 * visible MSR.
> +		 */
> +		vcpu->arch.shared->msr |= MSR_DE;
> +#else
> +		vcpu->arch.shadow_msr |= MSR_DE;
> +		vcpu->arch.shared->msr &= ~MSR_DE;
> +#endif
> +	}
> +}
> +
> /*
>  * Helper function for "full" MSR writes.  No need to call this if only
>  * EE/CE/ME/DE/RI are changing.
> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> 	kvmppc_vcpu_sync_spe(vcpu);
> 	kvmppc_vcpu_sync_fpu(vcpu);
> +	kvmppc_vcpu_sync_debug(vcpu);
> }
> 
> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
> @@ -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
> int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> {
> 	int ret, s;
> +	struct debug_reg debug;
> #ifdef CONFIG_PPC_FPU
> 	unsigned int fpscr;
> 	int fpexc_mode;
> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> 	kvmppc_load_guest_fp(vcpu);
> #endif
> 
> +	/*
> +	 * Clear current->thread.dbcr0 so that kernel does not
> +	 * restore h/w registers on context switch in vcpu running state.
> +	 */

Incorrect comment?

> +	/* Save thread->debug context on stack */

/* Switch to guest debug context */

> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));

debug = current->thread.debug;

> +	/* Load vcpu debug context in thread->debug */
> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> +	       sizeof(struct debug_reg));

current->thread.debug = vcpu->arch.shadow_dbg_reg;

> +
> +	switch_booke_debug_regs(&current->thread);
> +
> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> 
> 	/* No need for kvm_guest_exit. It's done in handle_exit.
> 	   We also get here with interrupts enabled. */
> 
> +	/* Restore userspace context in thread->dbcr0 from stack*/

/* Switch back to user space debug context */

> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));

current->thread.debug = debug;

> +	switch_booke_debug_regs(&current->thread);
> +
> #ifdef CONFIG_PPC_FPU
> 	kvmppc_save_guest_fp(vcpu);
> 
> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
> 	}
> }
> 
> +/*
> + * Currently we do not support debug resource emulation to guest,
> + * so always exit to user space irrespective of user space is
> + * expecting the debug exception or not. This is unexpected event
> + * and let us leave the action on user space.

Please rework your wording.

> + */
> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +	u32 dbsr = vcpu->arch.dbsr;
> +
> +	run->debug.arch.status = 0;
> +	run->debug.arch.address = vcpu->arch.pc;
> +
> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> +	} else {
> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> +			run->debug.arch.address = dbg_reg->dac1;
> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> +			run->debug.arch.address = dbg_reg->dac2;
> +	}
> +
> +	return RESUME_HOST;
> +}
> +
> static void kvmppc_fill_pt_regs(struct pt_regs *regs)
> {
> 	ulong r1, ip, msr, lr;
> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
> 	case BOOKE_INTERRUPT_CRITICAL:
> 		unknown_exception(&regs);
> 		break;
> +	case BOOKE_INTERRUPT_DEBUG:
> +		/* Save DBSR before preemption is enabled */
> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> +		kvmppc_clear_dbsr();
> +		break;
> 	}
> }
> 
> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> 	}
> 
> 	case BOOKE_INTERRUPT_DEBUG: {
> -		u32 dbsr;
> -
> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> -
> -		/* clear IAC events in DBSR register */
> -		dbsr = mfspr(SPRN_DBSR);
> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> -		mtspr(SPRN_DBSR, dbsr);
> -
> -		run->exit_reason = KVM_EXIT_DEBUG;
> +		r = kvmppc_handle_debug(run, vcpu);
> +		if (r == RESUME_HOST)
> +			run->exit_reason = KVM_EXIT_DEBUG;
> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> -		r = RESUME_HOST;
> 		break;
> 	}
> 
> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> 	kvmppc_set_msr(vcpu, 0);
> 
> #ifndef CONFIG_KVM_BOOKE_HV
> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> 	vcpu->arch.shadow_pid = 1;
> 	vcpu->arch.shared->msr = 0;
> #endif
> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
> 	return r;
> }
> 
> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> -					 struct kvm_guest_debug *dbg)
> -{
> -	return -EINVAL;
> -}
> -
> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
> {
> 	return -ENOTSUPP;
> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
> }
> 
> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu, uint64_t addr,

s/set/add/

> +				       int index)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	switch (index) {
> +	case 0:
> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> +		dbg_reg->iac1 = addr;
> +		break;
> +	case 1:
> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> +		dbg_reg->iac2 = addr;
> +		break;
> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> +	case 2:
> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> +		dbg_reg->iac3 = addr;
> +		break;
> +	case 3:
> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> +		dbg_reg->iac4 = addr;
> +		break;
> +#endif
> +	default:
> +		return -EINVAL;
> +	}

    dbg_reg->dbcr0 |= DBCR0_IDM;

> +	return 0;
> +}
> +
> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu, uint64_t addr,

s/set/add/

> +				       int type, int index)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	switch (index) {
> +	case 0:
> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> +		dbg_reg->dac1 = addr;
> +		break;
> +	case 1:
> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> +		dbg_reg->dac2 = addr;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}

    dbg_reg->dbcr0 |= DBCR0_IDM;

> +	return 0;
> +}
> +
> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> +					 struct kvm_guest_debug *dbg)
> +{
> +	struct debug_reg *dbg_reg;
> +	int n, b = 0, w = 0;
> +
> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> +		/* Clear All debug events */
> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> +		vcpu->guest_debug = 0;
> +#ifdef CONFIG_KVM_BOOKE_HV
> +		/*
> +		 * When user space is not using the debug resources
> +		 * then allow guest to change the MSR.DE.
> +		 */
> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP;
> +#endif

guest_may_set_msr_de(vcpu, true);

> +		return 0;
> +	}
> +
> +#ifdef CONFIG_KVM_BOOKE_HV
> +	/*
> +	 * When user space is using the debug resource then
> +	 * do not allow guest to change the MSR.DE.
> +	 */
> +	vcpu->arch.shadow_msrp |= MSRP_DEP;
> +#endif

guest_may_set_msr_de(vcpu, false);

> +	vcpu->guest_debug = dbg->control;
> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> +
> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> +
> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> +		return 0;
> +
> +	/* Code below handles only HW breakpoints */
> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	/*
> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> +	 * to occur when MSR.PR is set.
> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> +	 * that debug events will not come in hypervisor (GS = 0).

This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what TCG does. There is no point in making HV KVM behave differently.

> +	 */
> +#ifdef CONFIG_KVM_BOOKE_HV
> +	dbg_reg->dbcr1 = 0;
> +	dbg_reg->dbcr2 = 0;
> +#else
> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> +			  DBCR1_IAC4US;
> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
> +#endif
> +
> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> +		uint64_t addr = dbg->arch.bp[n].addr;
> +		uint32_t type = dbg->arch.bp[n].type;
> +
> +		if (type == KVMPPC_DEBUG_NONE)
> +			continue;
> +
> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> +			     KVMPPC_DEBUG_WATCH_WRITE |
> +			     KVMPPC_DEBUG_BREAKPOINT))
> +			return -EINVAL;
> +
> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> +			/* Setting H/W breakpoint */
> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))

Please pass dbg_reg into the function

> +				return -EINVAL;
> +		} else {
> +			/* Setting H/W watchpoint */
> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))

here too

> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> {
> 	vcpu->cpu = smp_processor_id();
> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu)
> {
> 	current->thread.kvm_vcpu = NULL;
> 	vcpu->cpu = -1;
> +
> +	/* Disable all debug events */
> +	mtspr(SPRN_DBCR0, 0x0);

Why? Wouldn't normal preemption handling take care of this already?

> +	/* Clear pending debug event in DBSR */
> +	kvmppc_clear_dbsr();

Is there a chance we will ever have to do this? On debug exits from guest context we already clear dbsr.

My question from the last review round still stands. What if a breakpoint for guest address 0xc0001234 is active and on the host 0xc0001234 happens to be at kvm_run? Will we get a breakpoint inside of the host context? That would be bad. We only want to get debug events when

  e500v2: MSR.PR == 1
  e500mc: MSR.GS == 1


Alex

> }
> 
> int __init kvmppc_booke_init(void)
> diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
> index 5fd1ba6..a1ff67d 100644
> --- a/arch/powerpc/kvm/booke.h
> +++ b/arch/powerpc/kvm/booke.h
> @@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
> 		giveup_fpu(current);
> #endif
> }
> +
> +static inline void kvmppc_clear_dbsr(void)
> +{
> +	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
> +}
> #endif /* __KVM_BOOKE_H__ */
> -- 
> 1.5.6.5
> 
> 

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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-10 10:18     ` Alexander Graf
  0 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10 10:18 UTC (permalink / raw)
  To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan


On 07.05.2013, at 11:40, Bharat Bhushan wrote:

> This patch adds the debug stub support on booke/bookehv.
> Now QEMU debug stub can use hw breakpoint, watchpoint and
> software breakpoint to debug guest.
> 
> This is how we save/restore debug register context when switching
> between guest, userspace and kernel user-process:
> 
> When QEMU is running
> -> thread->debug_reg = QEMU debug register context.
> -> Kernel will handle switching the debug register on context switch.
> -> no vcpu_load() called
> 
> QEMU makes ioctls (except RUN)
> -> This will call vcpu_load()
> -> should not change context.
> -> Some ioctls can change vcpu debug register, context saved in vcpu->debug_regs
> 
> QEMU Makes RUN ioctl
> -> Save thread->debug_reg on STACK
> -> Store thread->debug_reg = vcpu->debug_reg 
> -> load thread->debug_reg
> -> RUN VCPU ( So thread points to vcpu context )
> 
> Context switch happens When VCPU running 
> -> makes vcpu_load() should not load any context
> -> kernel loads the vcpu context as thread->debug_regs points to vcpu context.
> 
> On heavyweight_exit
> -> Load the context saved on stack in thread->debug_reg
> 
> Currently we do not support debug resource emulation to guest,
> On debug exception, always exit to user space irrespective of
> user space is expecting the debug exception or not. If this is
> unexpected exception (breakpoint/watchpoint event not set by
> userspace) then let us leave the action on user space. This
> is similar to what it was before, only thing is that now we
> have proper exit state available to user space.
> 
> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> ---
> arch/powerpc/include/asm/kvm_host.h |    3 +
> arch/powerpc/include/uapi/asm/kvm.h |    1 +
> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
> arch/powerpc/kvm/booke.h            |    5 +
> 4 files changed, 233 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index 838a577..1b29945 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> 	u32 eptcfg;
> 	u32 epr;
> 	u32 crit_save;
> +	/* guest debug registers*/
> 	struct debug_reg dbg_reg;
> +	/* shadow debug registers */

Please be more verbose here. What exactly does this contain? Why do we need shadow and non-shadow registers? The comment as it is reads like

  /* Add one plus one */
  x = 1 + 1;

> +	struct debug_reg shadow_dbg_reg;
> #endif
> 	gpa_t paddr_accessed;
> 	gva_t vaddr_accessed;
> diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
> index ded0607..f5077c2 100644
> --- a/arch/powerpc/include/uapi/asm/kvm.h
> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> @@ -27,6 +27,7 @@
> #define __KVM_HAVE_PPC_SMT
> #define __KVM_HAVE_IRQCHIP
> #define __KVM_HAVE_IRQ_LINE
> +#define __KVM_HAVE_GUEST_DEBUG
> 
> struct kvm_regs {
> 	__u64 pc;
> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> index ef99536..6a44ad4 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
> #endif
> }
> 
> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
> +{
> +	/* Synchronize guest's desire to get debug interrupts into shadow MSR */
> +#ifndef CONFIG_KVM_BOOKE_HV
> +	vcpu->arch.shadow_msr &= ~MSR_DE;
> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE;
> +#endif
> +
> +	/* Force enable debug interrupts when user space wants to debug */
> +	if (vcpu->guest_debug) {
> +#ifdef CONFIG_KVM_BOOKE_HV
> +		/*
> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> +		 * visible MSR.
> +		 */
> +		vcpu->arch.shared->msr |= MSR_DE;
> +#else
> +		vcpu->arch.shadow_msr |= MSR_DE;
> +		vcpu->arch.shared->msr &= ~MSR_DE;
> +#endif
> +	}
> +}
> +
> /*
>  * Helper function for "full" MSR writes.  No need to call this if only
>  * EE/CE/ME/DE/RI are changing.
> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> 	kvmppc_vcpu_sync_spe(vcpu);
> 	kvmppc_vcpu_sync_fpu(vcpu);
> +	kvmppc_vcpu_sync_debug(vcpu);
> }
> 
> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
> @@ -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
> int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> {
> 	int ret, s;
> +	struct debug_reg debug;
> #ifdef CONFIG_PPC_FPU
> 	unsigned int fpscr;
> 	int fpexc_mode;
> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> 	kvmppc_load_guest_fp(vcpu);
> #endif
> 
> +	/*
> +	 * Clear current->thread.dbcr0 so that kernel does not
> +	 * restore h/w registers on context switch in vcpu running state.
> +	 */

Incorrect comment?

> +	/* Save thread->debug context on stack */

/* Switch to guest debug context */

> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));

debug = current->thread.debug;

> +	/* Load vcpu debug context in thread->debug */
> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> +	       sizeof(struct debug_reg));

current->thread.debug = vcpu->arch.shadow_dbg_reg;

> +
> +	switch_booke_debug_regs(&current->thread);
> +
> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> 
> 	/* No need for kvm_guest_exit. It's done in handle_exit.
> 	   We also get here with interrupts enabled. */
> 
> +	/* Restore userspace context in thread->dbcr0 from stack*/

/* Switch back to user space debug context */

> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));

current->thread.debug = debug;

> +	switch_booke_debug_regs(&current->thread);
> +
> #ifdef CONFIG_PPC_FPU
> 	kvmppc_save_guest_fp(vcpu);
> 
> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
> 	}
> }
> 
> +/*
> + * Currently we do not support debug resource emulation to guest,
> + * so always exit to user space irrespective of user space is
> + * expecting the debug exception or not. This is unexpected event
> + * and let us leave the action on user space.

Please rework your wording.

> + */
> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +	u32 dbsr = vcpu->arch.dbsr;
> +
> +	run->debug.arch.status = 0;
> +	run->debug.arch.address = vcpu->arch.pc;
> +
> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> +	} else {
> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> +			run->debug.arch.address = dbg_reg->dac1;
> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> +			run->debug.arch.address = dbg_reg->dac2;
> +	}
> +
> +	return RESUME_HOST;
> +}
> +
> static void kvmppc_fill_pt_regs(struct pt_regs *regs)
> {
> 	ulong r1, ip, msr, lr;
> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
> 	case BOOKE_INTERRUPT_CRITICAL:
> 		unknown_exception(&regs);
> 		break;
> +	case BOOKE_INTERRUPT_DEBUG:
> +		/* Save DBSR before preemption is enabled */
> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> +		kvmppc_clear_dbsr();
> +		break;
> 	}
> }
> 
> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> 	}
> 
> 	case BOOKE_INTERRUPT_DEBUG: {
> -		u32 dbsr;
> -
> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> -
> -		/* clear IAC events in DBSR register */
> -		dbsr = mfspr(SPRN_DBSR);
> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> -		mtspr(SPRN_DBSR, dbsr);
> -
> -		run->exit_reason = KVM_EXIT_DEBUG;
> +		r = kvmppc_handle_debug(run, vcpu);
> +		if (r = RESUME_HOST)
> +			run->exit_reason = KVM_EXIT_DEBUG;
> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> -		r = RESUME_HOST;
> 		break;
> 	}
> 
> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> 	kvmppc_set_msr(vcpu, 0);
> 
> #ifndef CONFIG_KVM_BOOKE_HV
> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> 	vcpu->arch.shadow_pid = 1;
> 	vcpu->arch.shared->msr = 0;
> #endif
> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
> 	return r;
> }
> 
> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> -					 struct kvm_guest_debug *dbg)
> -{
> -	return -EINVAL;
> -}
> -
> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
> {
> 	return -ENOTSUPP;
> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
> }
> 
> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu, uint64_t addr,

s/set/add/

> +				       int index)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	switch (index) {
> +	case 0:
> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> +		dbg_reg->iac1 = addr;
> +		break;
> +	case 1:
> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> +		dbg_reg->iac2 = addr;
> +		break;
> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> +	case 2:
> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> +		dbg_reg->iac3 = addr;
> +		break;
> +	case 3:
> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> +		dbg_reg->iac4 = addr;
> +		break;
> +#endif
> +	default:
> +		return -EINVAL;
> +	}

    dbg_reg->dbcr0 |= DBCR0_IDM;

> +	return 0;
> +}
> +
> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu, uint64_t addr,

s/set/add/

> +				       int type, int index)
> +{
> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	switch (index) {
> +	case 0:
> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> +		dbg_reg->dac1 = addr;
> +		break;
> +	case 1:
> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> +		dbg_reg->dac2 = addr;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}

    dbg_reg->dbcr0 |= DBCR0_IDM;

> +	return 0;
> +}
> +
> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> +					 struct kvm_guest_debug *dbg)
> +{
> +	struct debug_reg *dbg_reg;
> +	int n, b = 0, w = 0;
> +
> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> +		/* Clear All debug events */
> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> +		vcpu->guest_debug = 0;
> +#ifdef CONFIG_KVM_BOOKE_HV
> +		/*
> +		 * When user space is not using the debug resources
> +		 * then allow guest to change the MSR.DE.
> +		 */
> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP;
> +#endif

guest_may_set_msr_de(vcpu, true);

> +		return 0;
> +	}
> +
> +#ifdef CONFIG_KVM_BOOKE_HV
> +	/*
> +	 * When user space is using the debug resource then
> +	 * do not allow guest to change the MSR.DE.
> +	 */
> +	vcpu->arch.shadow_msrp |= MSRP_DEP;
> +#endif

guest_may_set_msr_de(vcpu, false);

> +	vcpu->guest_debug = dbg->control;
> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> +
> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> +
> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> +		return 0;
> +
> +	/* Code below handles only HW breakpoints */
> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> +
> +	/*
> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> +	 * to occur when MSR.PR is set.
> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> +	 * that debug events will not come in hypervisor (GS = 0).

This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what TCG does. There is no point in making HV KVM behave differently.

> +	 */
> +#ifdef CONFIG_KVM_BOOKE_HV
> +	dbg_reg->dbcr1 = 0;
> +	dbg_reg->dbcr2 = 0;
> +#else
> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> +			  DBCR1_IAC4US;
> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
> +#endif
> +
> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> +		uint64_t addr = dbg->arch.bp[n].addr;
> +		uint32_t type = dbg->arch.bp[n].type;
> +
> +		if (type = KVMPPC_DEBUG_NONE)
> +			continue;
> +
> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> +			     KVMPPC_DEBUG_WATCH_WRITE |
> +			     KVMPPC_DEBUG_BREAKPOINT))
> +			return -EINVAL;
> +
> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> +			/* Setting H/W breakpoint */
> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))

Please pass dbg_reg into the function

> +				return -EINVAL;
> +		} else {
> +			/* Setting H/W watchpoint */
> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))

here too

> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> {
> 	vcpu->cpu = smp_processor_id();
> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu)
> {
> 	current->thread.kvm_vcpu = NULL;
> 	vcpu->cpu = -1;
> +
> +	/* Disable all debug events */
> +	mtspr(SPRN_DBCR0, 0x0);

Why? Wouldn't normal preemption handling take care of this already?

> +	/* Clear pending debug event in DBSR */
> +	kvmppc_clear_dbsr();

Is there a chance we will ever have to do this? On debug exits from guest context we already clear dbsr.

My question from the last review round still stands. What if a breakpoint for guest address 0xc0001234 is active and on the host 0xc0001234 happens to be at kvm_run? Will we get a breakpoint inside of the host context? That would be bad. We only want to get debug events when

  e500v2: MSR.PR = 1
  e500mc: MSR.GS = 1


Alex

> }
> 
> int __init kvmppc_booke_init(void)
> diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
> index 5fd1ba6..a1ff67d 100644
> --- a/arch/powerpc/kvm/booke.h
> +++ b/arch/powerpc/kvm/booke.h
> @@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
> 		giveup_fpu(current);
> #endif
> }
> +
> +static inline void kvmppc_clear_dbsr(void)
> +{
> +	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
> +}
> #endif /* __KVM_BOOKE_H__ */
> -- 
> 1.5.6.5
> 
> 


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

* RE: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-10 10:18     ` Alexander Graf
@ 2013-05-10 17:31       ` Bhushan Bharat-R65777
  -1 siblings, 0 replies; 28+ messages in thread
From: Bhushan Bharat-R65777 @ 2013-05-10 17:31 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Bhushan Bharat-R65777, kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Friday, May 10, 2013 3:48 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> tiejun.chen@windriver.com; Bhushan Bharat-R65777
> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> 
> 
> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
> 
> > This patch adds the debug stub support on booke/bookehv.
> > Now QEMU debug stub can use hw breakpoint, watchpoint and software
> > breakpoint to debug guest.
> >
> > This is how we save/restore debug register context when switching
> > between guest, userspace and kernel user-process:
> >
> > When QEMU is running
> > -> thread->debug_reg == QEMU debug register context.
> > -> Kernel will handle switching the debug register on context switch.
> > -> no vcpu_load() called
> >
> > QEMU makes ioctls (except RUN)
> > -> This will call vcpu_load()
> > -> should not change context.
> > -> Some ioctls can change vcpu debug register, context saved in
> > -> vcpu->debug_regs
> >
> > QEMU Makes RUN ioctl
> > -> Save thread->debug_reg on STACK
> > -> Store thread->debug_reg == vcpu->debug_reg load thread->debug_reg
> > -> RUN VCPU ( So thread points to vcpu context )
> >
> > Context switch happens When VCPU running
> > -> makes vcpu_load() should not load any context kernel loads the vcpu
> > -> context as thread->debug_regs points to vcpu context.
> >
> > On heavyweight_exit
> > -> Load the context saved on stack in thread->debug_reg
> >
> > Currently we do not support debug resource emulation to guest, On
> > debug exception, always exit to user space irrespective of user space
> > is expecting the debug exception or not. If this is unexpected
> > exception (breakpoint/watchpoint event not set by
> > userspace) then let us leave the action on user space. This is similar
> > to what it was before, only thing is that now we have proper exit
> > state available to user space.
> >
> > Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> > ---
> > arch/powerpc/include/asm/kvm_host.h |    3 +
> > arch/powerpc/include/uapi/asm/kvm.h |    1 +
> > arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
> > arch/powerpc/kvm/booke.h            |    5 +
> > 4 files changed, 233 insertions(+), 18 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/kvm_host.h
> > b/arch/powerpc/include/asm/kvm_host.h
> > index 838a577..1b29945 100644
> > --- a/arch/powerpc/include/asm/kvm_host.h
> > +++ b/arch/powerpc/include/asm/kvm_host.h
> > @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> > 	u32 eptcfg;
> > 	u32 epr;
> > 	u32 crit_save;
> > +	/* guest debug registers*/
> > 	struct debug_reg dbg_reg;
> > +	/* shadow debug registers */
> 
> Please be more verbose here. What exactly does this contain? Why do we need
> shadow and non-shadow registers? The comment as it is reads like
> 
>   /* Add one plus one */
>   x = 1 + 1;


/*
 * Shadow debug registers hold the debug register content
 * to be written in h/w debug register on behalf of guest
 * written value or user space written value.
 */


> 
> > +	struct debug_reg shadow_dbg_reg;
> > #endif
> > 	gpa_t paddr_accessed;
> > 	gva_t vaddr_accessed;
> > diff --git a/arch/powerpc/include/uapi/asm/kvm.h
> > b/arch/powerpc/include/uapi/asm/kvm.h
> > index ded0607..f5077c2 100644
> > --- a/arch/powerpc/include/uapi/asm/kvm.h
> > +++ b/arch/powerpc/include/uapi/asm/kvm.h
> > @@ -27,6 +27,7 @@
> > #define __KVM_HAVE_PPC_SMT
> > #define __KVM_HAVE_IRQCHIP
> > #define __KVM_HAVE_IRQ_LINE
> > +#define __KVM_HAVE_GUEST_DEBUG
> >
> > struct kvm_regs {
> > 	__u64 pc;
> > diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index
> > ef99536..6a44ad4 100644
> > --- a/arch/powerpc/kvm/booke.c
> > +++ b/arch/powerpc/kvm/booke.c
> > @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu
> > *vcpu) #endif }
> >
> > +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
> > +	/* Synchronize guest's desire to get debug interrupts into shadow
> > +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
> > +	vcpu->arch.shadow_msr &= ~MSR_DE;
> > +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
> > +
> > +	/* Force enable debug interrupts when user space wants to debug */
> > +	if (vcpu->guest_debug) {
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +		/*
> > +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> > +		 * visible MSR.
> > +		 */
> > +		vcpu->arch.shared->msr |= MSR_DE;
> > +#else
> > +		vcpu->arch.shadow_msr |= MSR_DE;
> > +		vcpu->arch.shared->msr &= ~MSR_DE;
> > +#endif
> > +	}
> > +}
> > +
> > /*
> >  * Helper function for "full" MSR writes.  No need to call this if
> > only
> >  * EE/CE/ME/DE/RI are changing.
> > @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> > 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> > 	kvmppc_vcpu_sync_spe(vcpu);
> > 	kvmppc_vcpu_sync_fpu(vcpu);
> > +	kvmppc_vcpu_sync_debug(vcpu);
> > }
> >
> > static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
> > -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
> > int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
> > 	int ret, s;
> > +	struct debug_reg debug;
> > #ifdef CONFIG_PPC_FPU
> > 	unsigned int fpscr;
> > 	int fpexc_mode;
> > @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct
> kvm_vcpu *vcpu)
> > 	kvmppc_load_guest_fp(vcpu);
> > #endif
> >
> > +	/*
> > +	 * Clear current->thread.dbcr0 so that kernel does not
> > +	 * restore h/w registers on context switch in vcpu running state.
> > +	 */
> 
> Incorrect comment?

Leftover from previous code, will remove this.

> 
> > +	/* Save thread->debug context on stack */
> 
> /* Switch to guest debug context */
> 
> > +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
> 
> debug = current->thread.debug;
> 
> > +	/* Load vcpu debug context in thread->debug */
> > +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> > +	       sizeof(struct debug_reg));
> 
> current->thread.debug = vcpu->arch.shadow_dbg_reg;
> 
> > +
> > +	switch_booke_debug_regs(&current->thread);
> > +
> > 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> >
> > 	/* No need for kvm_guest_exit. It's done in handle_exit.
> > 	   We also get here with interrupts enabled. */
> >
> > +	/* Restore userspace context in thread->dbcr0 from stack*/
> 
> /* Switch back to user space debug context */
> 
> > +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
> 
> current->thread.debug = debug;
> 
> > +	switch_booke_debug_regs(&current->thread);
> > +
> > #ifdef CONFIG_PPC_FPU
> > 	kvmppc_save_guest_fp(vcpu);
> >
> > @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu)
> > 	}
> > }
> >
> > +/*
> > + * Currently we do not support debug resource emulation to guest,
> > + * so always exit to user space irrespective of user space is
> > + * expecting the debug exception or not. This is unexpected event
> > + * and let us leave the action on user space.
> 
> Please rework your wording.
> 
> > + */
> > +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
> > +*vcpu) {
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +	u32 dbsr = vcpu->arch.dbsr;
> > +
> > +	run->debug.arch.status = 0;
> > +	run->debug.arch.address = vcpu->arch.pc;
> > +
> > +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> > +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> > +	} else {
> > +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> > +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> > +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> > +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> > +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> > +			run->debug.arch.address = dbg_reg->dac1;
> > +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> > +			run->debug.arch.address = dbg_reg->dac2;
> > +	}
> > +
> > +	return RESUME_HOST;
> > +}
> > +
> > static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
> > 	ulong r1, ip, msr, lr;
> > @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu
> *vcpu,
> > 	case BOOKE_INTERRUPT_CRITICAL:
> > 		unknown_exception(&regs);
> > 		break;
> > +	case BOOKE_INTERRUPT_DEBUG:
> > +		/* Save DBSR before preemption is enabled */
> > +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> > +		kvmppc_clear_dbsr();
> > +		break;
> > 	}
> > }
> >
> > @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
> > 	}
> >
> > 	case BOOKE_INTERRUPT_DEBUG: {
> > -		u32 dbsr;
> > -
> > -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> > -
> > -		/* clear IAC events in DBSR register */
> > -		dbsr = mfspr(SPRN_DBSR);
> > -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> > -		mtspr(SPRN_DBSR, dbsr);
> > -
> > -		run->exit_reason = KVM_EXIT_DEBUG;
> > +		r = kvmppc_handle_debug(run, vcpu);
> > +		if (r == RESUME_HOST)
> > +			run->exit_reason = KVM_EXIT_DEBUG;
> > 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> > -		r = RESUME_HOST;
> > 		break;
> > 	}
> >
> > @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> > 	kvmppc_set_msr(vcpu, 0);
> >
> > #ifndef CONFIG_KVM_BOOKE_HV
> > -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> > +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> > 	vcpu->arch.shadow_pid = 1;
> > 	vcpu->arch.shared->msr = 0;
> > #endif
> > @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
> struct kvm_one_reg *reg)
> > 	return r;
> > }
> >
> > -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> > -					 struct kvm_guest_debug *dbg)
> > -{
> > -	return -EINVAL;
> > -}
> > -
> > int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu
> > *fpu) {
> > 	return -ENOTSUPP;
> > @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> > 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
> > }
> >
> > +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
> > +uint64_t addr,
> 
> s/set/add/
> 
> > +				       int index)
> > +{
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	switch (index) {
> > +	case 0:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> > +		dbg_reg->iac1 = addr;
> > +		break;
> > +	case 1:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> > +		dbg_reg->iac2 = addr;
> > +		break;
> > +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> > +	case 2:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> > +		dbg_reg->iac3 = addr;
> > +		break;
> > +	case 3:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> > +		dbg_reg->iac4 = addr;
> > +		break;
> > +#endif
> > +	default:
> > +		return -EINVAL;
> > +	}
> 
>     dbg_reg->dbcr0 |= DBCR0_IDM;
> 
> > +	return 0;
> > +}
> > +
> > +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
> > +uint64_t addr,
> 
> s/set/add/
> 
> > +				       int type, int index)
> > +{
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	switch (index) {
> > +	case 0:
> > +		if (type & KVMPPC_DEBUG_WATCH_READ)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> > +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> > +		dbg_reg->dac1 = addr;
> > +		break;
> > +	case 1:
> > +		if (type & KVMPPC_DEBUG_WATCH_READ)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> > +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> > +		dbg_reg->dac2 = addr;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> 
>     dbg_reg->dbcr0 |= DBCR0_IDM;
> 
> > +	return 0;
> > +}
> > +
> > +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> > +					 struct kvm_guest_debug *dbg)
> > +{
> > +	struct debug_reg *dbg_reg;
> > +	int n, b = 0, w = 0;
> > +
> > +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> > +		/* Clear All debug events */
> > +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> > +		vcpu->guest_debug = 0;
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +		/*
> > +		 * When user space is not using the debug resources
> > +		 * then allow guest to change the MSR.DE.
> > +		 */
> > +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
> 
> guest_may_set_msr_de(vcpu, true);
> 
> > +		return 0;
> > +	}
> > +
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +	/*
> > +	 * When user space is using the debug resource then
> > +	 * do not allow guest to change the MSR.DE.
> > +	 */
> > +	vcpu->arch.shadow_msrp |= MSRP_DEP;
> > +#endif
> 
> guest_may_set_msr_de(vcpu, false);
> 
> > +	vcpu->guest_debug = dbg->control;
> > +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> > +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> > +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> > +
> > +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> > +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> > +
> > +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> > +		return 0;
> > +
> > +	/* Code below handles only HW breakpoints */
> > +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	/*
> > +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> > +	 * to occur when MSR.PR is set.
> > +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> > +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> > +	 * that debug events will not come in hypervisor (GS = 0).

Will rework the above comment as discussed.

> 
> This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what
> TCG does. There is no point in making HV KVM behave differently.

This comment is not valid.

> 
> > +	 */
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +	dbg_reg->dbcr1 = 0;
> > +	dbg_reg->dbcr2 = 0;
> > +#else
> > +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> > +			  DBCR1_IAC4US;
> > +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
> > +
> > +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> > +		uint64_t addr = dbg->arch.bp[n].addr;
> > +		uint32_t type = dbg->arch.bp[n].type;
> > +
> > +		if (type == KVMPPC_DEBUG_NONE)
> > +			continue;
> > +
> > +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> > +			     KVMPPC_DEBUG_WATCH_WRITE |
> > +			     KVMPPC_DEBUG_BREAKPOINT))
> > +			return -EINVAL;
> > +
> > +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> > +			/* Setting H/W breakpoint */
> > +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
> 
> Please pass dbg_reg into the function
> 
> > +				return -EINVAL;
> > +		} else {
> > +			/* Setting H/W watchpoint */
> > +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
> 
> here too
> 
> > +				return -EINVAL;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
> > 	vcpu->cpu = smp_processor_id();
> > @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
> > *vcpu) {
> > 	current->thread.kvm_vcpu = NULL;
> > 	vcpu->cpu = -1;
> > +
> > +	/* Disable all debug events */
> > +	mtspr(SPRN_DBCR0, 0x0);
> 
> Why? Wouldn't normal preemption handling take care of this already?

Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD and DBCR1/2.
So debug event will not be taken in host.

So yes, it is not needed here.

> 
> > +	/* Clear pending debug event in DBSR */
> > +	kvmppc_clear_dbsr();
> 
> Is there a chance we will ever have to do this? On debug exits from guest
> context we already clear dbsr.

DBSR can have events captured but not delivered as interrupt if MSR.DE is clear. I know with qemu debug stub we do not allow msr.de to be cleared by guest.

> 
> My question from the last review round still stands. What if a breakpoint for
> guest address 0xc0001234 is active and on the host 0xc0001234 happens to be at
> kvm_run? Will we get a breakpoint inside of the host context? That would be bad.
> We only want to get debug events when
> 
>   e500v2: MSR.PR == 1
>   e500mc: MSR.GS == 1

I responded last time also when you asked this question. Here I am pasting same answer again:
"No,
On e500v2, we uses DBCR1 and DBCR2 to not allow debug events when MSR.PR = 0 On e500mc+, we uses EPCR.DUVD to not allow debug events when in hypervisor mode.
"

This answer to your question as we discussed on IRC.

-Bharat

> 
> 
> Alex
> 
> > }
> >
> > int __init kvmppc_booke_init(void)
> > diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index
> > 5fd1ba6..a1ff67d 100644
> > --- a/arch/powerpc/kvm/booke.h
> > +++ b/arch/powerpc/kvm/booke.h
> > @@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu
> *vcpu)
> > 		giveup_fpu(current);
> > #endif
> > }
> > +
> > +static inline void kvmppc_clear_dbsr(void) {
> > +	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
> > +}
> > #endif /* __KVM_BOOKE_H__ */
> > --
> > 1.5.6.5
> >
> >
> 

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

* RE: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-10 17:31       ` Bhushan Bharat-R65777
  0 siblings, 0 replies; 28+ messages in thread
From: Bhushan Bharat-R65777 @ 2013-05-10 17:31 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Bhushan Bharat-R65777, kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Friday, May 10, 2013 3:48 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> tiejun.chen@windriver.com; Bhushan Bharat-R65777
> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> 
> 
> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
> 
> > This patch adds the debug stub support on booke/bookehv.
> > Now QEMU debug stub can use hw breakpoint, watchpoint and software
> > breakpoint to debug guest.
> >
> > This is how we save/restore debug register context when switching
> > between guest, userspace and kernel user-process:
> >
> > When QEMU is running
> > -> thread->debug_reg = QEMU debug register context.
> > -> Kernel will handle switching the debug register on context switch.
> > -> no vcpu_load() called
> >
> > QEMU makes ioctls (except RUN)
> > -> This will call vcpu_load()
> > -> should not change context.
> > -> Some ioctls can change vcpu debug register, context saved in
> > -> vcpu->debug_regs
> >
> > QEMU Makes RUN ioctl
> > -> Save thread->debug_reg on STACK
> > -> Store thread->debug_reg = vcpu->debug_reg load thread->debug_reg
> > -> RUN VCPU ( So thread points to vcpu context )
> >
> > Context switch happens When VCPU running
> > -> makes vcpu_load() should not load any context kernel loads the vcpu
> > -> context as thread->debug_regs points to vcpu context.
> >
> > On heavyweight_exit
> > -> Load the context saved on stack in thread->debug_reg
> >
> > Currently we do not support debug resource emulation to guest, On
> > debug exception, always exit to user space irrespective of user space
> > is expecting the debug exception or not. If this is unexpected
> > exception (breakpoint/watchpoint event not set by
> > userspace) then let us leave the action on user space. This is similar
> > to what it was before, only thing is that now we have proper exit
> > state available to user space.
> >
> > Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> > ---
> > arch/powerpc/include/asm/kvm_host.h |    3 +
> > arch/powerpc/include/uapi/asm/kvm.h |    1 +
> > arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
> > arch/powerpc/kvm/booke.h            |    5 +
> > 4 files changed, 233 insertions(+), 18 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/kvm_host.h
> > b/arch/powerpc/include/asm/kvm_host.h
> > index 838a577..1b29945 100644
> > --- a/arch/powerpc/include/asm/kvm_host.h
> > +++ b/arch/powerpc/include/asm/kvm_host.h
> > @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> > 	u32 eptcfg;
> > 	u32 epr;
> > 	u32 crit_save;
> > +	/* guest debug registers*/
> > 	struct debug_reg dbg_reg;
> > +	/* shadow debug registers */
> 
> Please be more verbose here. What exactly does this contain? Why do we need
> shadow and non-shadow registers? The comment as it is reads like
> 
>   /* Add one plus one */
>   x = 1 + 1;


/*
 * Shadow debug registers hold the debug register content
 * to be written in h/w debug register on behalf of guest
 * written value or user space written value.
 */


> 
> > +	struct debug_reg shadow_dbg_reg;
> > #endif
> > 	gpa_t paddr_accessed;
> > 	gva_t vaddr_accessed;
> > diff --git a/arch/powerpc/include/uapi/asm/kvm.h
> > b/arch/powerpc/include/uapi/asm/kvm.h
> > index ded0607..f5077c2 100644
> > --- a/arch/powerpc/include/uapi/asm/kvm.h
> > +++ b/arch/powerpc/include/uapi/asm/kvm.h
> > @@ -27,6 +27,7 @@
> > #define __KVM_HAVE_PPC_SMT
> > #define __KVM_HAVE_IRQCHIP
> > #define __KVM_HAVE_IRQ_LINE
> > +#define __KVM_HAVE_GUEST_DEBUG
> >
> > struct kvm_regs {
> > 	__u64 pc;
> > diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index
> > ef99536..6a44ad4 100644
> > --- a/arch/powerpc/kvm/booke.c
> > +++ b/arch/powerpc/kvm/booke.c
> > @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu
> > *vcpu) #endif }
> >
> > +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
> > +	/* Synchronize guest's desire to get debug interrupts into shadow
> > +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
> > +	vcpu->arch.shadow_msr &= ~MSR_DE;
> > +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
> > +
> > +	/* Force enable debug interrupts when user space wants to debug */
> > +	if (vcpu->guest_debug) {
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +		/*
> > +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> > +		 * visible MSR.
> > +		 */
> > +		vcpu->arch.shared->msr |= MSR_DE;
> > +#else
> > +		vcpu->arch.shadow_msr |= MSR_DE;
> > +		vcpu->arch.shared->msr &= ~MSR_DE;
> > +#endif
> > +	}
> > +}
> > +
> > /*
> >  * Helper function for "full" MSR writes.  No need to call this if
> > only
> >  * EE/CE/ME/DE/RI are changing.
> > @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> > 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> > 	kvmppc_vcpu_sync_spe(vcpu);
> > 	kvmppc_vcpu_sync_fpu(vcpu);
> > +	kvmppc_vcpu_sync_debug(vcpu);
> > }
> >
> > static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
> > -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
> > int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
> > 	int ret, s;
> > +	struct debug_reg debug;
> > #ifdef CONFIG_PPC_FPU
> > 	unsigned int fpscr;
> > 	int fpexc_mode;
> > @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct
> kvm_vcpu *vcpu)
> > 	kvmppc_load_guest_fp(vcpu);
> > #endif
> >
> > +	/*
> > +	 * Clear current->thread.dbcr0 so that kernel does not
> > +	 * restore h/w registers on context switch in vcpu running state.
> > +	 */
> 
> Incorrect comment?

Leftover from previous code, will remove this.

> 
> > +	/* Save thread->debug context on stack */
> 
> /* Switch to guest debug context */
> 
> > +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
> 
> debug = current->thread.debug;
> 
> > +	/* Load vcpu debug context in thread->debug */
> > +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> > +	       sizeof(struct debug_reg));
> 
> current->thread.debug = vcpu->arch.shadow_dbg_reg;
> 
> > +
> > +	switch_booke_debug_regs(&current->thread);
> > +
> > 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> >
> > 	/* No need for kvm_guest_exit. It's done in handle_exit.
> > 	   We also get here with interrupts enabled. */
> >
> > +	/* Restore userspace context in thread->dbcr0 from stack*/
> 
> /* Switch back to user space debug context */
> 
> > +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
> 
> current->thread.debug = debug;
> 
> > +	switch_booke_debug_regs(&current->thread);
> > +
> > #ifdef CONFIG_PPC_FPU
> > 	kvmppc_save_guest_fp(vcpu);
> >
> > @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu)
> > 	}
> > }
> >
> > +/*
> > + * Currently we do not support debug resource emulation to guest,
> > + * so always exit to user space irrespective of user space is
> > + * expecting the debug exception or not. This is unexpected event
> > + * and let us leave the action on user space.
> 
> Please rework your wording.
> 
> > + */
> > +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
> > +*vcpu) {
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +	u32 dbsr = vcpu->arch.dbsr;
> > +
> > +	run->debug.arch.status = 0;
> > +	run->debug.arch.address = vcpu->arch.pc;
> > +
> > +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> > +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> > +	} else {
> > +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> > +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> > +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> > +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> > +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> > +			run->debug.arch.address = dbg_reg->dac1;
> > +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> > +			run->debug.arch.address = dbg_reg->dac2;
> > +	}
> > +
> > +	return RESUME_HOST;
> > +}
> > +
> > static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
> > 	ulong r1, ip, msr, lr;
> > @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu
> *vcpu,
> > 	case BOOKE_INTERRUPT_CRITICAL:
> > 		unknown_exception(&regs);
> > 		break;
> > +	case BOOKE_INTERRUPT_DEBUG:
> > +		/* Save DBSR before preemption is enabled */
> > +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> > +		kvmppc_clear_dbsr();
> > +		break;
> > 	}
> > }
> >
> > @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
> > 	}
> >
> > 	case BOOKE_INTERRUPT_DEBUG: {
> > -		u32 dbsr;
> > -
> > -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> > -
> > -		/* clear IAC events in DBSR register */
> > -		dbsr = mfspr(SPRN_DBSR);
> > -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> > -		mtspr(SPRN_DBSR, dbsr);
> > -
> > -		run->exit_reason = KVM_EXIT_DEBUG;
> > +		r = kvmppc_handle_debug(run, vcpu);
> > +		if (r = RESUME_HOST)
> > +			run->exit_reason = KVM_EXIT_DEBUG;
> > 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> > -		r = RESUME_HOST;
> > 		break;
> > 	}
> >
> > @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> > 	kvmppc_set_msr(vcpu, 0);
> >
> > #ifndef CONFIG_KVM_BOOKE_HV
> > -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> > +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> > 	vcpu->arch.shadow_pid = 1;
> > 	vcpu->arch.shared->msr = 0;
> > #endif
> > @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
> struct kvm_one_reg *reg)
> > 	return r;
> > }
> >
> > -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> > -					 struct kvm_guest_debug *dbg)
> > -{
> > -	return -EINVAL;
> > -}
> > -
> > int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu
> > *fpu) {
> > 	return -ENOTSUPP;
> > @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> > 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
> > }
> >
> > +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
> > +uint64_t addr,
> 
> s/set/add/
> 
> > +				       int index)
> > +{
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	switch (index) {
> > +	case 0:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> > +		dbg_reg->iac1 = addr;
> > +		break;
> > +	case 1:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> > +		dbg_reg->iac2 = addr;
> > +		break;
> > +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> > +	case 2:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> > +		dbg_reg->iac3 = addr;
> > +		break;
> > +	case 3:
> > +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> > +		dbg_reg->iac4 = addr;
> > +		break;
> > +#endif
> > +	default:
> > +		return -EINVAL;
> > +	}
> 
>     dbg_reg->dbcr0 |= DBCR0_IDM;
> 
> > +	return 0;
> > +}
> > +
> > +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
> > +uint64_t addr,
> 
> s/set/add/
> 
> > +				       int type, int index)
> > +{
> > +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	switch (index) {
> > +	case 0:
> > +		if (type & KVMPPC_DEBUG_WATCH_READ)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> > +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> > +		dbg_reg->dac1 = addr;
> > +		break;
> > +	case 1:
> > +		if (type & KVMPPC_DEBUG_WATCH_READ)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> > +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> > +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> > +		dbg_reg->dac2 = addr;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> 
>     dbg_reg->dbcr0 |= DBCR0_IDM;
> 
> > +	return 0;
> > +}
> > +
> > +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> > +					 struct kvm_guest_debug *dbg)
> > +{
> > +	struct debug_reg *dbg_reg;
> > +	int n, b = 0, w = 0;
> > +
> > +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> > +		/* Clear All debug events */
> > +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> > +		vcpu->guest_debug = 0;
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +		/*
> > +		 * When user space is not using the debug resources
> > +		 * then allow guest to change the MSR.DE.
> > +		 */
> > +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
> 
> guest_may_set_msr_de(vcpu, true);
> 
> > +		return 0;
> > +	}
> > +
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +	/*
> > +	 * When user space is using the debug resource then
> > +	 * do not allow guest to change the MSR.DE.
> > +	 */
> > +	vcpu->arch.shadow_msrp |= MSRP_DEP;
> > +#endif
> 
> guest_may_set_msr_de(vcpu, false);
> 
> > +	vcpu->guest_debug = dbg->control;
> > +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> > +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> > +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> > +
> > +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> > +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> > +
> > +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> > +		return 0;
> > +
> > +	/* Code below handles only HW breakpoints */
> > +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> > +
> > +	/*
> > +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> > +	 * to occur when MSR.PR is set.
> > +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> > +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> > +	 * that debug events will not come in hypervisor (GS = 0).

Will rework the above comment as discussed.

> 
> This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what
> TCG does. There is no point in making HV KVM behave differently.

This comment is not valid.

> 
> > +	 */
> > +#ifdef CONFIG_KVM_BOOKE_HV
> > +	dbg_reg->dbcr1 = 0;
> > +	dbg_reg->dbcr2 = 0;
> > +#else
> > +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> > +			  DBCR1_IAC4US;
> > +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
> > +
> > +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> > +		uint64_t addr = dbg->arch.bp[n].addr;
> > +		uint32_t type = dbg->arch.bp[n].type;
> > +
> > +		if (type = KVMPPC_DEBUG_NONE)
> > +			continue;
> > +
> > +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> > +			     KVMPPC_DEBUG_WATCH_WRITE |
> > +			     KVMPPC_DEBUG_BREAKPOINT))
> > +			return -EINVAL;
> > +
> > +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> > +			/* Setting H/W breakpoint */
> > +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
> 
> Please pass dbg_reg into the function
> 
> > +				return -EINVAL;
> > +		} else {
> > +			/* Setting H/W watchpoint */
> > +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
> 
> here too
> 
> > +				return -EINVAL;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
> > 	vcpu->cpu = smp_processor_id();
> > @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
> > *vcpu) {
> > 	current->thread.kvm_vcpu = NULL;
> > 	vcpu->cpu = -1;
> > +
> > +	/* Disable all debug events */
> > +	mtspr(SPRN_DBCR0, 0x0);
> 
> Why? Wouldn't normal preemption handling take care of this already?

Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD and DBCR1/2.
So debug event will not be taken in host.

So yes, it is not needed here.

> 
> > +	/* Clear pending debug event in DBSR */
> > +	kvmppc_clear_dbsr();
> 
> Is there a chance we will ever have to do this? On debug exits from guest
> context we already clear dbsr.

DBSR can have events captured but not delivered as interrupt if MSR.DE is clear. I know with qemu debug stub we do not allow msr.de to be cleared by guest.

> 
> My question from the last review round still stands. What if a breakpoint for
> guest address 0xc0001234 is active and on the host 0xc0001234 happens to be at
> kvm_run? Will we get a breakpoint inside of the host context? That would be bad.
> We only want to get debug events when
> 
>   e500v2: MSR.PR = 1
>   e500mc: MSR.GS = 1

I responded last time also when you asked this question. Here I am pasting same answer again:
"No,
On e500v2, we uses DBCR1 and DBCR2 to not allow debug events when MSR.PR = 0 On e500mc+, we uses EPCR.DUVD to not allow debug events when in hypervisor mode.
"

This answer to your question as we discussed on IRC.

-Bharat

> 
> 
> Alex
> 
> > }
> >
> > int __init kvmppc_booke_init(void)
> > diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index
> > 5fd1ba6..a1ff67d 100644
> > --- a/arch/powerpc/kvm/booke.h
> > +++ b/arch/powerpc/kvm/booke.h
> > @@ -129,4 +129,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu
> *vcpu)
> > 		giveup_fpu(current);
> > #endif
> > }
> > +
> > +static inline void kvmppc_clear_dbsr(void) {
> > +	mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
> > +}
> > #endif /* __KVM_BOOKE_H__ */
> > --
> > 1.5.6.5
> >
> >
> 



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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-10 17:31       ` Bhushan Bharat-R65777
@ 2013-05-10 17:44         ` Alexander Graf
  -1 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10 17:44 UTC (permalink / raw)
  To: Bhushan Bharat-R65777; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen


On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:

> 
> 
>> -----Original Message-----
>> From: Alexander Graf [mailto:agraf@suse.de]
>> Sent: Friday, May 10, 2013 3:48 PM
>> To: Bhushan Bharat-R65777
>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>> tiejun.chen@windriver.com; Bhushan Bharat-R65777
>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>> 
>> 
>> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
>> 
>>> This patch adds the debug stub support on booke/bookehv.
>>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
>>> breakpoint to debug guest.
>>> 
>>> This is how we save/restore debug register context when switching
>>> between guest, userspace and kernel user-process:
>>> 
>>> When QEMU is running
>>> -> thread->debug_reg == QEMU debug register context.
>>> -> Kernel will handle switching the debug register on context switch.
>>> -> no vcpu_load() called
>>> 
>>> QEMU makes ioctls (except RUN)
>>> -> This will call vcpu_load()
>>> -> should not change context.
>>> -> Some ioctls can change vcpu debug register, context saved in
>>> -> vcpu->debug_regs
>>> 
>>> QEMU Makes RUN ioctl
>>> -> Save thread->debug_reg on STACK
>>> -> Store thread->debug_reg == vcpu->debug_reg load thread->debug_reg
>>> -> RUN VCPU ( So thread points to vcpu context )
>>> 
>>> Context switch happens When VCPU running
>>> -> makes vcpu_load() should not load any context kernel loads the vcpu
>>> -> context as thread->debug_regs points to vcpu context.
>>> 
>>> On heavyweight_exit
>>> -> Load the context saved on stack in thread->debug_reg
>>> 
>>> Currently we do not support debug resource emulation to guest, On
>>> debug exception, always exit to user space irrespective of user space
>>> is expecting the debug exception or not. If this is unexpected
>>> exception (breakpoint/watchpoint event not set by
>>> userspace) then let us leave the action on user space. This is similar
>>> to what it was before, only thing is that now we have proper exit
>>> state available to user space.
>>> 
>>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
>>> ---
>>> arch/powerpc/include/asm/kvm_host.h |    3 +
>>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
>>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
>>> arch/powerpc/kvm/booke.h            |    5 +
>>> 4 files changed, 233 insertions(+), 18 deletions(-)
>>> 
>>> diff --git a/arch/powerpc/include/asm/kvm_host.h
>>> b/arch/powerpc/include/asm/kvm_host.h
>>> index 838a577..1b29945 100644
>>> --- a/arch/powerpc/include/asm/kvm_host.h
>>> +++ b/arch/powerpc/include/asm/kvm_host.h
>>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
>>> 	u32 eptcfg;
>>> 	u32 epr;
>>> 	u32 crit_save;
>>> +	/* guest debug registers*/
>>> 	struct debug_reg dbg_reg;
>>> +	/* shadow debug registers */
>> 
>> Please be more verbose here. What exactly does this contain? Why do we need
>> shadow and non-shadow registers? The comment as it is reads like
>> 
>>  /* Add one plus one */
>>  x = 1 + 1;
> 
> 
> /*
> * Shadow debug registers hold the debug register content
> * to be written in h/w debug register on behalf of guest
> * written value or user space written value.
> */

/* hardware visible debug registers when in guest state */

> 
> 
>> 
>>> +	struct debug_reg shadow_dbg_reg;
>>> #endif
>>> 	gpa_t paddr_accessed;
>>> 	gva_t vaddr_accessed;
>>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
>>> b/arch/powerpc/include/uapi/asm/kvm.h
>>> index ded0607..f5077c2 100644
>>> --- a/arch/powerpc/include/uapi/asm/kvm.h
>>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
>>> @@ -27,6 +27,7 @@
>>> #define __KVM_HAVE_PPC_SMT
>>> #define __KVM_HAVE_IRQCHIP
>>> #define __KVM_HAVE_IRQ_LINE
>>> +#define __KVM_HAVE_GUEST_DEBUG
>>> 
>>> struct kvm_regs {
>>> 	__u64 pc;
>>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index
>>> ef99536..6a44ad4 100644
>>> --- a/arch/powerpc/kvm/booke.c
>>> +++ b/arch/powerpc/kvm/booke.c
>>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu
>>> *vcpu) #endif }
>>> 
>>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
>>> +	/* Synchronize guest's desire to get debug interrupts into shadow
>>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
>>> +	vcpu->arch.shadow_msr &= ~MSR_DE;
>>> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
>>> +
>>> +	/* Force enable debug interrupts when user space wants to debug */
>>> +	if (vcpu->guest_debug) {
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +		/*
>>> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
>>> +		 * visible MSR.
>>> +		 */
>>> +		vcpu->arch.shared->msr |= MSR_DE;
>>> +#else
>>> +		vcpu->arch.shadow_msr |= MSR_DE;
>>> +		vcpu->arch.shared->msr &= ~MSR_DE;
>>> +#endif
>>> +	}
>>> +}
>>> +
>>> /*
>>> * Helper function for "full" MSR writes.  No need to call this if
>>> only
>>> * EE/CE/ME/DE/RI are changing.
>>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
>>> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
>>> 	kvmppc_vcpu_sync_spe(vcpu);
>>> 	kvmppc_vcpu_sync_fpu(vcpu);
>>> +	kvmppc_vcpu_sync_debug(vcpu);
>>> }
>>> 
>>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
>>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
>>> int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
>>> 	int ret, s;
>>> +	struct debug_reg debug;
>>> #ifdef CONFIG_PPC_FPU
>>> 	unsigned int fpscr;
>>> 	int fpexc_mode;
>>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct
>> kvm_vcpu *vcpu)
>>> 	kvmppc_load_guest_fp(vcpu);
>>> #endif
>>> 
>>> +	/*
>>> +	 * Clear current->thread.dbcr0 so that kernel does not
>>> +	 * restore h/w registers on context switch in vcpu running state.
>>> +	 */
>> 
>> Incorrect comment?
> 
> Leftover from previous code, will remove this.
> 
>> 
>>> +	/* Save thread->debug context on stack */
>> 
>> /* Switch to guest debug context */
>> 
>>> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
>> 
>> debug = current->thread.debug;
>> 
>>> +	/* Load vcpu debug context in thread->debug */
>>> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
>>> +	       sizeof(struct debug_reg));
>> 
>> current->thread.debug = vcpu->arch.shadow_dbg_reg;
>> 
>>> +
>>> +	switch_booke_debug_regs(&current->thread);
>>> +
>>> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
>>> 
>>> 	/* No need for kvm_guest_exit. It's done in handle_exit.
>>> 	   We also get here with interrupts enabled. */
>>> 
>>> +	/* Restore userspace context in thread->dbcr0 from stack*/
>> 
>> /* Switch back to user space debug context */
>> 
>>> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
>> 
>> current->thread.debug = debug;
>> 
>>> +	switch_booke_debug_regs(&current->thread);
>>> +
>>> #ifdef CONFIG_PPC_FPU
>>> 	kvmppc_save_guest_fp(vcpu);
>>> 
>>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct
>> kvm_vcpu *vcpu)
>>> 	}
>>> }
>>> 
>>> +/*
>>> + * Currently we do not support debug resource emulation to guest,
>>> + * so always exit to user space irrespective of user space is
>>> + * expecting the debug exception or not. This is unexpected event
>>> + * and let us leave the action on user space.
>> 
>> Please rework your wording.
>> 
>>> + */
>>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
>>> +*vcpu) {
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +	u32 dbsr = vcpu->arch.dbsr;
>>> +
>>> +	run->debug.arch.status = 0;
>>> +	run->debug.arch.address = vcpu->arch.pc;
>>> +
>>> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
>>> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
>>> +	} else {
>>> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
>>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
>>> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
>>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
>>> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
>>> +			run->debug.arch.address = dbg_reg->dac1;
>>> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
>>> +			run->debug.arch.address = dbg_reg->dac2;
>>> +	}
>>> +
>>> +	return RESUME_HOST;
>>> +}
>>> +
>>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
>>> 	ulong r1, ip, msr, lr;
>>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu
>> *vcpu,
>>> 	case BOOKE_INTERRUPT_CRITICAL:
>>> 		unknown_exception(&regs);
>>> 		break;
>>> +	case BOOKE_INTERRUPT_DEBUG:
>>> +		/* Save DBSR before preemption is enabled */
>>> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
>>> +		kvmppc_clear_dbsr();
>>> +		break;
>>> 	}
>>> }
>>> 
>>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
>> kvm_vcpu *vcpu,
>>> 	}
>>> 
>>> 	case BOOKE_INTERRUPT_DEBUG: {
>>> -		u32 dbsr;
>>> -
>>> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
>>> -
>>> -		/* clear IAC events in DBSR register */
>>> -		dbsr = mfspr(SPRN_DBSR);
>>> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
>>> -		mtspr(SPRN_DBSR, dbsr);
>>> -
>>> -		run->exit_reason = KVM_EXIT_DEBUG;
>>> +		r = kvmppc_handle_debug(run, vcpu);
>>> +		if (r == RESUME_HOST)
>>> +			run->exit_reason = KVM_EXIT_DEBUG;
>>> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
>>> -		r = RESUME_HOST;
>>> 		break;
>>> 	}
>>> 
>>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>>> 	kvmppc_set_msr(vcpu, 0);
>>> 
>>> #ifndef CONFIG_KVM_BOOKE_HV
>>> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
>>> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
>>> 	vcpu->arch.shadow_pid = 1;
>>> 	vcpu->arch.shared->msr = 0;
>>> #endif
>>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
>> struct kvm_one_reg *reg)
>>> 	return r;
>>> }
>>> 
>>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>> -					 struct kvm_guest_debug *dbg)
>>> -{
>>> -	return -EINVAL;
>>> -}
>>> -
>>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu
>>> *fpu) {
>>> 	return -ENOTSUPP;
>>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
>>> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
>>> }
>>> 
>>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
>>> +uint64_t addr,
>> 
>> s/set/add/
>> 
>>> +				       int index)
>>> +{
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	switch (index) {
>>> +	case 0:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
>>> +		dbg_reg->iac1 = addr;
>>> +		break;
>>> +	case 1:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
>>> +		dbg_reg->iac2 = addr;
>>> +		break;
>>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
>>> +	case 2:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
>>> +		dbg_reg->iac3 = addr;
>>> +		break;
>>> +	case 3:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
>>> +		dbg_reg->iac4 = addr;
>>> +		break;
>>> +#endif
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>> 
>>    dbg_reg->dbcr0 |= DBCR0_IDM;
>> 
>>> +	return 0;
>>> +}
>>> +
>>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
>>> +uint64_t addr,
>> 
>> s/set/add/
>> 
>>> +				       int type, int index)
>>> +{
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	switch (index) {
>>> +	case 0:
>>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
>>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
>>> +		dbg_reg->dac1 = addr;
>>> +		break;
>>> +	case 1:
>>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
>>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
>>> +		dbg_reg->dac2 = addr;
>>> +		break;
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>> 
>>    dbg_reg->dbcr0 |= DBCR0_IDM;
>> 
>>> +	return 0;
>>> +}
>>> +
>>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>> +					 struct kvm_guest_debug *dbg)
>>> +{
>>> +	struct debug_reg *dbg_reg;
>>> +	int n, b = 0, w = 0;
>>> +
>>> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
>>> +		/* Clear All debug events */
>>> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>> +		vcpu->guest_debug = 0;
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +		/*
>>> +		 * When user space is not using the debug resources
>>> +		 * then allow guest to change the MSR.DE.
>>> +		 */
>>> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
>> 
>> guest_may_set_msr_de(vcpu, true);
>> 
>>> +		return 0;
>>> +	}
>>> +
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +	/*
>>> +	 * When user space is using the debug resource then
>>> +	 * do not allow guest to change the MSR.DE.
>>> +	 */
>>> +	vcpu->arch.shadow_msrp |= MSRP_DEP;
>>> +#endif
>> 
>> guest_may_set_msr_de(vcpu, false);
>> 
>>> +	vcpu->guest_debug = dbg->control;
>>> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
>>> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
>>> +
>>> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>>> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
>>> +
>>> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
>>> +		return 0;
>>> +
>>> +	/* Code below handles only HW breakpoints */
>>> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	/*
>>> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
>>> +	 * to occur when MSR.PR is set.
>>> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
>>> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
>>> +	 * that debug events will not come in hypervisor (GS = 0).
> 
> Will rework the above comment as discussed.
> 
>> 
>> This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what
>> TCG does. There is no point in making HV KVM behave differently.
> 
> This comment is not valid.
> 
>> 
>>> +	 */
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +	dbg_reg->dbcr1 = 0;
>>> +	dbg_reg->dbcr2 = 0;
>>> +#else
>>> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
>>> +			  DBCR1_IAC4US;
>>> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
>>> +
>>> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
>>> +		uint64_t addr = dbg->arch.bp[n].addr;
>>> +		uint32_t type = dbg->arch.bp[n].type;
>>> +
>>> +		if (type == KVMPPC_DEBUG_NONE)
>>> +			continue;
>>> +
>>> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
>>> +			     KVMPPC_DEBUG_WATCH_WRITE |
>>> +			     KVMPPC_DEBUG_BREAKPOINT))
>>> +			return -EINVAL;
>>> +
>>> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
>>> +			/* Setting H/W breakpoint */
>>> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
>> 
>> Please pass dbg_reg into the function
>> 
>>> +				return -EINVAL;
>>> +		} else {
>>> +			/* Setting H/W watchpoint */
>>> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
>> 
>> here too
>> 
>>> +				return -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
>>> 	vcpu->cpu = smp_processor_id();
>>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
>>> *vcpu) {
>>> 	current->thread.kvm_vcpu = NULL;
>>> 	vcpu->cpu = -1;
>>> +
>>> +	/* Disable all debug events */
>>> +	mtspr(SPRN_DBCR0, 0x0);
>> 
>> Why? Wouldn't normal preemption handling take care of this already?
> 
> Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD and DBCR1/2.
> So debug event will not be taken in host.
> 
> So yes, it is not needed here.
> 
>> 
>>> +	/* Clear pending debug event in DBSR */
>>> +	kvmppc_clear_dbsr();
>> 
>> Is there a chance we will ever have to do this? On debug exits from guest
>> context we already clear dbsr.
> 
> DBSR can have events captured but not delivered as interrupt if MSR.DE is clear. I know with qemu debug stub we do not allow msr.de to be cleared by guest.

I see. In that case we'd have to save the original DBSR value into vcpu->arch though, no? Otherwise we might lose guest debug events on preemption if we simply clear it.


Alex

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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-10 17:44         ` Alexander Graf
  0 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-10 17:44 UTC (permalink / raw)
  To: Bhushan Bharat-R65777; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen


On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:

> 
> 
>> -----Original Message-----
>> From: Alexander Graf [mailto:agraf@suse.de]
>> Sent: Friday, May 10, 2013 3:48 PM
>> To: Bhushan Bharat-R65777
>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>> tiejun.chen@windriver.com; Bhushan Bharat-R65777
>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>> 
>> 
>> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
>> 
>>> This patch adds the debug stub support on booke/bookehv.
>>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
>>> breakpoint to debug guest.
>>> 
>>> This is how we save/restore debug register context when switching
>>> between guest, userspace and kernel user-process:
>>> 
>>> When QEMU is running
>>> -> thread->debug_reg = QEMU debug register context.
>>> -> Kernel will handle switching the debug register on context switch.
>>> -> no vcpu_load() called
>>> 
>>> QEMU makes ioctls (except RUN)
>>> -> This will call vcpu_load()
>>> -> should not change context.
>>> -> Some ioctls can change vcpu debug register, context saved in
>>> -> vcpu->debug_regs
>>> 
>>> QEMU Makes RUN ioctl
>>> -> Save thread->debug_reg on STACK
>>> -> Store thread->debug_reg = vcpu->debug_reg load thread->debug_reg
>>> -> RUN VCPU ( So thread points to vcpu context )
>>> 
>>> Context switch happens When VCPU running
>>> -> makes vcpu_load() should not load any context kernel loads the vcpu
>>> -> context as thread->debug_regs points to vcpu context.
>>> 
>>> On heavyweight_exit
>>> -> Load the context saved on stack in thread->debug_reg
>>> 
>>> Currently we do not support debug resource emulation to guest, On
>>> debug exception, always exit to user space irrespective of user space
>>> is expecting the debug exception or not. If this is unexpected
>>> exception (breakpoint/watchpoint event not set by
>>> userspace) then let us leave the action on user space. This is similar
>>> to what it was before, only thing is that now we have proper exit
>>> state available to user space.
>>> 
>>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
>>> ---
>>> arch/powerpc/include/asm/kvm_host.h |    3 +
>>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
>>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++---
>>> arch/powerpc/kvm/booke.h            |    5 +
>>> 4 files changed, 233 insertions(+), 18 deletions(-)
>>> 
>>> diff --git a/arch/powerpc/include/asm/kvm_host.h
>>> b/arch/powerpc/include/asm/kvm_host.h
>>> index 838a577..1b29945 100644
>>> --- a/arch/powerpc/include/asm/kvm_host.h
>>> +++ b/arch/powerpc/include/asm/kvm_host.h
>>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
>>> 	u32 eptcfg;
>>> 	u32 epr;
>>> 	u32 crit_save;
>>> +	/* guest debug registers*/
>>> 	struct debug_reg dbg_reg;
>>> +	/* shadow debug registers */
>> 
>> Please be more verbose here. What exactly does this contain? Why do we need
>> shadow and non-shadow registers? The comment as it is reads like
>> 
>>  /* Add one plus one */
>>  x = 1 + 1;
> 
> 
> /*
> * Shadow debug registers hold the debug register content
> * to be written in h/w debug register on behalf of guest
> * written value or user space written value.
> */

/* hardware visible debug registers when in guest state */

> 
> 
>> 
>>> +	struct debug_reg shadow_dbg_reg;
>>> #endif
>>> 	gpa_t paddr_accessed;
>>> 	gva_t vaddr_accessed;
>>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
>>> b/arch/powerpc/include/uapi/asm/kvm.h
>>> index ded0607..f5077c2 100644
>>> --- a/arch/powerpc/include/uapi/asm/kvm.h
>>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
>>> @@ -27,6 +27,7 @@
>>> #define __KVM_HAVE_PPC_SMT
>>> #define __KVM_HAVE_IRQCHIP
>>> #define __KVM_HAVE_IRQ_LINE
>>> +#define __KVM_HAVE_GUEST_DEBUG
>>> 
>>> struct kvm_regs {
>>> 	__u64 pc;
>>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index
>>> ef99536..6a44ad4 100644
>>> --- a/arch/powerpc/kvm/booke.c
>>> +++ b/arch/powerpc/kvm/booke.c
>>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu
>>> *vcpu) #endif }
>>> 
>>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
>>> +	/* Synchronize guest's desire to get debug interrupts into shadow
>>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
>>> +	vcpu->arch.shadow_msr &= ~MSR_DE;
>>> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
>>> +
>>> +	/* Force enable debug interrupts when user space wants to debug */
>>> +	if (vcpu->guest_debug) {
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +		/*
>>> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
>>> +		 * visible MSR.
>>> +		 */
>>> +		vcpu->arch.shared->msr |= MSR_DE;
>>> +#else
>>> +		vcpu->arch.shadow_msr |= MSR_DE;
>>> +		vcpu->arch.shared->msr &= ~MSR_DE;
>>> +#endif
>>> +	}
>>> +}
>>> +
>>> /*
>>> * Helper function for "full" MSR writes.  No need to call this if
>>> only
>>> * EE/CE/ME/DE/RI are changing.
>>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
>>> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
>>> 	kvmppc_vcpu_sync_spe(vcpu);
>>> 	kvmppc_vcpu_sync_fpu(vcpu);
>>> +	kvmppc_vcpu_sync_debug(vcpu);
>>> }
>>> 
>>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
>>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
>>> int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
>>> 	int ret, s;
>>> +	struct debug_reg debug;
>>> #ifdef CONFIG_PPC_FPU
>>> 	unsigned int fpscr;
>>> 	int fpexc_mode;
>>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct
>> kvm_vcpu *vcpu)
>>> 	kvmppc_load_guest_fp(vcpu);
>>> #endif
>>> 
>>> +	/*
>>> +	 * Clear current->thread.dbcr0 so that kernel does not
>>> +	 * restore h/w registers on context switch in vcpu running state.
>>> +	 */
>> 
>> Incorrect comment?
> 
> Leftover from previous code, will remove this.
> 
>> 
>>> +	/* Save thread->debug context on stack */
>> 
>> /* Switch to guest debug context */
>> 
>>> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
>> 
>> debug = current->thread.debug;
>> 
>>> +	/* Load vcpu debug context in thread->debug */
>>> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
>>> +	       sizeof(struct debug_reg));
>> 
>> current->thread.debug = vcpu->arch.shadow_dbg_reg;
>> 
>>> +
>>> +	switch_booke_debug_regs(&current->thread);
>>> +
>>> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
>>> 
>>> 	/* No need for kvm_guest_exit. It's done in handle_exit.
>>> 	   We also get here with interrupts enabled. */
>>> 
>>> +	/* Restore userspace context in thread->dbcr0 from stack*/
>> 
>> /* Switch back to user space debug context */
>> 
>>> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
>> 
>> current->thread.debug = debug;
>> 
>>> +	switch_booke_debug_regs(&current->thread);
>>> +
>>> #ifdef CONFIG_PPC_FPU
>>> 	kvmppc_save_guest_fp(vcpu);
>>> 
>>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run, struct
>> kvm_vcpu *vcpu)
>>> 	}
>>> }
>>> 
>>> +/*
>>> + * Currently we do not support debug resource emulation to guest,
>>> + * so always exit to user space irrespective of user space is
>>> + * expecting the debug exception or not. This is unexpected event
>>> + * and let us leave the action on user space.
>> 
>> Please rework your wording.
>> 
>>> + */
>>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
>>> +*vcpu) {
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +	u32 dbsr = vcpu->arch.dbsr;
>>> +
>>> +	run->debug.arch.status = 0;
>>> +	run->debug.arch.address = vcpu->arch.pc;
>>> +
>>> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
>>> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
>>> +	} else {
>>> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
>>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
>>> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
>>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
>>> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
>>> +			run->debug.arch.address = dbg_reg->dac1;
>>> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
>>> +			run->debug.arch.address = dbg_reg->dac2;
>>> +	}
>>> +
>>> +	return RESUME_HOST;
>>> +}
>>> +
>>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
>>> 	ulong r1, ip, msr, lr;
>>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu
>> *vcpu,
>>> 	case BOOKE_INTERRUPT_CRITICAL:
>>> 		unknown_exception(&regs);
>>> 		break;
>>> +	case BOOKE_INTERRUPT_DEBUG:
>>> +		/* Save DBSR before preemption is enabled */
>>> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
>>> +		kvmppc_clear_dbsr();
>>> +		break;
>>> 	}
>>> }
>>> 
>>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
>> kvm_vcpu *vcpu,
>>> 	}
>>> 
>>> 	case BOOKE_INTERRUPT_DEBUG: {
>>> -		u32 dbsr;
>>> -
>>> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
>>> -
>>> -		/* clear IAC events in DBSR register */
>>> -		dbsr = mfspr(SPRN_DBSR);
>>> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
>>> -		mtspr(SPRN_DBSR, dbsr);
>>> -
>>> -		run->exit_reason = KVM_EXIT_DEBUG;
>>> +		r = kvmppc_handle_debug(run, vcpu);
>>> +		if (r = RESUME_HOST)
>>> +			run->exit_reason = KVM_EXIT_DEBUG;
>>> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
>>> -		r = RESUME_HOST;
>>> 		break;
>>> 	}
>>> 
>>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>>> 	kvmppc_set_msr(vcpu, 0);
>>> 
>>> #ifndef CONFIG_KVM_BOOKE_HV
>>> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
>>> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
>>> 	vcpu->arch.shadow_pid = 1;
>>> 	vcpu->arch.shared->msr = 0;
>>> #endif
>>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
>> struct kvm_one_reg *reg)
>>> 	return r;
>>> }
>>> 
>>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>> -					 struct kvm_guest_debug *dbg)
>>> -{
>>> -	return -EINVAL;
>>> -}
>>> -
>>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu
>>> *fpu) {
>>> 	return -ENOTSUPP;
>>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
>>> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
>>> }
>>> 
>>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
>>> +uint64_t addr,
>> 
>> s/set/add/
>> 
>>> +				       int index)
>>> +{
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	switch (index) {
>>> +	case 0:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
>>> +		dbg_reg->iac1 = addr;
>>> +		break;
>>> +	case 1:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
>>> +		dbg_reg->iac2 = addr;
>>> +		break;
>>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
>>> +	case 2:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
>>> +		dbg_reg->iac3 = addr;
>>> +		break;
>>> +	case 3:
>>> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
>>> +		dbg_reg->iac4 = addr;
>>> +		break;
>>> +#endif
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>> 
>>    dbg_reg->dbcr0 |= DBCR0_IDM;
>> 
>>> +	return 0;
>>> +}
>>> +
>>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
>>> +uint64_t addr,
>> 
>> s/set/add/
>> 
>>> +				       int type, int index)
>>> +{
>>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	switch (index) {
>>> +	case 0:
>>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
>>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
>>> +		dbg_reg->dac1 = addr;
>>> +		break;
>>> +	case 1:
>>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
>>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
>>> +		dbg_reg->dac2 = addr;
>>> +		break;
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>> 
>>    dbg_reg->dbcr0 |= DBCR0_IDM;
>> 
>>> +	return 0;
>>> +}
>>> +
>>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>> +					 struct kvm_guest_debug *dbg)
>>> +{
>>> +	struct debug_reg *dbg_reg;
>>> +	int n, b = 0, w = 0;
>>> +
>>> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
>>> +		/* Clear All debug events */
>>> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>> +		vcpu->guest_debug = 0;
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +		/*
>>> +		 * When user space is not using the debug resources
>>> +		 * then allow guest to change the MSR.DE.
>>> +		 */
>>> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
>> 
>> guest_may_set_msr_de(vcpu, true);
>> 
>>> +		return 0;
>>> +	}
>>> +
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +	/*
>>> +	 * When user space is using the debug resource then
>>> +	 * do not allow guest to change the MSR.DE.
>>> +	 */
>>> +	vcpu->arch.shadow_msrp |= MSRP_DEP;
>>> +#endif
>> 
>> guest_may_set_msr_de(vcpu, false);
>> 
>>> +	vcpu->guest_debug = dbg->control;
>>> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
>>> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
>>> +
>>> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>>> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
>>> +
>>> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
>>> +		return 0;
>>> +
>>> +	/* Code below handles only HW breakpoints */
>>> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>> +
>>> +	/*
>>> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
>>> +	 * to occur when MSR.PR is set.
>>> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
>>> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
>>> +	 * that debug events will not come in hypervisor (GS = 0).
> 
> Will rework the above comment as discussed.
> 
>> 
>> This is still wrong. We want to trap in PR=1. It's what PR KVM does, it's what
>> TCG does. There is no point in making HV KVM behave differently.
> 
> This comment is not valid.
> 
>> 
>>> +	 */
>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>> +	dbg_reg->dbcr1 = 0;
>>> +	dbg_reg->dbcr2 = 0;
>>> +#else
>>> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
>>> +			  DBCR1_IAC4US;
>>> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
>>> +
>>> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
>>> +		uint64_t addr = dbg->arch.bp[n].addr;
>>> +		uint32_t type = dbg->arch.bp[n].type;
>>> +
>>> +		if (type = KVMPPC_DEBUG_NONE)
>>> +			continue;
>>> +
>>> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
>>> +			     KVMPPC_DEBUG_WATCH_WRITE |
>>> +			     KVMPPC_DEBUG_BREAKPOINT))
>>> +			return -EINVAL;
>>> +
>>> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
>>> +			/* Setting H/W breakpoint */
>>> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
>> 
>> Please pass dbg_reg into the function
>> 
>>> +				return -EINVAL;
>>> +		} else {
>>> +			/* Setting H/W watchpoint */
>>> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
>> 
>> here too
>> 
>>> +				return -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
>>> 	vcpu->cpu = smp_processor_id();
>>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
>>> *vcpu) {
>>> 	current->thread.kvm_vcpu = NULL;
>>> 	vcpu->cpu = -1;
>>> +
>>> +	/* Disable all debug events */
>>> +	mtspr(SPRN_DBCR0, 0x0);
>> 
>> Why? Wouldn't normal preemption handling take care of this already?
> 
> Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD and DBCR1/2.
> So debug event will not be taken in host.
> 
> So yes, it is not needed here.
> 
>> 
>>> +	/* Clear pending debug event in DBSR */
>>> +	kvmppc_clear_dbsr();
>> 
>> Is there a chance we will ever have to do this? On debug exits from guest
>> context we already clear dbsr.
> 
> DBSR can have events captured but not delivered as interrupt if MSR.DE is clear. I know with qemu debug stub we do not allow msr.de to be cleared by guest.

I see. In that case we'd have to save the original DBSR value into vcpu->arch though, no? Otherwise we might lose guest debug events on preemption if we simply clear it.


Alex


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

* RE: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-10 17:44         ` Alexander Graf
@ 2013-05-11 10:24           ` Bhushan Bharat-R65777
  -1 siblings, 0 replies; 28+ messages in thread
From: Bhushan Bharat-R65777 @ 2013-05-11 10:24 UTC (permalink / raw)
  To: Alexander Graf; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Friday, May 10, 2013 11:14 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> tiejun.chen@windriver.com
> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> 
> 
> On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:
> 
> >
> >
> >> -----Original Message-----
> >> From: Alexander Graf [mailto:agraf@suse.de]
> >> Sent: Friday, May 10, 2013 3:48 PM
> >> To: Bhushan Bharat-R65777
> >> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> >> tiejun.chen@windriver.com; Bhushan Bharat-R65777
> >> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> >>
> >>
> >> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
> >>
> >>> This patch adds the debug stub support on booke/bookehv.
> >>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
> >>> breakpoint to debug guest.
> >>>
> >>> This is how we save/restore debug register context when switching
> >>> between guest, userspace and kernel user-process:
> >>>
> >>> When QEMU is running
> >>> -> thread->debug_reg == QEMU debug register context.
> >>> -> Kernel will handle switching the debug register on context switch.
> >>> -> no vcpu_load() called
> >>>
> >>> QEMU makes ioctls (except RUN)
> >>> -> This will call vcpu_load()
> >>> -> should not change context.
> >>> -> Some ioctls can change vcpu debug register, context saved in
> >>> -> vcpu->debug_regs
> >>>
> >>> QEMU Makes RUN ioctl
> >>> -> Save thread->debug_reg on STACK
> >>> -> Store thread->debug_reg == vcpu->debug_reg load thread->debug_reg
> >>> -> RUN VCPU ( So thread points to vcpu context )
> >>>
> >>> Context switch happens When VCPU running
> >>> -> makes vcpu_load() should not load any context kernel loads the
> >>> -> vcpu context as thread->debug_regs points to vcpu context.
> >>>
> >>> On heavyweight_exit
> >>> -> Load the context saved on stack in thread->debug_reg
> >>>
> >>> Currently we do not support debug resource emulation to guest, On
> >>> debug exception, always exit to user space irrespective of user
> >>> space is expecting the debug exception or not. If this is unexpected
> >>> exception (breakpoint/watchpoint event not set by
> >>> userspace) then let us leave the action on user space. This is
> >>> similar to what it was before, only thing is that now we have proper
> >>> exit state available to user space.
> >>>
> >>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> >>> ---
> >>> arch/powerpc/include/asm/kvm_host.h |    3 +
> >>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
> >>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++-
> --
> >>> arch/powerpc/kvm/booke.h            |    5 +
> >>> 4 files changed, 233 insertions(+), 18 deletions(-)
> >>>
> >>> diff --git a/arch/powerpc/include/asm/kvm_host.h
> >>> b/arch/powerpc/include/asm/kvm_host.h
> >>> index 838a577..1b29945 100644
> >>> --- a/arch/powerpc/include/asm/kvm_host.h
> >>> +++ b/arch/powerpc/include/asm/kvm_host.h
> >>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> >>> 	u32 eptcfg;
> >>> 	u32 epr;
> >>> 	u32 crit_save;
> >>> +	/* guest debug registers*/
> >>> 	struct debug_reg dbg_reg;
> >>> +	/* shadow debug registers */
> >>
> >> Please be more verbose here. What exactly does this contain? Why do
> >> we need shadow and non-shadow registers? The comment as it is reads
> >> like
> >>
> >>  /* Add one plus one */
> >>  x = 1 + 1;
> >
> >
> > /*
> > * Shadow debug registers hold the debug register content
> > * to be written in h/w debug register on behalf of guest
> > * written value or user space written value.
> > */
> 
> /* hardware visible debug registers when in guest state */
> 
> >
> >
> >>
> >>> +	struct debug_reg shadow_dbg_reg;
> >>> #endif
> >>> 	gpa_t paddr_accessed;
> >>> 	gva_t vaddr_accessed;
> >>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
> >>> b/arch/powerpc/include/uapi/asm/kvm.h
> >>> index ded0607..f5077c2 100644
> >>> --- a/arch/powerpc/include/uapi/asm/kvm.h
> >>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> >>> @@ -27,6 +27,7 @@
> >>> #define __KVM_HAVE_PPC_SMT
> >>> #define __KVM_HAVE_IRQCHIP
> >>> #define __KVM_HAVE_IRQ_LINE
> >>> +#define __KVM_HAVE_GUEST_DEBUG
> >>>
> >>> struct kvm_regs {
> >>> 	__u64 pc;
> >>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> >>> index
> >>> ef99536..6a44ad4 100644
> >>> --- a/arch/powerpc/kvm/booke.c
> >>> +++ b/arch/powerpc/kvm/booke.c
> >>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct
> >>> kvm_vcpu
> >>> *vcpu) #endif }
> >>>
> >>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
> >>> +	/* Synchronize guest's desire to get debug interrupts into shadow
> >>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
> >>> +	vcpu->arch.shadow_msr &= ~MSR_DE;
> >>> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
> >>> +
> >>> +	/* Force enable debug interrupts when user space wants to debug */
> >>> +	if (vcpu->guest_debug) {
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +		/*
> >>> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> >>> +		 * visible MSR.
> >>> +		 */
> >>> +		vcpu->arch.shared->msr |= MSR_DE; #else
> >>> +		vcpu->arch.shadow_msr |= MSR_DE;
> >>> +		vcpu->arch.shared->msr &= ~MSR_DE; #endif
> >>> +	}
> >>> +}
> >>> +
> >>> /*
> >>> * Helper function for "full" MSR writes.  No need to call this if
> >>> only
> >>> * EE/CE/ME/DE/RI are changing.
> >>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> >>> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> >>> 	kvmppc_vcpu_sync_spe(vcpu);
> >>> 	kvmppc_vcpu_sync_fpu(vcpu);
> >>> +	kvmppc_vcpu_sync_debug(vcpu);
> >>> }
> >>>
> >>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
> >>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu
> >>> *vcpu) int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
> >>> 	int ret, s;
> >>> +	struct debug_reg debug;
> >>> #ifdef CONFIG_PPC_FPU
> >>> 	unsigned int fpscr;
> >>> 	int fpexc_mode;
> >>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run,
> >>> struct
> >> kvm_vcpu *vcpu)
> >>> 	kvmppc_load_guest_fp(vcpu);
> >>> #endif
> >>>
> >>> +	/*
> >>> +	 * Clear current->thread.dbcr0 so that kernel does not
> >>> +	 * restore h/w registers on context switch in vcpu running state.
> >>> +	 */
> >>
> >> Incorrect comment?
> >
> > Leftover from previous code, will remove this.
> >
> >>
> >>> +	/* Save thread->debug context on stack */
> >>
> >> /* Switch to guest debug context */
> >>
> >>> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
> >>
> >> debug = current->thread.debug;
> >>
> >>> +	/* Load vcpu debug context in thread->debug */
> >>> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> >>> +	       sizeof(struct debug_reg));
> >>
> >> current->thread.debug = vcpu->arch.shadow_dbg_reg;
> >>
> >>> +
> >>> +	switch_booke_debug_regs(&current->thread);
> >>> +
> >>> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> >>>
> >>> 	/* No need for kvm_guest_exit. It's done in handle_exit.
> >>> 	   We also get here with interrupts enabled. */
> >>>
> >>> +	/* Restore userspace context in thread->dbcr0 from stack*/
> >>
> >> /* Switch back to user space debug context */
> >>
> >>> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
> >>
> >> current->thread.debug = debug;
> >>
> >>> +	switch_booke_debug_regs(&current->thread);
> >>> +
> >>> #ifdef CONFIG_PPC_FPU
> >>> 	kvmppc_save_guest_fp(vcpu);
> >>>
> >>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run,
> >>> struct
> >> kvm_vcpu *vcpu)
> >>> 	}
> >>> }
> >>>
> >>> +/*
> >>> + * Currently we do not support debug resource emulation to guest,
> >>> + * so always exit to user space irrespective of user space is
> >>> + * expecting the debug exception or not. This is unexpected event
> >>> + * and let us leave the action on user space.
> >>
> >> Please rework your wording.
> >>
> >>> + */
> >>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
> >>> +*vcpu) {
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +	u32 dbsr = vcpu->arch.dbsr;
> >>> +
> >>> +	run->debug.arch.status = 0;
> >>> +	run->debug.arch.address = vcpu->arch.pc;
> >>> +
> >>> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> >>> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> >>> +	} else {
> >>> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> >>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> >>> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> >>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> >>> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> >>> +			run->debug.arch.address = dbg_reg->dac1;
> >>> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> >>> +			run->debug.arch.address = dbg_reg->dac2;
> >>> +	}
> >>> +
> >>> +	return RESUME_HOST;
> >>> +}
> >>> +
> >>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
> >>> 	ulong r1, ip, msr, lr;
> >>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct
> >>> kvm_vcpu
> >> *vcpu,
> >>> 	case BOOKE_INTERRUPT_CRITICAL:
> >>> 		unknown_exception(&regs);
> >>> 		break;
> >>> +	case BOOKE_INTERRUPT_DEBUG:
> >>> +		/* Save DBSR before preemption is enabled */
> >>> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> >>> +		kvmppc_clear_dbsr();
> >>> +		break;
> >>> 	}
> >>> }
> >>>
> >>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run,
> >>> struct
> >> kvm_vcpu *vcpu,
> >>> 	}
> >>>
> >>> 	case BOOKE_INTERRUPT_DEBUG: {
> >>> -		u32 dbsr;
> >>> -
> >>> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> >>> -
> >>> -		/* clear IAC events in DBSR register */
> >>> -		dbsr = mfspr(SPRN_DBSR);
> >>> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> >>> -		mtspr(SPRN_DBSR, dbsr);
> >>> -
> >>> -		run->exit_reason = KVM_EXIT_DEBUG;
> >>> +		r = kvmppc_handle_debug(run, vcpu);
> >>> +		if (r == RESUME_HOST)
> >>> +			run->exit_reason = KVM_EXIT_DEBUG;
> >>> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> >>> -		r = RESUME_HOST;
> >>> 		break;
> >>> 	}
> >>>
> >>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> >>> 	kvmppc_set_msr(vcpu, 0);
> >>>
> >>> #ifndef CONFIG_KVM_BOOKE_HV
> >>> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> >>> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> >>> 	vcpu->arch.shadow_pid = 1;
> >>> 	vcpu->arch.shared->msr = 0;
> >>> #endif
> >>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct
> >>> kvm_vcpu *vcpu,
> >> struct kvm_one_reg *reg)
> >>> 	return r;
> >>> }
> >>>
> >>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> >>> -					 struct kvm_guest_debug *dbg)
> >>> -{
> >>> -	return -EINVAL;
> >>> -}
> >>> -
> >>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct
> >>> kvm_fpu
> >>> *fpu) {
> >>> 	return -ENOTSUPP;
> >>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> >>> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS); }
> >>>
> >>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
> >>> +uint64_t addr,
> >>
> >> s/set/add/
> >>
> >>> +				       int index)
> >>> +{
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	switch (index) {
> >>> +	case 0:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> >>> +		dbg_reg->iac1 = addr;
> >>> +		break;
> >>> +	case 1:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> >>> +		dbg_reg->iac2 = addr;
> >>> +		break;
> >>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> >>> +	case 2:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> >>> +		dbg_reg->iac3 = addr;
> >>> +		break;
> >>> +	case 3:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> >>> +		dbg_reg->iac4 = addr;
> >>> +		break;
> >>> +#endif
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>
> >>    dbg_reg->dbcr0 |= DBCR0_IDM;
> >>
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
> >>> +uint64_t addr,
> >>
> >> s/set/add/
> >>
> >>> +				       int type, int index)
> >>> +{
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	switch (index) {
> >>> +	case 0:
> >>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> >>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> >>> +		dbg_reg->dac1 = addr;
> >>> +		break;
> >>> +	case 1:
> >>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> >>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> >>> +		dbg_reg->dac2 = addr;
> >>> +		break;
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>
> >>    dbg_reg->dbcr0 |= DBCR0_IDM;
> >>
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> >>> +					 struct kvm_guest_debug *dbg)
> >>> +{
> >>> +	struct debug_reg *dbg_reg;
> >>> +	int n, b = 0, w = 0;
> >>> +
> >>> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> >>> +		/* Clear All debug events */
> >>> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> >>> +		vcpu->guest_debug = 0;
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +		/*
> >>> +		 * When user space is not using the debug resources
> >>> +		 * then allow guest to change the MSR.DE.
> >>> +		 */
> >>> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
> >>
> >> guest_may_set_msr_de(vcpu, true);
> >>
> >>> +		return 0;
> >>> +	}
> >>> +
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +	/*
> >>> +	 * When user space is using the debug resource then
> >>> +	 * do not allow guest to change the MSR.DE.
> >>> +	 */
> >>> +	vcpu->arch.shadow_msrp |= MSRP_DEP; #endif
> >>
> >> guest_may_set_msr_de(vcpu, false);
> >>
> >>> +	vcpu->guest_debug = dbg->control;
> >>> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> >>> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> >>> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> >>> +
> >>> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> >>> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> >>> +
> >>> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> >>> +		return 0;
> >>> +
> >>> +	/* Code below handles only HW breakpoints */
> >>> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	/*
> >>> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> >>> +	 * to occur when MSR.PR is set.
> >>> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> >>> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> >>> +	 * that debug events will not come in hypervisor (GS = 0).
> >
> > Will rework the above comment as discussed.
> >
> >>
> >> This is still wrong. We want to trap in PR=1. It's what PR KVM does,
> >> it's what TCG does. There is no point in making HV KVM behave differently.
> >
> > This comment is not valid.
> >
> >>
> >>> +	 */
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +	dbg_reg->dbcr1 = 0;
> >>> +	dbg_reg->dbcr2 = 0;
> >>> +#else
> >>> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> >>> +			  DBCR1_IAC4US;
> >>> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
> >>> +
> >>> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> >>> +		uint64_t addr = dbg->arch.bp[n].addr;
> >>> +		uint32_t type = dbg->arch.bp[n].type;
> >>> +
> >>> +		if (type == KVMPPC_DEBUG_NONE)
> >>> +			continue;
> >>> +
> >>> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> >>> +			     KVMPPC_DEBUG_WATCH_WRITE |
> >>> +			     KVMPPC_DEBUG_BREAKPOINT))
> >>> +			return -EINVAL;
> >>> +
> >>> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> >>> +			/* Setting H/W breakpoint */
> >>> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
> >>
> >> Please pass dbg_reg into the function
> >>
> >>> +				return -EINVAL;
> >>> +		} else {
> >>> +			/* Setting H/W watchpoint */
> >>> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
> >>
> >> here too
> >>
> >>> +				return -EINVAL;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
> >>> 	vcpu->cpu = smp_processor_id();
> >>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
> >>> *vcpu) {
> >>> 	current->thread.kvm_vcpu = NULL;
> >>> 	vcpu->cpu = -1;
> >>> +
> >>> +	/* Disable all debug events */
> >>> +	mtspr(SPRN_DBCR0, 0x0);
> >>
> >> Why? Wouldn't normal preemption handling take care of this already?
> >
> > Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD
> and DBCR1/2.
> > So debug event will not be taken in host.
> >
> > So yes, it is not needed here.
> >
> >>
> >>> +	/* Clear pending debug event in DBSR */
> >>> +	kvmppc_clear_dbsr();
> >>
> >> Is there a chance we will ever have to do this? On debug exits from
> >> guest context we already clear dbsr.
> >
> > DBSR can have events captured but not delivered as interrupt if MSR.DE is
> clear. I know with qemu debug stub we do not allow msr.de to be cleared by
> guest.
> 
> I see. In that case we'd have to save the original DBSR value into vcpu->arch
> though, no? Otherwise we might lose guest debug events on preemption if we
> simply clear it.

We do not want to keep the delayed debug events as they does not carry much value. Example: taking h/w breakpoint at some other execution address.

-Bharat

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

* RE: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-11 10:24           ` Bhushan Bharat-R65777
  0 siblings, 0 replies; 28+ messages in thread
From: Bhushan Bharat-R65777 @ 2013-05-11 10:24 UTC (permalink / raw)
  To: Alexander Graf; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Friday, May 10, 2013 11:14 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> tiejun.chen@windriver.com
> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> 
> 
> On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:
> 
> >
> >
> >> -----Original Message-----
> >> From: Alexander Graf [mailto:agraf@suse.de]
> >> Sent: Friday, May 10, 2013 3:48 PM
> >> To: Bhushan Bharat-R65777
> >> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
> >> tiejun.chen@windriver.com; Bhushan Bharat-R65777
> >> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
> >>
> >>
> >> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
> >>
> >>> This patch adds the debug stub support on booke/bookehv.
> >>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
> >>> breakpoint to debug guest.
> >>>
> >>> This is how we save/restore debug register context when switching
> >>> between guest, userspace and kernel user-process:
> >>>
> >>> When QEMU is running
> >>> -> thread->debug_reg = QEMU debug register context.
> >>> -> Kernel will handle switching the debug register on context switch.
> >>> -> no vcpu_load() called
> >>>
> >>> QEMU makes ioctls (except RUN)
> >>> -> This will call vcpu_load()
> >>> -> should not change context.
> >>> -> Some ioctls can change vcpu debug register, context saved in
> >>> -> vcpu->debug_regs
> >>>
> >>> QEMU Makes RUN ioctl
> >>> -> Save thread->debug_reg on STACK
> >>> -> Store thread->debug_reg = vcpu->debug_reg load thread->debug_reg
> >>> -> RUN VCPU ( So thread points to vcpu context )
> >>>
> >>> Context switch happens When VCPU running
> >>> -> makes vcpu_load() should not load any context kernel loads the
> >>> -> vcpu context as thread->debug_regs points to vcpu context.
> >>>
> >>> On heavyweight_exit
> >>> -> Load the context saved on stack in thread->debug_reg
> >>>
> >>> Currently we do not support debug resource emulation to guest, On
> >>> debug exception, always exit to user space irrespective of user
> >>> space is expecting the debug exception or not. If this is unexpected
> >>> exception (breakpoint/watchpoint event not set by
> >>> userspace) then let us leave the action on user space. This is
> >>> similar to what it was before, only thing is that now we have proper
> >>> exit state available to user space.
> >>>
> >>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
> >>> ---
> >>> arch/powerpc/include/asm/kvm_host.h |    3 +
> >>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
> >>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++-
> --
> >>> arch/powerpc/kvm/booke.h            |    5 +
> >>> 4 files changed, 233 insertions(+), 18 deletions(-)
> >>>
> >>> diff --git a/arch/powerpc/include/asm/kvm_host.h
> >>> b/arch/powerpc/include/asm/kvm_host.h
> >>> index 838a577..1b29945 100644
> >>> --- a/arch/powerpc/include/asm/kvm_host.h
> >>> +++ b/arch/powerpc/include/asm/kvm_host.h
> >>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
> >>> 	u32 eptcfg;
> >>> 	u32 epr;
> >>> 	u32 crit_save;
> >>> +	/* guest debug registers*/
> >>> 	struct debug_reg dbg_reg;
> >>> +	/* shadow debug registers */
> >>
> >> Please be more verbose here. What exactly does this contain? Why do
> >> we need shadow and non-shadow registers? The comment as it is reads
> >> like
> >>
> >>  /* Add one plus one */
> >>  x = 1 + 1;
> >
> >
> > /*
> > * Shadow debug registers hold the debug register content
> > * to be written in h/w debug register on behalf of guest
> > * written value or user space written value.
> > */
> 
> /* hardware visible debug registers when in guest state */
> 
> >
> >
> >>
> >>> +	struct debug_reg shadow_dbg_reg;
> >>> #endif
> >>> 	gpa_t paddr_accessed;
> >>> 	gva_t vaddr_accessed;
> >>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
> >>> b/arch/powerpc/include/uapi/asm/kvm.h
> >>> index ded0607..f5077c2 100644
> >>> --- a/arch/powerpc/include/uapi/asm/kvm.h
> >>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> >>> @@ -27,6 +27,7 @@
> >>> #define __KVM_HAVE_PPC_SMT
> >>> #define __KVM_HAVE_IRQCHIP
> >>> #define __KVM_HAVE_IRQ_LINE
> >>> +#define __KVM_HAVE_GUEST_DEBUG
> >>>
> >>> struct kvm_regs {
> >>> 	__u64 pc;
> >>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> >>> index
> >>> ef99536..6a44ad4 100644
> >>> --- a/arch/powerpc/kvm/booke.c
> >>> +++ b/arch/powerpc/kvm/booke.c
> >>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct
> >>> kvm_vcpu
> >>> *vcpu) #endif }
> >>>
> >>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
> >>> +	/* Synchronize guest's desire to get debug interrupts into shadow
> >>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
> >>> +	vcpu->arch.shadow_msr &= ~MSR_DE;
> >>> +	vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
> >>> +
> >>> +	/* Force enable debug interrupts when user space wants to debug */
> >>> +	if (vcpu->guest_debug) {
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +		/*
> >>> +		 * Since there is no shadow MSR, sync MSR_DE into the guest
> >>> +		 * visible MSR.
> >>> +		 */
> >>> +		vcpu->arch.shared->msr |= MSR_DE; #else
> >>> +		vcpu->arch.shadow_msr |= MSR_DE;
> >>> +		vcpu->arch.shared->msr &= ~MSR_DE; #endif
> >>> +	}
> >>> +}
> >>> +
> >>> /*
> >>> * Helper function for "full" MSR writes.  No need to call this if
> >>> only
> >>> * EE/CE/ME/DE/RI are changing.
> >>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
> >>> 	kvmppc_mmu_msr_notify(vcpu, old_msr);
> >>> 	kvmppc_vcpu_sync_spe(vcpu);
> >>> 	kvmppc_vcpu_sync_fpu(vcpu);
> >>> +	kvmppc_vcpu_sync_debug(vcpu);
> >>> }
> >>>
> >>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
> >>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu
> >>> *vcpu) int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
> >>> 	int ret, s;
> >>> +	struct debug_reg debug;
> >>> #ifdef CONFIG_PPC_FPU
> >>> 	unsigned int fpscr;
> >>> 	int fpexc_mode;
> >>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run,
> >>> struct
> >> kvm_vcpu *vcpu)
> >>> 	kvmppc_load_guest_fp(vcpu);
> >>> #endif
> >>>
> >>> +	/*
> >>> +	 * Clear current->thread.dbcr0 so that kernel does not
> >>> +	 * restore h/w registers on context switch in vcpu running state.
> >>> +	 */
> >>
> >> Incorrect comment?
> >
> > Leftover from previous code, will remove this.
> >
> >>
> >>> +	/* Save thread->debug context on stack */
> >>
> >> /* Switch to guest debug context */
> >>
> >>> +	memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
> >>
> >> debug = current->thread.debug;
> >>
> >>> +	/* Load vcpu debug context in thread->debug */
> >>> +	memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
> >>> +	       sizeof(struct debug_reg));
> >>
> >> current->thread.debug = vcpu->arch.shadow_dbg_reg;
> >>
> >>> +
> >>> +	switch_booke_debug_regs(&current->thread);
> >>> +
> >>> 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
> >>>
> >>> 	/* No need for kvm_guest_exit. It's done in handle_exit.
> >>> 	   We also get here with interrupts enabled. */
> >>>
> >>> +	/* Restore userspace context in thread->dbcr0 from stack*/
> >>
> >> /* Switch back to user space debug context */
> >>
> >>> +	memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
> >>
> >> current->thread.debug = debug;
> >>
> >>> +	switch_booke_debug_regs(&current->thread);
> >>> +
> >>> #ifdef CONFIG_PPC_FPU
> >>> 	kvmppc_save_guest_fp(vcpu);
> >>>
> >>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run,
> >>> struct
> >> kvm_vcpu *vcpu)
> >>> 	}
> >>> }
> >>>
> >>> +/*
> >>> + * Currently we do not support debug resource emulation to guest,
> >>> + * so always exit to user space irrespective of user space is
> >>> + * expecting the debug exception or not. This is unexpected event
> >>> + * and let us leave the action on user space.
> >>
> >> Please rework your wording.
> >>
> >>> + */
> >>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
> >>> +*vcpu) {
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +	u32 dbsr = vcpu->arch.dbsr;
> >>> +
> >>> +	run->debug.arch.status = 0;
> >>> +	run->debug.arch.address = vcpu->arch.pc;
> >>> +
> >>> +	if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
> >>> +		run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
> >>> +	} else {
> >>> +		if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
> >>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
> >>> +		else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
> >>> +			run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
> >>> +		if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
> >>> +			run->debug.arch.address = dbg_reg->dac1;
> >>> +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> >>> +			run->debug.arch.address = dbg_reg->dac2;
> >>> +	}
> >>> +
> >>> +	return RESUME_HOST;
> >>> +}
> >>> +
> >>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
> >>> 	ulong r1, ip, msr, lr;
> >>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct
> >>> kvm_vcpu
> >> *vcpu,
> >>> 	case BOOKE_INTERRUPT_CRITICAL:
> >>> 		unknown_exception(&regs);
> >>> 		break;
> >>> +	case BOOKE_INTERRUPT_DEBUG:
> >>> +		/* Save DBSR before preemption is enabled */
> >>> +		vcpu->arch.dbsr = mfspr(SPRN_DBSR);
> >>> +		kvmppc_clear_dbsr();
> >>> +		break;
> >>> 	}
> >>> }
> >>>
> >>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run,
> >>> struct
> >> kvm_vcpu *vcpu,
> >>> 	}
> >>>
> >>> 	case BOOKE_INTERRUPT_DEBUG: {
> >>> -		u32 dbsr;
> >>> -
> >>> -		vcpu->arch.pc = mfspr(SPRN_CSRR0);
> >>> -
> >>> -		/* clear IAC events in DBSR register */
> >>> -		dbsr = mfspr(SPRN_DBSR);
> >>> -		dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
> >>> -		mtspr(SPRN_DBSR, dbsr);
> >>> -
> >>> -		run->exit_reason = KVM_EXIT_DEBUG;
> >>> +		r = kvmppc_handle_debug(run, vcpu);
> >>> +		if (r = RESUME_HOST)
> >>> +			run->exit_reason = KVM_EXIT_DEBUG;
> >>> 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> >>> -		r = RESUME_HOST;
> >>> 		break;
> >>> 	}
> >>>
> >>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
> >>> 	kvmppc_set_msr(vcpu, 0);
> >>>
> >>> #ifndef CONFIG_KVM_BOOKE_HV
> >>> -	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
> >>> +	vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
> >>> 	vcpu->arch.shadow_pid = 1;
> >>> 	vcpu->arch.shared->msr = 0;
> >>> #endif
> >>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct
> >>> kvm_vcpu *vcpu,
> >> struct kvm_one_reg *reg)
> >>> 	return r;
> >>> }
> >>>
> >>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> >>> -					 struct kvm_guest_debug *dbg)
> >>> -{
> >>> -	return -EINVAL;
> >>> -}
> >>> -
> >>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct
> >>> kvm_fpu
> >>> *fpu) {
> >>> 	return -ENOTSUPP;
> >>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
> >>> 	kvmppc_set_tsr_bits(vcpu, TSR_DIS); }
> >>>
> >>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
> >>> +uint64_t addr,
> >>
> >> s/set/add/
> >>
> >>> +				       int index)
> >>> +{
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	switch (index) {
> >>> +	case 0:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
> >>> +		dbg_reg->iac1 = addr;
> >>> +		break;
> >>> +	case 1:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
> >>> +		dbg_reg->iac2 = addr;
> >>> +		break;
> >>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
> >>> +	case 2:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
> >>> +		dbg_reg->iac3 = addr;
> >>> +		break;
> >>> +	case 3:
> >>> +		dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
> >>> +		dbg_reg->iac4 = addr;
> >>> +		break;
> >>> +#endif
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>
> >>    dbg_reg->dbcr0 |= DBCR0_IDM;
> >>
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
> >>> +uint64_t addr,
> >>
> >> s/set/add/
> >>
> >>> +				       int type, int index)
> >>> +{
> >>> +	struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	switch (index) {
> >>> +	case 0:
> >>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
> >>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
> >>> +		dbg_reg->dac1 = addr;
> >>> +		break;
> >>> +	case 1:
> >>> +		if (type & KVMPPC_DEBUG_WATCH_READ)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
> >>> +		if (type & KVMPPC_DEBUG_WATCH_WRITE)
> >>> +			dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
> >>> +		dbg_reg->dac2 = addr;
> >>> +		break;
> >>> +	default:
> >>> +		return -EINVAL;
> >>> +	}
> >>
> >>    dbg_reg->dbcr0 |= DBCR0_IDM;
> >>
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> >>> +					 struct kvm_guest_debug *dbg)
> >>> +{
> >>> +	struct debug_reg *dbg_reg;
> >>> +	int n, b = 0, w = 0;
> >>> +
> >>> +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> >>> +		/* Clear All debug events */
> >>> +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> >>> +		vcpu->guest_debug = 0;
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +		/*
> >>> +		 * When user space is not using the debug resources
> >>> +		 * then allow guest to change the MSR.DE.
> >>> +		 */
> >>> +		vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
> >>
> >> guest_may_set_msr_de(vcpu, true);
> >>
> >>> +		return 0;
> >>> +	}
> >>> +
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +	/*
> >>> +	 * When user space is using the debug resource then
> >>> +	 * do not allow guest to change the MSR.DE.
> >>> +	 */
> >>> +	vcpu->arch.shadow_msrp |= MSRP_DEP; #endif
> >>
> >> guest_may_set_msr_de(vcpu, false);
> >>
> >>> +	vcpu->guest_debug = dbg->control;
> >>> +	vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> >>> +	/* Set DBCR0_EDM in guest visible DBCR0 register. */
> >>> +	vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
> >>> +
> >>> +	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
> >>> +		vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
> >>> +
> >>> +	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
> >>> +		return 0;
> >>> +
> >>> +	/* Code below handles only HW breakpoints */
> >>> +	dbg_reg = &(vcpu->arch.shadow_dbg_reg);
> >>> +
> >>> +	/*
> >>> +	 * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
> >>> +	 * to occur when MSR.PR is set.
> >>> +	 * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
> >>> +	 * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
> >>> +	 * that debug events will not come in hypervisor (GS = 0).
> >
> > Will rework the above comment as discussed.
> >
> >>
> >> This is still wrong. We want to trap in PR=1. It's what PR KVM does,
> >> it's what TCG does. There is no point in making HV KVM behave differently.
> >
> > This comment is not valid.
> >
> >>
> >>> +	 */
> >>> +#ifdef CONFIG_KVM_BOOKE_HV
> >>> +	dbg_reg->dbcr1 = 0;
> >>> +	dbg_reg->dbcr2 = 0;
> >>> +#else
> >>> +	dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
> >>> +			  DBCR1_IAC4US;
> >>> +	dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
> >>> +
> >>> +	for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
> >>> +		uint64_t addr = dbg->arch.bp[n].addr;
> >>> +		uint32_t type = dbg->arch.bp[n].type;
> >>> +
> >>> +		if (type = KVMPPC_DEBUG_NONE)
> >>> +			continue;
> >>> +
> >>> +		if (type & !(KVMPPC_DEBUG_WATCH_READ |
> >>> +			     KVMPPC_DEBUG_WATCH_WRITE |
> >>> +			     KVMPPC_DEBUG_BREAKPOINT))
> >>> +			return -EINVAL;
> >>> +
> >>> +		if (type & KVMPPC_DEBUG_BREAKPOINT) {
> >>> +			/* Setting H/W breakpoint */
> >>> +			if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
> >>
> >> Please pass dbg_reg into the function
> >>
> >>> +				return -EINVAL;
> >>> +		} else {
> >>> +			/* Setting H/W watchpoint */
> >>> +			if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
> >>
> >> here too
> >>
> >>> +				return -EINVAL;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
> >>> 	vcpu->cpu = smp_processor_id();
> >>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
> >>> *vcpu) {
> >>> 	current->thread.kvm_vcpu = NULL;
> >>> 	vcpu->cpu = -1;
> >>> +
> >>> +	/* Disable all debug events */
> >>> +	mtspr(SPRN_DBCR0, 0x0);
> >>
> >> Why? Wouldn't normal preemption handling take care of this already?
> >
> > Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD
> and DBCR1/2.
> > So debug event will not be taken in host.
> >
> > So yes, it is not needed here.
> >
> >>
> >>> +	/* Clear pending debug event in DBSR */
> >>> +	kvmppc_clear_dbsr();
> >>
> >> Is there a chance we will ever have to do this? On debug exits from
> >> guest context we already clear dbsr.
> >
> > DBSR can have events captured but not delivered as interrupt if MSR.DE is
> clear. I know with qemu debug stub we do not allow msr.de to be cleared by
> guest.
> 
> I see. In that case we'd have to save the original DBSR value into vcpu->arch
> though, no? Otherwise we might lose guest debug events on preemption if we
> simply clear it.

We do not want to keep the delayed debug events as they does not carry much value. Example: taking h/w breakpoint at some other execution address.

-Bharat


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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-11 10:24           ` Bhushan Bharat-R65777
@ 2013-05-11 13:18             ` Alexander Graf
  -1 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-11 13:18 UTC (permalink / raw)
  To: Bhushan Bharat-R65777; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



Am 11.05.2013 um 12:24 schrieb Bhushan Bharat-R65777 <R65777@freescale.com>:

> 
> 
>> -----Original Message-----
>> From: Alexander Graf [mailto:agraf@suse.de]
>> Sent: Friday, May 10, 2013 11:14 PM
>> To: Bhushan Bharat-R65777
>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>> tiejun.chen@windriver.com
>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>> 
>> 
>> On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:
>> 
>>> 
>>> 
>>>> -----Original Message-----
>>>> From: Alexander Graf [mailto:agraf@suse.de]
>>>> Sent: Friday, May 10, 2013 3:48 PM
>>>> To: Bhushan Bharat-R65777
>>>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>>>> tiejun.chen@windriver.com; Bhushan Bharat-R65777
>>>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>>>> 
>>>> 
>>>> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
>>>> 
>>>>> This patch adds the debug stub support on booke/bookehv.
>>>>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
>>>>> breakpoint to debug guest.
>>>>> 
>>>>> This is how we save/restore debug register context when switching
>>>>> between guest, userspace and kernel user-process:
>>>>> 
>>>>> When QEMU is running
>>>>> -> thread->debug_reg == QEMU debug register context.
>>>>> -> Kernel will handle switching the debug register on context switch.
>>>>> -> no vcpu_load() called
>>>>> 
>>>>> QEMU makes ioctls (except RUN)
>>>>> -> This will call vcpu_load()
>>>>> -> should not change context.
>>>>> -> Some ioctls can change vcpu debug register, context saved in
>>>>> -> vcpu->debug_regs
>>>>> 
>>>>> QEMU Makes RUN ioctl
>>>>> -> Save thread->debug_reg on STACK
>>>>> -> Store thread->debug_reg == vcpu->debug_reg load thread->debug_reg
>>>>> -> RUN VCPU ( So thread points to vcpu context )
>>>>> 
>>>>> Context switch happens When VCPU running
>>>>> -> makes vcpu_load() should not load any context kernel loads the
>>>>> -> vcpu context as thread->debug_regs points to vcpu context.
>>>>> 
>>>>> On heavyweight_exit
>>>>> -> Load the context saved on stack in thread->debug_reg
>>>>> 
>>>>> Currently we do not support debug resource emulation to guest, On
>>>>> debug exception, always exit to user space irrespective of user
>>>>> space is expecting the debug exception or not. If this is unexpected
>>>>> exception (breakpoint/watchpoint event not set by
>>>>> userspace) then let us leave the action on user space. This is
>>>>> similar to what it was before, only thing is that now we have proper
>>>>> exit state available to user space.
>>>>> 
>>>>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
>>>>> ---
>>>>> arch/powerpc/include/asm/kvm_host.h |    3 +
>>>>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
>>>>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++-
>> --
>>>>> arch/powerpc/kvm/booke.h            |    5 +
>>>>> 4 files changed, 233 insertions(+), 18 deletions(-)
>>>>> 
>>>>> diff --git a/arch/powerpc/include/asm/kvm_host.h
>>>>> b/arch/powerpc/include/asm/kvm_host.h
>>>>> index 838a577..1b29945 100644
>>>>> --- a/arch/powerpc/include/asm/kvm_host.h
>>>>> +++ b/arch/powerpc/include/asm/kvm_host.h
>>>>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
>>>>>    u32 eptcfg;
>>>>>    u32 epr;
>>>>>    u32 crit_save;
>>>>> +    /* guest debug registers*/
>>>>>    struct debug_reg dbg_reg;
>>>>> +    /* shadow debug registers */
>>>> 
>>>> Please be more verbose here. What exactly does this contain? Why do
>>>> we need shadow and non-shadow registers? The comment as it is reads
>>>> like
>>>> 
>>>> /* Add one plus one */
>>>> x = 1 + 1;
>>> 
>>> 
>>> /*
>>> * Shadow debug registers hold the debug register content
>>> * to be written in h/w debug register on behalf of guest
>>> * written value or user space written value.
>>> */
>> 
>> /* hardware visible debug registers when in guest state */
>> 
>>> 
>>> 
>>>> 
>>>>> +    struct debug_reg shadow_dbg_reg;
>>>>> #endif
>>>>>    gpa_t paddr_accessed;
>>>>>    gva_t vaddr_accessed;
>>>>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
>>>>> b/arch/powerpc/include/uapi/asm/kvm.h
>>>>> index ded0607..f5077c2 100644
>>>>> --- a/arch/powerpc/include/uapi/asm/kvm.h
>>>>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
>>>>> @@ -27,6 +27,7 @@
>>>>> #define __KVM_HAVE_PPC_SMT
>>>>> #define __KVM_HAVE_IRQCHIP
>>>>> #define __KVM_HAVE_IRQ_LINE
>>>>> +#define __KVM_HAVE_GUEST_DEBUG
>>>>> 
>>>>> struct kvm_regs {
>>>>>    __u64 pc;
>>>>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
>>>>> index
>>>>> ef99536..6a44ad4 100644
>>>>> --- a/arch/powerpc/kvm/booke.c
>>>>> +++ b/arch/powerpc/kvm/booke.c
>>>>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct
>>>>> kvm_vcpu
>>>>> *vcpu) #endif }
>>>>> 
>>>>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
>>>>> +    /* Synchronize guest's desire to get debug interrupts into shadow
>>>>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
>>>>> +    vcpu->arch.shadow_msr &= ~MSR_DE;
>>>>> +    vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
>>>>> +
>>>>> +    /* Force enable debug interrupts when user space wants to debug */
>>>>> +    if (vcpu->guest_debug) {
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +        /*
>>>>> +         * Since there is no shadow MSR, sync MSR_DE into the guest
>>>>> +         * visible MSR.
>>>>> +         */
>>>>> +        vcpu->arch.shared->msr |= MSR_DE; #else
>>>>> +        vcpu->arch.shadow_msr |= MSR_DE;
>>>>> +        vcpu->arch.shared->msr &= ~MSR_DE; #endif
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> /*
>>>>> * Helper function for "full" MSR writes.  No need to call this if
>>>>> only
>>>>> * EE/CE/ME/DE/RI are changing.
>>>>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
>>>>>    kvmppc_mmu_msr_notify(vcpu, old_msr);
>>>>>    kvmppc_vcpu_sync_spe(vcpu);
>>>>>    kvmppc_vcpu_sync_fpu(vcpu);
>>>>> +    kvmppc_vcpu_sync_debug(vcpu);
>>>>> }
>>>>> 
>>>>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
>>>>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu
>>>>> *vcpu) int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
>>>>>    int ret, s;
>>>>> +    struct debug_reg debug;
>>>>> #ifdef CONFIG_PPC_FPU
>>>>>    unsigned int fpscr;
>>>>>    int fpexc_mode;
>>>>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run,
>>>>> struct
>>>> kvm_vcpu *vcpu)
>>>>>    kvmppc_load_guest_fp(vcpu);
>>>>> #endif
>>>>> 
>>>>> +    /*
>>>>> +     * Clear current->thread.dbcr0 so that kernel does not
>>>>> +     * restore h/w registers on context switch in vcpu running state.
>>>>> +     */
>>>> 
>>>> Incorrect comment?
>>> 
>>> Leftover from previous code, will remove this.
>>> 
>>>> 
>>>>> +    /* Save thread->debug context on stack */
>>>> 
>>>> /* Switch to guest debug context */
>>>> 
>>>>> +    memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
>>>> 
>>>> debug = current->thread.debug;
>>>> 
>>>>> +    /* Load vcpu debug context in thread->debug */
>>>>> +    memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
>>>>> +           sizeof(struct debug_reg));
>>>> 
>>>> current->thread.debug = vcpu->arch.shadow_dbg_reg;
>>>> 
>>>>> +
>>>>> +    switch_booke_debug_regs(&current->thread);
>>>>> +
>>>>>    ret = __kvmppc_vcpu_run(kvm_run, vcpu);
>>>>> 
>>>>>    /* No need for kvm_guest_exit. It's done in handle_exit.
>>>>>       We also get here with interrupts enabled. */
>>>>> 
>>>>> +    /* Restore userspace context in thread->dbcr0 from stack*/
>>>> 
>>>> /* Switch back to user space debug context */
>>>> 
>>>>> +    memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
>>>> 
>>>> current->thread.debug = debug;
>>>> 
>>>>> +    switch_booke_debug_regs(&current->thread);
>>>>> +
>>>>> #ifdef CONFIG_PPC_FPU
>>>>>    kvmppc_save_guest_fp(vcpu);
>>>>> 
>>>>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run,
>>>>> struct
>>>> kvm_vcpu *vcpu)
>>>>>    }
>>>>> }
>>>>> 
>>>>> +/*
>>>>> + * Currently we do not support debug resource emulation to guest,
>>>>> + * so always exit to user space irrespective of user space is
>>>>> + * expecting the debug exception or not. This is unexpected event
>>>>> + * and let us leave the action on user space.
>>>> 
>>>> Please rework your wording.
>>>> 
>>>>> + */
>>>>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
>>>>> +*vcpu) {
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +    u32 dbsr = vcpu->arch.dbsr;
>>>>> +
>>>>> +    run->debug.arch.status = 0;
>>>>> +    run->debug.arch.address = vcpu->arch.pc;
>>>>> +
>>>>> +    if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
>>>>> +        run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
>>>>> +    } else {
>>>>> +        if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
>>>>> +            run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
>>>>> +        else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
>>>>> +            run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
>>>>> +        if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
>>>>> +            run->debug.arch.address = dbg_reg->dac1;
>>>>> +        else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
>>>>> +            run->debug.arch.address = dbg_reg->dac2;
>>>>> +    }
>>>>> +
>>>>> +    return RESUME_HOST;
>>>>> +}
>>>>> +
>>>>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
>>>>>    ulong r1, ip, msr, lr;
>>>>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct
>>>>> kvm_vcpu
>>>> *vcpu,
>>>>>    case BOOKE_INTERRUPT_CRITICAL:
>>>>>        unknown_exception(&regs);
>>>>>        break;
>>>>> +    case BOOKE_INTERRUPT_DEBUG:
>>>>> +        /* Save DBSR before preemption is enabled */
>>>>> +        vcpu->arch.dbsr = mfspr(SPRN_DBSR);
>>>>> +        kvmppc_clear_dbsr();
>>>>> +        break;
>>>>>    }
>>>>> }
>>>>> 
>>>>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run,
>>>>> struct
>>>> kvm_vcpu *vcpu,
>>>>>    }
>>>>> 
>>>>>    case BOOKE_INTERRUPT_DEBUG: {
>>>>> -        u32 dbsr;
>>>>> -
>>>>> -        vcpu->arch.pc = mfspr(SPRN_CSRR0);
>>>>> -
>>>>> -        /* clear IAC events in DBSR register */
>>>>> -        dbsr = mfspr(SPRN_DBSR);
>>>>> -        dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
>>>>> -        mtspr(SPRN_DBSR, dbsr);
>>>>> -
>>>>> -        run->exit_reason = KVM_EXIT_DEBUG;
>>>>> +        r = kvmppc_handle_debug(run, vcpu);
>>>>> +        if (r == RESUME_HOST)
>>>>> +            run->exit_reason = KVM_EXIT_DEBUG;
>>>>>        kvmppc_account_exit(vcpu, DEBUG_EXITS);
>>>>> -        r = RESUME_HOST;
>>>>>        break;
>>>>>    }
>>>>> 
>>>>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>>>>>    kvmppc_set_msr(vcpu, 0);
>>>>> 
>>>>> #ifndef CONFIG_KVM_BOOKE_HV
>>>>> -    vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
>>>>> +    vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
>>>>>    vcpu->arch.shadow_pid = 1;
>>>>>    vcpu->arch.shared->msr = 0;
>>>>> #endif
>>>>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct
>>>>> kvm_vcpu *vcpu,
>>>> struct kvm_one_reg *reg)
>>>>>    return r;
>>>>> }
>>>>> 
>>>>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>>>> -                     struct kvm_guest_debug *dbg)
>>>>> -{
>>>>> -    return -EINVAL;
>>>>> -}
>>>>> -
>>>>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct
>>>>> kvm_fpu
>>>>> *fpu) {
>>>>>    return -ENOTSUPP;
>>>>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
>>>>>    kvmppc_set_tsr_bits(vcpu, TSR_DIS); }
>>>>> 
>>>>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
>>>>> +uint64_t addr,
>>>> 
>>>> s/set/add/
>>>> 
>>>>> +                       int index)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    switch (index) {
>>>>> +    case 0:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
>>>>> +        dbg_reg->iac1 = addr;
>>>>> +        break;
>>>>> +    case 1:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
>>>>> +        dbg_reg->iac2 = addr;
>>>>> +        break;
>>>>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
>>>>> +    case 2:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
>>>>> +        dbg_reg->iac3 = addr;
>>>>> +        break;
>>>>> +    case 3:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
>>>>> +        dbg_reg->iac4 = addr;
>>>>> +        break;
>>>>> +#endif
>>>>> +    default:
>>>>> +        return -EINVAL;
>>>>> +    }
>>>> 
>>>>   dbg_reg->dbcr0 |= DBCR0_IDM;
>>>> 
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
>>>>> +uint64_t addr,
>>>> 
>>>> s/set/add/
>>>> 
>>>>> +                       int type, int index)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    switch (index) {
>>>>> +    case 0:
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_READ)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
>>>>> +        dbg_reg->dac1 = addr;
>>>>> +        break;
>>>>> +    case 1:
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_READ)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
>>>>> +        dbg_reg->dac2 = addr;
>>>>> +        break;
>>>>> +    default:
>>>>> +        return -EINVAL;
>>>>> +    }
>>>> 
>>>>   dbg_reg->dbcr0 |= DBCR0_IDM;
>>>> 
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>>>> +                     struct kvm_guest_debug *dbg)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg;
>>>>> +    int n, b = 0, w = 0;
>>>>> +
>>>>> +    if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
>>>>> +        /* Clear All debug events */
>>>>> +        vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>>>> +        vcpu->guest_debug = 0;
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +        /*
>>>>> +         * When user space is not using the debug resources
>>>>> +         * then allow guest to change the MSR.DE.
>>>>> +         */
>>>>> +        vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
>>>> 
>>>> guest_may_set_msr_de(vcpu, true);
>>>> 
>>>>> +        return 0;
>>>>> +    }
>>>>> +
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +    /*
>>>>> +     * When user space is using the debug resource then
>>>>> +     * do not allow guest to change the MSR.DE.
>>>>> +     */
>>>>> +    vcpu->arch.shadow_msrp |= MSRP_DEP; #endif
>>>> 
>>>> guest_may_set_msr_de(vcpu, false);
>>>> 
>>>>> +    vcpu->guest_debug = dbg->control;
>>>>> +    vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>>>> +    /* Set DBCR0_EDM in guest visible DBCR0 register. */
>>>>> +    vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
>>>>> +
>>>>> +    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>>>>> +        vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
>>>>> +
>>>>> +    if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* Code below handles only HW breakpoints */
>>>>> +    dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    /*
>>>>> +     * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
>>>>> +     * to occur when MSR.PR is set.
>>>>> +     * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
>>>>> +     * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
>>>>> +     * that debug events will not come in hypervisor (GS = 0).
>>> 
>>> Will rework the above comment as discussed.
>>> 
>>>> 
>>>> This is still wrong. We want to trap in PR=1. It's what PR KVM does,
>>>> it's what TCG does. There is no point in making HV KVM behave differently.
>>> 
>>> This comment is not valid.
>>> 
>>>> 
>>>>> +     */
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +    dbg_reg->dbcr1 = 0;
>>>>> +    dbg_reg->dbcr2 = 0;
>>>>> +#else
>>>>> +    dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
>>>>> +              DBCR1_IAC4US;
>>>>> +    dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
>>>>> +
>>>>> +    for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
>>>>> +        uint64_t addr = dbg->arch.bp[n].addr;
>>>>> +        uint32_t type = dbg->arch.bp[n].type;
>>>>> +
>>>>> +        if (type == KVMPPC_DEBUG_NONE)
>>>>> +            continue;
>>>>> +
>>>>> +        if (type & !(KVMPPC_DEBUG_WATCH_READ |
>>>>> +                 KVMPPC_DEBUG_WATCH_WRITE |
>>>>> +                 KVMPPC_DEBUG_BREAKPOINT))
>>>>> +            return -EINVAL;
>>>>> +
>>>>> +        if (type & KVMPPC_DEBUG_BREAKPOINT) {
>>>>> +            /* Setting H/W breakpoint */
>>>>> +            if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
>>>> 
>>>> Please pass dbg_reg into the function
>>>> 
>>>>> +                return -EINVAL;
>>>>> +        } else {
>>>>> +            /* Setting H/W watchpoint */
>>>>> +            if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
>>>> 
>>>> here too
>>>> 
>>>>> +                return -EINVAL;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
>>>>>    vcpu->cpu = smp_processor_id();
>>>>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
>>>>> *vcpu) {
>>>>>    current->thread.kvm_vcpu = NULL;
>>>>>    vcpu->cpu = -1;
>>>>> +
>>>>> +    /* Disable all debug events */
>>>>> +    mtspr(SPRN_DBCR0, 0x0);
>>>> 
>>>> Why? Wouldn't normal preemption handling take care of this already?
>>> 
>>> Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD
>> and DBCR1/2.
>>> So debug event will not be taken in host.
>>> 
>>> So yes, it is not needed here.
>>> 
>>>> 
>>>>> +    /* Clear pending debug event in DBSR */
>>>>> +    kvmppc_clear_dbsr();
>>>> 
>>>> Is there a chance we will ever have to do this? On debug exits from
>>>> guest context we already clear dbsr.
>>> 
>>> DBSR can have events captured but not delivered as interrupt if MSR.DE is
>> clear. I know with qemu debug stub we do not allow msr.de to be cleared by
>> guest.
>> 
>> I see. In that case we'd have to save the original DBSR value into vcpu->arch
>> though, no? Otherwise we might lose guest debug events on preemption if we
>> simply clear it.
> 
> We do not want to keep the delayed debug events as they does not carry much value. Example: taking h/w breakpoint at some other execution address.

That's for the guest to decide, no? If the guest wants to poll debug events rather than receive interrupts, we should enable it to do so.

Alex

> 
> -Bharat
> 

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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-11 13:18             ` Alexander Graf
  0 siblings, 0 replies; 28+ messages in thread
From: Alexander Graf @ 2013-05-11 13:18 UTC (permalink / raw)
  To: Bhushan Bharat-R65777; +Cc: kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen



Am 11.05.2013 um 12:24 schrieb Bhushan Bharat-R65777 <R65777@freescale.com>:

> 
> 
>> -----Original Message-----
>> From: Alexander Graf [mailto:agraf@suse.de]
>> Sent: Friday, May 10, 2013 11:14 PM
>> To: Bhushan Bharat-R65777
>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>> tiejun.chen@windriver.com
>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>> 
>> 
>> On 10.05.2013, at 19:31, Bhushan Bharat-R65777 wrote:
>> 
>>> 
>>> 
>>>> -----Original Message-----
>>>> From: Alexander Graf [mailto:agraf@suse.de]
>>>> Sent: Friday, May 10, 2013 3:48 PM
>>>> To: Bhushan Bharat-R65777
>>>> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; Wood Scott-B07421;
>>>> tiejun.chen@windriver.com; Bhushan Bharat-R65777
>>>> Subject: Re: [PATCH] KVM: PPC: Add userspace debug stub support
>>>> 
>>>> 
>>>> On 07.05.2013, at 11:40, Bharat Bhushan wrote:
>>>> 
>>>>> This patch adds the debug stub support on booke/bookehv.
>>>>> Now QEMU debug stub can use hw breakpoint, watchpoint and software
>>>>> breakpoint to debug guest.
>>>>> 
>>>>> This is how we save/restore debug register context when switching
>>>>> between guest, userspace and kernel user-process:
>>>>> 
>>>>> When QEMU is running
>>>>> -> thread->debug_reg = QEMU debug register context.
>>>>> -> Kernel will handle switching the debug register on context switch.
>>>>> -> no vcpu_load() called
>>>>> 
>>>>> QEMU makes ioctls (except RUN)
>>>>> -> This will call vcpu_load()
>>>>> -> should not change context.
>>>>> -> Some ioctls can change vcpu debug register, context saved in
>>>>> -> vcpu->debug_regs
>>>>> 
>>>>> QEMU Makes RUN ioctl
>>>>> -> Save thread->debug_reg on STACK
>>>>> -> Store thread->debug_reg = vcpu->debug_reg load thread->debug_reg
>>>>> -> RUN VCPU ( So thread points to vcpu context )
>>>>> 
>>>>> Context switch happens When VCPU running
>>>>> -> makes vcpu_load() should not load any context kernel loads the
>>>>> -> vcpu context as thread->debug_regs points to vcpu context.
>>>>> 
>>>>> On heavyweight_exit
>>>>> -> Load the context saved on stack in thread->debug_reg
>>>>> 
>>>>> Currently we do not support debug resource emulation to guest, On
>>>>> debug exception, always exit to user space irrespective of user
>>>>> space is expecting the debug exception or not. If this is unexpected
>>>>> exception (breakpoint/watchpoint event not set by
>>>>> userspace) then let us leave the action on user space. This is
>>>>> similar to what it was before, only thing is that now we have proper
>>>>> exit state available to user space.
>>>>> 
>>>>> Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
>>>>> ---
>>>>> arch/powerpc/include/asm/kvm_host.h |    3 +
>>>>> arch/powerpc/include/uapi/asm/kvm.h |    1 +
>>>>> arch/powerpc/kvm/booke.c            |  242 ++++++++++++++++++++++++++++++++-
>> --
>>>>> arch/powerpc/kvm/booke.h            |    5 +
>>>>> 4 files changed, 233 insertions(+), 18 deletions(-)
>>>>> 
>>>>> diff --git a/arch/powerpc/include/asm/kvm_host.h
>>>>> b/arch/powerpc/include/asm/kvm_host.h
>>>>> index 838a577..1b29945 100644
>>>>> --- a/arch/powerpc/include/asm/kvm_host.h
>>>>> +++ b/arch/powerpc/include/asm/kvm_host.h
>>>>> @@ -524,7 +524,10 @@ struct kvm_vcpu_arch {
>>>>>    u32 eptcfg;
>>>>>    u32 epr;
>>>>>    u32 crit_save;
>>>>> +    /* guest debug registers*/
>>>>>    struct debug_reg dbg_reg;
>>>>> +    /* shadow debug registers */
>>>> 
>>>> Please be more verbose here. What exactly does this contain? Why do
>>>> we need shadow and non-shadow registers? The comment as it is reads
>>>> like
>>>> 
>>>> /* Add one plus one */
>>>> x = 1 + 1;
>>> 
>>> 
>>> /*
>>> * Shadow debug registers hold the debug register content
>>> * to be written in h/w debug register on behalf of guest
>>> * written value or user space written value.
>>> */
>> 
>> /* hardware visible debug registers when in guest state */
>> 
>>> 
>>> 
>>>> 
>>>>> +    struct debug_reg shadow_dbg_reg;
>>>>> #endif
>>>>>    gpa_t paddr_accessed;
>>>>>    gva_t vaddr_accessed;
>>>>> diff --git a/arch/powerpc/include/uapi/asm/kvm.h
>>>>> b/arch/powerpc/include/uapi/asm/kvm.h
>>>>> index ded0607..f5077c2 100644
>>>>> --- a/arch/powerpc/include/uapi/asm/kvm.h
>>>>> +++ b/arch/powerpc/include/uapi/asm/kvm.h
>>>>> @@ -27,6 +27,7 @@
>>>>> #define __KVM_HAVE_PPC_SMT
>>>>> #define __KVM_HAVE_IRQCHIP
>>>>> #define __KVM_HAVE_IRQ_LINE
>>>>> +#define __KVM_HAVE_GUEST_DEBUG
>>>>> 
>>>>> struct kvm_regs {
>>>>>    __u64 pc;
>>>>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
>>>>> index
>>>>> ef99536..6a44ad4 100644
>>>>> --- a/arch/powerpc/kvm/booke.c
>>>>> +++ b/arch/powerpc/kvm/booke.c
>>>>> @@ -133,6 +133,29 @@ static void kvmppc_vcpu_sync_fpu(struct
>>>>> kvm_vcpu
>>>>> *vcpu) #endif }
>>>>> 
>>>>> +static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) {
>>>>> +    /* Synchronize guest's desire to get debug interrupts into shadow
>>>>> +MSR */ #ifndef CONFIG_KVM_BOOKE_HV
>>>>> +    vcpu->arch.shadow_msr &= ~MSR_DE;
>>>>> +    vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE; #endif
>>>>> +
>>>>> +    /* Force enable debug interrupts when user space wants to debug */
>>>>> +    if (vcpu->guest_debug) {
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +        /*
>>>>> +         * Since there is no shadow MSR, sync MSR_DE into the guest
>>>>> +         * visible MSR.
>>>>> +         */
>>>>> +        vcpu->arch.shared->msr |= MSR_DE; #else
>>>>> +        vcpu->arch.shadow_msr |= MSR_DE;
>>>>> +        vcpu->arch.shared->msr &= ~MSR_DE; #endif
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> /*
>>>>> * Helper function for "full" MSR writes.  No need to call this if
>>>>> only
>>>>> * EE/CE/ME/DE/RI are changing.
>>>>> @@ -150,6 +173,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
>>>>>    kvmppc_mmu_msr_notify(vcpu, old_msr);
>>>>>    kvmppc_vcpu_sync_spe(vcpu);
>>>>>    kvmppc_vcpu_sync_fpu(vcpu);
>>>>> +    kvmppc_vcpu_sync_debug(vcpu);
>>>>> }
>>>>> 
>>>>> static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, @@
>>>>> -655,6 +679,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu
>>>>> *vcpu) int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) {
>>>>>    int ret, s;
>>>>> +    struct debug_reg debug;
>>>>> #ifdef CONFIG_PPC_FPU
>>>>>    unsigned int fpscr;
>>>>>    int fpexc_mode;
>>>>> @@ -699,11 +724,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run,
>>>>> struct
>>>> kvm_vcpu *vcpu)
>>>>>    kvmppc_load_guest_fp(vcpu);
>>>>> #endif
>>>>> 
>>>>> +    /*
>>>>> +     * Clear current->thread.dbcr0 so that kernel does not
>>>>> +     * restore h/w registers on context switch in vcpu running state.
>>>>> +     */
>>>> 
>>>> Incorrect comment?
>>> 
>>> Leftover from previous code, will remove this.
>>> 
>>>> 
>>>>> +    /* Save thread->debug context on stack */
>>>> 
>>>> /* Switch to guest debug context */
>>>> 
>>>>> +    memcpy(&debug, &current->thread.debug, sizeof(struct debug_reg));
>>>> 
>>>> debug = current->thread.debug;
>>>> 
>>>>> +    /* Load vcpu debug context in thread->debug */
>>>>> +    memcpy(&current->thread.debug, &vcpu->arch.shadow_dbg_reg,
>>>>> +           sizeof(struct debug_reg));
>>>> 
>>>> current->thread.debug = vcpu->arch.shadow_dbg_reg;
>>>> 
>>>>> +
>>>>> +    switch_booke_debug_regs(&current->thread);
>>>>> +
>>>>>    ret = __kvmppc_vcpu_run(kvm_run, vcpu);
>>>>> 
>>>>>    /* No need for kvm_guest_exit. It's done in handle_exit.
>>>>>       We also get here with interrupts enabled. */
>>>>> 
>>>>> +    /* Restore userspace context in thread->dbcr0 from stack*/
>>>> 
>>>> /* Switch back to user space debug context */
>>>> 
>>>>> +    memcpy(&current->thread.debug, &debug, sizeof(struct debug_reg));
>>>> 
>>>> current->thread.debug = debug;
>>>> 
>>>>> +    switch_booke_debug_regs(&current->thread);
>>>>> +
>>>>> #ifdef CONFIG_PPC_FPU
>>>>>    kvmppc_save_guest_fp(vcpu);
>>>>> 
>>>>> @@ -759,6 +800,36 @@ static int emulation_exit(struct kvm_run *run,
>>>>> struct
>>>> kvm_vcpu *vcpu)
>>>>>    }
>>>>> }
>>>>> 
>>>>> +/*
>>>>> + * Currently we do not support debug resource emulation to guest,
>>>>> + * so always exit to user space irrespective of user space is
>>>>> + * expecting the debug exception or not. This is unexpected event
>>>>> + * and let us leave the action on user space.
>>>> 
>>>> Please rework your wording.
>>>> 
>>>>> + */
>>>>> +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
>>>>> +*vcpu) {
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +    u32 dbsr = vcpu->arch.dbsr;
>>>>> +
>>>>> +    run->debug.arch.status = 0;
>>>>> +    run->debug.arch.address = vcpu->arch.pc;
>>>>> +
>>>>> +    if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
>>>>> +        run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
>>>>> +    } else {
>>>>> +        if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
>>>>> +            run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
>>>>> +        else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
>>>>> +            run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
>>>>> +        if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
>>>>> +            run->debug.arch.address = dbg_reg->dac1;
>>>>> +        else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
>>>>> +            run->debug.arch.address = dbg_reg->dac2;
>>>>> +    }
>>>>> +
>>>>> +    return RESUME_HOST;
>>>>> +}
>>>>> +
>>>>> static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
>>>>>    ulong r1, ip, msr, lr;
>>>>> @@ -819,6 +890,11 @@ static void kvmppc_restart_interrupt(struct
>>>>> kvm_vcpu
>>>> *vcpu,
>>>>>    case BOOKE_INTERRUPT_CRITICAL:
>>>>>        unknown_exception(&regs);
>>>>>        break;
>>>>> +    case BOOKE_INTERRUPT_DEBUG:
>>>>> +        /* Save DBSR before preemption is enabled */
>>>>> +        vcpu->arch.dbsr = mfspr(SPRN_DBSR);
>>>>> +        kvmppc_clear_dbsr();
>>>>> +        break;
>>>>>    }
>>>>> }
>>>>> 
>>>>> @@ -1118,18 +1194,10 @@ int kvmppc_handle_exit(struct kvm_run *run,
>>>>> struct
>>>> kvm_vcpu *vcpu,
>>>>>    }
>>>>> 
>>>>>    case BOOKE_INTERRUPT_DEBUG: {
>>>>> -        u32 dbsr;
>>>>> -
>>>>> -        vcpu->arch.pc = mfspr(SPRN_CSRR0);
>>>>> -
>>>>> -        /* clear IAC events in DBSR register */
>>>>> -        dbsr = mfspr(SPRN_DBSR);
>>>>> -        dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
>>>>> -        mtspr(SPRN_DBSR, dbsr);
>>>>> -
>>>>> -        run->exit_reason = KVM_EXIT_DEBUG;
>>>>> +        r = kvmppc_handle_debug(run, vcpu);
>>>>> +        if (r = RESUME_HOST)
>>>>> +            run->exit_reason = KVM_EXIT_DEBUG;
>>>>>        kvmppc_account_exit(vcpu, DEBUG_EXITS);
>>>>> -        r = RESUME_HOST;
>>>>>        break;
>>>>>    }
>>>>> 
>>>>> @@ -1180,7 +1248,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>>>>>    kvmppc_set_msr(vcpu, 0);
>>>>> 
>>>>> #ifndef CONFIG_KVM_BOOKE_HV
>>>>> -    vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
>>>>> +    vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
>>>>>    vcpu->arch.shadow_pid = 1;
>>>>>    vcpu->arch.shared->msr = 0;
>>>>> #endif
>>>>> @@ -1557,12 +1625,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct
>>>>> kvm_vcpu *vcpu,
>>>> struct kvm_one_reg *reg)
>>>>>    return r;
>>>>> }
>>>>> 
>>>>> -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>>>> -                     struct kvm_guest_debug *dbg)
>>>>> -{
>>>>> -    return -EINVAL;
>>>>> -}
>>>>> -
>>>>> int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct
>>>>> kvm_fpu
>>>>> *fpu) {
>>>>>    return -ENOTSUPP;
>>>>> @@ -1668,6 +1730,145 @@ void kvmppc_decrementer_func(unsigned long data)
>>>>>    kvmppc_set_tsr_bits(vcpu, TSR_DIS); }
>>>>> 
>>>>> +static int kvmppc_booke_set_breakpoint(struct kvm_vcpu *vcpu,
>>>>> +uint64_t addr,
>>>> 
>>>> s/set/add/
>>>> 
>>>>> +                       int index)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    switch (index) {
>>>>> +    case 0:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC1 | DBCR0_IDM;
>>>>> +        dbg_reg->iac1 = addr;
>>>>> +        break;
>>>>> +    case 1:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC2 | DBCR0_IDM;
>>>>> +        dbg_reg->iac2 = addr;
>>>>> +        break;
>>>>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2
>>>>> +    case 2:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC3 | DBCR0_IDM;
>>>>> +        dbg_reg->iac3 = addr;
>>>>> +        break;
>>>>> +    case 3:
>>>>> +        dbg_reg->dbcr0 |= DBCR0_IAC4 | DBCR0_IDM;
>>>>> +        dbg_reg->iac4 = addr;
>>>>> +        break;
>>>>> +#endif
>>>>> +    default:
>>>>> +        return -EINVAL;
>>>>> +    }
>>>> 
>>>>   dbg_reg->dbcr0 |= DBCR0_IDM;
>>>> 
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static int kvmppc_booke_set_watchpoint(struct kvm_vcpu *vcpu,
>>>>> +uint64_t addr,
>>>> 
>>>> s/set/add/
>>>> 
>>>>> +                       int type, int index)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    switch (index) {
>>>>> +    case 0:
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_READ)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC1R | DBCR0_IDM;
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC1W | DBCR0_IDM;
>>>>> +        dbg_reg->dac1 = addr;
>>>>> +        break;
>>>>> +    case 1:
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_READ)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC2R | DBCR0_IDM;
>>>>> +        if (type & KVMPPC_DEBUG_WATCH_WRITE)
>>>>> +            dbg_reg->dbcr0 |= DBCR0_DAC2W | DBCR0_IDM;
>>>>> +        dbg_reg->dac2 = addr;
>>>>> +        break;
>>>>> +    default:
>>>>> +        return -EINVAL;
>>>>> +    }
>>>> 
>>>>   dbg_reg->dbcr0 |= DBCR0_IDM;
>>>> 
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
>>>>> +                     struct kvm_guest_debug *dbg)
>>>>> +{
>>>>> +    struct debug_reg *dbg_reg;
>>>>> +    int n, b = 0, w = 0;
>>>>> +
>>>>> +    if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
>>>>> +        /* Clear All debug events */
>>>>> +        vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>>>> +        vcpu->guest_debug = 0;
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +        /*
>>>>> +         * When user space is not using the debug resources
>>>>> +         * then allow guest to change the MSR.DE.
>>>>> +         */
>>>>> +        vcpu->arch.shadow_msrp &= ~MSRP_DEP; #endif
>>>> 
>>>> guest_may_set_msr_de(vcpu, true);
>>>> 
>>>>> +        return 0;
>>>>> +    }
>>>>> +
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +    /*
>>>>> +     * When user space is using the debug resource then
>>>>> +     * do not allow guest to change the MSR.DE.
>>>>> +     */
>>>>> +    vcpu->arch.shadow_msrp |= MSRP_DEP; #endif
>>>> 
>>>> guest_may_set_msr_de(vcpu, false);
>>>> 
>>>>> +    vcpu->guest_debug = dbg->control;
>>>>> +    vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
>>>>> +    /* Set DBCR0_EDM in guest visible DBCR0 register. */
>>>>> +    vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
>>>>> +
>>>>> +    if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
>>>>> +        vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
>>>>> +
>>>>> +    if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* Code below handles only HW breakpoints */
>>>>> +    dbg_reg = &(vcpu->arch.shadow_dbg_reg);
>>>>> +
>>>>> +    /*
>>>>> +     * On BOOKE (e500v2); Set DBCR1 and DBCR2 to allow debug events
>>>>> +     * to occur when MSR.PR is set.
>>>>> +     * On BOOKE-HV (e500mc+); MSR.PR = 0 when guest is running. So we
>>>>> +     * should clear DBCR1 and DBCR2. And EPCR.DUVD is used to control
>>>>> +     * that debug events will not come in hypervisor (GS = 0).
>>> 
>>> Will rework the above comment as discussed.
>>> 
>>>> 
>>>> This is still wrong. We want to trap in PR=1. It's what PR KVM does,
>>>> it's what TCG does. There is no point in making HV KVM behave differently.
>>> 
>>> This comment is not valid.
>>> 
>>>> 
>>>>> +     */
>>>>> +#ifdef CONFIG_KVM_BOOKE_HV
>>>>> +    dbg_reg->dbcr1 = 0;
>>>>> +    dbg_reg->dbcr2 = 0;
>>>>> +#else
>>>>> +    dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
>>>>> +              DBCR1_IAC4US;
>>>>> +    dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; #endif
>>>>> +
>>>>> +    for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
>>>>> +        uint64_t addr = dbg->arch.bp[n].addr;
>>>>> +        uint32_t type = dbg->arch.bp[n].type;
>>>>> +
>>>>> +        if (type = KVMPPC_DEBUG_NONE)
>>>>> +            continue;
>>>>> +
>>>>> +        if (type & !(KVMPPC_DEBUG_WATCH_READ |
>>>>> +                 KVMPPC_DEBUG_WATCH_WRITE |
>>>>> +                 KVMPPC_DEBUG_BREAKPOINT))
>>>>> +            return -EINVAL;
>>>>> +
>>>>> +        if (type & KVMPPC_DEBUG_BREAKPOINT) {
>>>>> +            /* Setting H/W breakpoint */
>>>>> +            if (kvmppc_booke_set_breakpoint(vcpu, addr, b++))
>>>> 
>>>> Please pass dbg_reg into the function
>>>> 
>>>>> +                return -EINVAL;
>>>>> +        } else {
>>>>> +            /* Setting H/W watchpoint */
>>>>> +            if (kvmppc_booke_set_watchpoint(vcpu, addr, type, w++))
>>>> 
>>>> here too
>>>> 
>>>>> +                return -EINVAL;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) {
>>>>>    vcpu->cpu = smp_processor_id();
>>>>> @@ -1678,6 +1879,11 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu
>>>>> *vcpu) {
>>>>>    current->thread.kvm_vcpu = NULL;
>>>>>    vcpu->cpu = -1;
>>>>> +
>>>>> +    /* Disable all debug events */
>>>>> +    mtspr(SPRN_DBCR0, 0x0);
>>>> 
>>>> Why? Wouldn't normal preemption handling take care of this already?
>>> 
>>> Yes, normal preemption will take care. On vcpu_put we do not clear EPCR.DUVD
>> and DBCR1/2.
>>> So debug event will not be taken in host.
>>> 
>>> So yes, it is not needed here.
>>> 
>>>> 
>>>>> +    /* Clear pending debug event in DBSR */
>>>>> +    kvmppc_clear_dbsr();
>>>> 
>>>> Is there a chance we will ever have to do this? On debug exits from
>>>> guest context we already clear dbsr.
>>> 
>>> DBSR can have events captured but not delivered as interrupt if MSR.DE is
>> clear. I know with qemu debug stub we do not allow msr.de to be cleared by
>> guest.
>> 
>> I see. In that case we'd have to save the original DBSR value into vcpu->arch
>> though, no? Otherwise we might lose guest debug events on preemption if we
>> simply clear it.
> 
> We do not want to keep the delayed debug events as they does not carry much value. Example: taking h/w breakpoint at some other execution address.

That's for the guest to decide, no? If the guest wants to poll debug events rather than receive interrupts, we should enable it to do so.

Alex

> 
> -Bharat
> 

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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
  2013-05-11 13:18             ` Alexander Graf
@ 2013-05-13 14:33               ` Scott Wood
  -1 siblings, 0 replies; 28+ messages in thread
From: Scott Wood @ 2013-05-13 14:33 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Bhushan Bharat-R65777, kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen

On 05/11/2013 08:18:50 AM, Alexander Graf wrote:
> 
> 
> Am 11.05.2013 um 12:24 schrieb Bhushan Bharat-R65777  
> <R65777@freescale.com>:
> > We do not want to keep the delayed debug events as they does not  
> carry much value. Example: taking h/w breakpoint at some other  
> execution address.
> 
> That's for the guest to decide, no?

No more so than with the various other things that don't get fully  
emulated.

> If the guest wants to poll debug events rather than receive  
> interrupts, we should enable it to do so.

Someone who cares can enable it to do so.  Note that the value of  
deferred debug events is so low that it got ripped out of the hardware  
starting with e6500.  Didn't we discuss this a while back?

-Scott

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

* Re: [PATCH] KVM: PPC: Add userspace debug stub support
@ 2013-05-13 14:33               ` Scott Wood
  0 siblings, 0 replies; 28+ messages in thread
From: Scott Wood @ 2013-05-13 14:33 UTC (permalink / raw)
  To: Alexander Graf
  Cc: Bhushan Bharat-R65777, kvm-ppc, kvm, Wood Scott-B07421, tiejun.chen

On 05/11/2013 08:18:50 AM, Alexander Graf wrote:
> 
> 
> Am 11.05.2013 um 12:24 schrieb Bhushan Bharat-R65777  
> <R65777@freescale.com>:
> > We do not want to keep the delayed debug events as they does not  
> carry much value. Example: taking h/w breakpoint at some other  
> execution address.
> 
> That's for the guest to decide, no?

No more so than with the various other things that don't get fully  
emulated.

> If the guest wants to poll debug events rather than receive  
> interrupts, we should enable it to do so.

Someone who cares can enable it to do so.  Note that the value of  
deferred debug events is so low that it got ripped out of the hardware  
starting with e6500.  Didn't we discuss this a while back?

-Scott

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

end of thread, other threads:[~2013-05-13 14:33 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-07  9:40 [PATCH v4] KVM :PPC: Userspace Debug support Bharat Bhushan
2013-05-07  9:52 ` Bharat Bhushan
2013-05-07  9:40 ` [PATCH] powerpc: remove unnecessary line continuations Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-07  9:40 ` [PATCH] powerpc: move debug registers in a structure Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-07  9:40 ` [PATCH] powerpc: export debug register save function for KVM Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-10  9:15   ` Alexander Graf
2013-05-10  9:15     ` Alexander Graf
2013-05-07  9:40 ` [PATCH] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-07  9:40 ` [PATCH] KVM: PPC: Using "struct debug_reg" Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-07  9:40 ` [PATCH] KVM: PPC: Add userspace debug stub support Bharat Bhushan
2013-05-07  9:52   ` Bharat Bhushan
2013-05-10 10:18   ` Alexander Graf
2013-05-10 10:18     ` Alexander Graf
2013-05-10 17:31     ` Bhushan Bharat-R65777
2013-05-10 17:31       ` Bhushan Bharat-R65777
2013-05-10 17:44       ` Alexander Graf
2013-05-10 17:44         ` Alexander Graf
2013-05-11 10:24         ` Bhushan Bharat-R65777
2013-05-11 10:24           ` Bhushan Bharat-R65777
2013-05-11 13:18           ` Alexander Graf
2013-05-11 13:18             ` Alexander Graf
2013-05-13 14:33             ` Scott Wood
2013-05-13 14:33               ` Scott Wood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.