From: Bharat Bhushan <r65777@freescale.com>
To: <kvm-ppc@vger.kernel.org>, <kvm@vger.kernel.org>, <agraf@suse.de>
Cc: Bharat Bhushan <Bharat.Bhushan@freescale.com>
Subject: [PATCH 2/2] KVM: PPC: booke/bookehv: Add guest debug support
Date: Thu, 26 Jul 2012 11:02:14 +0530 [thread overview]
Message-ID: <1343280734-3359-2-git-send-email-Bharat.Bhushan@freescale.com> (raw)
In-Reply-To: <1343280734-3359-1-git-send-email-Bharat.Bhushan@freescale.com>
This patch adds:
1) KVM debug handler added for e500v2.
2) Guest debug by qemu gdb stub.
Signed-off-by: Liu Yu <yu.liu@freescale.com>
Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
[bharat.bhushan@freescale.com: Substantial changes]
Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
arch/powerpc/include/asm/kvm.h | 21 +++++
arch/powerpc/include/asm/kvm_host.h | 7 ++
arch/powerpc/include/asm/kvm_ppc.h | 2 +
arch/powerpc/include/asm/reg_booke.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 31 ++++++-
arch/powerpc/kvm/booke.c | 146 +++++++++++++++++++++++++++---
arch/powerpc/kvm/booke_interrupts.S | 160 ++++++++++++++++++++++++++++++++-
arch/powerpc/kvm/bookehv_interrupts.S | 141 ++++++++++++++++++++++++++++-
arch/powerpc/kvm/e500mc.c | 3 +-
arch/powerpc/kvm/powerpc.c | 2 +-
10 files changed, 492 insertions(+), 22 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 3c14202..da71c84 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -25,6 +25,7 @@
/* Select powerpc specific features in <linux/kvm.h> */
#define __KVM_HAVE_SPAPR_TCE
#define __KVM_HAVE_PPC_SMT
+#define __KVM_HAVE_GUEST_DEBUG
struct kvm_regs {
__u64 pc;
@@ -265,10 +266,19 @@ struct kvm_fpu {
};
struct kvm_debug_exit_arch {
+ __u32 exception;
+ __u32 pc;
+ __u32 status;
};
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
+ struct {
+ __u64 addr;
+ __u32 type;
+ __u32 pad1;
+ __u64 pad2;
+ } bp[16];
};
/* definition of registers in kvm_run */
@@ -285,6 +295,17 @@ struct kvm_sync_regs {
#define KVM_CPU_3S_64 4
#define KVM_CPU_E500MC 5
+/* Debug related defines */
+#define KVM_INST_GUESTGDB 0x7C00021C /* ehpriv OC=0 */
+
+#define KVM_GUESTDBG_USE_SW_BP 0x00010000
+#define KVM_GUESTDBG_USE_HW_BP 0x00020000
+
+#define KVMPPC_DEBUG_NOTYPE 0x0
+#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1)
+#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2)
+#define KVMPPC_DEBUG_WATCH_READ (1UL << 3)
+
/* for KVM_CAP_SPAPR_TCE */
struct kvm_create_spapr_tce {
__u64 liobn;
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 7a45194..524af7a 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -458,7 +458,12 @@ struct kvm_vcpu_arch {
u32 ccr0;
u32 ccr1;
u32 dbsr;
+ /* guest debug regiters*/
struct kvmppc_booke_debug_reg dbg_reg;
+ /* shadow debug registers */
+ struct kvmppc_booke_debug_reg shadow_dbg_reg;
+ /* host debug regiters*/
+ struct kvmppc_booke_debug_reg host_dbg_reg;
u64 mmcr[3];
u32 pmc[8];
@@ -492,6 +497,7 @@ struct kvm_vcpu_arch {
u32 tlbcfg[4];
u32 mmucfg;
u32 epr;
+ u32 crit_save;
#endif
gpa_t paddr_accessed;
gva_t vaddr_accessed;
@@ -533,6 +539,7 @@ struct kvm_vcpu_arch {
struct kvm_vcpu_arch_shared *shared;
unsigned long magic_page_pa; /* phys addr to map the magic page to */
unsigned long magic_page_ea; /* effect. addr to map the magic page to */
+ struct kvm_guest_debug_arch dbg; /* debug arg between kvm and qemu */
#ifdef CONFIG_KVM_BOOK3S_64_HV
struct kvm_vcpu_arch_shared shregs;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 823d563..c97b234 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -115,6 +115,8 @@ extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn,
ulong val);
extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn,
ulong *val);
+extern int kvmppc_core_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg);
extern int kvmppc_booke_init(void);
extern void kvmppc_booke_exit(void);
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index e07e6af..b417de3 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -56,6 +56,7 @@
#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */
#define SPRN_EPCR 0x133 /* Embedded Processor Control Register */
#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */
+#define SPRN_DBCR4 0x233 /* Debug Control Register 4 */
#define SPRN_MSRP 0x137 /* MSR Protect Register */
#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */
#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 52c7ad7..1310775 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -116,7 +116,7 @@ int main(void)
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu));
#endif
-#ifdef CONFIG_KVM_BOOKE_HV
+#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
DEFINE(THREAD_KVM_VCPU, offsetof(struct thread_struct, kvm_vcpu));
#endif
@@ -431,6 +431,9 @@ int main(void)
DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid));
+#ifdef CONFIG_BOOKE
+ DEFINE(VCPU_CRIT_SAVE, offsetof(struct kvm_vcpu, arch.crit_save));
+#endif
/* book3s */
#ifdef CONFIG_KVM_BOOK3S_64_HV
@@ -562,6 +565,32 @@ int main(void)
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
+ DEFINE(VCPU_DBSR, offsetof(struct kvm_vcpu, arch.dbsr));
+ DEFINE(VCPU_SHADOW_DBG, offsetof(struct kvm_vcpu, arch.shadow_dbg_reg));
+ DEFINE(VCPU_HOST_DBG, offsetof(struct kvm_vcpu, arch.host_dbg_reg));
+ DEFINE(KVMPPC_DBG_DBCR0, offsetof(struct kvmppc_booke_debug_reg,
+ dbcr0));
+ DEFINE(KVMPPC_DBG_DBCR1, offsetof(struct kvmppc_booke_debug_reg,
+ dbcr1));
+ DEFINE(KVMPPC_DBG_DBCR2, offsetof(struct kvmppc_booke_debug_reg,
+ dbcr2));
+#ifdef CONFIG_KVM_E500MC
+ DEFINE(KVMPPC_DBG_DBCR4, offsetof(struct kvmppc_booke_debug_reg,
+ dbcr4));
+#endif
+ DEFINE(KVMPPC_DBG_IAC1, offsetof(struct kvmppc_booke_debug_reg,
+ iac[0]));
+ DEFINE(KVMPPC_DBG_IAC2, offsetof(struct kvmppc_booke_debug_reg,
+ iac[1]));
+ DEFINE(KVMPPC_DBG_IAC3, offsetof(struct kvmppc_booke_debug_reg,
+ iac[2]));
+ DEFINE(KVMPPC_DBG_IAC4, offsetof(struct kvmppc_booke_debug_reg,
+ iac[3]));
+ DEFINE(KVMPPC_DBG_DAC1, offsetof(struct kvmppc_booke_debug_reg,
+ dac[0]));
+ DEFINE(KVMPPC_DBG_DAC2, offsetof(struct kvmppc_booke_debug_reg,
+ dac[1]));
+ DEFINE(VCPU_GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug));
#endif /* CONFIG_PPC_BOOK3S */
#endif /* CONFIG_KVM */
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 6fbdcfc..784a6bf 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -130,6 +130,9 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
#ifdef CONFIG_KVM_BOOKE_HV
new_msr |= MSR_GS;
+
+ if (vcpu->guest_debug)
+ new_msr |= MSR_DE;
#endif
vcpu->arch.shared->msr = new_msr;
@@ -684,10 +687,21 @@ out:
return ret;
}
-static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
+static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ int exit_nr)
{
enum emulation_result er;
+ if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) &&
+ (vcpu->arch.last_inst == KVM_INST_GUESTGDB)) {
+ run->exit_reason = KVM_EXIT_DEBUG;
+ run->debug.arch.pc = vcpu->arch.pc;
+ run->debug.arch.exception = exit_nr;
+ run->debug.arch.status = 0;
+ kvmppc_account_exit(vcpu, DEBUG_EXITS);
+ return RESUME_HOST;
+ }
+
er = kvmppc_emulate_instruction(run, vcpu);
switch (er) {
case EMULATE_DONE:
@@ -714,6 +728,44 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
default:
BUG();
}
+
+ if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_ENABLE) &&
+ (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) {
+ run->exit_reason = KVM_EXIT_DEBUG;
+ return RESUME_HOST;
+ }
+}
+
+static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ u32 dbsr;
+
+#ifndef CONFIG_KVM_BOOKE_HV
+ if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
+ vcpu->arch.pc = mfspr(SPRN_DSRR0);
+ else
+ vcpu->arch.pc = mfspr(SPRN_CSRR0);
+#endif
+ dbsr = vcpu->arch.dbsr;
+
+ run->debug.arch.pc = vcpu->arch.pc;
+ run->debug.arch.status = 0;
+ vcpu->arch.dbsr = 0;
+
+ 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.pc = vcpu->arch.shadow_dbg_reg.dac[0];
+ else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
+ run->debug.arch.pc = vcpu->arch.shadow_dbg_reg.dac[1];
+ }
+
+ return RESUME_HOST;
}
static void kvmppc_fill_pt_regs(struct pt_regs *regs)
@@ -856,7 +908,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break;
case BOOKE_INTERRUPT_HV_PRIV:
- r = emulation_exit(run, vcpu);
+ r = emulation_exit(run, vcpu, exit_nr);
break;
case BOOKE_INTERRUPT_PROGRAM:
@@ -875,7 +927,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break;
}
- r = emulation_exit(run, vcpu);
+ r = emulation_exit(run, vcpu, exit_nr);
break;
case BOOKE_INTERRUPT_FP_UNAVAIL:
@@ -1065,18 +1117,12 @@ 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->debug.arch.exception = exit_nr;
+ run->exit_reason = KVM_EXIT_DEBUG;
+ }
kvmppc_account_exit(vcpu, DEBUG_EXITS);
- r = RESUME_HOST;
break;
}
@@ -1107,6 +1153,78 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
return r;
}
+#define BP_NUM KVMPPC_BOOKE_IAC_NUM
+#define WP_NUM KVMPPC_BOOKE_DAC_NUM
+
+int kvmppc_core_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg)
+{
+ if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
+ vcpu->guest_debug = 0;
+ return 0;
+ }
+
+ vcpu->guest_debug = dbg->control;
+ vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+
+ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+ vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
+ struct kvmppc_booke_debug_reg *gdbgr =
+ &(vcpu->arch.shadow_dbg_reg);
+ int n, b = 0, w = 0;
+ const u32 bp_code[] = {
+ DBCR0_IAC1 | DBCR0_IDM,
+ DBCR0_IAC2 | DBCR0_IDM,
+ DBCR0_IAC3 | DBCR0_IDM,
+ DBCR0_IAC4 | DBCR0_IDM
+ };
+ const u32 wp_code[] = {
+ DBCR0_DAC1W | DBCR0_IDM,
+ DBCR0_DAC2W | DBCR0_IDM,
+ DBCR0_DAC1R | DBCR0_IDM,
+ DBCR0_DAC2R | DBCR0_IDM
+ };
+
+#ifndef CONFIG_KVM_BOOKE_HV
+ gdbgr->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |
+ DBCR1_IAC3US | DBCR1_IAC4US;
+ gdbgr->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+#else
+ gdbgr->dbcr1 = 0;
+ gdbgr->dbcr2 = 0;
+#endif
+
+ for (n = 0; n < (BP_NUM + WP_NUM); n++) {
+ u32 type = dbg->arch.bp[n].type;
+
+ if (!type)
+ break;
+
+ if (type & (KVMPPC_DEBUG_WATCH_READ |
+ KVMPPC_DEBUG_WATCH_WRITE)) {
+ if (w < WP_NUM) {
+ if (type & KVMPPC_DEBUG_WATCH_READ)
+ gdbgr->dbcr0 |= wp_code[w + 2];
+ if (type & KVMPPC_DEBUG_WATCH_WRITE)
+ gdbgr->dbcr0 |= wp_code[w];
+ gdbgr->dac[w] = dbg->arch.bp[n].addr;
+ w++;
+ }
+ } else if (type & KVMPPC_DEBUG_BREAKPOINT) {
+ if (b < BP_NUM) {
+ gdbgr->dbcr0 |= bp_code[b];
+ gdbgr->iac[b] = dbg->arch.bp[n].addr;
+ b++;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index bcb34ea..fb85606 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -40,6 +40,8 @@
#define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + 4)
#define HOST_STACK_SIZE (((HOST_MIN_STACK_SIZE + 15) / 16) * 16) /* Align. */
#define HOST_STACK_LR (HOST_STACK_SIZE + 4) /* In caller stack frame. */
+#define DBCR0_AC_BITS (DBCR0_IAC1 | DBCR0_IAC2 | DBCR0_IAC3 | DBCR0_IAC4 | \
+ DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W)
#define NEED_INST_MASK ((1<<BOOKE_INTERRUPT_PROGRAM) | \
(1<<BOOKE_INTERRUPT_DTLB_MISS) | \
@@ -53,11 +55,17 @@
(1<<BOOKE_INTERRUPT_PROGRAM) | \
(1<<BOOKE_INTERRUPT_DTLB_MISS))
+#define NEED_DEBUG_SAVE (1<<BOOKE_INTERRUPT_DEBUG)
+
+#define GET_VCPU_POINT(regd) \
+ mfspr regd, SPRN_SPRG_THREAD; \
+ lwz regd, THREAD_KVM_VCPU(regd)
+
.macro KVM_HANDLER ivor_nr scratch srr0
_GLOBAL(kvmppc_handler_\ivor_nr)
/* Get pointer to vcpu and record exit number. */
mtspr \scratch , r4
- mfspr r4, SPRN_SPRG_RVCPU
+ GET_VCPU_POINT(r4)
stw r3, VCPU_GPR(r3)(r4)
stw r5, VCPU_GPR(r5)(r4)
stw r6, VCPU_GPR(r6)(r4)
@@ -74,6 +82,48 @@ _GLOBAL(kvmppc_handler_\ivor_nr)
bctr
.endm
+.macro KVM_DBG_HANDLER ivor_nr scratch srr0
+_GLOBAL(kvmppc_handler_\ivor_nr)
+ mtspr \scratch, r4
+ GET_VCPU_POINT(r4)
+ stw r3, VCPU_CRIT_SAVE(r4)
+ mfcr r3
+ mfspr r4, SPRN_CSRR1
+ andi. r4, r4, MSR_PR
+ bne 1f
+ /* debug interrupt happened in enter/exit path */
+ mfspr r4, SPRN_CSRR1
+ rlwinm r4, r4, 0, ~MSR_DE
+ mtspr SPRN_CSRR1, r4
+ lis r4, 0xffff
+ ori r4, r4, 0xffff
+ mtspr SPRN_DBSR, r4
+ GET_VCPU_POINT(r4)
+ mtcr r3
+ lwz r3, VCPU_CRIT_SAVE(r4)
+ mfspr r4, \scratch
+ rfci
+1: /* debug interrupt happened in guest */
+ mfspr r4, \scratch
+ mtcr r3
+ mr r3, r4
+ GET_VCPU_POINT(r4)
+ stw r3, VCPU_GPR(r4)(r4)
+ stw r5, VCPU_GPR(r5)(r4)
+ stw r6, VCPU_GPR(r6)(r4)
+ lwz r3, VCPU_CRIT_SAVE(r4)
+ mfspr r5, \srr0
+ stw r3, VCPU_GPR(r3)(r4)
+ stw r5, VCPU_PC(r4)
+ mfctr r5
+ lis r6, kvmppc_resume_host@h
+ stw r5, VCPU_CTR(r4)
+ li r5, \ivor_nr
+ ori r6, r6, kvmppc_resume_host@l
+ mtctr r6
+ bctr
+.endm
+
.macro KVM_HANDLER_ADDR ivor_nr
.long kvmppc_handler_\ivor_nr
.endm
@@ -94,7 +144,7 @@ KVM_HANDLER BOOKE_INTERRUPT_FIT SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS SPRN_SPRG_RSCRATCH0 SPRN_SRR0
-KVM_HANDLER BOOKE_INTERRUPT_DEBUG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
+KVM_DBG_HANDLER BOOKE_INTERRUPT_DEBUG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0
@@ -176,6 +226,61 @@ _GLOBAL(kvmppc_resume_host)
stw r9, VCPU_FAULT_ESR(r4)
..skip_esr:
+ addi r7, r4, VCPU_HOST_DBG
+ mfspr r9, SPRN_DBCR0
+ lwz r8, KVMPPC_DBG_DBCR0(r7)
+ andis. r9, r9, DBCR0_AC_BITS@h
+ beq ..skip_load_host_debug
+ li r9, 0
+ mtspr SPRN_DBCR0, r9 /* disable all debug event */
+ lwz r9, KVMPPC_DBG_DBCR1(r7)
+ mtspr SPRN_DBCR1, r9
+ lwz r9, KVMPPC_DBG_DBCR2(r7)
+ mtspr SPRN_DBCR2, r9
+ lwz r9, KVMPPC_DBG_IAC1+4(r7)
+ mtspr SPRN_IAC1, r9
+ lwz r9, KVMPPC_DBG_IAC2+4(r7)
+ mtspr SPRN_IAC2, r9
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ lwz r9, KVMPPC_DBG_IAC3+4(r7)
+ mtspr SPRN_IAC3, r9
+ lwz r9, KVMPPC_DBG_IAC4+4(r7)
+ mtspr SPRN_IAC4, r9
+#endif
+ lwz r9, KVMPPC_DBG_DAC1+4(r7)
+ mtspr SPRN_DAC1, r9
+ lwz r9, KVMPPC_DBG_DAC2+4(r7)
+ mtspr SPRN_DAC2, r9
+..skip_load_host_debug:
+ /* Clear h/w DBSR and save current(guest) DBSR */
+ mfspr r9, SPRN_DBSR
+ mtspr SPRN_DBSR, r9
+ isync
+ andi. r7, r6, NEED_DEBUG_SAVE
+ beq ..skip_dbsr_save
+ /*
+ * If vcpu->guest_debug flag is set then do not check for
+ * shared->msr.DE as this debugging (say by QEMU) does not
+ * depends on shared->msr.de. In these scanerios MSR.DE is
+ * always set using shared_msr and should be handled always.
+ */
+ lwz r7, VCPU_GUEST_DEBUG(r4)
+ cmpwi r7, 0
+ bne ..skip_save_trap_event
+ PPC_LL r3, VCPU_SHARED(r4)
+#ifndef CONFIG_64BIT
+ lwz r3, (VCPU_SHARED_MSR + 4)(r3)
+#else
+ ld r3, (VCPU_SHARED_MSR)(r3)
+#endif
+ andi. r3, r3, MSR_DE
+ bne ..skip_save_trap_event
+ andis. r9, r9, DBSR_TIE@h
+..skip_save_trap_event:
+ stw r9, VCPU_DBSR(r4)
+..skip_dbsr_save:
+ mtspr SPRN_DBCR0, r8
+
/* Save remaining volatile guest register state to vcpu. */
stw r0, VCPU_GPR(r0)(r4)
stw r1, VCPU_GPR(r1)(r4)
@@ -432,6 +537,57 @@ lightweight_exit:
PPC_LD(r3, VCPU_SHARED_SPRG7, r5)
mtspr SPRN_SPRG7W, r3
+ mfmsr r7
+ rlwinm r7, r7, 0, ~MSR_DE
+ mtmsr r7
+ addi r5, r4, VCPU_SHADOW_DBG
+ addi r7, r4, VCPU_HOST_DBG
+ lwz r6, 0(r5)
+ mfspr r8, SPRN_DBCR0
+ andis. r3, r6, DBCR0_AC_BITS@h
+ stw r8, KVMPPC_DBG_DBCR0(r7)
+ beq ..skip_load_guest_debug
+ mfspr r8, SPRN_DBCR1
+ stw r8, KVMPPC_DBG_DBCR1(r7)
+ mfspr r8, SPRN_DBCR2
+ stw r8, KVMPPC_DBG_DBCR2(r7)
+ mfspr r8, SPRN_IAC1
+ stw r8, KVMPPC_DBG_IAC1+4(r7)
+ mfspr r8, SPRN_IAC2
+ stw r8, KVMPPC_DBG_IAC2+4(r7)
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ mfspr r8, SPRN_IAC3
+ stw r8, KVMPPC_DBG_IAC3+4(r7)
+ mfspr r8, SPRN_IAC4
+ stw r8, KVMPPC_DBG_IAC4+4(r7)
+#endif
+ mfspr r8, SPRN_DAC1
+ stw r8, KVMPPC_DBG_DAC1+4(r7)
+ mfspr r8, SPRN_DAC2
+ stw r8, KVMPPC_DBG_DAC2+4(r7)
+ li r8, 0
+ mtspr SPRN_DBCR0, r8 /* disable all debug event */
+ lwz r8, KVMPPC_DBG_DBCR1(r5)
+ mtspr SPRN_DBCR1, r8
+ lwz r8, KVMPPC_DBG_DBCR2(r5)
+ mtspr SPRN_DBCR2, r8
+ lwz r8, KVMPPC_DBG_IAC1+4(r5)
+ mtspr SPRN_IAC1, r8
+ lwz r8, KVMPPC_DBG_IAC2+4(r5)
+ mtspr SPRN_IAC2, r8
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ lwz r8, KVMPPC_DBG_IAC3+4(r5)
+ mtspr SPRN_IAC3, r8
+ lwz r8, KVMPPC_DBG_IAC4+4(r5)
+ mtspr SPRN_IAC4, r8
+#endif
+ lwz r8, KVMPPC_DBG_DAC1+4(r5)
+ mtspr SPRN_DAC1, r8
+ lwz r8, KVMPPC_DBG_DAC2+4(r5)
+ mtspr SPRN_DAC2, r8
+..skip_load_guest_debug:
+ mtspr SPRN_DBCR0, r6
+
#ifdef CONFIG_KVM_EXIT_TIMING
/* save enter time */
1:
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index 0fa2ef7..32b9a41 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -59,6 +59,10 @@
#define NEED_EMU 0x00000001 /* emulation -- save nv regs */
#define NEED_DEAR 0x00000002 /* save faulting DEAR */
#define NEED_ESR 0x00000004 /* save faulting ESR */
+#define NEED_DBSR 0x00000008 /* save DBSR */
+
+#define DBCR0_AC_BITS (DBCR0_IAC1 | DBCR0_IAC2 | DBCR0_IAC3 | DBCR0_IAC4 | \
+ DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W)
/*
* On entry:
@@ -202,6 +206,11 @@
PPC_STL r9, VCPU_FAULT_DEAR(r4)
.endif
+ .if \flags & NEED_DBSR
+ mfspr r9, SPRN_DBSR
+ stw r9, VCPU_DBSR(r4)
+ .endif
+
b kvmppc_resume_host
.endm
@@ -296,9 +305,9 @@ kvm_handler BOOKE_INTERRUPT_GUEST_DBELL, SPRN_GSRR0, SPRN_GSRR1, 0
kvm_lvl_handler BOOKE_INTERRUPT_GUEST_DBELL_CRIT, \
SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0
kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \
- SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, 0
+ SPRN_SPRG_RSCRATCH_CRIT, SPRN_CSRR0, SPRN_CSRR1, NEED_DBSR
kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \
- SPRN_SPRG_RSCRATCH_DBG, SPRN_DSRR0, SPRN_DSRR1, 0
+ SPRN_SPRG_RSCRATCH_DBG, SPRN_DSRR0, SPRN_DSRR1, NEED_DBSR
/* Registers:
@@ -308,6 +317,56 @@ kvm_lvl_handler BOOKE_INTERRUPT_DEBUG, \
* r14: KVM exit number
*/
_GLOBAL(kvmppc_resume_host)
+ /*
+ * If guest not used debug facility then hw debug registers
+ * already have proper host values. If guest used debug
+ * facility then restore host debug registers.
+ * No Need to save guest debug registers as they are already intact
+ * in guest/shadow registers.
+ */
+ lwz r9, VCPU_SHADOW_DBG(r4)
+ rlwinm. r8, r9, 0, ~DBCR0_IDM
+ beq skip_load_host_debug
+ lwz r3, VCPU_HOST_DBG(r4)
+ andis. r9, r9, DBCR0_AC_BITS@h
+ li r9, 0
+ mtspr SPRN_DBCR0, r9 /* disable all debug event */
+ beq ..skip_load_hw_bkpts
+ lwz r7, VCPU_HOST_DBG+KVMPPC_DBG_DBCR1(r4)
+ lwz r8, VCPU_HOST_DBG+KVMPPC_DBG_DBCR2(r4)
+ lwz r9, VCPU_HOST_DBG+KVMPPC_DBG_DBCR4(r4)
+ mtspr SPRN_DBCR1, r7
+ PPC_LD(r6, VCPU_HOST_DBG+KVMPPC_DBG_IAC1, r4)
+ PPC_LD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC2, r4)
+ mtspr SPRN_DBCR2, r8
+ mtspr SPRN_DBCR4, r9
+ mtspr SPRN_IAC1, r6
+ mtspr SPRN_IAC2, r7
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ PPC_LD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC3, r4)
+ PPC_LD(r8, VCPU_HOST_DBG+KVMPPC_DBG_IAC4, r4)
+ mtspr SPRN_IAC3, r7
+ mtspr SPRN_IAC4, r8
+#endif
+ PPC_LD(r8, VCPU_HOST_DBG+KVMPPC_DBG_DAC1, r4)
+ PPC_LD(r9, VCPU_HOST_DBG+KVMPPC_DBG_DAC2, r4)
+ mtspr SPRN_DAC1, r8
+ mtspr SPRN_DAC2, r9
+..skip_load_hw_bkpts:
+ isync
+ /* Clear h/w DBSR and save current(guest) DBSR */
+ mfspr r8, SPRN_DBSR
+ mtspr SPRN_DBSR, r8
+ isync
+ /* Clear EPCR.DUVD and set host DBCR0 */
+ mfspr r8, SPRN_EPCR
+ rlwinm r8, r8, 0, ~SPRN_EPCR_DUVD
+ mtspr SPRN_EPCR, r8
+ isync
+ mtspr SPRN_DBCR0, r3
+ isync
+skip_load_host_debug:
+
/* Save remaining volatile guest register state to vcpu. */
mfspr r3, SPRN_VRSAVE
PPC_STL r0, VCPU_GPR(r0)(r4)
@@ -547,6 +606,84 @@ lightweight_exit:
mtspr SPRN_SPRG6W, r7
mtspr SPRN_SPRG7W, r8
+ mfmsr r7
+ rlwinm r7, r7, 0, ~MSR_DE
+ mtmsr r7
+ /*
+ * Load hw debug registers with guest(shadow) debug registers
+ * if guest is using the debug facility and also set EPCR.DUVD
+ * to not allow debug events in HV mode. Do not change the
+ * debug registers if guest is not using the debug facility.
+ */
+ lwz r6, VCPU_SHADOW_DBG(r4)
+ rlwinm. r7, r6, 0, ~DBCR0_IDM
+ beq ..skip_load_guest_debug
+ /* Save host DBCR0 */
+ mfspr r8, SPRN_DBCR0
+ stw r8, VCPU_HOST_DBG(r4)
+ /*
+ * Save host DBCR1/2, IACx and DACx and load guest DBCR1/2,
+ * IACx and DACx if guest using hw breakpoint/watchpoints.
+ */
+ andis. r3, r6, DBCR0_AC_BITS@h
+ beq ..skip_hw_bkpts
+ mfspr r7, SPRN_DBCR1
+ stw r7, VCPU_HOST_DBG+KVMPPC_DBG_DBCR1(r4)
+ mfspr r8, SPRN_DBCR2
+ stw r8, VCPU_HOST_DBG+KVMPPC_DBG_DBCR2(r4)
+ mfspr r7, SPRN_DBCR4
+ stw r7, VCPU_HOST_DBG+KVMPPC_DBG_DBCR4(r4)
+ mfspr r8, SPRN_IAC1
+ PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_IAC1, r4)
+ mfspr r7, SPRN_IAC2
+ PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC2, r4)
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ mfspr r8, SPRN_IAC3
+ PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_IAC3, r4)
+ mfspr r7, SPRN_IAC4
+ PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC4, r4)
+#endif
+ mfspr r8, SPRN_DAC1
+ PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_DAC1, r4)
+ mfspr r7, SPRN_DAC2
+ PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_DAC2, r4)
+ li r8, 0
+ mtspr SPRN_DBCR0, r8 /* disable all debug event */
+ lwz r7, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR1(r4)
+ lwz r8, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR2(r4)
+ lwz r9, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR4(r4)
+ mtspr SPRN_DBCR1, r7
+ PPC_LD(r7, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC1, r4)
+ PPC_LD(r3, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC2, r4)
+ mtspr SPRN_DBCR2, r8
+ mtspr SPRN_DBCR4, r9
+ mtspr SPRN_IAC1, r7
+ mtspr SPRN_IAC2, r3
+#ifndef CONFIG_PPC_FSL_BOOK3E
+ PPC_LD(r7, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC3, r4)
+ PPC_LD(r8, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC4, r4)
+ mtspr SPRN_IAC3, r7
+ mtspr SPRN_IAC4, r8
+#endif
+ PPC_LD(r7, VCPU_SHADOW_DBG+KVMPPC_DBG_DAC1, r4)
+ PPC_LD(r8, VCPU_SHADOW_DBG+KVMPPC_DBG_DAC2, r4)
+ mtspr SPRN_DAC1, r7
+ mtspr SPRN_DAC2, r8
+..skip_hw_bkpts:
+ /* Set EPCR.DUVD and guest DBCR0 */
+ mfspr r7, SPRN_EPCR
+ oris r7, r7, SPRN_EPCR_DUVD@h
+ mtspr SPRN_EPCR, r7
+ isync
+ /* Clear if any deferred debug event */
+ mfspr r8, SPRN_DBSR
+ mtspr SPRN_DBSR, r8
+ isync
+ /* Restore guest DBCR */
+ mtspr SPRN_DBCR0, r6
+ isync
+..skip_load_guest_debug:
+
/* Load some guest volatiles. */
PPC_LL r3, VCPU_LR(r4)
PPC_LL r5, VCPU_XER(r4)
diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
index 1f89d26..f5fc6f5 100644
--- a/arch/powerpc/kvm/e500mc.c
+++ b/arch/powerpc/kvm/e500mc.c
@@ -182,8 +182,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- vcpu->arch.shadow_epcr = SPRN_EPCR_DSIGS | SPRN_EPCR_DGTMI | \
- SPRN_EPCR_DUVD;
+ vcpu->arch.shadow_epcr = SPRN_EPCR_DSIGS | SPRN_EPCR_DGTMI;
#ifdef CONFIG_64BIT
vcpu->arch.shadow_epcr |= SPRN_EPCR_ICM;
#endif
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 685829a..38b5d02 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -427,7 +427,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
- return -EINVAL;
+ return kvmppc_core_set_guest_debug(vcpu, dbg);
}
static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
--
1.7.0.4
next prev parent reply other threads:[~2012-07-26 5:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-26 5:32 [PATCH 1/2] KVM: PPC: booke: Allow multiple exception types Bharat Bhushan
2012-07-26 5:32 ` Bharat Bhushan [this message]
2012-07-27 1:29 ` [PATCH 2/2] KVM: PPC: booke/bookehv: Add guest debug support Scott Wood
2012-07-30 7:37 ` Bhushan Bharat-R65777
2012-07-30 22:00 ` Scott Wood
2012-08-16 8:48 ` Bhushan Bharat-R65777
2012-08-20 23:53 ` Scott Wood
2012-08-16 15:12 ` Bhushan Bharat-R65777
2012-08-20 23:55 ` Scott Wood
2012-07-26 23:01 ` [PATCH 1/2] KVM: PPC: booke: Allow multiple exception types Scott Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1343280734-3359-2-git-send-email-Bharat.Bhushan@freescale.com \
--to=r65777@freescale.com \
--cc=Bharat.Bhushan@freescale.com \
--cc=agraf@suse.de \
--cc=kvm-ppc@vger.kernel.org \
--cc=kvm@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).