Added patch to update user_shared_data timers.

This commit is contained in:
Sebastian Lackner 2017-05-05 13:37:34 +02:00
parent 31212d2845
commit 26438ad74c
4 changed files with 343 additions and 1 deletions

View File

@ -0,0 +1,253 @@
From b01774078f03dcdc89d045d6c27106ce4059904e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Fri, 5 May 2017 05:40:50 +0200
Subject: ntdll: Create thread to update user_shared_data time values when
necessary.
---
dlls/kernel32/cpu.c | 4 +--
dlls/ntdll/loader.c | 32 ++++++++++++++++++++++
dlls/ntdll/ntdll_misc.h | 3 +++
dlls/ntdll/thread.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-----
dlls/ntdll/virtual.c | 16 +++++++++++
5 files changed, 116 insertions(+), 9 deletions(-)
diff --git a/dlls/kernel32/cpu.c b/dlls/kernel32/cpu.c
index 01cb469b8db..d112368dcb4 100644
--- a/dlls/kernel32/cpu.c
+++ b/dlls/kernel32/cpu.c
@@ -46,7 +46,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(reg);
-#define SHARED_DATA ((KSHARED_USER_DATA*)0x7ffe0000)
+extern KSHARED_USER_DATA* CDECL __wine_user_shared_data(void);
/****************************************************************************
* QueryPerformanceCounter (KERNEL32.@)
@@ -206,7 +206,7 @@ BOOL WINAPI IsProcessorFeaturePresent (
DWORD feature /* [in] Feature number, (PF_ constants from "winnt.h") */)
{
if (feature < PROCESSOR_FEATURE_MAX)
- return SHARED_DATA->ProcessorFeatures[feature];
+ return __wine_user_shared_data()->ProcessorFeatures[feature];
else
return FALSE;
}
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 630a9f66dc8..a00c3e17734 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -3514,6 +3514,37 @@ static void start_process( void *arg )
call_thread_entry_point( start_params->kernel_start, start_params->entry );
}
+
+/***********************************************************************
+ * user_shared_data_init
+ *
+ * Initializes a user shared
+ */
+static void user_shared_data_init(void)
+{
+ void *addr = user_shared_data_external;
+ SIZE_T data_size = page_size;
+ ULONG old_prot;
+
+ /* initialize time fields */
+ __wine_user_shared_data();
+
+ /* invalidate high times to prevent race conditions */
+ user_shared_data->SystemTime.High2Time = 0;
+ user_shared_data->SystemTime.High1Time = -1;
+
+ user_shared_data->InterruptTime.High2Time = 0;
+ user_shared_data->InterruptTime.High1Time = -1;
+
+ user_shared_data->u.TickCount.High2Time = 0;
+ user_shared_data->u.TickCount.High1Time = -1;
+
+ /* copy to correct address and make it non accessible */
+ memcpy(user_shared_data_external, user_shared_data, sizeof(*user_shared_data));
+ NtProtectVirtualMemory( NtCurrentProcess(), &addr, &data_size, PAGE_NOACCESS, &old_prot );
+}
+
+
/******************************************************************
* LdrInitializeThunk (NTDLL.@)
*
@@ -3545,6 +3576,7 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
peb->ProcessParameters->WindowTitle = wm->ldr.FullDllName;
version_init( wm->ldr.FullDllName.Buffer );
hidden_exports_init( wm->ldr.FullDllName.Buffer );
+ user_shared_data_init();
virtual_set_large_address_space();
LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index d556a21ee67..3ddbb6367c4 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -180,6 +180,9 @@ extern void VIRTUAL_SetForceExec( BOOL enable ) DECLSPEC_HIDDEN;
extern void virtual_release_address_space(void) DECLSPEC_HIDDEN;
extern void virtual_set_large_address_space(void) DECLSPEC_HIDDEN;
extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
+extern struct _KUSER_SHARED_DATA *user_shared_data_external DECLSPEC_HIDDEN;
+extern void create_user_shared_data_thread(void) DECLSPEC_HIDDEN;
+extern BYTE* __wine_user_shared_data(void);
/* completion */
extern NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 8da0779f4b2..b6cf2c8b794 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -43,6 +43,7 @@
#include "wine/library.h"
#include "wine/server.h"
#include "wine/debug.h"
+#include "winbase.h"
#include "ntdll_misc.h"
#include "ddk/wdm.h"
#include "wine/exception.h"
@@ -50,7 +51,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(thread);
WINE_DECLARE_DEBUG_CHANNEL(relay);
-struct _KUSER_SHARED_DATA *user_shared_data = NULL;
+static struct _KUSER_SHARED_DATA user_shared_data_internal;
+struct _KUSER_SHARED_DATA *user_shared_data_external;
+struct _KUSER_SHARED_DATA *user_shared_data = &user_shared_data_internal;
PUNHANDLED_EXCEPTION_FILTER unhandled_exception_filter = NULL;
@@ -345,18 +348,71 @@ static ULONG_PTR get_image_addr(void)
*/
BYTE* CDECL __wine_user_shared_data(void)
{
+ static int spinlock;
+ ULARGE_INTEGER interrupt;
LARGE_INTEGER now;
+
+ while (interlocked_cmpxchg( &spinlock, 1, 0 ) != 0);
+
NtQuerySystemTime( &now );
- user_shared_data->SystemTime.LowPart = now.u.LowPart;
- user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
- user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
- user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
- user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
+ user_shared_data->SystemTime.High2Time = now.u.HighPart;
+ user_shared_data->SystemTime.LowPart = now.u.LowPart;
+ user_shared_data->SystemTime.High1Time = now.u.HighPart;
+
+ RtlQueryUnbiasedInterruptTime( &interrupt.QuadPart );
+ user_shared_data->InterruptTime.High2Time = interrupt.HighPart;
+ user_shared_data->InterruptTime.LowPart = interrupt.LowPart;
+ user_shared_data->InterruptTime.High1Time = interrupt.HighPart;
+
+ interrupt.QuadPart /= 10000;
+ user_shared_data->u.TickCount.High2Time = interrupt.HighPart;
+ user_shared_data->u.TickCount.LowPart = interrupt.LowPart;
+ user_shared_data->u.TickCount.High1Time = interrupt.HighPart;
+ user_shared_data->TickCountLowDeprecated = interrupt.LowPart;
user_shared_data->TickCountMultiplier = 1 << 24;
+
+ spinlock = 0;
return (BYTE *)user_shared_data;
}
+static void *user_shared_data_thread(void *arg)
+{
+ struct timeval tv;
+
+ while (TRUE)
+ {
+ __wine_user_shared_data();
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 15600;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+ return NULL;
+}
+
+
+void create_user_shared_data_thread(void)
+{
+ static int thread_created;
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ if (interlocked_cmpxchg(&thread_created, 1, 0) != 0)
+ return;
+
+ FIXME("Creating user shared data update thread.\n");
+
+ user_shared_data = user_shared_data_external;
+ __wine_user_shared_data();
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 0x10000);
+ pthread_create(&thread, &attr, user_shared_data_thread, NULL);
+ pthread_attr_destroy(&attr);
+}
+
+
/***********************************************************************
* thread_init
*
@@ -388,7 +444,7 @@ HANDLE thread_init(void)
MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
exit(1);
}
- user_shared_data = addr;
+ user_shared_data_external = addr;
/* allocate and initialize the PEB */
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 872b1ce2d8f..bd8f54f78c3 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1561,6 +1561,7 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
struct file_view *view;
NTSTATUS ret = STATUS_ACCESS_VIOLATION;
sigset_t sigset;
+ BOOL update_shared_data = FALSE;
server_enter_uninterrupted_section( &csVirtual, &sigset );
if ((view = VIRTUAL_FindView( addr, 0 )))
@@ -1582,6 +1583,17 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
/* ignore fault if page is writable now */
if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS;
}
+ else if (page == user_shared_data_external)
+ {
+ if (!(*vprot & VPROT_READ))
+ {
+ *vprot |= VPROT_READ | VPROT_WRITE;
+ VIRTUAL_SetProt( view, page, page_size, *vprot );
+ update_shared_data = TRUE;
+ }
+ /* ignore fault if page is readable now */
+ if (VIRTUAL_GetUnixProt( *vprot ) & PROT_READ) ret = STATUS_SUCCESS;
+ }
if (!on_signal_stack && (*vprot & VPROT_GUARD))
{
VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD );
@@ -1589,6 +1601,10 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
}
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
+
+ if (update_shared_data)
+ create_user_shared_data_thread();
+
return ret;
}
--
2.12.2

