arch/powerpc/kvm/book3s_hv_p9_entry.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kvm/book3s_hv_p9_entry.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kvm/book3s_hv_p9_entry.c
Extension
.c
Size
26641 bytes
Lines
931
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) {
		unsigned long guest_msr = vcpu->arch.shregs.msr;
		if (MSR_TM_ACTIVE(guest_msr)) {
			kvmppc_restore_tm_hv(vcpu, guest_msr, true);
			ret = true;
		} else if (vcpu->arch.hfscr & HFSCR_TM) {
			mtspr(SPRN_TEXASR, vcpu->arch.texasr);
			mtspr(SPRN_TFHAR, vcpu->arch.tfhar);
			mtspr(SPRN_TFIAR, vcpu->arch.tfiar);
		}
	}
#endif

	load_spr_state(vcpu, host_os_sprs);

	load_fp_state(&vcpu->arch.fp);
#ifdef CONFIG_ALTIVEC
	load_vr_state(&vcpu->arch.vr);
#endif

	return ret;
}
EXPORT_SYMBOL_GPL(load_vcpu_state);

void store_vcpu_state(struct kvm_vcpu *vcpu)
{
	store_spr_state(vcpu);

	store_fp_state(&vcpu->arch.fp);
#ifdef CONFIG_ALTIVEC
	store_vr_state(&vcpu->arch.vr);
#endif

#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
	if (cpu_has_feature(CPU_FTR_TM) ||
	    cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) {
		unsigned long guest_msr = vcpu->arch.shregs.msr;
		if (MSR_TM_ACTIVE(guest_msr)) {
			kvmppc_save_tm_hv(vcpu, guest_msr, true);
		} else if (vcpu->arch.hfscr & HFSCR_TM) {
			vcpu->arch.texasr = mfspr(SPRN_TEXASR);
			vcpu->arch.tfhar = mfspr(SPRN_TFHAR);
			vcpu->arch.tfiar = mfspr(SPRN_TFIAR);

			if (!vcpu->arch.nested) {
				vcpu->arch.load_tm++; /* see load_ebb comment */
				if (!vcpu->arch.load_tm)
					vcpu->arch.hfscr &= ~HFSCR_TM;
			}
		}
	}
#endif
}
EXPORT_SYMBOL_GPL(store_vcpu_state);

void save_p9_host_os_sprs(struct p9_host_os_sprs *host_os_sprs)
{
	host_os_sprs->iamr = mfspr(SPRN_IAMR);
	host_os_sprs->amr = mfspr(SPRN_AMR);
}
EXPORT_SYMBOL_GPL(save_p9_host_os_sprs);

/* vcpu guest regs must already be saved */
void restore_p9_host_os_sprs(struct kvm_vcpu *vcpu,
			     struct p9_host_os_sprs *host_os_sprs)
{
	/*
	 * current->thread.xxx registers must all be restored to host
	 * values before a potential context switch, otherwise the context
	 * switch itself will overwrite current->thread.xxx with the values
	 * from the guest SPRs.
	 */

	mtspr(SPRN_SPRG_VDSO_WRITE, local_paca->sprg_vdso);

	if (cpu_has_feature(CPU_FTR_P9_TIDR) &&
			current->thread.tidr != vcpu->arch.tid)
		mtspr(SPRN_TIDR, current->thread.tidr);
	if (host_os_sprs->iamr != vcpu->arch.iamr)
		mtspr(SPRN_IAMR, host_os_sprs->iamr);
	if (vcpu->arch.uamor != 0)
		mtspr(SPRN_UAMOR, 0);
	if (host_os_sprs->amr != vcpu->arch.amr)
		mtspr(SPRN_AMR, host_os_sprs->amr);
	if (current->thread.fscr != vcpu->arch.fscr)
		mtspr(SPRN_FSCR, current->thread.fscr);
	if (current->thread.dscr != vcpu->arch.dscr)
		mtspr(SPRN_DSCR, current->thread.dscr);
	if (vcpu->arch.pspb != 0)
		mtspr(SPRN_PSPB, 0);

Annotation

Implementation Notes