arch/arm64/kvm/hyp/vhe/switch.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/hyp/vhe/switch.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/hyp/vhe/switch.c
Extension
.c
Size
18186 bytes
Lines
690
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source 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

if (guest_hcr & HCR_NV) {
			u64 va = __fix_to_virt(vncr_fixmap(smp_processor_id()));

			/* Inherit the low bits from the actual register */
			va |= __vcpu_sys_reg(vcpu, VNCR_EL2) & GENMASK(PAGE_SHIFT - 1, 0);
			write_sysreg_s(va, SYS_VNCR_EL2);

			/* Force NV2 in case the guest is forgetful... */
			guest_hcr |= HCR_NV2;
		}

		/*
		 * Exclude the guest's TWED configuration if it hasn't set TWE
		 * to avoid potentially delaying traps for the host.
		 */
		if (!(guest_hcr & HCR_TWE))
			guest_hcr &= ~(HCR_EL2_TWEDEn | HCR_EL2_TWEDEL);
	}

	BUG_ON(host_data_test_flag(VCPU_IN_HYP_CONTEXT) &&
	       host_data_test_flag(L1_VNCR_MAPPED));

	return hcr | (guest_hcr & ~NV_HCR_GUEST_EXCLUDE);
}

static void __activate_traps(struct kvm_vcpu *vcpu)
{
	u64 val;

	___activate_traps(vcpu, __compute_hcr(vcpu));

	if (has_cntpoff()) {
		struct timer_map map;

		get_timer_map(vcpu, &map);

		/*
		 * We're entrering the guest. Reload the correct
		 * values from memory now that TGE is clear.
		 */
		if (map.direct_ptimer == vcpu_ptimer(vcpu))
			val = __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0);
		if (map.direct_ptimer == vcpu_hptimer(vcpu))
			val = __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2);

		if (map.direct_ptimer) {
			write_sysreg_el0(val, SYS_CNTP_CVAL);
			isb();
		}
	}

	__activate_cptr_traps(vcpu);

	write_sysreg(__this_cpu_read(kvm_hyp_vector), vbar_el1);
}
NOKPROBE_SYMBOL(__activate_traps);

static void __deactivate_traps(struct kvm_vcpu *vcpu)
{
	const char *host_vectors = vectors;

	___deactivate_traps(vcpu);

	write_sysreg_hcr(HCR_HOST_VHE_FLAGS);

	if (has_cntpoff()) {
		struct timer_map map;
		u64 val, offset;

		get_timer_map(vcpu, &map);

		/*
		 * We're exiting the guest. Save the latest CVAL value
		 * to memory and apply the offset now that TGE is set.
		 */
		val = read_sysreg_el0(SYS_CNTP_CVAL);
		if (map.direct_ptimer == vcpu_ptimer(vcpu))
			__vcpu_assign_sys_reg(vcpu, CNTP_CVAL_EL0, val);
		if (map.direct_ptimer == vcpu_hptimer(vcpu))
			__vcpu_assign_sys_reg(vcpu, CNTHP_CVAL_EL2, val);

		offset = read_sysreg_s(SYS_CNTPOFF_EL2);

		if (map.direct_ptimer && offset) {
			write_sysreg_el0(val + offset, SYS_CNTP_CVAL);
			isb();
		}
	}

	/*

Annotation

Implementation Notes