View File

@ -0,0 +1,69 @@
From 3f4763cc335ea4d8293862677fabe0f8218c5542 Mon Sep 17 00:00:00 2001
From: Andrew Wesie <awesie@gmail.com>
Date: Tue, 2 May 2017 21:19:03 -0500
Subject: ntdll/tests: Test updating TickCount in user_shared_data.
---
dlls/ntdll/tests/time.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/dlls/ntdll/tests/time.c b/dlls/ntdll/tests/time.c
index b684bc1980d..0c8300a3428 100644
--- a/dlls/ntdll/tests/time.c
+++ b/dlls/ntdll/tests/time.c
@@ -18,7 +18,9 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define NONAMELESSUNION
#include "ntdll_test.h"
+#include "ddk/wdm.h"
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
@@ -27,6 +29,7 @@
static VOID (WINAPI *pRtlTimeToTimeFields)( const LARGE_INTEGER *liTime, PTIME_FIELDS TimeFields) ;
static VOID (WINAPI *pRtlTimeFieldsToTime)( PTIME_FIELDS TimeFields, PLARGE_INTEGER Time) ;
static NTSTATUS (WINAPI *pNtQueryPerformanceCounter)( LARGE_INTEGER *counter, LARGE_INTEGER *frequency );
+static ULONG (WINAPI *pNtGetTickCount)(void);
static const int MonthLengths[2][12] =
{
@@ -115,15 +118,34 @@ static void test_NtQueryPerformanceCounter(void)
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
}
+static void test_NtGetTickCount(void)
+{
+#ifndef _WIN64
+ KSHARED_USER_DATA *user_shared_data = (void *)0x7ffe0000;
+ LONG diff;
+ int i;
+
+ for (i = 0; i < 5; ++i)
+ {
+ diff = (user_shared_data->u.TickCountQuad * user_shared_data->TickCountMultiplier) >> 24;
+ diff = NtGetTickCount() - diff;
+ ok(diff < 32, "NtGetTickCount - TickCountQuad too high, expected < 32 got %d\n", diff);
+ Sleep(50);
+ }
+#endif
+}
+
START_TEST(time)
{
HMODULE mod = GetModuleHandleA("ntdll.dll");
pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields");
pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime");
pNtQueryPerformanceCounter = (void *)GetProcAddress(mod, "NtQueryPerformanceCounter");
+ pNtGetTickCount = (void *)GetProcAddress(mod,"NtGetTickCount");
if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
test_pRtlTimeToTimeFields();
else
win_skip("Required time conversion functions are not available\n");
test_NtQueryPerformanceCounter();
+ test_NtGetTickCount();
}
--
2.12.2

