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:
commit
4d6ce52e7b
@ -18,6 +18,7 @@
|
||||
#include "random-seed.h"
|
||||
#include "secure-boot.h"
|
||||
#include "shim.h"
|
||||
#include "ticks.h"
|
||||
#include "util.h"
|
||||
#include "xbootldr.h"
|
||||
|
||||
|
@ -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
101
src/boot/efi/ticks.c
Normal 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
7
src/boot/efi/ticks.h
Normal 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);
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user