From a30ed15cebd0f8d7176897bbeaf9baca079327e6 Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Thu, 29 Jan 2026 15:17:33 -0800 Subject: [PATCH] [WIN32SS:NTGDI] Handle AMD GPUs being dumb when they do a double restore (#8644) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the kerestorefloatingpointstate msdn article shouldn't be on the kernel's responsibility to handle. for the life of me i couldn't figure out why this specific driver does this until finally I tried this on Windows and low and behold on checked builds of windows it actually tells you it does the exact same thing. Investigating deeper I realized win32k just has some extra handling for this dumb case. Co-authored-by: Hermès BÉLUSCA - MAÏTO Co-authored-by: Timo Kreuzer --- win32ss/gdi/eng/float.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/win32ss/gdi/eng/float.c b/win32ss/gdi/eng/float.c index 69e5c519b7b..caf75bea8e5 100644 --- a/win32ss/gdi/eng/float.c +++ b/win32ss/gdi/eng/float.c @@ -13,6 +13,12 @@ #define NDEBUG #include +typedef struct _WIN32K_FLOATING_SAVE +{ + KFLOATING_SAVE FloatState; + BOOLEAN IsFloatingPointSaved; +} WIN32K_FLOATING_SAVE, *PWIN32K_FLOATING_SAVE; + /* FUNCTIONS *****************************************************************/ #ifdef _PREFAST_ @@ -31,8 +37,18 @@ EngRestoreFloatingPointState( _In_reads_(_Inexpressible_(statesize)) PVOID pBuffer) { NTSTATUS Status; + PWIN32K_FLOATING_SAVE State = (PWIN32K_FLOATING_SAVE)pBuffer; - Status = KeRestoreFloatingPointState((PKFLOATING_SAVE)pBuffer); + if (!State->IsFloatingPointSaved) + { + DPRINT1("The driver has attempted to restore floating point state after already restoring it.\n"); + DPRINT1("This (probably ICafe AMD) driver has done an incorrect behavior.\n"); + return FALSE; + } + + State->IsFloatingPointSaved = FALSE; + + Status = KeRestoreFloatingPointState(&State->FloatState); if (!NT_SUCCESS(Status)) { return FALSE; @@ -55,33 +71,44 @@ EngSaveFloatingPointState( _Out_writes_bytes_opt_(cjBufferSize) PVOID pBuffer, _Inout_ ULONG cjBufferSize) { - KFLOATING_SAVE TempBuffer; + PWIN32K_FLOATING_SAVE State; NTSTATUS Status; if ((pBuffer == NULL) || (cjBufferSize == 0)) { + KFLOATING_SAVE TempBuffer; + /* Check for floating point support. */ Status = KeSaveFloatingPointState(&TempBuffer); if (Status != STATUS_SUCCESS) { return(0); } - KeRestoreFloatingPointState(&TempBuffer); - return(sizeof(KFLOATING_SAVE)); + return sizeof(WIN32K_FLOATING_SAVE); } - if (cjBufferSize < sizeof(KFLOATING_SAVE)) + if (cjBufferSize < sizeof(WIN32K_FLOATING_SAVE)) { return(0); } - Status = KeSaveFloatingPointState((PKFLOATING_SAVE)pBuffer); + /* Per MSDN, "This buffer must be zero-initialized, and must be in nonpaged memory." */ + State = (PWIN32K_FLOATING_SAVE)pBuffer; + + if (State->IsFloatingPointSaved) + { + DPRINT1("The driver has attempted to save floating point state after already saving it.\n"); + DPRINT1("This (probably ICafe AMD) driver has done an incorrect behavior.\n"); + } + + Status = KeSaveFloatingPointState(&State->FloatState); if (!NT_SUCCESS(Status)) { return FALSE; } + State->IsFloatingPointSaved = TRUE; return TRUE; }