View File

@ -0,0 +1,2 @@
Fixes: [29168] Update user shared data at realtime
Depends: ntdll-Hide_Wine_Exports

View File

@ -2273,6 +2273,13 @@ if test "$enable_ntdll_WRITECOPY" -eq 1; then
enable_ws2_32_WriteWatches=1
fi
if test "$enable_ntdll_User_Shared_Data" -eq 1; then
if test "$enable_ntdll_Hide_Wine_Exports" -gt 1; then
abort "Patchset ntdll-Hide_Wine_Exports disabled, but ntdll-User_Shared_Data depends on that."
fi
enable_ntdll_Hide_Wine_Exports=1
fi
if test "$enable_ntdll_SystemRoot_Symlink" -eq 1; then
if test "$enable_ntdll_Exception" -gt 1; then
abort "Patchset ntdll-Exception disabled, but ntdll-SystemRoot_Symlink depends on that."
@ -6008,15 +6015,26 @@ fi
# Patchset ntdll-User_Shared_Data
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-Attach_Process_DLLs, ntdll-ThreadTime, ntdll-Hide_Wine_Exports
# |
# | This patchset fixes the following Wine bugs:
# | * [#29168] Update user shared data at realtime
# |
# | Modified files:
# | * dlls/ntdll/ntdll.spec, dlls/ntdll/thread.c, dlls/ntoskrnl.exe/instr.c
# | * dlls/kernel32/cpu.c, dlls/ntdll/loader.c, dlls/ntdll/ntdll.spec, dlls/ntdll/ntdll_misc.h, dlls/ntdll/tests/time.c,
# | dlls/ntdll/thread.c, dlls/ntdll/virtual.c, dlls/ntoskrnl.exe/instr.c
# |
if test "$enable_ntdll_User_Shared_Data" -eq 1; then
patch_apply ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch
patch_apply ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch
patch_apply ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch
patch_apply ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch
(
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Move code to update user shared data into a separate function.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "ntoskrnl: Update USER_SHARED_DATA before accessing memory.", 1 },';
printf '%s\n' '+ { "Michael Müller", "ntdll: Create thread to update user_shared_data time values when necessary.", 1 },';
printf '%s\n' '+ { "Andrew Wesie", "ntdll/tests: Test updating TickCount in user_shared_data.", 1 },';
) >> "$patchlist"
fi