> 
> Writable shared memory is unacceptable, but as long as it's read-only
> from the client there's no problem in principle.
> 

Excellent, thanks Alexandre.

I'm attaching my current shared memory diff.  It uses shm_open + mmap in
wineserver to map the shared memory area read/write, and shm_open +
NtCreateSection + NtMapViewOfSection in wine to map read only.  A thread
is run in wineserver which does a clock_nanosleep to set the times
without drift.

The wineserver code appears to work, and successfully writes to shared
memory.  The wine code fails in NtMapViewOfSection with error C0000018,
which is STATUS_CONFLICTING_ADDRESSES.  Can someone who understands
NtMapViewOfSection look at my code and tell me if I've done something
stupid?  I thought there might be code buried in NtMapViewOfSection
which tries to reserve that code block, but I didn't see it when I looked.

Some notes:

I didn't use CreateFileMapping/MapViewOfFile because that lives in
kernel32.dll, so I pulled the code in and called
NtCreateSection/NtMapViewOfSection directly.

I also had to pull out all of the ntdll code which writes to
USER_SHARED_DATA, and move that to wineserver.

I had to link ntdll and wineserver against -lrt; this should of course
be done more clealy via configure.

Finally, the mmap call in wineserver only succeeds if I pass in a
candidate address; if I pass in NULL, it fails with 'Operation not
permitted'.

cheers,

Joey
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 0047731..80d7f5a 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -2,7 +2,7 @@ EXTRADEFS = -D_NTSYSTEM_
 MODULE    = ntdll.dll
 IMPORTLIB = ntdll
 IMPORTS   = winecrt0
-EXTRALIBS = @IOKITLIB@ @LIBPTHREAD@
+EXTRALIBS = @IOKITLIB@ @LIBPTHREAD@ -lrt
 EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x7bc00000
 
 C_SRCS = \
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 381e2ac..e6112eb 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2812,7 +2812,7 @@ void CDECL __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir )
     PLIST_ENTRY mark, entry;
     LPWSTR buffer, p;
 
-    strcpyW( user_shared_data->NtSystemRoot, windir );
+    /* strcpyW( user_shared_data->NtSystemRoot, windir ); */
     DIR_init_windows_dir( windir, sysdir );
 
     /* prepend the system dir to the name of the already created modules */
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 3ed8038..dea32ee 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -1038,6 +1038,7 @@ void fill_cpu_info(void)
             }
             if (!strcasecmp(line, "flags") || !strcasecmp(line, "features"))
             {
+#if 0
                 if (strstr(value, "cx8"))
                     user_shared_data->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
                 if (strstr(value, "cx16"))
@@ -1062,6 +1063,7 @@ void fill_cpu_info(void)
                     user_shared_data->ProcessorFeatures[PF_PAE_ENABLED] = TRUE;
                 if (strstr(value, "ht"))
                     cached_sci.FeatureSet |= CPU_FEATURE_HTT;
+#endif
                 continue;
             }
 	}
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index e328c5f..eb926d2 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -23,6 +23,8 @@
 
 #include <assert.h>
 #include <stdarg.h>
+#include <stdint.h>
+#include <errno.h>
 #include <sys/types.h>
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
@@ -183,6 +185,98 @@ done:
     return status;
 }
 
