static int shadow_scb()

in kvm/vsie.c [433:557]


static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
	struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
	/* READ_ONCE does not work on bitfields - use a temporary variable */
	const uint32_t __new_prefix = scb_o->prefix;
	const uint32_t new_prefix = READ_ONCE(__new_prefix);
	const bool wants_tx = READ_ONCE(scb_o->ecb) & ECB_TE;
	bool had_tx = scb_s->ecb & ECB_TE;
	unsigned long new_mso = 0;
	int rc;

	/* make sure we don't have any leftovers when reusing the scb */
	scb_s->icptcode = 0;
	scb_s->eca = 0;
	scb_s->ecb = 0;
	scb_s->ecb2 = 0;
	scb_s->ecb3 = 0;
	scb_s->ecd = 0;
	scb_s->fac = 0;
	scb_s->fpf = 0;

	rc = prepare_cpuflags(vcpu, vsie_page);
	if (rc)
		goto out;

	/* timer */
	scb_s->cputm = scb_o->cputm;
	scb_s->ckc = scb_o->ckc;
	scb_s->todpr = scb_o->todpr;
	scb_s->epoch = scb_o->epoch;

	/* guest state */
	scb_s->gpsw = scb_o->gpsw;
	scb_s->gg14 = scb_o->gg14;
	scb_s->gg15 = scb_o->gg15;
	memcpy(scb_s->gcr, scb_o->gcr, 128);
	scb_s->pp = scb_o->pp;

	/* interception / execution handling */
	scb_s->gbea = scb_o->gbea;
	scb_s->lctl = scb_o->lctl;
	scb_s->svcc = scb_o->svcc;
	scb_s->ictl = scb_o->ictl;
	/*
	 * SKEY handling functions can't deal with false setting of PTE invalid
	 * bits. Therefore we cannot provide interpretation and would later
	 * have to provide own emulation handlers.
	 */
	if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_KSS))
		scb_s->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;

	scb_s->icpua = scb_o->icpua;

	if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM))
		new_mso = READ_ONCE(scb_o->mso) & 0xfffffffffff00000UL;
	/* if the hva of the prefix changes, we have to remap the prefix */
	if (scb_s->mso != new_mso || scb_s->prefix != new_prefix)
		prefix_unmapped(vsie_page);
	 /* SIE will do mso/msl validity and exception checks for us */
	scb_s->msl = scb_o->msl & 0xfffffffffff00000UL;
	scb_s->mso = new_mso;
	scb_s->prefix = new_prefix;

	/* We have to definetly flush the tlb if this scb never ran */
	if (scb_s->ihcpu != 0xffffU)
		scb_s->ihcpu = scb_o->ihcpu;

	/* MVPG and Protection Exception Interpretation are always available */
	scb_s->eca |= scb_o->eca & (ECA_MVPGI | ECA_PROTEXCI);
	/* Host-protection-interruption introduced with ESOP */
	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP))
		scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT;
	/* transactional execution */
	if (test_kvm_facility(vcpu->kvm, 73) && wants_tx) {
		/* remap the prefix is tx is toggled on */
		if (!had_tx)
			prefix_unmapped(vsie_page);
		scb_s->ecb |= ECB_TE;
	}
	/* specification exception interpretation */
	scb_s->ecb |= scb_o->ecb & ECB_SPECI;
	/* branch prediction */
	if (test_kvm_facility(vcpu->kvm, 82))
		scb_s->fpf |= scb_o->fpf & FPF_BPBC;
	/* SIMD */
	if (test_kvm_facility(vcpu->kvm, 129)) {
		scb_s->eca |= scb_o->eca & ECA_VX;
		scb_s->ecd |= scb_o->ecd & ECD_HOSTREGMGMT;
	}
	/* Run-time-Instrumentation */
	if (test_kvm_facility(vcpu->kvm, 64))
		scb_s->ecb3 |= scb_o->ecb3 & ECB3_RI;
	/* Instruction Execution Prevention */
	if (test_kvm_facility(vcpu->kvm, 130))
		scb_s->ecb2 |= scb_o->ecb2 & ECB2_IEP;
	/* Guarded Storage */
	if (test_kvm_facility(vcpu->kvm, 133)) {
		scb_s->ecb |= scb_o->ecb & ECB_GS;
		scb_s->ecd |= scb_o->ecd & ECD_HOSTREGMGMT;
	}
	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIIF))
		scb_s->eca |= scb_o->eca & ECA_SII;
	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_IB))
		scb_s->eca |= scb_o->eca & ECA_IB;
	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
		scb_s->eca |= scb_o->eca & ECA_CEI;
	/* Epoch Extension */
	if (test_kvm_facility(vcpu->kvm, 139))
		scb_s->ecd |= scb_o->ecd & ECD_MEF;

	/* etoken */
	if (test_kvm_facility(vcpu->kvm, 156))
		scb_s->ecd |= scb_o->ecd & ECD_ETOKENF;

	scb_s->hpid = HPID_VSIE;
	scb_s->cpnc = scb_o->cpnc;

	prepare_ibc(vcpu, vsie_page);
	rc = shadow_crycb(vcpu, vsie_page);
out:
	if (rc)
		unshadow_scb(vcpu, vsie_page);
	return rc;
}