hypervisor_cpuid_base

A guest running on a kvm host, can check some of its features using cpuid. This is not always guaranteed to work, since userspace can mask-out some, or even all KVM-related cpuid features before launching a guest.

How to check all the PV features in guest?

PV features 需要:

  • Host KVM 支持;
  • Userspace VMM 比如说 QEMU 会把这个 feature 暴露给 guest;
  • Guest kernel 有 pv 支持,会使用这个 feature

需要保证这三者都支持才行。

// cpuid -l 0x40000000
// cpuid -l 
// In guest kernel
hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
hypervisor_cpuid_base("ACRNACRNACRN", 0);
hypervisor_cpuid_base("XenVMMXenVMM", 2);
static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
{
	uint32_t base, eax, signature[3];

	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
		cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);

		if (!memcmp(sig, signature, 12) &&
		    (leaves == 0 || ((eax - base) >= leaves)))
			return base;
	}

	return 0;
}

Pv sched yield kvm-pv-sched-yield

kvm_guest_init
    if (pv_sched_yield_supported()) {
		smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
		pr_info("setup PV sched yield\n");
	}

static bool pv_sched_yield_supported(void)
{
	return (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
		!kvm_para_has_hint(KVM_HINTS_REALTIME) &&
	    kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
}

PV qspinlock, PV spinlock, kvm-pv-unhalt

kvm_spinlock_init
    pr_info("PV spinlocks enabled\n");

CONFIG_PARAVIRT_SPINLOCKS

这些应该都是一样的,只不过在演进的过程中有了不同的名字。 都是 spinlock,只不过这些 spinlock 在 kernel 里实现不一样,对应的 pv 实现也是不一样的。

PV qspinlock 指的是 queue spinlock^。

pvqspinlock 是一个 ARM 的 guest kernel parameter,x86 没有此 kernel parameter,默认是开启的。可以看下面的代码来验证:

#if defined(CONFIG_PARAVIRT_SPINLOCKS)
	/* Lock ops. */
#ifdef CONFIG_SMP
	.lock.queued_spin_lock_slowpath	= native_queued_spin_lock_slowpath,
	.lock.queued_spin_unlock	=
				PV_CALLEE_SAVE(__native_queued_spin_unlock),
	.lock.wait			= paravirt_nop,
	.lock.kick			= paravirt_nop,
	.lock.vcpu_is_preempted		=
				PV_CALLEE_SAVE(__native_vcpu_is_preempted),
#endif /* SMP */
#endif
//...