1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-30 06:25:37 +03:00

Merge pull request #22446 from poettering/sd-boot-cpuid-vm-tscd

sd-boot: don't read TSC in VM environments, and other TSC fixes
This commit is contained in:
Lennart Poettering 2022-02-08 21:57:38 +01:00 committed by GitHub
commit 4d6ce52e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 78 deletions

View File

@ -18,6 +18,7 @@
#include "random-seed.h"
#include "secure-boot.h"
#include "shim.h"
#include "ticks.h"
#include "util.h"
#include "xbootldr.h"

View File

@ -322,6 +322,7 @@ efi_headers = files(
'secure-boot.h',
'shim.h',
'splash.h',
'ticks.h',
'util.h',
'xbootldr.h',
)
@ -334,6 +335,7 @@ common_sources = files(
'measure.c',
'pe.c',
'secure-boot.c',
'ticks.c',
'util.c',
)

101
src/boot/efi/ticks.c Normal file
View File

@ -0,0 +1,101 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#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;
}
#elif defined(__aarch64__)
static UINT64 ticks_read(void) {
UINT64 val;
__asm__ volatile ("mrs %0, cntpct_el0" : "=r" (val));
return val;
}
#else
static UINT64 ticks_read(void) {
return 0;
}
#endif
#if defined(__aarch64__)
static UINT64 ticks_freq(void) {
UINT64 freq;
__asm__ volatile ("mrs %0, cntfrq_el0": "=r" (freq));
return freq;
}
#else
/* count TSC ticks during a millisecond delay */
static UINT64 ticks_freq(void) {
UINT64 ticks_start, ticks_end;
static UINT64 cache = 0;
if (cache != 0)
return cache;
ticks_start = ticks_read();
BS->Stall(1000);
ticks_end = ticks_read();
if (ticks_end < ticks_start) /* Check for an overflow (which is not that unlikely, given on some
* archs the value is 32bit) */
return 0;
cache = (ticks_end - ticks_start) * 1000UL;
return cache;
}
#endif
UINT64 time_usec(void) {
UINT64 ticks, freq;
ticks = ticks_read();
if (ticks == 0)
return 0;
freq = ticks_freq();
if (freq == 0)
return 0;
return 1000UL * 1000UL * ticks / freq;
}

7
src/boot/efi/ticks.h Normal file
View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <efi.h>
#include <efilib.h>
UINT64 time_usec(void);

View File

@ -3,69 +3,9 @@
#include <efi.h>
#include <efilib.h>
#include "ticks.h"
#include "util.h"
#ifdef __x86_64__
UINT64 ticks_read(void) {
UINT64 a, d;
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
return (d << 32) | a;
}
#elif defined(__i386__)
UINT64 ticks_read(void) {
UINT64 val;
__asm__ volatile ("rdtsc" : "=A" (val));
return val;
}
#elif defined(__aarch64__)
UINT64 ticks_read(void) {
UINT64 val;
__asm__ volatile ("mrs %0, cntpct_el0" : "=r" (val));
return val;
}
#else
UINT64 ticks_read(void) {
UINT64 val = 1;
return val;
}
#endif
#if defined(__aarch64__)
UINT64 ticks_freq(void) {
UINT64 freq;
__asm__ volatile ("mrs %0, cntfrq_el0": "=r" (freq));
return freq;
}
#else
/* count TSC ticks during a millisecond delay */
UINT64 ticks_freq(void) {
UINT64 ticks_start, ticks_end;
ticks_start = ticks_read();
BS->Stall(1000);
ticks_end = ticks_read();
return (ticks_end - ticks_start) * 1000UL;
}
#endif
UINT64 time_usec(void) {
UINT64 ticks;
static UINT64 freq;
ticks = ticks_read();
if (ticks == 0)
return 0;
if (freq == 0) {
freq = ticks_freq();
if (freq == 0)
return 0;
}
return 1000UL * 1000UL * ticks / freq;
}
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
assert(b);

View File

@ -41,10 +41,6 @@
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
UINT64 ticks_read(void);
UINT64 ticks_freq(void);
UINT64 time_usec(void);
EFI_STATUS efivar_set(const EFI_GUID *vendor, const CHAR16 *name, const CHAR16 *value, UINT32 flags);
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const void *buf, UINTN size, UINT32 flags);
EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN i, UINT32 flags);

View File

@ -5,13 +5,11 @@
#include "efi-loader.h"
#include "macro.h"
#include "time-util.h"
#include "virt.h"
int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
usec_t x = 0, y = 0, a;
int r;
dual_timestamp _n;
bool use_firmware = true;
assert(firmware);
assert(loader);
@ -26,10 +24,6 @@ int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_time
r = efi_loader_get_boot_usec(&x, &y);
if (r < 0)
return r;
/* If we are running in a VM, the init timestamp would
* be equivalent to the host uptime. */
use_firmware = detect_vm() <= 0;
}
/* Let's convert this to timestamps where the firmware
@ -39,14 +33,12 @@ int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_time
* the monotonic timestamps here as negative of the actual
* value. */
if (use_firmware) {
firmware->monotonic = y;
a = n->monotonic + firmware->monotonic;
firmware->realtime = n->realtime > a ? n->realtime - a : 0;
} else
firmware->monotonic = firmware->realtime = 0;
firmware->monotonic = y;
loader->monotonic = y - x;
a = n->monotonic + firmware->monotonic;
firmware->realtime = n->realtime > a ? n->realtime - a : 0;
a = n->monotonic + loader->monotonic;
loader->realtime = n->realtime > a ? n->realtime - a : 0;