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/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" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html