* [PATCH 0/6 v5] KVM :PPC: Userspace Debug support
@ 2013-06-24 9:20 Bharat Bhushan
2013-06-24 9:20 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan
` (6 more replies)
0 siblings, 7 replies; 22+ messages in thread
From: Bharat Bhushan @ 2013-06-24 9:20 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.
v4->v5
- Some comments reworded and other cleanup (like change of function name etc)
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 | 267 ++++++++++++++++++++++++++++----
arch/powerpc/kvm/booke.h | 5 +
arch/powerpc/kvm/e500_emulate.c | 27 ++++
14 files changed, 449 insertions(+), 184 deletions(-)
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 1/6 v5] powerpc: remove unnecessary line continuations 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 9:20 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan ` (5 subsequent siblings) 6 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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> --- v5: - no change 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 ceb4e7b..639a8de 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/6 v5] powerpc: move debug registers in a structure 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 2013-06-24 9:20 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 9:20 ` [PATCH 3/6 v5] powerpc: export debug register save function for KVM Bharat Bhushan ` (4 subsequent siblings) 6 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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 d7e67ca..5b8a7f1 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -147,22 +147,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 @@ -199,6 +184,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 b51a97c..c241c60 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 639a8de..01ff496 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 3b14d32..80b902f 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -853,8 +853,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; @@ -870,8 +870,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; @@ -893,16 +893,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 @@ -1030,14 +1030,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; } @@ -1049,7 +1049,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 */ @@ -1079,10 +1079,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; @@ -1101,9 +1101,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; @@ -1112,9 +1112,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; @@ -1134,30 +1134,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; @@ -1167,49 +1167,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: @@ -1239,18 +1239,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 @@ -1260,19 +1260,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; @@ -1284,32 +1284,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; @@ -1351,22 +1351,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; @@ -1504,9 +1504,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; } } @@ -1688,7 +1688,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 95068bf..3e46b2c 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -1294,7 +1294,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++) { @@ -1309,7 +1309,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; } @@ -1344,7 +1344,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 83efa2f..86d5bd8 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 @@ -1389,7 +1389,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); @@ -1400,24 +1400,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; @@ -1427,19 +1427,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 @@ -1456,8 +1457,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; } @@ -1485,13 +1486,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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/6 v5] powerpc: export debug register save function for KVM 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 2013-06-24 9:20 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan 2013-06-24 9:20 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 9:33 ` Alexander Graf 2013-06-24 9:20 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan ` (3 subsequent siblings) 6 siblings, 1 reply; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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 01ff496..3375cb7 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 3/6 v5] powerpc: export debug register save function for KVM 2013-06-24 9:20 ` [PATCH 3/6 v5] powerpc: export debug register save function for KVM Bharat Bhushan @ 2013-06-24 9:33 ` Alexander Graf 2013-06-24 10:08 ` Bhushan Bharat-R65777 0 siblings, 1 reply; 22+ messages in thread From: Alexander Graf @ 2013-06-24 9:33 UTC (permalink / raw) To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan On 24.06.2013, at 11:08, 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 01ff496..3375cb7 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 > #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ > #ifndef CONFIG_HAVE_HW_BREAKPOINT > static void set_debug_reg_defaults(struct thread_struct *thread) > -- > 1.7.0.4 > > > -- > To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 3/6 v5] powerpc: export debug register save function for KVM 2013-06-24 9:33 ` Alexander Graf @ 2013-06-24 10:08 ` Bhushan Bharat-R65777 0 siblings, 0 replies; 22+ messages in thread From: Bhushan Bharat-R65777 @ 2013-06-24 10:08 UTC (permalink / raw) To: Alexander Graf Cc: kvm-ppc@vger.kernel.org, kvm@vger.kernel.org, Wood Scott-B07421, tiejun.chen@windriver.com > -----Original Message----- > From: Alexander Graf [mailto:agraf@suse.de] > Sent: Monday, June 24, 2013 3:03 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 3/6 v5] powerpc: export debug register save function for KVM > > > On 24.06.2013, at 11:08, 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 > > 01ff496..3375cb7 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? Oops, I missed this comment. Will correct in next version. -Bharat > > > Alex > > > #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ > > #ifndef CONFIG_HAVE_HW_BREAKPOINT > > static void set_debug_reg_defaults(struct thread_struct *thread) > > -- > > 1.7.0.4 > > > > > > -- > > To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in > > the body of a message to majordomo@vger.kernel.org More majordomo info > > at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (2 preceding siblings ...) 2013-06-24 9:20 ` [PATCH 3/6 v5] powerpc: export debug register save function for KVM Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 9:20 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan ` (2 subsequent siblings) 6 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (3 preceding siblings ...) 2013-06-24 9:20 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 9:20 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 6 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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 62d4ece..3e9fc1d 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (4 preceding siblings ...) 2013-06-24 9:20 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan @ 2013-06-24 9:20 ` Bharat Bhushan 2013-06-24 10:43 ` Alexander Graf 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 6 siblings, 1 reply; 22+ messages in thread From: Bharat Bhushan @ 2013-06-24 9:20 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 | 233 ++++++++++++++++++++++++++++++++--- arch/powerpc/kvm/booke.h | 5 + 4 files changed, 224 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 838a577..aeb490d 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; + /* 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 3e9fc1d..8be3502 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 thread_struct thread; #ifdef CONFIG_PPC_FPU unsigned int fpscr; int fpexc_mode; @@ -698,12 +723,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) kvmppc_load_guest_fp(vcpu); #endif + /* Switch to guest debug context */ + thread.debug = vcpu->arch.shadow_dbg_reg; + switch_booke_debug_regs(&thread); + thread.debug = current->thread.debug; + current->thread.debug = vcpu->arch.shadow_dbg_reg; 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. */ + /* Switch back to user space debug context */ + switch_booke_debug_regs(&thread); + current->thread.debug = thread.debug; + #ifdef CONFIG_PPC_FPU kvmppc_save_guest_fp(vcpu); @@ -759,6 +793,30 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) } } +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 +877,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu, case BOOKE_INTERRUPT_CRITICAL: unknown_exception(®s); break; + case BOOKE_INTERRUPT_DEBUG: + /* Save DBSR before preemption is enabled */ + vcpu->arch.dbsr = mfspr(SPRN_DBSR); + kvmppc_clear_dbsr(); + break; } } @@ -1118,18 +1181,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 +1235,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 +1612,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 +1717,151 @@ void kvmppc_decrementer_func(unsigned long data) kvmppc_set_tsr_bits(vcpu, TSR_DIS); } +static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg, + uint64_t addr, int index) +{ + switch (index) { + case 0: + dbg_reg->dbcr0 |= DBCR0_IAC1; + dbg_reg->iac1 = addr; + break; + case 1: + dbg_reg->dbcr0 |= DBCR0_IAC2; + dbg_reg->iac2 = addr; + break; +#if CONFIG_PPC_ADV_DEBUG_IACS > 2 + case 2: + dbg_reg->dbcr0 |= DBCR0_IAC3; + dbg_reg->iac3 = addr; + break; + case 3: + dbg_reg->dbcr0 |= DBCR0_IAC4; + dbg_reg->iac4 = addr; + break; +#endif + default: + return -EINVAL; + } + + dbg_reg->dbcr0 |= DBCR0_IDM; + return 0; +} + +static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr, + int type, int index) +{ + switch (index) { + case 0: + if (type & KVMPPC_DEBUG_WATCH_READ) + dbg_reg->dbcr0 |= DBCR0_DAC1R; + if (type & KVMPPC_DEBUG_WATCH_WRITE) + dbg_reg->dbcr0 |= DBCR0_DAC1W; + dbg_reg->dac1 = addr; + break; + case 1: + if (type & KVMPPC_DEBUG_WATCH_READ) + dbg_reg->dbcr0 |= DBCR0_DAC2R; + if (type & KVMPPC_DEBUG_WATCH_WRITE) + dbg_reg->dbcr0 |= DBCR0_DAC2W; + dbg_reg->dac2 = addr; + break; + default: + return -EINVAL; + } + + dbg_reg->dbcr0 |= DBCR0_IDM; + return 0; +} + +#ifdef CONFIG_KVM_BOOKE_HV +void kvm_guest_may_change_msr_de(struct kvm_vcpu *vcpu, bool may_change) +{ + if (may_change) + /* Allow guest to change MSR.DE */ + vcpu->arch.shadow_msrp &= ~MSRP_DEP; + else + /* Don't allow guest to change MSR.DE */ + vcpu->arch.shadow_msrp |= MSRP_DEP; + +} +#endif + +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)) { + vcpu->arch.shadow_dbg_reg.dbcr0 = 0; + vcpu->guest_debug = 0; +#ifdef CONFIG_KVM_BOOKE_HV + kvm_guest_may_change_msr_de(vcpu, true); +#endif + return 0; + } + +#ifdef CONFIG_KVM_BOOKE_HV + kvm_guest_may_change_msr_de(vcpu, false); +#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; + + /* Code below handles only HW breakpoints */ + dbg_reg = &(vcpu->arch.shadow_dbg_reg); + +#ifdef CONFIG_KVM_BOOKE_HV + /* + * On BookE-HV (e500mc) the guest is always executed with MSR.GS=1 + * DBCR1 and DBCR2 are set to trigger debug events when MSR.PR is 0 + */ + dbg_reg->dbcr1 = 0; + dbg_reg->dbcr2 = 0; +#else + /* + * On BookE-PR (e500v2) the guest is always executed with MSR.PR=1 + * We set DBCR1 and DBCR2 to only trigger debug events when MSR.PR + * is set. + */ + dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US | + DBCR1_IAC4US; + dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; +#endif + + if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) + return 0; + + 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_add_breakpoint(dbg_reg, addr, b++)) + return -EINVAL; + } else { + /* Setting H/W watchpoint */ + if (kvmppc_booke_add_watchpoint(dbg_reg, 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 +1872,9 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu) { current->thread.kvm_vcpu = NULL; vcpu->cpu = -1; + + /* 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support 2013-06-24 9:20 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan @ 2013-06-24 10:43 ` Alexander Graf 2013-06-24 11:22 ` Bhushan Bharat-R65777 0 siblings, 1 reply; 22+ messages in thread From: Alexander Graf @ 2013-06-24 10:43 UTC (permalink / raw) To: Bharat Bhushan; +Cc: kvm-ppc, kvm, scottwood, tiejun.chen, Bharat Bhushan On 24.06.2013, at 11:08, 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 | 233 ++++++++++++++++++++++++++++++++--- > arch/powerpc/kvm/booke.h | 5 + > 4 files changed, 224 insertions(+), 18 deletions(-) > > diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h > index 838a577..aeb490d 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; > + /* 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 3e9fc1d..8be3502 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 thread_struct thread; > #ifdef CONFIG_PPC_FPU > unsigned int fpscr; > int fpexc_mode; > @@ -698,12 +723,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) > > kvmppc_load_guest_fp(vcpu); > #endif > + /* Switch to guest debug context */ > + thread.debug = vcpu->arch.shadow_dbg_reg; > + switch_booke_debug_regs(&thread); > + thread.debug = current->thread.debug; > + current->thread.debug = vcpu->arch.shadow_dbg_reg; > > 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. */ > > + /* Switch back to user space debug context */ > + switch_booke_debug_regs(&thread); > + current->thread.debug = thread.debug; > + > #ifdef CONFIG_PPC_FPU > kvmppc_save_guest_fp(vcpu); > > @@ -759,6 +793,30 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) > } > } > > +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 +877,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu, > case BOOKE_INTERRUPT_CRITICAL: > unknown_exception(®s); > break; > + case BOOKE_INTERRUPT_DEBUG: > + /* Save DBSR before preemption is enabled */ > + vcpu->arch.dbsr = mfspr(SPRN_DBSR); > + kvmppc_clear_dbsr(); > + break; > } > } > > @@ -1118,18 +1181,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 +1235,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 +1612,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 +1717,151 @@ void kvmppc_decrementer_func(unsigned long data) > kvmppc_set_tsr_bits(vcpu, TSR_DIS); > } > > +static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg, > + uint64_t addr, int index) > +{ > + switch (index) { > + case 0: > + dbg_reg->dbcr0 |= DBCR0_IAC1; > + dbg_reg->iac1 = addr; > + break; > + case 1: > + dbg_reg->dbcr0 |= DBCR0_IAC2; > + dbg_reg->iac2 = addr; > + break; > +#if CONFIG_PPC_ADV_DEBUG_IACS > 2 > + case 2: > + dbg_reg->dbcr0 |= DBCR0_IAC3; > + dbg_reg->iac3 = addr; > + break; > + case 3: > + dbg_reg->dbcr0 |= DBCR0_IAC4; > + dbg_reg->iac4 = addr; > + break; > +#endif > + default: > + return -EINVAL; > + } > + > + dbg_reg->dbcr0 |= DBCR0_IDM; > + return 0; > +} > + > +static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr, > + int type, int index) > +{ > + switch (index) { > + case 0: > + if (type & KVMPPC_DEBUG_WATCH_READ) > + dbg_reg->dbcr0 |= DBCR0_DAC1R; > + if (type & KVMPPC_DEBUG_WATCH_WRITE) > + dbg_reg->dbcr0 |= DBCR0_DAC1W; > + dbg_reg->dac1 = addr; > + break; > + case 1: > + if (type & KVMPPC_DEBUG_WATCH_READ) > + dbg_reg->dbcr0 |= DBCR0_DAC2R; > + if (type & KVMPPC_DEBUG_WATCH_WRITE) > + dbg_reg->dbcr0 |= DBCR0_DAC2W; > + dbg_reg->dac2 = addr; > + break; > + default: > + return -EINVAL; > + } > + > + dbg_reg->dbcr0 |= DBCR0_IDM; > + return 0; > +} > + > +#ifdef CONFIG_KVM_BOOKE_HV > +void kvm_guest_may_change_msr_de(struct kvm_vcpu *vcpu, bool may_change) > +{ > + if (may_change) > + /* Allow guest to change MSR.DE */ > + vcpu->arch.shadow_msrp &= ~MSRP_DEP; > + else > + /* Don't allow guest to change MSR.DE */ > + vcpu->arch.shadow_msrp |= MSRP_DEP; > + > +} > +#endif Could you please provide this function regardless of CONFIG_KVM_BOOKE_HV? For PR, just save a bool away somewhere and emulate the same behavior (guest may not modify MSR.DE). That way we ensure consistency between the targets and get rid of ugly #ifdef's :). Alex ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support 2013-06-24 10:43 ` Alexander Graf @ 2013-06-24 11:22 ` Bhushan Bharat-R65777 2013-06-24 12:05 ` Alexander Graf 0 siblings, 1 reply; 22+ messages in thread From: Bhushan Bharat-R65777 @ 2013-06-24 11:22 UTC (permalink / raw) To: Alexander Graf Cc: kvm-ppc@vger.kernel.org, kvm@vger.kernel.org, Wood Scott-B07421, tiejun.chen@windriver.com > -----Original Message----- > From: Alexander Graf [mailto:agraf@suse.de] > Sent: Monday, June 24, 2013 4:13 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 6/6 v5] KVM: PPC: Add userspace debug stub support > > > On 24.06.2013, at 11:08, 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 | 233 ++++++++++++++++++++++++++++++++--- > > arch/powerpc/kvm/booke.h | 5 + > > 4 files changed, 224 insertions(+), 18 deletions(-) > > > > diff --git a/arch/powerpc/include/asm/kvm_host.h > > b/arch/powerpc/include/asm/kvm_host.h > > index 838a577..aeb490d 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; > > + /* 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 > > 3e9fc1d..8be3502 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 thread_struct thread; > > #ifdef CONFIG_PPC_FPU > > unsigned int fpscr; > > int fpexc_mode; > > @@ -698,12 +723,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, > > struct kvm_vcpu *vcpu) > > > > kvmppc_load_guest_fp(vcpu); > > #endif > > + /* Switch to guest debug context */ > > + thread.debug = vcpu->arch.shadow_dbg_reg; > > + switch_booke_debug_regs(&thread); > > + thread.debug = current->thread.debug; > > + current->thread.debug = vcpu->arch.shadow_dbg_reg; > > > > 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. */ > > > > + /* Switch back to user space debug context */ > > + switch_booke_debug_regs(&thread); > > + current->thread.debug = thread.debug; > > + > > #ifdef CONFIG_PPC_FPU > > kvmppc_save_guest_fp(vcpu); > > > > @@ -759,6 +793,30 @@ static int emulation_exit(struct kvm_run *run, struct > kvm_vcpu *vcpu) > > } > > } > > > > +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 +877,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu > *vcpu, > > case BOOKE_INTERRUPT_CRITICAL: > > unknown_exception(®s); > > break; > > + case BOOKE_INTERRUPT_DEBUG: > > + /* Save DBSR before preemption is enabled */ > > + vcpu->arch.dbsr = mfspr(SPRN_DBSR); > > + kvmppc_clear_dbsr(); > > + break; > > } > > } > > > > @@ -1118,18 +1181,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 +1235,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 +1612,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 +1717,151 @@ void kvmppc_decrementer_func(unsigned long data) > > kvmppc_set_tsr_bits(vcpu, TSR_DIS); > > } > > > > +static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg, > > + uint64_t addr, int index) > > +{ > > + switch (index) { > > + case 0: > > + dbg_reg->dbcr0 |= DBCR0_IAC1; > > + dbg_reg->iac1 = addr; > > + break; > > + case 1: > > + dbg_reg->dbcr0 |= DBCR0_IAC2; > > + dbg_reg->iac2 = addr; > > + break; > > +#if CONFIG_PPC_ADV_DEBUG_IACS > 2 > > + case 2: > > + dbg_reg->dbcr0 |= DBCR0_IAC3; > > + dbg_reg->iac3 = addr; > > + break; > > + case 3: > > + dbg_reg->dbcr0 |= DBCR0_IAC4; > > + dbg_reg->iac4 = addr; > > + break; > > +#endif > > + default: > > + return -EINVAL; > > + } > > + > > + dbg_reg->dbcr0 |= DBCR0_IDM; > > + return 0; > > +} > > + > > +static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t > addr, > > + int type, int index) > > +{ > > + switch (index) { > > + case 0: > > + if (type & KVMPPC_DEBUG_WATCH_READ) > > + dbg_reg->dbcr0 |= DBCR0_DAC1R; > > + if (type & KVMPPC_DEBUG_WATCH_WRITE) > > + dbg_reg->dbcr0 |= DBCR0_DAC1W; > > + dbg_reg->dac1 = addr; > > + break; > > + case 1: > > + if (type & KVMPPC_DEBUG_WATCH_READ) > > + dbg_reg->dbcr0 |= DBCR0_DAC2R; > > + if (type & KVMPPC_DEBUG_WATCH_WRITE) > > + dbg_reg->dbcr0 |= DBCR0_DAC2W; > > + dbg_reg->dac2 = addr; > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + dbg_reg->dbcr0 |= DBCR0_IDM; > > + return 0; > > +} > > + > > +#ifdef CONFIG_KVM_BOOKE_HV > > +void kvm_guest_may_change_msr_de(struct kvm_vcpu *vcpu, bool > > +may_change) { > > + if (may_change) > > + /* Allow guest to change MSR.DE */ > > + vcpu->arch.shadow_msrp &= ~MSRP_DEP; > > + else > > + /* Don't allow guest to change MSR.DE */ > > + vcpu->arch.shadow_msrp |= MSRP_DEP; > > + > > +} > > +#endif > > Could you please provide this function regardless of CONFIG_KVM_BOOKE_HV? For > PR, just save a bool away somewhere and emulate the same behavior (guest may not > modify MSR.DE). You mean modify kvmppc_set_msr() (kvmppc_vcpu_sync_debug()) to consider this bool to change/not_change msr.de? Thanks -Bharat > > That way we ensure consistency between the targets and get rid of ugly #ifdef's > :). > > > Alex > ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support 2013-06-24 11:22 ` Bhushan Bharat-R65777 @ 2013-06-24 12:05 ` Alexander Graf 0 siblings, 0 replies; 22+ messages in thread From: Alexander Graf @ 2013-06-24 12:05 UTC (permalink / raw) To: Bhushan Bharat-R65777 Cc: kvm-ppc@vger.kernel.org, kvm@vger.kernel.org, Wood Scott-B07421, tiejun.chen@windriver.com On 24.06.2013, at 13:22, Bhushan Bharat-R65777 wrote: > > >> -----Original Message----- >> From: Alexander Graf [mailto:agraf@suse.de] >> Sent: Monday, June 24, 2013 4:13 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 6/6 v5] KVM: PPC: Add userspace debug stub support >> >> >> On 24.06.2013, at 11:08, 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 | 233 ++++++++++++++++++++++++++++++++--- >>> arch/powerpc/kvm/booke.h | 5 + >>> 4 files changed, 224 insertions(+), 18 deletions(-) >>> >>> diff --git a/arch/powerpc/include/asm/kvm_host.h >>> b/arch/powerpc/include/asm/kvm_host.h >>> index 838a577..aeb490d 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; >>> + /* 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 >>> 3e9fc1d..8be3502 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 thread_struct thread; >>> #ifdef CONFIG_PPC_FPU >>> unsigned int fpscr; >>> int fpexc_mode; >>> @@ -698,12 +723,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, >>> struct kvm_vcpu *vcpu) >>> >>> kvmppc_load_guest_fp(vcpu); >>> #endif >>> + /* Switch to guest debug context */ >>> + thread.debug = vcpu->arch.shadow_dbg_reg; >>> + switch_booke_debug_regs(&thread); >>> + thread.debug = current->thread.debug; >>> + current->thread.debug = vcpu->arch.shadow_dbg_reg; >>> >>> 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. */ >>> >>> + /* Switch back to user space debug context */ >>> + switch_booke_debug_regs(&thread); >>> + current->thread.debug = thread.debug; >>> + >>> #ifdef CONFIG_PPC_FPU >>> kvmppc_save_guest_fp(vcpu); >>> >>> @@ -759,6 +793,30 @@ static int emulation_exit(struct kvm_run *run, struct >> kvm_vcpu *vcpu) >>> } >>> } >>> >>> +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 +877,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu >> *vcpu, >>> case BOOKE_INTERRUPT_CRITICAL: >>> unknown_exception(®s); >>> break; >>> + case BOOKE_INTERRUPT_DEBUG: >>> + /* Save DBSR before preemption is enabled */ >>> + vcpu->arch.dbsr = mfspr(SPRN_DBSR); >>> + kvmppc_clear_dbsr(); >>> + break; >>> } >>> } >>> >>> @@ -1118,18 +1181,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 +1235,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 +1612,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 +1717,151 @@ void kvmppc_decrementer_func(unsigned long data) >>> kvmppc_set_tsr_bits(vcpu, TSR_DIS); >>> } >>> >>> +static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg, >>> + uint64_t addr, int index) >>> +{ >>> + switch (index) { >>> + case 0: >>> + dbg_reg->dbcr0 |= DBCR0_IAC1; >>> + dbg_reg->iac1 = addr; >>> + break; >>> + case 1: >>> + dbg_reg->dbcr0 |= DBCR0_IAC2; >>> + dbg_reg->iac2 = addr; >>> + break; >>> +#if CONFIG_PPC_ADV_DEBUG_IACS > 2 >>> + case 2: >>> + dbg_reg->dbcr0 |= DBCR0_IAC3; >>> + dbg_reg->iac3 = addr; >>> + break; >>> + case 3: >>> + dbg_reg->dbcr0 |= DBCR0_IAC4; >>> + dbg_reg->iac4 = addr; >>> + break; >>> +#endif >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + dbg_reg->dbcr0 |= DBCR0_IDM; >>> + return 0; >>> +} >>> + >>> +static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t >> addr, >>> + int type, int index) >>> +{ >>> + switch (index) { >>> + case 0: >>> + if (type & KVMPPC_DEBUG_WATCH_READ) >>> + dbg_reg->dbcr0 |= DBCR0_DAC1R; >>> + if (type & KVMPPC_DEBUG_WATCH_WRITE) >>> + dbg_reg->dbcr0 |= DBCR0_DAC1W; >>> + dbg_reg->dac1 = addr; >>> + break; >>> + case 1: >>> + if (type & KVMPPC_DEBUG_WATCH_READ) >>> + dbg_reg->dbcr0 |= DBCR0_DAC2R; >>> + if (type & KVMPPC_DEBUG_WATCH_WRITE) >>> + dbg_reg->dbcr0 |= DBCR0_DAC2W; >>> + dbg_reg->dac2 = addr; >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + dbg_reg->dbcr0 |= DBCR0_IDM; >>> + return 0; >>> +} >>> + >>> +#ifdef CONFIG_KVM_BOOKE_HV >>> +void kvm_guest_may_change_msr_de(struct kvm_vcpu *vcpu, bool >>> +may_change) { >>> + if (may_change) >>> + /* Allow guest to change MSR.DE */ >>> + vcpu->arch.shadow_msrp &= ~MSRP_DEP; >>> + else >>> + /* Don't allow guest to change MSR.DE */ >>> + vcpu->arch.shadow_msrp |= MSRP_DEP; >>> + >>> +} >>> +#endif >> >> Could you please provide this function regardless of CONFIG_KVM_BOOKE_HV? For >> PR, just save a bool away somewhere and emulate the same behavior (guest may not >> modify MSR.DE). > > You mean modify kvmppc_set_msr() (kvmppc_vcpu_sync_debug()) to consider this bool to change/not_change msr.de? Yep :). Alex ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 0/6 v5] KVM :PPC: Userspace Debug support 2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (5 preceding siblings ...) 2013-06-24 9:20 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-26 5:54 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan ` (5 more replies) 6 siblings, 6 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey Cc: Bharat Bhushan From: Bharat Bhushan <bharat.bhushan@freescale.com> Note: These patches are based on http://github.com/agraf/linux-2.6.git queue 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. v4->v5 - Some comments reworded and other cleanup (like change of function name etc) - Added a function for setting MSRP rather than inline 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 registers 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 | 273 ++++++++++++++++++++++++++++---- arch/powerpc/kvm/booke.h | 5 + arch/powerpc/kvm/e500_emulate.c | 27 +++ 14 files changed, 455 insertions(+), 184 deletions(-) ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/6 v5] powerpc: remove unnecessary line continuations 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-26 5:54 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan ` (4 subsequent siblings) 5 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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 ceb4e7b..639a8de 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/6 v5] powerpc: move debug registers in a structure 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 2013-06-26 5:54 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-26 5:54 ` [PATCH 3/6 v5] powerpc: export debug registers save function for KVM Bharat Bhushan ` (3 subsequent siblings) 5 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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 d7e67ca..5b8a7f1 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -147,22 +147,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 @@ -199,6 +184,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 b51a97c..c241c60 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 639a8de..01ff496 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 3b14d32..80b902f 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -853,8 +853,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; @@ -870,8 +870,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; @@ -893,16 +893,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 @@ -1030,14 +1030,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; } @@ -1049,7 +1049,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 */ @@ -1079,10 +1079,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; @@ -1101,9 +1101,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; @@ -1112,9 +1112,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; @@ -1134,30 +1134,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; @@ -1167,49 +1167,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: @@ -1239,18 +1239,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 @@ -1260,19 +1260,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; @@ -1284,32 +1284,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; @@ -1351,22 +1351,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; @@ -1504,9 +1504,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; } } @@ -1688,7 +1688,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 95068bf..3e46b2c 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -1294,7 +1294,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++) { @@ -1309,7 +1309,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; } @@ -1344,7 +1344,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 83efa2f..86d5bd8 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 @@ -1389,7 +1389,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); @@ -1400,24 +1400,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; @@ -1427,19 +1427,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 @@ -1456,8 +1457,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; } @@ -1485,13 +1486,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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/6 v5] powerpc: export debug registers save function for KVM 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan 2013-06-26 5:54 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan 2013-06-26 5:54 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-27 4:47 ` Stephen Rothwell 2013-06-26 5:54 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan ` (2 subsequent siblings) 5 siblings, 1 reply; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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 01ff496..da586aa 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_GPL(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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 3/6 v5] powerpc: export debug registers save function for KVM 2013-06-26 5:54 ` [PATCH 3/6 v5] powerpc: export debug registers save function for KVM Bharat Bhushan @ 2013-06-27 4:47 ` Stephen Rothwell 0 siblings, 0 replies; 22+ messages in thread From: Stephen Rothwell @ 2013-06-27 4:47 UTC (permalink / raw) To: Bharat Bhushan Cc: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey, Bharat Bhushan [-- Attachment #1: Type: text/plain, Size: 729 bytes --] Hi, On Wed, 26 Jun 2013 11:12:23 +0530 Bharat Bhushan <r65777@freescale.com> wrote: > > 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 We usually don't bother guarding function declarations. -- Cheers, Stephen Rothwell sfr@canb.auug.org.au [-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (2 preceding siblings ...) 2013-06-26 5:54 ` [PATCH 3/6 v5] powerpc: export debug registers save function for KVM Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-26 6:54 ` tiejun.chen 2013-06-26 5:54 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan 2013-06-26 5:54 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan 5 siblings, 1 reply; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction 2013-06-26 5:54 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan @ 2013-06-26 6:54 ` tiejun.chen [not found] ` <6A3DF150A5B70D4F9B66A25E3F7C888D07086C2F@039-SN2MPN1-013.039d.mgd.msft.net> 0 siblings, 1 reply; 22+ messages in thread From: tiejun.chen @ 2013-06-26 6:54 UTC (permalink / raw) To: Bharat Bhushan Cc: kvm-ppc, kvm, agraf, scottwood, benh, linuxppc-dev, linux-kernel, mikey, Bharat Bhushan On 06/26/2013 01:42 PM, Bharat Bhushan wrote: > "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 As I think the case, "OC = 0", is a bit specific since IIRC, if the OC operand is omitted, its equal 0 by default. So I think we should start this OC value from 1 or other magic number. And if possible, we'd better add some comments to describe this to make the OC definition readable. Tiejun > > #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; > } > ^ permalink raw reply [flat|nested] 22+ messages in thread
[parent not found: <6A3DF150A5B70D4F9B66A25E3F7C888D07086C2F@039-SN2MPN1-013.039d.mgd.msft.net>]
* Re: [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction [not found] ` <6A3DF150A5B70D4F9B66A25E3F7C888D07086C2F@039-SN2MPN1-013.039d.mgd.msft.net> @ 2013-06-26 9:17 ` tiejun.chen 0 siblings, 0 replies; 22+ messages in thread From: tiejun.chen @ 2013-06-26 9:17 UTC (permalink / raw) To: Bhushan Bharat-R65777 Cc: kvm-ppc@vger.kernel.org, kvm@vger.kernel.org, agraf@suse.de, Wood Scott-B07421, benh@kernel.crashing.org, linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, mikey@neuling.org On 06/26/2013 04:44 PM, Bhushan Bharat-R65777 wrote: > > >> -----Original Message----- >> From: tiejun.chen [mailto:tiejun.chen@windriver.com] >> Sent: Wednesday, June 26, 2013 12:25 PM >> To: Bhushan Bharat-R65777 >> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; agraf@suse.de; Wood Scott- >> B07421; benh@kernel.crashing.org; linuxppc-dev@lists.ozlabs.org; linux- >> kernel@vger.kernel.org; mikey@neuling.org; Bhushan Bharat-R65777 >> Subject: Re: [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction >> >> On 06/26/2013 01:42 PM, Bharat Bhushan wrote: >>> "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 >> >> As I think the case, "OC = 0", is a bit specific since IIRC, if the OC >> operand is omitted, its equal 0 by default. So I think we should start this OC >> value from 1 or other magic number. > > ehpriv instruction is defined to be used as: > ehpriv OC // where OC can be 0,1, ... n > and in extended for it can be used as > ehpriv // With no OC, and here it assumes OC = 0 > So OC = 0 is not specific but "ehpriv" is same as "ehpriv 0". Yes, this is just what I mean. > > I do not think of any special reason to reserve "ehpriv" and "ehpriv 0". So I still prefer we can reserve the 'ehpriv' without OC operand as one simple approach to test or develop something for KVM quickly because its really convenient to trap into the hypervisor only with one 'ehpriv' instruction easily. But I have no further objection if you guys are fine to this ;-) Tiejun > > Thanks > -Bharat > >> >> And if possible, we'd better add some comments to describe this to make the OC >> definition readable. >> >> Tiejun >> >>> >>> #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; >>> } >>> >> > ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (3 preceding siblings ...) 2013-06-26 5:54 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 2013-06-26 5:54 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan 5 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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 62d4ece..3e9fc1d 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support 2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan ` (4 preceding siblings ...) 2013-06-26 5:54 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan @ 2013-06-26 5:54 ` Bharat Bhushan 5 siblings, 0 replies; 22+ messages in thread From: Bharat Bhushan @ 2013-06-26 5:54 UTC (permalink / raw) To: kvm-ppc, kvm, agraf, scottwood, tiejun.chen, benh, linuxppc-dev, linux-kernel, mikey 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 | 239 ++++++++++++++++++++++++++++++++--- arch/powerpc/kvm/booke.h | 5 + 4 files changed, 230 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 838a577..aeb490d 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; + /* 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 3e9fc1d..8cd8d41 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 thread_struct thread; #ifdef CONFIG_PPC_FPU unsigned int fpscr; int fpexc_mode; @@ -698,12 +723,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) kvmppc_load_guest_fp(vcpu); #endif + /* Switch to guest debug context */ + thread.debug = vcpu->arch.shadow_dbg_reg; + switch_booke_debug_regs(&thread); + thread.debug = current->thread.debug; + current->thread.debug = vcpu->arch.shadow_dbg_reg; 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. */ + /* Switch back to user space debug context */ + switch_booke_debug_regs(&thread); + current->thread.debug = thread.debug; + #ifdef CONFIG_PPC_FPU kvmppc_save_guest_fp(vcpu); @@ -759,6 +793,30 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) } } +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 +877,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu, case BOOKE_INTERRUPT_CRITICAL: unknown_exception(®s); break; + case BOOKE_INTERRUPT_DEBUG: + /* Save DBSR before preemption is enabled */ + vcpu->arch.dbsr = mfspr(SPRN_DBSR); + kvmppc_clear_dbsr(); + break; } } @@ -1118,18 +1181,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 +1235,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 +1612,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 +1717,157 @@ void kvmppc_decrementer_func(unsigned long data) kvmppc_set_tsr_bits(vcpu, TSR_DIS); } +static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg, + uint64_t addr, int index) +{ + switch (index) { + case 0: + dbg_reg->dbcr0 |= DBCR0_IAC1; + dbg_reg->iac1 = addr; + break; + case 1: + dbg_reg->dbcr0 |= DBCR0_IAC2; + dbg_reg->iac2 = addr; + break; +#if CONFIG_PPC_ADV_DEBUG_IACS > 2 + case 2: + dbg_reg->dbcr0 |= DBCR0_IAC3; + dbg_reg->iac3 = addr; + break; + case 3: + dbg_reg->dbcr0 |= DBCR0_IAC4; + dbg_reg->iac4 = addr; + break; +#endif + default: + return -EINVAL; + } + + dbg_reg->dbcr0 |= DBCR0_IDM; + return 0; +} + +static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr, + int type, int index) +{ + switch (index) { + case 0: + if (type & KVMPPC_DEBUG_WATCH_READ) + dbg_reg->dbcr0 |= DBCR0_DAC1R; + if (type & KVMPPC_DEBUG_WATCH_WRITE) + dbg_reg->dbcr0 |= DBCR0_DAC1W; + dbg_reg->dac1 = addr; + break; + case 1: + if (type & KVMPPC_DEBUG_WATCH_READ) + dbg_reg->dbcr0 |= DBCR0_DAC2R; + if (type & KVMPPC_DEBUG_WATCH_WRITE) + dbg_reg->dbcr0 |= DBCR0_DAC2W; + dbg_reg->dac2 = addr; + break; + default: + return -EINVAL; + } + + dbg_reg->dbcr0 |= DBCR0_IDM; + return 0; +} +void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, bool set) +{ + /* XXX: Add similar MSR protection for BookE-PR */ +#ifdef CONFIG_KVM_BOOKE_HV + BUG_ON(prot_bitmap & ~(MSRP_UCLEP | MSRP_DEP | MSRP_PMMP)); + if (set) { + if (prot_bitmap & MSR_UCLE) + vcpu->arch.shadow_msrp |= MSRP_UCLEP; + if (prot_bitmap & MSR_DE) + vcpu->arch.shadow_msrp |= MSRP_DEP; + if (prot_bitmap & MSR_PMM) + vcpu->arch.shadow_msrp |= MSRP_PMMP; + } else { + if (prot_bitmap & MSR_UCLE) + vcpu->arch.shadow_msrp &= ~MSRP_UCLEP; + if (prot_bitmap & MSR_DE) + vcpu->arch.shadow_msrp &= ~MSRP_DEP; + if (prot_bitmap & MSR_PMM) + vcpu->arch.shadow_msrp &= ~MSRP_PMMP; + } +#endif +} + +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)) { + vcpu->arch.shadow_dbg_reg.dbcr0 = 0; + vcpu->guest_debug = 0; + kvm_guest_protect_msr(vcpu, MSR_DE, false); + return 0; + } + + kvm_guest_protect_msr(vcpu, MSR_DE, true); + 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; + + /* Code below handles only HW breakpoints */ + dbg_reg = &(vcpu->arch.shadow_dbg_reg); + +#ifdef CONFIG_KVM_BOOKE_HV + /* + * On BookE-HV (e500mc) the guest is always executed with MSR.GS=1 + * DBCR1 and DBCR2 are set to trigger debug events when MSR.PR is 0 + */ + dbg_reg->dbcr1 = 0; + dbg_reg->dbcr2 = 0; +#else + /* + * On BookE-PR (e500v2) the guest is always executed with MSR.PR=1 + * We set DBCR1 and DBCR2 to only trigger debug events when MSR.PR + * is set. + */ + dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US | + DBCR1_IAC4US; + dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; +#endif + + if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) + return 0; + + 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_add_breakpoint(dbg_reg, addr, b++)) + return -EINVAL; + } else { + /* Setting H/W watchpoint */ + if (kvmppc_booke_add_watchpoint(dbg_reg, 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 +1878,9 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu) { current->thread.kvm_vcpu = NULL; vcpu->cpu = -1; + + /* 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.7.0.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2013-06-27 4:47 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-24 9:20 [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan
2013-06-24 9:20 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan
2013-06-24 9:20 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan
2013-06-24 9:20 ` [PATCH 3/6 v5] powerpc: export debug register save function for KVM Bharat Bhushan
2013-06-24 9:33 ` Alexander Graf
2013-06-24 10:08 ` Bhushan Bharat-R65777
2013-06-24 9:20 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan
2013-06-24 9:20 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan
2013-06-24 9:20 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan
2013-06-24 10:43 ` Alexander Graf
2013-06-24 11:22 ` Bhushan Bharat-R65777
2013-06-24 12:05 ` Alexander Graf
2013-06-26 5:54 ` [PATCH 0/6 v5] KVM :PPC: Userspace Debug support Bharat Bhushan
2013-06-26 5:54 ` [PATCH 1/6 v5] powerpc: remove unnecessary line continuations Bharat Bhushan
2013-06-26 5:54 ` [PATCH 2/6 v5] powerpc: move debug registers in a structure Bharat Bhushan
2013-06-26 5:54 ` [PATCH 3/6 v5] powerpc: export debug registers save function for KVM Bharat Bhushan
2013-06-27 4:47 ` Stephen Rothwell
2013-06-26 5:54 ` [PATCH 4/6 v5] KVM: PPC: exit to user space on "ehpriv" instruction Bharat Bhushan
2013-06-26 6:54 ` tiejun.chen
[not found] ` <6A3DF150A5B70D4F9B66A25E3F7C888D07086C2F@039-SN2MPN1-013.039d.mgd.msft.net>
2013-06-26 9:17 ` tiejun.chen
2013-06-26 5:54 ` [PATCH 5/6 v5] KVM: PPC: Using "struct debug_reg" Bharat Bhushan
2013-06-26 5:54 ` [PATCH 6/6 v5] KVM: PPC: Add userspace debug stub support Bharat Bhushan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox