From 3bcc999fa555198b5155ae5bb1989bee141267bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Feb 2022 11:35:10 +0100 Subject: [PATCH] sd-boot: don't use TSC in virtualized environments Replaces: f699bd81e8e18da2d2fc11e7fb7dce95f8bb3f9e Fixes: #22060 --- src/boot/efi/ticks.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) 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; } -- 2.47.3