arch/x86/virt/hw.c

Source file repositories/reference/linux-study-clean/arch/x86/virt/hw.c

File Facts

System
Linux kernel
Corpus path
arch/x86/virt/hw.c
Extension
.c
Size
9443 bytes
Lines
374
Domain
Architecture Layer
Bucket
arch/x86
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

struct x86_virt_ops {
	int feature;
	int (*enable_virtualization_cpu)(void);
	int (*disable_virtualization_cpu)(void);
	void (*emergency_disable_virtualization_cpu)(void);
};
static struct x86_virt_ops virt_ops __ro_after_init;

__visible bool virt_rebooting;
EXPORT_SYMBOL_FOR_KVM(virt_rebooting);

static DEFINE_PER_CPU(int, virtualization_nr_users);

static cpu_emergency_virt_cb __rcu *kvm_emergency_callback;

void x86_virt_register_emergency_callback(cpu_emergency_virt_cb *callback)
{
	if (WARN_ON_ONCE(rcu_access_pointer(kvm_emergency_callback)))
		return;

	rcu_assign_pointer(kvm_emergency_callback, callback);
}
EXPORT_SYMBOL_FOR_KVM(x86_virt_register_emergency_callback);

void x86_virt_unregister_emergency_callback(cpu_emergency_virt_cb *callback)
{
	if (WARN_ON_ONCE(rcu_access_pointer(kvm_emergency_callback) != callback))
		return;

	rcu_assign_pointer(kvm_emergency_callback, NULL);
	synchronize_rcu();
}
EXPORT_SYMBOL_FOR_KVM(x86_virt_unregister_emergency_callback);

static void x86_virt_invoke_kvm_emergency_callback(void)
{
	cpu_emergency_virt_cb *kvm_callback;

	/*
	 * RCU may not be watching the crashing CPU here, so rcu_dereference()
	 * triggers a suspicious-RCU-usage splat. In principle, a concurrent
	 * KVM module unload could race with this read; see commit 2baa33a8ddd6
	 * ("KVM: x86: Leave user-return notifier registered on reboot/shutdown")
	 * which notes that nothing prevents module unload during panic/reboot.
	 *
	 * However, taking a lock here would be riskier than the current race:
	 * the system is going down via NMI shootdown, and any lock could be
	 * held by an already-stopped CPU. Use rcu_dereference_raw() to silence
	 * the lockdep splat and accept the comically small remaining race;
	 * panic context inherently cannot guarantee complete correctness.
	 */
	kvm_callback = rcu_dereference_raw(kvm_emergency_callback);
	if (kvm_callback)
		kvm_callback();
}

#if IS_ENABLED(CONFIG_KVM_INTEL)
static DEFINE_PER_CPU(struct vmcs *, root_vmcs);

static int x86_virt_cpu_vmxon(void)
{
	u64 vmxon_pointer = __pa(per_cpu(root_vmcs, raw_smp_processor_id()));
	u64 msr;

	cr4_set_bits(X86_CR4_VMXE);

	asm goto("1: vmxon %[vmxon_pointer]\n\t"
			  _ASM_EXTABLE(1b, %l[fault])
			  : : [vmxon_pointer] "m"(vmxon_pointer)
			  : : fault);
	return 0;

fault:
	WARN_ONCE(1, "VMXON faulted, MSR_IA32_FEAT_CTL (0x3a) = 0x%llx\n",
		  rdmsrq_safe(MSR_IA32_FEAT_CTL, &msr) ? 0xdeadbeef : msr);
	cr4_clear_bits(X86_CR4_VMXE);

	return -EFAULT;
}

static int x86_vmx_enable_virtualization_cpu(void)
{
	int r;

	if (cr4_read_shadow() & X86_CR4_VMXE)
		return -EBUSY;

	intel_pt_handle_vmx(1);

	r = x86_virt_cpu_vmxon();

Annotation

Implementation Notes