mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-14 16:26:30 +00:00
hw: always serialize rdtsc reads
While implementing TSC calibration in #5215, the issue of properly serializing TSC reads came up. Some learnings of the discussion were noted in #5430. Using `cpuid` for serialization as in Trace::timestamp() is portable, but will cause VM exits on VMX and SVM and is therefore unsuitable to retain a roughly working calibration loop while running virtualized. On the other hand on most AMD systems, dispatch serializing `lfence` needs to be explicitly enabled via a non-architectural MSR. Enable setting up dispatch serializing lfence on AMD systems and always serialize rdtsc accesses in Hw::Tsc::rdtsc() for maximum reliability. Issues #5215, #5430
This commit is contained in:
parent
ec5e1a6b4b
commit
02b7878229
@ -131,7 +131,7 @@ static void disable_pit()
|
||||
PIT_MODE = 0x43,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Disable PIT timer channel. This is necessary since BIOS sets up
|
||||
* channel 0 to fire periodically.
|
||||
*/
|
||||
@ -141,6 +141,35 @@ static void disable_pit()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enable dispatch serializing lfence instruction on AMD processors
|
||||
*
|
||||
* See Software techniques for managing speculation on AMD processors
|
||||
* Revision 5.09.23
|
||||
* Mitigation G-2
|
||||
*/
|
||||
static void amd_enable_serializing_lfence()
|
||||
{
|
||||
using Cpu = Hw::X86_64_cpu;
|
||||
|
||||
if (Hw::Vendor::get_vendor_id() != Hw::Vendor::Vendor_id::AMD)
|
||||
return;
|
||||
|
||||
unsigned const family = Hw::Vendor::get_family();
|
||||
|
||||
/*
|
||||
* In family 0Fh and 11h, lfence is always dispatch serializing and
|
||||
* "AMD plans support for this MSR and access to this bit for all future
|
||||
* processors." from family 14h on.
|
||||
*/
|
||||
if ((family == 0x10) || (family == 0x12) || (family >= 0x14)) {
|
||||
Cpu::Amd_lfence::access_t amd_lfence = Cpu::Amd_lfence::read();
|
||||
Cpu::Amd_lfence::Enable_dispatch_serializing::set(amd_lfence);
|
||||
Cpu::Amd_lfence::write(amd_lfence);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bootstrap::Platform::Board::Board()
|
||||
:
|
||||
core_mmio(Memory_region { 0, 0x1000 },
|
||||
@ -325,6 +354,14 @@ Bootstrap::Platform::Board::Board()
|
||||
cpus = !cpus ? 1 : max_cpus;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable serializing lfence on supported AMD processors
|
||||
*
|
||||
* For APs this will be set up later, but we need it already to obtain
|
||||
* the most acurate results when calibrating the TSC frequency.
|
||||
*/
|
||||
amd_enable_serializing_lfence();
|
||||
|
||||
auto r = calibrate_lapic_frequency(info.acpi_fadt);
|
||||
info.lapic_freq_khz = r.freq_khz;
|
||||
info.lapic_div = r.div;
|
||||
@ -401,9 +438,12 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
if (board.cpus <= 1)
|
||||
return (unsigned)cpu_id;
|
||||
|
||||
if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr))
|
||||
if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr)) {
|
||||
/* AP - done */
|
||||
/* enable serializing lfence on supported AMD processors. */
|
||||
amd_enable_serializing_lfence();
|
||||
return (unsigned)cpu_id;
|
||||
}
|
||||
|
||||
/* BSP - we're primary CPU - wake now all other CPUs */
|
||||
|
||||
|
@ -118,6 +118,12 @@ struct Hw::X86_64_cpu
|
||||
/* AMD host save physical address */
|
||||
X86_64_MSR_REGISTER(Amd_vm_hsavepa, 0xC0010117);
|
||||
|
||||
|
||||
/* Non-architectural MSR used to make lfence serializing */
|
||||
X86_64_MSR_REGISTER(Amd_lfence, 0xC0011029,
|
||||
struct Enable_dispatch_serializing : Bitfield<1, 1> { }; /* Enable lfence dispatch serializing */
|
||||
)
|
||||
|
||||
X86_64_MSR_REGISTER(Platform_id, 0x17,
|
||||
struct Bus_ratio : Bitfield<8, 5> { }; /* Bus ratio on Core 2, see SDM 19.7.3 */
|
||||
);
|
||||
|
@ -109,10 +109,22 @@ public:
|
||||
|
||||
struct Hw::Tsc
|
||||
{
|
||||
/*
|
||||
* Provide serialized access to the Timestamp Counter
|
||||
*
|
||||
* See #5430 for more information.
|
||||
*/
|
||||
static Genode::uint64_t rdtsc()
|
||||
{
|
||||
Genode::uint32_t low, high;
|
||||
asm volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||
asm volatile(
|
||||
"lfence;"
|
||||
"rdtsc;"
|
||||
"lfence;"
|
||||
: "=a"(low), "=d"(high)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return (Genode::uint64_t)(high) << 32 | low;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user