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@xxxxxxxxxxxxx> --- arch/powerpc/kvm/bookehv_interrupts.S | 145 ++++++++++++++++++++++++++++++++- 1 files changed, 141 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index e8ed7d6..0d830cc 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -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) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html