]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: don't use TSC in virtualized environments 22446/head
authorLennart Poettering <lennart@poettering.net>
Tue, 8 Feb 2022 10:35:10 +0000 (11:35 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 8 Feb 2022 12:46:26 +0000 (13:46 +0100)
Replaces: f699bd81e8e18da2d2fc11e7fb7dce95f8bb3f9e

Fixes: #22060
src/boot/efi/ticks.c

index 4ed43d09705a3a99fab445dcaa1a78dd704a33f8..45980bafe867ad62526693213646f22e7966871f 100644 (file)
@@ -2,18 +2,47 @@
 
 #include <efi.h>
 #include <efilib.h>
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h>
+#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;
 }