mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-01 23:20:55 +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,
|
PIT_MODE = 0x43,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Disable PIT timer channel. This is necessary since BIOS sets up
|
* Disable PIT timer channel. This is necessary since BIOS sets up
|
||||||
* channel 0 to fire periodically.
|
* 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()
|
Bootstrap::Platform::Board::Board()
|
||||||
:
|
:
|
||||||
core_mmio(Memory_region { 0, 0x1000 },
|
core_mmio(Memory_region { 0, 0x1000 },
|
||||||
@ -325,6 +354,14 @@ Bootstrap::Platform::Board::Board()
|
|||||||
cpus = !cpus ? 1 : max_cpus;
|
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);
|
auto r = calibrate_lapic_frequency(info.acpi_fadt);
|
||||||
info.lapic_freq_khz = r.freq_khz;
|
info.lapic_freq_khz = r.freq_khz;
|
||||||
info.lapic_div = r.div;
|
info.lapic_div = r.div;
|
||||||
@ -401,9 +438,12 @@ unsigned Bootstrap::Platform::enable_mmu()
|
|||||||
if (board.cpus <= 1)
|
if (board.cpus <= 1)
|
||||||
return (unsigned)cpu_id;
|
return (unsigned)cpu_id;
|
||||||
|
|
||||||
if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr))
|
if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr)) {
|
||||||
/* AP - done */
|
/* AP - done */
|
||||||
|
/* enable serializing lfence on supported AMD processors. */
|
||||||
|
amd_enable_serializing_lfence();
|
||||||
return (unsigned)cpu_id;
|
return (unsigned)cpu_id;
|
||||||
|
}
|
||||||
|
|
||||||
/* BSP - we're primary CPU - wake now all other CPUs */
|
/* BSP - we're primary CPU - wake now all other CPUs */
|
||||||
|
|
||||||
|
@ -118,6 +118,12 @@ struct Hw::X86_64_cpu
|
|||||||
/* AMD host save physical address */
|
/* AMD host save physical address */
|
||||||
X86_64_MSR_REGISTER(Amd_vm_hsavepa, 0xC0010117);
|
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,
|
X86_64_MSR_REGISTER(Platform_id, 0x17,
|
||||||
struct Bus_ratio : Bitfield<8, 5> { }; /* Bus ratio on Core 2, see SDM 19.7.3 */
|
struct Bus_ratio : Bitfield<8, 5> { }; /* Bus ratio on Core 2, see SDM 19.7.3 */
|
||||||
);
|
);
|
||||||
|
@ -109,10 +109,22 @@ public:
|
|||||||
|
|
||||||
struct Hw::Tsc
|
struct Hw::Tsc
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Provide serialized access to the Timestamp Counter
|
||||||
|
*
|
||||||
|
* See #5430 for more information.
|
||||||
|
*/
|
||||||
static Genode::uint64_t rdtsc()
|
static Genode::uint64_t rdtsc()
|
||||||
{
|
{
|
||||||
Genode::uint32_t low, high;
|
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;
|
return (Genode::uint64_t)(high) << 32 | low;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user