diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc index 77aeec6e5b..8ec2e444ac 100644 --- a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc @@ -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 */ diff --git a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h index 324f37af67..f538c9e65d 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/cpu.h @@ -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 */ ); diff --git a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h index c451fac22c..6bca48fe9a 100644 --- a/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h +++ b/repos/base-hw/src/include/hw/spec/x86_64/x86_64.h @@ -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; }