+static void map_user_shared_data(void) 
+{
+    int shmfd;
+    void *addr;
+
+    FIXME("open KUSER_SHARED_DATA\n");
+    shmfd = shm_open("/KUSER_SHARED_DATA", O_RDONLY | O_CREAT, 0600);
+
+    FIXME("shmfd %d\n", shmfd);
+
+    if(shmfd != -1) {
+        HANDLE fdh = NULL, cfmh = NULL;
+        NTSTATUS mstatus = STATUS_SUCCESS, cstatus = STATUS_SUCCESS;
+        LARGE_INTEGER offset;
+        ULONG protect = PAGE_READONLY;
+        //ULONG protect = PAGE_READWRITE;
+        SIZE_T count;
+
+        if(0)
+        {
+            addr = (void *)0x7ffe0000;
+            count = 0x10000;
+            addr = mmap(addr, count, PROT_READ, MAP_FILE|MAP_SHARED|MAP_FIXED, shmfd, 0);
+            
+            if(addr == MAP_FAILED) {
+                FIXME("mmap(addr, SZ, PROT_READ, MAP_FILE|MAP_SHARED|MAP_FIXED, fd, 0) failed: %s\n", strerror(errno));
+                return;
+            }
+            
+            FIXME("mapped USER_SHARED_DATA to %p\n", addr);
+            user_shared_data = addr;
+            return;
+        }
+
+        FIXME("calling wine_server_fd_to_handle( shmfd, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, &fdh )\n");
+
+        wine_server_fd_to_handle( shmfd, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, &fdh );
+
+        FIXME("fdh %p\n", fdh);
+        {
+            static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
+
+            DWORD access, sec_type;
+            LARGE_INTEGER size;
+
+            sec_type = protect & sec_flags;
+            protect &= ~sec_flags;
+            if (!sec_type) sec_type = SEC_COMMIT;
+
+            /* Win9x compatibility */
+            if (!protect && (GetVersion() & 0x80000000)) protect = PAGE_READONLY;
+
+            access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_EXECUTE;
+
+            size.u.LowPart  = 0x10000;
+            size.u.HighPart = 0;
+
+            cstatus = NtCreateSection( &cfmh, access, NULL, &size, protect, sec_type, fdh );
+            if(cstatus != STATUS_SUCCESS) {
+                FIXME("NtCreateSection failed: %X\n", cstatus);
+                return;
+            }
+        }
+
+
+        FIXME("cfmh %p\n", cfmh);
+
+        //cfmh = CreateFileMappingA( fdh, NULL, PAGE_READONLY, 1, 0, NULL );
+
+        addr = (void *)0x7ffe0000;
+
+        offset.u.LowPart  = 0;
+        offset.u.HighPart = 0;
+        
+        count = 0x10000;
+        protect = PAGE_READONLY;
+        
+        mstatus = NtMapViewOfSection( cfmh, GetCurrentProcess(), &addr, 0, 0, &offset,
+                                      &count, ViewShare, 0, protect );
+
+        if(mstatus != STATUS_SUCCESS) {
+            FIXME("NtMapViewOfSection failed: %X\n", mstatus);
+            return;
+        }
+        
+                
+        FIXME("mapped USER_SHARED_DATA to %p\n", addr);
+
+        user_shared_data = addr;
+    }
+}
+
 /***********************************************************************
  *           thread_init
  *
@@ -196,19 +290,11 @@ HANDLE thread_init(void)
     void *addr;
     SIZE_T size, info_size;
     HANDLE exe_file = 0;
-    LARGE_INTEGER now;
     struct ntdll_thread_data *thread_data;
     static struct debug_info debug_info;  /* debug info for initial thread */
 
     virtual_init();
 
-    /* reserve space for shared user data */
-
-    addr = (void *)0x7ffe0000;
-    size = 0x10000;
-    NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
-    user_shared_data = addr;
-
     /* allocate and initialize the PEB */
 
     addr = NULL;
@@ -260,6 +346,7 @@ HANDLE thread_init(void)
     debug_init();
 
     /* setup the server connection */
+
     server_init_process();
     info_size = server_init_thread( peb );
 
@@ -287,17 +374,11 @@ HANDLE thread_init(void)
             wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdError );
     }
 
-    /* initialize time values in user_shared_data */
-    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->TickCountMultiplier = 1 << 24;
-
+    map_user_shared_data();
     fill_cpu_info();
 
+    FIXME("InterruptTime: %lu %ld\n", user_shared_data->InterruptTime.LowPart, user_shared_data->InterruptTime.High1Time);
+
     return exe_file;
 }
 
diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c
index 0185d7f..9294136 100644
--- a/dlls/ntdll/version.c
+++ b/dlls/ntdll/version.c
@@ -529,11 +529,13 @@ done:
     NtCurrentTeb()->Peb->OSBuildNumber  = current_version->dwBuildNumber;
     NtCurrentTeb()->Peb->OSPlatformId   = current_version->dwPlatformId;
 
