@@ -62,6 +62,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:
@@ -201,6 +205,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
@@ -316,9 +325,9 @@ kvm_handler BOOKE_INTERRUPT_GUEST_DBELL, EX_PARAMS(GDBELL), \
kvm_handler BOOKE_INTERRUPT_GUEST_DBELL_CRIT, EX_PARAMS(CRIT), \
SPRN_CSRR0, SPRN_CSRR1, 0
kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \
- SPRN_DSRR0, SPRN_DSRR1, 0
+ SPRN_DSRR0, SPRN_DSRR1, NEED_DBSR
kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \
- SPRN_CSRR0, SPRN_CSRR1, 0
+ SPRN_CSRR0, SPRN_CSRR1, NEED_DBSR
#else
/*
* For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h
@@ -411,9 +420,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
#endif
/* Registers:
@@ -423,6 +432,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+KVMPPC_DBG_DBCR0(r4)
+ rlwinm. r8, r9, 0, ~DBCR0_IDM
+ beq skip_load_host_debug
+ lwz r3, 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 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
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ 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 */
+ 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)
@@ -662,6 +721,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+KVMPPC_DBG_DBCR0(r4)
+ rlwinm. r7, r6, 0, ~DBCR0_IDM
+ beq skip_load_guest_debug
+ /* Save host DBCR0 */
+ mfspr r8, SPRN_DBCR0
+ stw r8, VCPU_HOST_DBG+KVMPPC_DBG_DBCR0(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)
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+ 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
+#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:
+ /* 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)
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.bhushan@freescale.com> --- arch/powerpc/kvm/bookehv_interrupts.S | 145 ++++++++++++++++++++++++++++++++- 1 files changed, 141 insertions(+), 4 deletions(-)