RE: [PATCH 7/8] KVM: PPC: booke/bookehv: Add debug stub support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Alexander Graf [mailto:agraf@xxxxxxx]
> Sent: Friday, January 25, 2013 5:37 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@xxxxxxxxxxxxxxx; kvm@xxxxxxxxxxxxxxx; Bhushan Bharat-R65777
> Subject: Re: [PATCH 7/8] KVM: PPC: booke/bookehv: Add debug stub support
> 
> 
> On 16.01.2013, at 09:24, Bharat Bhushan wrote:
> 
> > This patch adds the debug stub support on booke/bookehv.
> > Now QEMU debug stub can use hw breakpoint, watchpoint and software
> > breakpoint to debug guest.
> >
> > Signed-off-by: Bharat Bhushan <bharat.bhushan@xxxxxxxxxxxxx>
> > ---
> > arch/powerpc/include/asm/kvm_host.h   |    5 +
> > arch/powerpc/include/asm/kvm_ppc.h    |    2 +
> > arch/powerpc/include/uapi/asm/kvm.h   |   22 ++++-
> > arch/powerpc/kernel/asm-offsets.c     |   26 ++++++
> > arch/powerpc/kvm/booke.c              |  124 +++++++++++++++++++++++++----
> > arch/powerpc/kvm/booke_interrupts.S   |  114 ++++++++++++++++++++++++++
> > arch/powerpc/kvm/bookehv_interrupts.S |  145 ++++++++++++++++++++++++++++++++-
> > arch/powerpc/kvm/e500_emulate.c       |    6 ++
> > arch/powerpc/kvm/e500mc.c             |    3 +-
> > 9 files changed, 422 insertions(+), 25 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/include/asm/kvm_ppc.h
> > b/arch/powerpc/include/asm/kvm_ppc.h
> > index b3c481e..e4b3398 100644
> > --- a/arch/powerpc/include/asm/kvm_ppc.h
> > +++ b/arch/powerpc/include/asm/kvm_ppc.h
> > @@ -45,6 +45,8 @@ enum emulation_result {
> > 	EMULATE_FAIL,         /* can't emulate this instruction */
> > 	EMULATE_AGAIN,        /* something went wrong. go again */
> > 	EMULATE_DO_PAPR,      /* kvm_run filled with PAPR request */
> > +	EMULATE_DEBUG_INST,   /* debug instruction for software
> > +				 breakpoint, exit to userspace */
> 
> Does this do something different from DO_PAPR? Maybe it makes sense to have an
> exit code EMULATE_EXIT_USER?

I think EMULATE_DO_PAPR does something similar but the name is confusing. May be we can rename EMULATE_DO_PAPR to 
EMULATE_EXIT_USER.

Thanks
-Bharat
> 
> > };
> >
> > extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu
> > *vcpu); diff --git a/arch/powerpc/include/uapi/asm/kvm.h
> > b/arch/powerpc/include/uapi/asm/kvm.h
> > index e8842ed..a81ab29 100644
> > --- a/arch/powerpc/include/uapi/asm/kvm.h
> > +++ b/arch/powerpc/include/uapi/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;
> > @@ -267,7 +268,24 @@ struct kvm_fpu {
> > 	__u64 fpr[32];
> > };
> >
> > +/*
> > + * Defines for h/w breakpoint, watchpoint (read, write or both) and
> > + * software breakpoint.
> > + * These are used as "type" in KVM_SET_GUEST_DEBUG ioctl and "status"
> > + * for KVM_DEBUG_EXIT.
> > + */
> > +#define KVMPPC_DEBUG_NONE		0x0
> > +#define KVMPPC_DEBUG_BREAKPOINT		(1UL << 1)
> > +#define KVMPPC_DEBUG_WATCH_WRITE	(1UL << 2)
> > +#define KVMPPC_DEBUG_WATCH_READ		(1UL << 3)
> > struct kvm_debug_exit_arch {
> > +	__u64 address;
> > +	/*
> > +	 * exiting to userspace because of h/w breakpoint, watchpoint
> > +	 * (read, write or both) and software breakpoint.
> > +	 */
> > +	__u32 status;
> > +	__u32 reserved;
> > };
> >
> > /* for KVM_SET_GUEST_DEBUG */
> > @@ -279,10 +297,6 @@ struct kvm_guest_debug_arch {
> > 		 * Type denotes h/w breakpoint, read watchpoint, write
> > 		 * watchpoint or watchpoint (both read and write).
> > 		 */
> > -#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)
> > 		__u32 type;
> > 		__u32 reserved;
> > 	} bp[16];
> > 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.c b/arch/powerpc/kvm/booke.c index
> > 7d5a51c..faa0a0b 100644
> > --- a/arch/powerpc/kvm/booke.c
> > +++ b/arch/powerpc/kvm/booke.c
> > @@ -143,6 +143,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;
> > @@ -711,7 +714,8 @@ 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)
> 
> Why pass in exit_nr?
> 
> > {
> > 	enum emulation_result er;
> >
> > @@ -728,6 +732,13 @@ static int emulation_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu)
> > 		run->exit_reason = KVM_EXIT_DCR;
> > 		return RESUME_HOST;
> >
> > +	case EMULATE_DEBUG_INST:
> > +		run->exit_reason = KVM_EXIT_DEBUG;
> > +		run->debug.arch.address = vcpu->arch.pc;
> > +		run->debug.arch.status = 0;
> > +		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> > +		return RESUME_HOST;
> > +
> > 	case EMULATE_FAIL:
> > 		printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
> > 		       __func__, vcpu->arch.pc, vcpu->arch.last_inst); @@ -743,6
> > +754,28 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu
> *vcpu)
> > 	}
> > }
> >
> > +static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu
> > +*vcpu) {
> > +	u32 dbsr = vcpu->arch.dbsr;
> > +	run->debug.arch.status = 0;
> > +	run->debug.arch.address = vcpu->arch.pc;
> > +
> > +	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.address = vcpu->arch.shadow_dbg_reg.dac[0];
> > +		else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
> > +			run->debug.arch.address = vcpu->arch.shadow_dbg_reg.dac[1];
> > +	}
> > +
> > +	return RESUME_HOST;
> > +}
> > +
> > static void kvmppc_fill_pt_regs(struct pt_regs *regs) {
> > 	ulong r1, ip, msr, lr;
> > @@ -887,7 +920,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:
> > @@ -906,7 +939,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:
> > @@ -1096,18 +1129,11 @@ 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->exit_reason = KVM_EXIT_DEBUG;
> > +		}
> > 		kvmppc_account_exit(vcpu, DEBUG_EXITS);
> > -		r = RESUME_HOST;
> > 		break;
> > 	}
> >
> > @@ -1483,10 +1509,78 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
> struct kvm_one_reg *reg)
> > 	return r;
> > }
> >
> > +#define BP_NUM	KVMPPC_BOOKE_IAC_NUM
> > +#define WP_NUM	KVMPPC_BOOKE_DAC_NUM
> > +
> > int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> > 					 struct kvm_guest_debug *dbg)
> > {
> > -	return -EINVAL;
> > +
> > +	if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
> > +		/* Clear All debug events */
> > +		vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
> > +		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
> 
> Please reverse the logic here. #ifndef ... #else is always a bad idea.
> 
> > +		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;
> > }
> 
> I'll stop reviewing here. This patch is way too big. Please split it up in
> smaller, understandable bits.
> 
> 
> Alex
> 
> >
> > int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu
> > *fpu) diff --git a/arch/powerpc/kvm/booke_interrupts.S
> > b/arch/powerpc/kvm/booke_interrupts.S
> > index dd9c5d4..734c549 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) | \ @@ -52,6
> > +54,8 @@
> >                        (1<<BOOKE_INTERRUPT_PROGRAM) | \
> >                        (1<<BOOKE_INTERRUPT_DTLB_MISS))
> >
> > +#define NEED_DEBUG_SAVE (1<<BOOKE_INTERRUPT_DEBUG)
> > +
> > .macro __KVM_HANDLER ivor_nr scratch srr0
> > 	stw	r3, VCPU_GPR(R3)(r4)
> > 	stw	r5, VCPU_GPR(R5)(r4)
> > @@ -212,6 +216,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)
> > @@ -465,6 +522,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:
> > 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)
> > diff --git a/arch/powerpc/kvm/e500_emulate.c
> > b/arch/powerpc/kvm/e500_emulate.c index e78f353..ddb903e 100644
> > --- a/arch/powerpc/kvm/e500_emulate.c
> > +++ b/arch/powerpc/kvm/e500_emulate.c
> > @@ -26,6 +26,7 @@
> > #define XOP_TLBRE   946
> > #define XOP_TLBWE   978
> > #define XOP_TLBILX  18
> > +#define XOP_EHPRIV  270
> >
> > #ifdef CONFIG_KVM_E500MC
> > static int dbell2prio(ulong param)
> > @@ -130,6 +131,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
> > 			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
> > 			break;
> >
> > +		case XOP_EHPRIV:
> > +			emulated = EMULATE_DEBUG_INST;
> > +			*advance = 0;
> > +			break;
> > +
> > 		default:
> > 			emulated = EMULATE_FAIL;
> > 		}
> > diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
> > index dead142..81abe92 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
> > --
> > 1.7.0.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
> > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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


[Index of Archives]     [KVM Development]     [KVM ARM]     [KVM ia64]     [Linux Virtualization]     [Linux USB Devel]     [Linux Video]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux