On Guest entry: if guest is wants to use the debug register then
save h/w debug register in host_dbg_reg and load the debug registers
with shadow_dbg_reg. Otherwise leave h/w debug registers as is.

On guest exit: If guest/user-space is using the debug resource then
restore the h/w debug register with host_dbg_reg. No need to save guest
debug register as shadow_dbg_reg is having required values. If guest is not
using the debug resources then no need to restore h/w registers.

Signed-off-by: Bharat Bhushan <bharat.bhus...@freescale.com>
---
 arch/powerpc/include/asm/kvm_host.h |    5 ++
 arch/powerpc/kernel/asm-offsets.c   |   26 ++++++++
 arch/powerpc/kvm/booke_interrupts.S |  114 +++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index f4ba881..a9feeb0 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -504,7 +504,12 @@ struct kvm_vcpu_arch {
        u32 mmucfg;
        u32 epr;
        u32 crit_save;
+       /* guest debug registers*/
        struct kvmppc_booke_debug_reg dbg_reg;
+       /* shadow debug registers */
+       struct kvmppc_booke_debug_reg shadow_dbg_reg;
+       /* host debug registers*/
+       struct kvmppc_booke_debug_reg host_dbg_reg;
 #endif
        gpa_t paddr_accessed;
        gva_t vaddr_accessed;
diff --git a/arch/powerpc/kernel/asm-offsets.c 
b/arch/powerpc/kernel/asm-offsets.c
index 02048f3..22deda7 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -563,6 +563,32 @@ int main(void)
        DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
        DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
        DEFINE(VCPU_CRIT_SAVE, offsetof(struct kvm_vcpu, arch.crit_save));
+       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_interrupts.S 
b/arch/powerpc/kvm/booke_interrupts.S
index 2c6deb5..6d78e01 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -39,6 +39,8 @@
 #define HOST_MIN_STACK_SIZE (HOST_NV_GPR(R31) + 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) | \
@@ -54,6 +56,8 @@
                        (1<<BOOKE_INTERRUPT_DTLB_MISS) | \
                        (1<<BOOKE_INTERRUPT_ALIGNMENT))
 
+#define NEED_DEBUG_SAVE (1<<BOOKE_INTERRUPT_DEBUG)
+
 .macro __KVM_HANDLER ivor_nr scratch srr0
        /* Get pointer to vcpu and record exit number. */
        mtspr   \scratch , r4
@@ -215,6 +219,59 @@ _GLOBAL(kvmppc_resume_host)
        stw     r9, VCPU_FAULT_ESR(r4)
 ..skip_esr:
 
+       lwz     r9, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR0(r4)
+       rlwinm. r8, r9, 0, ~DBCR0_IDM
+       beq     skip_load_host_debug
+       lwz     r8, VCPU_HOST_DBG+KVMPPC_DBG_DBCR0(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     r9, VCPU_HOST_DBG+KVMPPC_DBG_DBCR2(r4)
+       mtspr   SPRN_DBCR1, r7
+       mtspr   SPRN_DBCR2, r9
+       PPC_LD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC1, r4)
+       PPC_LD(r9, VCPU_HOST_DBG+KVMPPC_DBG_IAC2, r4)
+       mtspr   SPRN_IAC1, r7
+       mtspr   SPRN_IAC2, r9
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+       PPC_LD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC3, r4)
+       PPC_LD(r9, VCPU_HOST_DBG+KVMPPC_DBG_IAC4, r4)
+       mtspr   SPRN_IAC3, r3
+       mtspr   SPRN_IAC4, r4
+#endif
+       PPC_LD(r7, VCPU_HOST_DBG+KVMPPC_DBG_DAC1, r4)
+       PPC_LD(r9, VCPU_HOST_DBG+KVMPPC_DBG_DAC2, r4)
+       mtspr   SPRN_DAC1, r7
+       mtspr   SPRN_DAC2, r9
+skip_load_hw_bkpts:
+       /* 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)
+       PPC_LD(r3, VCPU_SHARED_MSR, r3)
+       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
+skip_load_host_debug:
+
        /* Save remaining volatile guest register state to vcpu. */
        stw     r0, VCPU_GPR(R0)(r4)
        stw     r1, VCPU_GPR(R1)(r4)
@@ -468,6 +525,63 @@ lightweight_exit:
        PPC_LD(r3, VCPU_SHARED_SPRG7, r5)
        mtspr   SPRN_SPRG7W, r3
 
+       mfmsr   r7
+       rlwinm  r7, r7, 0, ~MSR_DE
+       mtmsr   r7
+       lwz     r6, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR0(r4)
+       rlwinm. r7, r6, 0, ~DBCR0_IDM
+       beq     skip_load_guest_debug
+       mfspr   r8, SPRN_DBCR0
+       stw     r8, VCPU_HOST_DBG+KVMPPC_DBG_DBCR0(r4)
+       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_IAC1
+       PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC1, r4)
+       mfspr   r8, SPRN_IAC2
+       PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_IAC2, r4)
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+       mfspr   r7, SPRN_IAC3
+       PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_IAC3, r4)
+       mfspr   r8, SPRN_IAC4
+       PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_IAC4, r4)
+#endif
+       mfspr   r7, SPRN_DAC1
+       PPC_STD(r7, VCPU_HOST_DBG+KVMPPC_DBG_DAC1, r4)
+       mfspr   r8, SPRN_DAC2
+       PPC_STD(r8, VCPU_HOST_DBG+KVMPPC_DBG_DAC2, r4)
+       li      r8, 0
+       mtspr   SPRN_DBCR0, r8          /* disable all debug event */
+       PPC_LD(r7, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR1, r4)
+       PPC_LD(r8, VCPU_SHADOW_DBG+KVMPPC_DBG_DBCR2, r4)
+       mtspr   SPRN_DBCR1, r7
+       mtspr   SPRN_DBCR2, r8
+       PPC_LD(r7, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC1, r4)
+       PPC_LD(r8, VCPU_SHADOW_DBG+KVMPPC_DBG_IAC2, r4)
+       mtspr   SPRN_IAC1, r7
+       mtspr   SPRN_IAC2, r8
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+       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:
+       /* Clear if any deferred debug event */
+       mfspr   r8, SPRN_DBSR
+       mtspr   SPRN_DBSR, r8
+       isync
+       /* Restore guest DBCR */
+       mtspr   SPRN_DBCR0, r6
+skip_load_guest_debug:
+
 #ifdef CONFIG_KVM_EXIT_TIMING
        /* save enter time */
 1:
-- 
1.7.0.4


--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to