+    /*
     user_shared_data->NtProductType      = current_version->wProductType;
     user_shared_data->ProductTypeIsValid = TRUE;
     user_shared_data->NtMajorVersion     = current_version->dwMajorVersion;
     user_shared_data->NtMinorVersion     = current_version->dwMinorVersion;
     user_shared_data->SuiteMask          = current_version->wSuiteMask;
+    */
 
     TRACE( "got %d.%d platform %d build %x name %s service pack %d.%d product %d\n",
            current_version->dwMajorVersion, current_version->dwMinorVersion,
diff --git a/loader/Makefile.in b/loader/Makefile.in
index 41d69c7..9c3d4f6 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -39,10 +39,10 @@ wine-preloader wine64-preloader: preloader.o Makefile.in
 	$(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000 preloader.o $(LIBPORT) $(LDFLAGS)
 
 $(MAIN_BINARY): main.o Makefile.in
-	$(CC) -o $@ $(LDEXECFLAGS) main.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_LOCAL)
+	$(CC) -o $@ $(LDEXECFLAGS) main.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_LOCAL) -lrt
 
 wine-installed: main.o Makefile.in
-	$(CC) -o $@ $(LDEXECFLAGS) main.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_INSTALL)
+	$(CC) -o $@ $(LDEXECFLAGS) main.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_INSTALL) -lrt
 
 $(EXTRA_BINARIES:%=__install__%): $(EXTRA_BINARIES) $(DESTDIR)$(bindir) dummy
 	f=`expr $@ : '__install__\(.*\)'` && $(INSTALL_PROGRAM) $$f $(DESTDIR)$(bindir)/$$f
diff --git a/server/Makefile.in b/server/Makefile.in
index a2f1a52..bfe5175 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -1,5 +1,5 @@
 DEFS      = -D__WINESRC__
-EXTRALIBS = @LIBPOLL@
+EXTRALIBS = @LIBPOLL@ -lrt -lpthread
 
 C_SRCS = \
 	async.c \
@@ -43,6 +43,7 @@ C_SRCS = \
 	trace.c \
 	unicode.c \
 	user.c \
+	user_shared_data.c \
 	window.c \
 	winstation.c
 
@@ -62,10 +63,10 @@ all: $(PROGRAMS)
 @MAKE_RULES@
 
 wineserver: $(OBJS)
-	$(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_LOCAL)
+	$(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_LOCAL) -lrt -lpthread
 
 wineserver-installed: $(OBJS)
-	$(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_INSTALL)
+	$(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_INSTALL) -lrt -lpthread
 
 install install-lib:: wineserver-installed $(DESTDIR)$(bindir) install-man-pages
 	$(INSTALL_PROGRAM) wineserver-installed $(DESTDIR)$(bindir)/wineserver
diff --git a/server/main.c b/server/main.c
index 2d841e8..fc9bae8 100644
--- a/server/main.c
+++ b/server/main.c
@@ -32,12 +32,18 @@
 # include <getopt.h>
 #endif
 
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
 #include "object.h"
 #include "file.h"
 #include "thread.h"
 #include "request.h"
 #include "wine/library.h"
 
+#include "user_shared_data.h"
+
 /* command-line options */
 int debug_level = 0;
 int foreground = 0;
@@ -138,6 +144,8 @@ int main( int argc, char *argv[] )
     signal( SIGTERM, sigterm_handler );
     signal( SIGABRT, sigterm_handler );
 
+    init_shm();
+
     sock_init();
     open_master_socket();
 
