From: Lennart Poettering Date: Tue, 8 Feb 2022 10:35:10 +0000 (+0100) Subject: sd-boot: don't use TSC in virtualized environments X-Git-Tag: v251-rc1~326^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3bcc999fa555198b5155ae5bb1989bee141267bc;p=thirdparty%2Fsystemd.git sd-boot: don't use TSC in virtualized environments Replaces: f699bd81e8e18da2d2fc11e7fb7dce95f8bb3f9e Fixes: #22060 --- diff --git a/src/boot/efi/ticks.c b/src/boot/efi/ticks.c index 4ed43d09705..45980bafe86 100644 --- a/src/boot/efi/ticks.c +++ b/src/boot/efi/ticks.c @@ -2,18 +2,47 @@ #include #include +#if defined(__i386__) || defined(__x86_64__) +#include +#endif #include "ticks.h" +#if defined(__i386__) || defined(__x86_64__) +static BOOLEAN in_hypervisor(void) { + uint32_t eax, ebx, ecx, edx; + + /* The TSC might or might not be virtualized in VMs (and thus might not be accurate or start at zero + * at boot), depending on hypervisor and CPU functionality. If it's not virtualized it's not useful + * for keeping time, hence don't attempt to use it. + * + * This is a dumbed down version of src/basic/virt.c's detect_vm() that safely works in the UEFI + * environment. */ + + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) + return FALSE; + + return !!(ecx & 0x80000000U); +} +#endif + #ifdef __x86_64__ static UINT64 ticks_read(void) { UINT64 a, d; + + if (in_hypervisor()) + return 0; + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); return (d << 32) | a; } #elif defined(__i386__) static UINT64 ticks_read(void) { UINT64 val; + + if (in_hypervisor()) + return 0; + __asm__ volatile ("rdtsc" : "=A" (val)); return val; }