From b34c23fe3d320e8dedb6d70d93b7b3011639ebd9 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 18 Jun 2024 13:25:02 -0700 Subject: [PATCH] HostFeatures: Work around Qualcomm Oryon RNG errata The Oryon is the first CPU we know of that implemented support for the RNG extension. It also has an errata where reading the RNDRRS register never returns success. X86's RDSEED guarantees forward progress with enough retries. When an x86 processor messed this up at one point, some Linux systems would infinite loop (presumably when something in boot was filling an entropy pool). This required a microcode change to fix that processor. The rdseed unittest infinite loops on this platform if RNG was exposed. --- .../Source/Interface/Core/HostFeatures.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/FEXCore/Source/Interface/Core/HostFeatures.cpp b/FEXCore/Source/Interface/Core/HostFeatures.cpp index 9b45aae6d..991fb4c37 100644 --- a/FEXCore/Source/Interface/Core/HostFeatures.cpp +++ b/FEXCore/Source/Interface/Core/HostFeatures.cpp @@ -44,6 +44,13 @@ static uint32_t GetFPCR() { static void SetFPCR(uint64_t Value) { __asm("msr FPCR, %[Value]" ::[Value] "r"(Value)); } + +static uint32_t GetMIDR() { + uint64_t Result {}; + __asm("mrs %[Res], MIDR_EL1" : [Res] "=r"(Result)); + return Result; +} + #else static uint32_t GetDCZID() { // Return unsupported @@ -194,6 +201,24 @@ HostFeatures::HostFeatures() { // Set FPCR back to original just in case anything changed SetFPCR(OriginalFPCR); + + if (SupportsRAND) { + const auto MIDR = GetMIDR(); + constexpr uint32_t Implementer_QCOM = 0x51; + constexpr uint32_t PartNum_Oryon1 = 0x001; + const uint32_t MIDR_Implementer = (MIDR >> 24) & 0xFF; + const uint32_t MIDR_PartNum = (MIDR >> 4) & 0xFFF; + if (MIDR_Implementer == Implementer_QCOM && MIDR_PartNum == PartNum_Oryon1) { + // Work around an errata in Qualcomm's Oryon. + // While this CPU implements the RAND extension: + // - The RNDR register works. + // - The RNDRRS register will never read a random number. (Always return failure) + // This is contrary to x86 RNG behaviour where it allows spurious failure with RDSEED, but guarantees eventual success. + // This manifested itself on Linux when an x86 processor failed to guarantee forward progress and boot of services would infinite + // loop. Just disable this extension if this CPU is detected. + SupportsRAND = false; + } + } #endif #ifdef VIXL_SIMULATOR