x86: skip clock_sync_test on QEMU

Try detect if we are running as a guest based on the CPUID
and skip clock_sync_test if we are.

Similar as previous patches for skipping QEMU on ARM/RISC-V
but at run-time instead of build-time.

Tested with qemu-system-x86_64 using `-smp 4`, the test is now
skipped with regular QEMU as well as `-accel kvm`.

Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
This commit is contained in:
Ivan Velickovic 2026-01-08 20:41:50 +11:00 committed by Ivan Velickovic
parent 33636e983d
commit 04db8cebcc
2 changed files with 42 additions and 1 deletions

View file

@ -96,6 +96,23 @@
#define IA32_PRED_CMD_MSR 0x49
/*
* CPUID bits for detecting the kernel is running as a guest.
*
* These bits correspond to the strings "KVMKVMKVM" for KVM and "TCGTCGTCGTCG"
* for QEMU's Tiny Code Generator (TCG).
*
* https://docs.kernel.org/virt/kvm/x86/cpuid.html.
*/
#define KVM_CPUID_SIGNATURE 0x40000000
#define CPUID_TCG_EBX 0x54474354
#define CPUID_TCG_ECX 0x43544743
#define CPUID_TCG_EDX 0x47435447
#define CPUID_KVM_EBX 0x4b4d564b
#define CPUID_KVM_ECX 0x564b4d56
#define CPUID_KVM_EDX 0x4d
word_t PURE getRestartPC(tcb_t *thread);
void setNextPC(tcb_t *thread, word_t v);

View file

@ -578,6 +578,21 @@ BOOT_CODE tcb_t *create_initial_thread(cap_t root_cnode_cap, cap_t it_pd_cap, vp
}
#ifdef ENABLE_SMP_CLOCK_SYNC_TEST_ON_BOOT
BOOT_CODE static bool_t hypervisor_present(void)
{
#ifdef CONFIG_ARCH_X86
uint32_t ebx = x86_cpuid_ebx(KVM_CPUID_SIGNATURE, 0);
uint32_t ecx = x86_cpuid_ecx(KVM_CPUID_SIGNATURE, 0);
uint32_t edx = x86_cpuid_edx(KVM_CPUID_SIGNATURE, 0);
if ((ebx == CPUID_KVM_EBX && ecx == CPUID_KVM_ECX && edx == CPUID_KVM_EDX)
|| (ebx == CPUID_TCG_EBX && ecx == CPUID_TCG_ECX && edx == CPUID_TCG_EDX)) {
return true;
}
#endif
return false;
}
BOOT_CODE void clock_sync_test(void)
{
ticks_t t, t0;
@ -593,7 +608,16 @@ BOOT_CODE void clock_sync_test(void)
t = getCurrentTime();
printf("clock_sync_test[%d]: t0 = %"PRIu64", t = %"PRIu64", td = %"PRIi64"\n",
(int)getCurrentCPUIndex(), t0, t, t - t0);
assert(t0 <= margin + t && t <= t0 + margin);
/*
* The test does not consistently work if we are in a virtual machine (e.g
* within QEMU) because the measurement cannot distinguish between
* interrupted clock reads and out-of-sync clocks.
*/
if (hypervisor_present()) {
printf("clock_sync_test[%d]: disabled, detected running as VM\n", (int)getCurrentCPUIndex());
} else {
assert(t0 <= margin + t && t <= t0 + margin);
}
}
#endif