diff --git a/server/user_shared_data.c b/server/user_shared_data.c
new file mode 100644
index 0000000..5f0c7f8
--- /dev/null
+++ b/server/user_shared_data.c
@@ -0,0 +1,377 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "user_shared_data.h"
+
+#include "wine/library.h"
+
+struct _KUSER_SHARED_DATA *user_shared_data = NULL;
+
+typedef enum
+{
+    WIN20,   /* Windows 2.0 */
+    WIN30,   /* Windows 3.0 */
+    WIN31,   /* Windows 3.1 */
+    WIN95,   /* Windows 95 */
+    WIN98,   /* Windows 98 */
+    WINME,   /* Windows Me */
+    NT351,   /* Windows NT 3.51 */
+    NT40,    /* Windows NT 4.0 */
+    NT2K,    /* Windows 2000 */
+    WINXP,   /* Windows XP */
+    WIN2K3,  /* Windows 2003 */
+    WINVISTA,/* Windows Vista */
+    WIN2K8,  /* Windows 2008 */
+    WIN2K8R2,/* Windows 2008 R2 */
+    WIN7,    /* Windows 7 */
+    NB_WINDOWS_VERSIONS
+} WINDOWS_VERSION;
+
+/* FIXME: compare values below with original and fix.
+ * An *excellent* win9x version page (ALL versions !)
+ * can be found at www.mdgx.com/ver.htm */
+static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
+{
+    /* WIN20 FIXME: verify values */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 2, 0, 0, VER_PLATFORM_WIN32s,
+        {'W','i','n','3','2','s',' ','1','.','3',0},
+        0, 0, 0, 0, 0
+    },
+    /* WIN30 FIXME: verify values */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 3, 0, 0, VER_PLATFORM_WIN32s,
+        {'W','i','n','3','2','s',' ','1','.','3',0},
+        0, 0, 0, 0, 0
+    },
+    /* WIN31 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 3, 10, 0, VER_PLATFORM_WIN32s,
+        {'W','i','n','3','2','s',' ','1','.','3',0},
+        0, 0, 0, 0, 0
+    },
+    /* WIN95 */
+    {
+        /* Win95:       4, 0, 0x40003B6, ""
+         * Win95sp1:    4, 0, 0x40003B6, " A " (according to doc)
+         * Win95osr2:   4, 0, 0x4000457, " B " (according to doc)
+         * Win95osr2.1: 4, 3, 0x40304BC, " B " (according to doc)
+         * Win95osr2.5: 4, 3, 0x40304BE, " C " (according to doc)
+         * Win95a/b can be discerned via regkey SubVersionNumber
+         */
+        sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x40003B6, VER_PLATFORM_WIN32_WINDOWS,
+        {0},
+        0, 0, 0, 0, 0
+    },
+    /* WIN98 (second edition) */
+    {
+        /* Win98:   4, 10, 0x40A07CE, " "   4.10.1998
+         * Win98SE: 4, 10, 0x40A08AE, " A " 4.10.2222
+         */
+        sizeof(RTL_OSVERSIONINFOEXW), 4, 10, 0x40A08AE, VER_PLATFORM_WIN32_WINDOWS,
+        {' ','A',' ',0},
+        0, 0, 0, 0, 0
+    },
+    /* WINME */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 4, 90, 0x45A0BB8, VER_PLATFORM_WIN32_WINDOWS,
+        {' ',0},
+        0, 0, 0, 0, 0
+    },
+    /* NT351 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 3, 51, 0x421, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','5',0},
+        5, 0, 0, VER_NT_WORKSTATION, 0
+    },
+    /* NT40 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 4, 0, 0x565, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','6','a',0},
+        6, 0, 0, VER_NT_WORKSTATION, 0
+    },
+    /* NT2K */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 5, 0, 0x893, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','4',0},
+        4, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
+    },
+    /* WINXP */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 5, 1, 0xA28, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','3',0},
+        3, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */
+    },
+    /* WIN2K3 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 5, 2, 0xECE, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
+        2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
+    },
+    /* WINVISTA */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
+        2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
+    },
+    /* WIN2K8 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 6, 0, 0x1772, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','2',0},
+        2, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
+    },
+    /* WIN7 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','1',0},
+        1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
+    },
+    /* WIN2K8R2 */
+    {
+        sizeof(RTL_OSVERSIONINFOEXW), 6, 1, 0x1DB1, VER_PLATFORM_WIN32_NT,
+        {'S','e','r','v','i','c','e',' ','P','a','c','k',' ','1',0},
+        1, 0, VER_SUITE_SINGLEUSERTS, VER_NT_SERVER, 0
+    },
+
+};
+
+static const char * const WinVersionNames[NB_WINDOWS_VERSIONS] =
+{ /* no spaces in here ! */
+    "win20",                      /* WIN20 */
+    "win30",                      /* WIN30 */
+    "win31",                      /* WIN31 */
+    "win95",                      /* WIN95 */
+    "win98",                      /* WIN98 */
+    "winme",                      /* WINME */
+    "nt351",                      /* NT351 */
+    "nt40",                       /* NT40 */
+    "win2000,win2k,nt2k,nt2000",  /* NT2K */
+    "winxp",                      /* WINXP */
+    "win2003,win2k3",             /* WIN2K3 */
+    "vista,winvista",             /* WINVISTA*/
+    "win2008,win2k8",             /* WIN2K8 */
+    "win2008r2,win2k8r2",         /* WIN2K8R2 */
+    "win7",                       /* WIN7 */
+};
+
+/* initialized to null so that we crash if we try to retrieve the version too early at startup */
+static const RTL_OSVERSIONINFOEXW *current_version;
+
+
+extern void fill_cpu_info(void) 
+{
+	char line[200];
+	FILE *f = fopen ("/proc/cpuinfo", "r");
+
+	if (!f)
+		return;
+	while (fgets(line,200,f) != NULL)
+    {
+        char	*s,*value;
+
+        /* NOTE: the ':' is the only character we can rely on */
+        if (!(value = strchr(line,':')))
+            continue;
+
+        /* terminate the valuename */
+        s = value - 1;
+        while ((s >= line) && ((*s == ' ') || (*s == '\t'))) s--;
+        *(s + 1) = '\0';
+
+        /* and strip leading spaces from value */
+        value += 1;
+        while (*value==' ') value++;
+        if ((s = strchr(value,'\n')))
+            *s='\0';
+
+        if (!strcasecmp(line, "fdiv_bug"))
+        {
+            if (!strncasecmp(value, "yes",3))
+                user_shared_data->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
+            continue;
+        }
+        if (!strcasecmp(line, "fpu"))
+        {
+            if (!strncasecmp(value, "no",2))
+                user_shared_data->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = TRUE;
+            continue;
+        }
+        if (!strcasecmp(line, "flags") || !strcasecmp(line, "features"))
+        {
+            if (strstr(value, "cx8"))
+                user_shared_data->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
+            if (strstr(value, "cx16"))
+                user_shared_data->ProcessorFeatures[PF_COMPARE_EXCHANGE128] = TRUE;
+            if (strstr(value, "mmx"))
+                user_shared_data->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
+            if (strstr(value, "nx"))
+                user_shared_data->ProcessorFeatures[PF_NX_ENABLED] = TRUE;
+            if (strstr(value, "tsc"))
+                user_shared_data->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
+            if (strstr(value, "3dnow"))
+                user_shared_data->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = TRUE;
+            /* This will also catch sse2, but we have sse itself
+             * if we have sse2, so no problem */
+            if (strstr(value, "sse"))
+                user_shared_data->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = TRUE;
+            if (strstr(value, "sse2"))
+                user_shared_data->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = TRUE;
+            if (strstr(value, "pni"))
+                user_shared_data->ProcessorFeatures[PF_SSE3_INSTRUCTIONS_AVAILABLE] = TRUE;
+            if (strstr(value, "pae"))
+                user_shared_data->ProcessorFeatures[PF_PAE_ENABLED] = TRUE;
+            /*
+            if (strstr(value, "ht"))
+                cached_sci.FeatureSet |= CPU_FEATURE_HTT;
+            */
+            continue;
+        }
+	}
+	fclose(f);
+}
+
+void version_init(void)
+{
+    static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
+    static const WCHAR default_sysdirW[] = {'\\','s','y','s','t','e','m','3','2',0};
+
+    strcpyW( user_shared_data->NtSystemRoot, default_windirW );
+
+    current_version = &VersionData[WINXP];  /* default if nothing else is specified */
+
+    user_shared_data->NtProductType      = current_version->wProductType;
+    user_shared_data->ProductTypeIsValid = TRUE;
+    user_shared_data->NtMajorVersion     = current_version->dwMajorVersion;
+    user_shared_data->NtMinorVersion     = current_version->dwMinorVersion;
+    user_shared_data->SuiteMask          = current_version->wSuiteMask;
+}
+
+
+#define TICKSPERSEC        10000000
+#define TICKSPERMSEC       10000
+#define SECSPERDAY         86400
+#define SECSPERHOUR        3600
+#define SECSPERMIN         60
+#define MINSPERHOUR        60
+#define HOURSPERDAY        24
+#define EPOCHWEEKDAY       1  /* Jan 1, 1601 was Monday */
+#define DAYSPERWEEK        7
+#define EPOCHYEAR          1601
+#define DAYSPERNORMALYEAR  365
+#define DAYSPERLEAPYEAR    366
+#define MONSPERYEAR        12
+#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
+#define DAYSPERNORMALCENTURY (365 * 100 + 24)
+#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
+
+/* 1601 to 1970 is 369 years plus 89 leap days */
+#define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
+
+static void update_shared_data_time(void)
+{
+    LARGE_INTEGER now, start, irq;
+    struct timeval tv;
+
+    gettimeofday( &tv, 0 );
+    now.QuadPart = tv.tv_sec * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
+    now.QuadPart += tv.tv_usec * 10;
+
+    fprintf(stderr, "%lld\n", now.QuadPart);
+
+    irq.QuadPart = (now.QuadPart - server_start_time);
+
+    user_shared_data->InterruptTime.High2Time = irq.HighPart;
+    user_shared_data->InterruptTime.LowPart = irq.LowPart;
+    user_shared_data->InterruptTime.High1Time = irq.HighPart;
+
+    user_shared_data->SystemTime.High2Time = now.HighPart;
+    user_shared_data->SystemTime.LowPart = now.LowPart;
+    user_shared_data->SystemTime.High1Time = now.HighPart;
+
+    start.QuadPart = irq.QuadPart / 10000;
+
+    user_shared_data->TickCount.High2Time = start.HighPart;
+    user_shared_data->TickCount.LowPart = start.LowPart;
+    user_shared_data->TickCount.High1Time = start.HighPart;
+    user_shared_data->TickCountLowDeprecated = start.LowPart;
+}
+
+static void* shared_data_thread(void *arg) 
+{
+    struct timespec req, rem;
+
+    req.tv_sec = 0;
+    req.tv_nsec = 15600000;
+
+    while(1) {
+        update_shared_data_time();
+        nanosleep(&req, &rem);
+    }
+
+    return NULL;
+}
+
+
+extern void init_shm(void)
+{
+    int fd;
+    void *addr;
+    const SIZE_T SZ = 0x10000;
+    SIZE_T size;
+    char buf[SZ];
+    int e;
+    pthread_t thread;
+
+    memset(buf, 0, SZ);
+
+    fd = shm_open("/KUSER_SHARED_DATA", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+    if(fd == -1) {
+        fprintf(stderr, "shm_open(\"/KUSER_SHARED_DATA\", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR) failed\n");
+        return;
+    }
+
+    e = read(fd, buf, SZ);
+    if(e != SZ) {
+        fprintf(stderr, "Unable to read %ld bytes from shm, try writing them\n", SZ);
+        e = write(fd, buf, SZ);
+        if(e != SZ) {
+            fprintf(stderr, "Unable to write %ld bytes to shm, give up\n", SZ);
+            return;
+        }
+    }
+
+    /* reserve space for shared user data */
+
+    addr = (void *)0x7ffe0000;
+    size = SZ;
+    addr = mmap(addr, SZ, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
+
+    if(addr == MAP_FAILED) {
+        fprintf(stderr, "mmap(addr, SZ, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0) failed: %s\n", strerror(errno));
+        return;
+    }
+
+    fprintf(stderr, "mapped USER_SHARED_DATA to %p\n", addr);
+
+    user_shared_data = addr;
+
+    user_shared_data->TickCountMultiplier = 1 << 24;
+
+    fill_cpu_info();
+    version_init();
+
+    update_shared_data_time();
+
+    if(!(e = pthread_create(&thread, NULL, &shared_data_thread, NULL))) {
+        if(pthread_detach(thread))
+            fprintf(stderr, "Unable to detach thread\n");
+    } else {
+        fprintf(stderr, "unable to spawn thread: %s (%d)\n", strerror(e), e);
+    }
+
+}
+
diff --git a/server/user_shared_data.h b/server/user_shared_data.h
new file mode 100644
index 0000000..9de82af
--- /dev/null
+++ b/server/user_shared_data.h
@@ -0,0 +1,111 @@
+#ifndef WINESERVER_USER_SHARED_DATA_H
+#define WINESERVER_USER_SHARED_DATA_H
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "request.h"
+#include "wine/library.h"
+
+/* Processor feature flags.  */
+#define PF_FLOATING_POINT_PRECISION_ERRATA	0
+#define PF_FLOATING_POINT_EMULATED		1
+#define PF_COMPARE_EXCHANGE_DOUBLE		2
+#define PF_MMX_INSTRUCTIONS_AVAILABLE		3
+#define PF_PPC_MOVEMEM_64BIT_OK			4
+#define PF_ALPHA_BYTE_INSTRUCTIONS		5
+#define PF_XMMI_INSTRUCTIONS_AVAILABLE		6
+#define PF_3DNOW_INSTRUCTIONS_AVAILABLE		7
+#define PF_RDTSC_INSTRUCTION_AVAILABLE		8
+#define PF_PAE_ENABLED				9
+#define PF_XMMI64_INSTRUCTIONS_AVAILABLE	10
+#define PF_SSE_DAZ_MODE_AVAILABLE		11
+#define PF_NX_ENABLED				12
+#define PF_SSE3_INSTRUCTIONS_AVAILABLE		13
+#define PF_COMPARE_EXCHANGE128			14
+#define PF_COMPARE64_EXCHANGE128		15
+#define PF_CHANNELS_ENABLED			16
+#define PF_XSAVE_ENABLED			17
+
+typedef struct _KSYSTEM_TIME {
+    ULONG LowPart;
+    LONG High1Time;
+    LONG High2Time;
+} KSYSTEM_TIME, *PKSYSTEM_TIME;
+
+typedef enum _NT_PRODUCT_TYPE {
+    NtProductWinNt = 1,
+    NtProductLanManNt,
+    NtProductServer
+} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
+
+#define PROCESSOR_FEATURE_MAX 64
+
+typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
+{
+   StandardDesign,
+   NEC98x86,
+   EndAlternatives
+} ALTERNATIVE_ARCHITECTURE_TYPE;
+
+#define NX_SUPPORT_POLICY_ALWAYSOFF     0
+#define NX_SUPPORT_POLICY_ALWAYSON      1
+#define NX_SUPPORT_POLICY_OPTIN         2
+#define NX_SUPPORT_POLICY_OPTOUT        3
+
+#define MAX_WOW64_SHARED_ENTRIES 16
+
+typedef struct _KUSER_SHARED_DATA {
+    ULONG TickCountLowDeprecated;
+    ULONG TickCountMultiplier;
+    volatile KSYSTEM_TIME InterruptTime;
+    volatile KSYSTEM_TIME SystemTime;
+    volatile KSYSTEM_TIME TimeZoneBias;
+    USHORT ImageNumberLow;
+    USHORT ImageNumberHigh;
+    WCHAR NtSystemRoot[260];
+    ULONG MaxStackTraceDepth;
+    ULONG CryptoExponent;
+    ULONG TimeZoneId;
+    ULONG LargePageMinimum;
+    ULONG Reserved2[7];
+    NT_PRODUCT_TYPE NtProductType;
+    BOOLEAN ProductTypeIsValid;
+    ULONG NtMajorVersion;
+    ULONG NtMinorVersion;
+    BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
+    ULONG Reserved1;
+    ULONG Reserved3;
+    volatile ULONG TimeSlip;
+    ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
+    LARGE_INTEGER SystemExpirationDate;
+    ULONG SuiteMask;
+    BOOLEAN KdDebuggerEnabled;
+    UCHAR NXSupportPolicy;
+    volatile ULONG ActiveConsoleId;
+    volatile ULONG DismountCount;
+    ULONG ComPlusPackage;
+    ULONG LastSystemRITEventTickCount;
+    ULONG NumberOfPhysicalPages;
+    BOOLEAN SafeBootMode;
+    ULONG TraceLogging;
+    ULONGLONG TestRetInstruction;
+    ULONG SystemCall;
+    ULONG SystemCallReturn;
+    ULONGLONG SystemCallPad[3];
+    union {
+        volatile KSYSTEM_TIME TickCount;
+        volatile ULONG64 TickCountQuad;
+    } DUMMYUNIONNAME;
+    ULONG Cookie;
+    ULONG Wow64SharedInformation[MAX_WOW64_SHARED_ENTRIES];
+} KSHARED_USER_DATA, *PKSHARED_USER_DATA;
+
+
+extern struct _KUSER_SHARED_DATA *user_shared_data;
+
+extern void fill_cpu_info(void);
+extern void init_shm(void);
+
+#endif


Reply via email to