Signed-off-by: Fan WenJie fanwj@mail.ustc.edu.cn
Hook mmap and munmap seem to be the only solution for drivers such as OpenGL to allocate over 32-bit address. For example, Fairy and Sword 4 has some render problems on master branch of wine. The patch can solve the problems.
From: Fan WenJie fanwj@mail.ustc.edu.cn
Signed-off-by: Fan WenJie fanwj@mail.ustc.edu.cn --- dlls/ntdll/unix/loader.c | 9 +- dlls/ntdll/unix/virtual.c | 234 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 28f0c4bf245..fabe338cb15 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2380,7 +2380,14 @@ void __wine_main( int argc, char *argv[], char *envp[] ) { static char noexec[] = "WINELOADERNOEXEC=1"; char **new_argv = malloc( (argc + 2) * sizeof(*argv) ); - + +#ifdef _WIN64 + { + Dl_info info = { 0 }; + dladdr(&__wine_main, &info); + setenv("LD_PRELOAD", info.dli_fname, 1); + } +#endif memcpy( new_argv + 1, argv, (argc + 1) * sizeof(*argv) ); putenv( noexec ); loader_exec( new_argv, current_machine ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 62fc1c9dd1f..4aea8091c5c 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -223,6 +223,240 @@ struct range_entry static struct range_entry *free_ranges; static struct range_entry *free_ranges_end;
+#ifdef _WIN64 + +#include <sys/syscall.h> +#include <stdatomic.h> +#include <stdint.h> + + +static void* mmap_native(void *addr, size_t size, int prot, int flags, int fd, off_t offset) +{ + return (void*)syscall(SYS_mmap, addr, size, prot, flags, fd, offset); +} + +static int munmap_native(void* addr, size_t size) +{ + return (int)syscall(SYS_munmap, addr, size); +} + +#define EXTMEM_LIMIT_HIGH 0x100000000 +#define EXTMEM_LIMIT_LOW 0x080000000 +#define EXTMEM_PAGE_INDEX(x) (((size_t)(x) - EXTMEM_LIMIT_LOW) / page_size) +#define EXTMEM_GET_FLAG(x) ((1 << (x)) - 1) + +static uint8_t* external_memory_flags; +static size_t external_page_count; + +static volatile atomic_flag mmap_flag = ATOMIC_FLAG_INIT; + +static inline void mmap_lock(void) +{ + while (atomic_flag_test_and_set(&mmap_flag)); +} + +static inline void mmap_unlock(void) +{ + atomic_flag_clear(&mmap_flag); +} + +static void set_external_page_flags(size_t page_start, size_t page_count) +{ + size_t page_end = page_start + page_count; + size_t page_1 = (page_start + 8) & (size_t)~7; + size_t page_2 = page_end & (size_t)~7; + uint8_t flags; + if (page_end <= page_1) + { + flags = EXTMEM_GET_FLAG(page_count) << (page_start & 7); + external_memory_flags[page_start >> 3] |= flags; + return; + } + flags = EXTMEM_GET_FLAG(page_1 - page_start) << (page_start & 7); + external_memory_flags[page_start >> 3] |= flags; + flags = EXTMEM_GET_FLAG(page_end - page_2); + external_memory_flags[page_end >> 3] |= flags; + if (page_1 < page_2) + { + memset(external_memory_flags + (page_1 >> 3), -1, (page_2 - page_1) >> 3); + } +} + +static void clear_external_page_flags(size_t page_start, size_t page_count) +{ + size_t page_end = page_start + page_count; + size_t page_1 = (page_start + 8) & (size_t)~7; + size_t page_2 = page_end & (size_t)~7; + uint8_t flags; + if (page_end <= page_1) + { + flags = EXTMEM_GET_FLAG(page_count) << (page_start & 7); + external_memory_flags[page_start >> 3] &= (uint8_t)~flags; + return; + } + flags = EXTMEM_GET_FLAG(page_1 - page_start) << (page_start & 7); + external_memory_flags[page_start >> 3] &= (uint8_t)~flags; + flags = EXTMEM_GET_FLAG(page_end - page_2); + external_memory_flags[page_end >> 3] &= (uint8_t)~flags; + if (page_1 < page_2) + { + memset(external_memory_flags + (page_1 >> 3), 0, (page_2 - page_1) >> 3); + } +} + +__attribute__((constructor)) void reserve_external_memory(void) +{ + size_t n; + mmap_native((void*)EXTMEM_LIMIT_LOW, EXTMEM_LIMIT_HIGH - EXTMEM_LIMIT_LOW, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ); + external_page_count = (EXTMEM_LIMIT_HIGH - EXTMEM_LIMIT_LOW) / page_size; + n = external_page_count + page_size - 1; + n -= n % page_size; + external_memory_flags = mmap_native(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(external_memory_flags, 0, n); +} + + +static size_t check_external_page_free(size_t page_start, size_t page_count) +{ + size_t i; + const size_t page_end = page_start + page_count; + for (i = page_start; i < page_end;) + { + uint8_t* pflags = external_memory_flags + (i >> 3); + if (!((i & 63) || *(uint64_t*)pflags)) + { + i += 64; + } + else if (!((i & 31) || *(uint32_t*)pflags)) + { + i += 32; + } + else if (!((i & 15) || *(uint16_t*)pflags)) + { + i += 16; + } + else + { + const uint8_t flags = *pflags; + const size_t k = i & 7; + if (!(k || flags)) + i += 8; + else if (flags >> k & 1) + break; + else + ++i; + } + } + return i < page_end ? i - page_start : page_count; +} + +static size_t get_external_free_page(size_t page_count) +{ + size_t i; + for (i = 0; i < external_page_count;) + { + uint8_t* pflags = external_memory_flags + (i >> 3); + if (!((i & 63) || (uint64_t)~*(uint64_t*)pflags)) + { + i += 64; + } + else if (!((i & 31) || (uint32_t)~*(uint32_t*)pflags)) + { + i += 32; + } + else if (!((i & 15) || (uint16_t)~*(uint16_t*)pflags)) + { + i += 16; + } + else + { + const uint8_t flags = *pflags; + const size_t k = i & 7; + if (!(k || (uint8_t)~flags)) + i += 8; + else if (flags >> k & 1) + ++i; + else + { + size_t j = check_external_page_free(i, page_count); + if (j == page_count) return i; + i += j; + } + } + } + return (size_t)-1; +} + +void *mmap64(void *addr, size_t size, int prot, int flags, int fd, off64_t offset) +{ + void* ret = NULL; + if (!size) return (void*)EXTMEM_LIMIT_LOW; + if ((size_t)addr < EXTMEM_LIMIT_HIGH && (size_t)addr + size > EXTMEM_LIMIT_HIGH) + { + FIXME("External mmap Memory cannot cross 0x100000000\n"); + return NULL; + } + if ((size_t)addr < EXTMEM_LIMIT_LOW && (size_t)addr + size > EXTMEM_LIMIT_LOW) + { + FIXME("External mmap Memory cannot cross 0x80000000\n"); + return NULL; + } + if (wow_peb && (!addr || ((size_t)addr >= EXTMEM_LIMIT_LOW && (size_t)addr < EXTMEM_LIMIT_HIGH))) + { + const size_t page_count = (size + page_size - 1) / page_size; + size_t page_index; + int f = flags | MAP_FIXED; + ret = addr; + mmap_lock(); + if (ret) + { + page_index = EXTMEM_PAGE_INDEX(ret); + if (page_count != check_external_page_free(page_index, page_count)) + goto finish; +#if MAP_FIXED_NOREPLACE + if (f & MAP_FIXED_NOREPLACE) f &= ~MAP_FIXED_NOREPLACE; +#endif + } + else + { + page_index = get_external_free_page(page_count); + if ((size_t)-1 == page_index) goto finish; + ret = (void*)(EXTMEM_LIMIT_LOW + page_index * page_size); + } + ret = mmap_native( ret, size, prot, f, fd, offset ); + if ((void*)ret == (void*)-1 || !ret) ret = NULL; + else set_external_page_flags(page_index, page_count); +finish: + mmap_unlock(); + } + return ret ? ret : mmap_native( addr, size, prot, flags, fd, offset); +} + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + return mmap64(addr, length, prot, flags, fd, offset); +} + +int munmap(void* addr, size_t size) +{ + if (wow_peb && (size_t)addr >= EXTMEM_LIMIT_LOW && (size_t)addr < EXTMEM_LIMIT_HIGH) + { + const size_t page_index = EXTMEM_PAGE_INDEX(addr); + const size_t page_count = (size + page_size - 1) / page_size; + mmap_lock(); + mmap_native( addr, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ); + clear_external_page_flags(page_index, page_count); + mmap_unlock(); + return 0; + } + return munmap_native(addr, size); +} + +#define mmap(addr, size, prot, flags, fd, offset) mmap_native(addr, size, prot, flags, fd, offset) + +#define munmap(addr, size) munmap_native(addr, size) + +#endif
static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit ) {
From: Fan WenJie fanwj@mail.ustc.edu.cn
Signed-off-by: Fan WenJie fanwj@mail.ustc.edu.cn --- dlls/opengl32/unix_wgl.c | 25 ------------------------- 1 file changed, 25 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index a03f8337fbf..a1b054c6679 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -412,21 +412,6 @@ static BOOL check_extension_support( TEB *teb, const char *extension, const char return FALSE; }
-static void parse_gl_version( const char *gl_version, int *major, int *minor ) -{ - const char *ptr = gl_version; - - *major = atoi( ptr ); - if (*major <= 0) - ERR( "Invalid OpenGL major version %d.\n", *major ); - - while (isdigit( *ptr )) ++ptr; - if (*ptr++ != '.') - ERR( "Invalid OpenGL version string %s.\n", debugstr_a(gl_version) ); - - *minor = atoi( ptr ); -} - static void wrap_glGetIntegerv( TEB *teb, GLenum pname, GLint *data ) { const struct opengl_funcs *funcs = teb->glTable; @@ -467,16 +452,6 @@ static const GLubyte *wrap_glGetString( TEB *teb, GLenum name ) GLuint **disabled = &ptr->u.context->disabled_exts; if (*extensions || filter_extensions( teb, (const char *)ret, extensions, disabled )) return *extensions; } - else if (name == GL_VERSION && is_win64 && is_wow64()) - { - int major, minor; - - parse_gl_version( (const char *)ret, &major, &minor ); - - /* 4.4 depends on ARB_buffer_storage, which we don't support on wow64. */ - if (major > 4 || (major == 4 && minor >= 4)) - return (const GLubyte *)"4.3"; - } }
return ret;