Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Win32 virtual memory functions |
| 3 | * |
| 4 | * Copyright 1997, 2002 Alexandre Julliard |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | */ |
| 20 | |
| 21 | #include "config.h" |
| 22 | #include "wine/port.h" |
| 23 | |
| 24 | #include <assert.h> |
| 25 | #include <errno.h> |
| 26 | #ifdef HAVE_SYS_ERRNO_H |
| 27 | #include <sys/errno.h> |
| 28 | #endif |
| 29 | #include <fcntl.h> |
| 30 | #ifdef HAVE_UNISTD_H |
| 31 | # include <unistd.h> |
| 32 | #endif |
Alexandre Julliard | bd000a0 | 2005-06-06 20:13:08 +0000 | [diff] [blame] | 33 | #include <stdarg.h> |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 34 | #include <stdlib.h> |
| 35 | #include <stdio.h> |
| 36 | #include <string.h> |
| 37 | #include <sys/types.h> |
| 38 | #ifdef HAVE_SYS_MMAN_H |
| 39 | #include <sys/mman.h> |
| 40 | #endif |
| 41 | |
Dimitrie O. Paun | 297f3d8 | 2003-01-07 20:36:20 +0000 | [diff] [blame] | 42 | #define NONAMELESSUNION |
| 43 | #define NONAMELESSSTRUCT |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 44 | #include "ntstatus.h" |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 45 | #define WIN32_NO_STATUS |
Alexandre Julliard | bd000a0 | 2005-06-06 20:13:08 +0000 | [diff] [blame] | 46 | #include "windef.h" |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 47 | #include "winternl.h" |
Alexandre Julliard | 670711e | 2004-04-06 23:13:47 +0000 | [diff] [blame] | 48 | #include "winioctl.h" |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 49 | #include "wine/library.h" |
| 50 | #include "wine/server.h" |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 51 | #include "wine/list.h" |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 52 | #include "wine/debug.h" |
Pavel Roskin | 3ec73af | 2003-10-08 19:11:08 +0000 | [diff] [blame] | 53 | #include "ntdll_misc.h" |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 54 | |
| 55 | WINE_DEFAULT_DEBUG_CHANNEL(virtual); |
| 56 | WINE_DECLARE_DEBUG_CHANNEL(module); |
| 57 | |
| 58 | #ifndef MS_SYNC |
| 59 | #define MS_SYNC 0 |
| 60 | #endif |
| 61 | |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 62 | #ifndef MAP_NORESERVE |
| 63 | #define MAP_NORESERVE 0 |
| 64 | #endif |
| 65 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 66 | /* File view */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 67 | typedef struct file_view |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 68 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 69 | struct list entry; /* Entry in global view list */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 70 | void *base; /* Base address */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 71 | size_t size; /* Size in bytes */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 72 | HANDLE mapping; /* Handle to the file mapping */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 73 | BYTE flags; /* Allocation flags (VFLAG_*) */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 74 | BYTE protect; /* Protection for all pages at allocation time */ |
| 75 | BYTE prot[1]; /* Protection byte for each page */ |
| 76 | } FILE_VIEW; |
| 77 | |
| 78 | /* Per-view flags */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 79 | #define VFLAG_SYSTEM 0x01 /* system view (underlying mmap not under our control) */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 80 | #define VFLAG_VALLOC 0x02 /* allocated by VirtualAlloc */ |
| 81 | |
| 82 | /* Conversion from VPROT_* to Win32 flags */ |
| 83 | static const BYTE VIRTUAL_Win32Flags[16] = |
| 84 | { |
| 85 | PAGE_NOACCESS, /* 0 */ |
| 86 | PAGE_READONLY, /* READ */ |
| 87 | PAGE_READWRITE, /* WRITE */ |
| 88 | PAGE_READWRITE, /* READ | WRITE */ |
| 89 | PAGE_EXECUTE, /* EXEC */ |
| 90 | PAGE_EXECUTE_READ, /* READ | EXEC */ |
| 91 | PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */ |
| 92 | PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */ |
| 93 | PAGE_WRITECOPY, /* WRITECOPY */ |
| 94 | PAGE_WRITECOPY, /* READ | WRITECOPY */ |
| 95 | PAGE_WRITECOPY, /* WRITE | WRITECOPY */ |
| 96 | PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */ |
| 97 | PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */ |
| 98 | PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */ |
| 99 | PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */ |
| 100 | PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */ |
| 101 | }; |
| 102 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 103 | static struct list views_list = LIST_INIT(views_list); |
Alexandre Julliard | 19b6a49 | 2003-08-12 23:50:54 +0000 | [diff] [blame] | 104 | |
Mike McCormack | 6b636e3 | 2005-06-25 18:00:57 +0000 | [diff] [blame] | 105 | static RTL_CRITICAL_SECTION csVirtual; |
| 106 | static RTL_CRITICAL_SECTION_DEBUG critsect_debug = |
Alexandre Julliard | 19b6a49 | 2003-08-12 23:50:54 +0000 | [diff] [blame] | 107 | { |
| 108 | 0, 0, &csVirtual, |
| 109 | { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, |
Alexandre Julliard | 20a1a20 | 2005-09-09 10:19:44 +0000 | [diff] [blame] | 110 | 0, 0, { (DWORD_PTR)(__FILE__ ": csVirtual") } |
Alexandre Julliard | 19b6a49 | 2003-08-12 23:50:54 +0000 | [diff] [blame] | 111 | }; |
Mike McCormack | 6b636e3 | 2005-06-25 18:00:57 +0000 | [diff] [blame] | 112 | static RTL_CRITICAL_SECTION csVirtual = { &critsect_debug, -1, 0, 0, 0, 0 }; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 113 | |
| 114 | #ifdef __i386__ |
| 115 | /* These are always the same on an i386, and it will be faster this way */ |
| 116 | # define page_mask 0xfff |
| 117 | # define page_shift 12 |
| 118 | # define page_size 0x1000 |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 119 | /* Note: these are Windows limits, you cannot change them. */ |
| 120 | # define ADDRESS_SPACE_LIMIT ((void *)0xc0000000) /* top of the total available address space */ |
| 121 | # define USER_SPACE_LIMIT ((void *)0x80000000) /* top of the user address space */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 122 | #else |
| 123 | static UINT page_shift; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 124 | static UINT page_size; |
Alexandre Julliard | 06ea6e6 | 2005-09-16 18:54:19 +0000 | [diff] [blame] | 125 | static UINT_PTR page_mask; |
Alexandre Julliard | ac36f95 | 2002-11-06 22:33:17 +0000 | [diff] [blame] | 126 | # define ADDRESS_SPACE_LIMIT 0 /* no limit needed on other platforms */ |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 127 | # define USER_SPACE_LIMIT 0 /* no limit needed on other platforms */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 128 | #endif /* __i386__ */ |
Alexandre Julliard | 06ea6e6 | 2005-09-16 18:54:19 +0000 | [diff] [blame] | 129 | static const UINT_PTR granularity_mask = 0xffff; /* Allocation granularity (usually 64k) */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 130 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 131 | #define ROUND_ADDR(addr,mask) \ |
Alexandre Julliard | 06ea6e6 | 2005-09-16 18:54:19 +0000 | [diff] [blame] | 132 | ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 133 | |
| 134 | #define ROUND_SIZE(addr,size) \ |
| 135 | (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) |
| 136 | |
| 137 | #define VIRTUAL_DEBUG_DUMP_VIEW(view) \ |
Francois Gouget | baab789 | 2005-09-26 09:57:38 +0000 | [diff] [blame] | 138 | do { if (TRACE_ON(virtual)) VIRTUAL_DumpView(view); } while (0) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 139 | |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 140 | static void *user_space_limit = USER_SPACE_LIMIT; |
| 141 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 142 | |
| 143 | /*********************************************************************** |
| 144 | * VIRTUAL_GetProtStr |
| 145 | */ |
| 146 | static const char *VIRTUAL_GetProtStr( BYTE prot ) |
| 147 | { |
| 148 | static char buffer[6]; |
| 149 | buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; |
| 150 | buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-'; |
| 151 | buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 152 | buffer[3] = (prot & VPROT_WRITECOPY) ? 'W' : ((prot & VPROT_WRITE) ? 'w' : '-'); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 153 | buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; |
| 154 | buffer[5] = 0; |
| 155 | return buffer; |
| 156 | } |
| 157 | |
| 158 | |
| 159 | /*********************************************************************** |
| 160 | * VIRTUAL_DumpView |
| 161 | */ |
| 162 | static void VIRTUAL_DumpView( FILE_VIEW *view ) |
| 163 | { |
| 164 | UINT i, count; |
| 165 | char *addr = view->base; |
| 166 | BYTE prot = view->prot[0]; |
| 167 | |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 168 | TRACE( "View: %p - %p", addr, addr + view->size - 1 ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 169 | if (view->flags & VFLAG_SYSTEM) |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 170 | TRACE( " (system)\n" ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 171 | else if (view->flags & VFLAG_VALLOC) |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 172 | TRACE( " (valloc)\n" ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 173 | else if (view->mapping) |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 174 | TRACE( " %p\n", view->mapping ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 175 | else |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 176 | TRACE( " (anonymous)\n"); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 177 | |
| 178 | for (count = i = 1; i < view->size >> page_shift; i++, count++) |
| 179 | { |
| 180 | if (view->prot[i] == prot) continue; |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 181 | TRACE( " %p - %p %s\n", |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 182 | addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); |
| 183 | addr += (count << page_shift); |
| 184 | prot = view->prot[i]; |
| 185 | count = 0; |
| 186 | } |
| 187 | if (count) |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 188 | TRACE( " %p - %p %s\n", |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 189 | addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) ); |
| 190 | } |
| 191 | |
| 192 | |
| 193 | /*********************************************************************** |
| 194 | * VIRTUAL_Dump |
| 195 | */ |
| 196 | void VIRTUAL_Dump(void) |
| 197 | { |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 198 | struct file_view *view; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 199 | |
Alexandre Julliard | 9f85969 | 2005-09-25 15:23:21 +0000 | [diff] [blame] | 200 | TRACE( "Dump of all virtual memory views:\n" ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 201 | RtlEnterCriticalSection(&csVirtual); |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 202 | LIST_FOR_EACH_ENTRY( view, &views_list, FILE_VIEW, entry ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 203 | { |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 204 | VIRTUAL_DumpView( view ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 205 | } |
| 206 | RtlLeaveCriticalSection(&csVirtual); |
| 207 | } |
| 208 | |
| 209 | |
| 210 | /*********************************************************************** |
| 211 | * VIRTUAL_FindView |
| 212 | * |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 213 | * Find the view containing a given address. The csVirtual section must be held by caller. |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 214 | * |
Dimi Paun | 88fe1ff | 2005-05-18 09:45:12 +0000 | [diff] [blame] | 215 | * PARAMS |
| 216 | * addr [I] Address |
| 217 | * |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 218 | * RETURNS |
| 219 | * View: Success |
| 220 | * NULL: Failure |
| 221 | */ |
Dimi Paun | 88fe1ff | 2005-05-18 09:45:12 +0000 | [diff] [blame] | 222 | static struct file_view *VIRTUAL_FindView( const void *addr ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 223 | { |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 224 | struct file_view *view; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 225 | |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 226 | LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 227 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 228 | if (view->base > addr) break; |
Eric Pouech | db52588 | 2004-06-15 00:47:00 +0000 | [diff] [blame] | 229 | if ((const char*)view->base + view->size > (const char*)addr) return view; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 230 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 231 | return NULL; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | |
| 235 | /*********************************************************************** |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 236 | * find_view_range |
| 237 | * |
| 238 | * Find the first view overlapping at least part of the specified range. |
| 239 | * The csVirtual section must be held by caller. |
| 240 | */ |
| 241 | static struct file_view *find_view_range( const void *addr, size_t size ) |
| 242 | { |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 243 | struct file_view *view; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 244 | |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 245 | LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry ) |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 246 | { |
Eric Pouech | db52588 | 2004-06-15 00:47:00 +0000 | [diff] [blame] | 247 | if ((const char *)view->base >= (const char *)addr + size) break; |
| 248 | if ((const char *)view->base + view->size > (const char *)addr) return view; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 249 | } |
| 250 | return NULL; |
| 251 | } |
| 252 | |
| 253 | |
| 254 | /*********************************************************************** |
| 255 | * add_reserved_area |
| 256 | * |
| 257 | * Add a reserved area to the list maintained by libwine. |
| 258 | * The csVirtual section must be held by caller. |
| 259 | */ |
| 260 | static void add_reserved_area( void *addr, size_t size ) |
| 261 | { |
| 262 | TRACE( "adding %p-%p\n", addr, (char *)addr + size ); |
| 263 | |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 264 | if (addr < user_space_limit) |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 265 | { |
| 266 | /* unmap the part of the area that is below the limit */ |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 267 | assert( (char *)addr + size > (char *)user_space_limit ); |
| 268 | munmap( addr, (char *)user_space_limit - (char *)addr ); |
| 269 | size -= (char *)user_space_limit - (char *)addr; |
| 270 | addr = user_space_limit; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 271 | } |
Alexandre Julliard | dc4d056 | 2004-05-28 03:48:09 +0000 | [diff] [blame] | 272 | /* blow away existing mappings */ |
| 273 | wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 274 | wine_mmap_add_reserved_area( addr, size ); |
| 275 | } |
| 276 | |
| 277 | |
| 278 | /*********************************************************************** |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 279 | * remove_reserved_area |
| 280 | * |
| 281 | * Remove a reserved area from the list maintained by libwine. |
| 282 | * The csVirtual section must be held by caller. |
| 283 | */ |
| 284 | static void remove_reserved_area( void *addr, size_t size ) |
| 285 | { |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 286 | struct file_view *view; |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 287 | |
Mike McCormack | cc4ed13 | 2005-05-23 09:51:02 +0000 | [diff] [blame] | 288 | LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry ) |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 289 | { |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 290 | if ((char *)view->base >= (char *)addr + size) break; |
| 291 | if ((char *)view->base + view->size <= (char *)addr) continue; |
| 292 | /* now we have an overlapping view */ |
| 293 | if (view->base > addr) |
| 294 | { |
| 295 | wine_mmap_remove_reserved_area( addr, (char *)view->base - (char *)addr, TRUE ); |
| 296 | size -= (char *)view->base - (char *)addr; |
| 297 | addr = view->base; |
| 298 | } |
| 299 | if ((char *)view->base + view->size >= (char *)addr + size) |
| 300 | { |
| 301 | /* view covers all the remaining area */ |
| 302 | wine_mmap_remove_reserved_area( addr, size, FALSE ); |
| 303 | size = 0; |
| 304 | break; |
| 305 | } |
| 306 | else /* view covers only part of the area */ |
| 307 | { |
| 308 | wine_mmap_remove_reserved_area( addr, (char *)view->base + view->size - (char *)addr, FALSE ); |
| 309 | size -= (char *)view->base + view->size - (char *)addr; |
| 310 | addr = (char *)view->base + view->size; |
| 311 | } |
| 312 | } |
| 313 | /* remove remaining space */ |
| 314 | if (size) wine_mmap_remove_reserved_area( addr, size, TRUE ); |
| 315 | } |
| 316 | |
| 317 | |
| 318 | /*********************************************************************** |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 319 | * is_beyond_limit |
| 320 | * |
| 321 | * Check if an address range goes beyond a given limit. |
| 322 | */ |
| 323 | static inline int is_beyond_limit( void *addr, size_t size, void *limit ) |
| 324 | { |
| 325 | return (limit && (addr >= limit || (char *)addr + size > (char *)limit)); |
| 326 | } |
| 327 | |
| 328 | |
| 329 | /*********************************************************************** |
| 330 | * unmap_area |
| 331 | * |
| 332 | * Unmap an area, or simply replace it by an empty mapping if it is |
| 333 | * in a reserved area. The csVirtual section must be held by caller. |
| 334 | */ |
| 335 | static inline void unmap_area( void *addr, size_t size ) |
| 336 | { |
| 337 | if (wine_mmap_is_in_reserved_area( addr, size )) |
| 338 | wine_anon_mmap( addr, size, PROT_NONE, MAP_NORESERVE | MAP_FIXED ); |
Alexandre Julliard | cb56bdf | 2005-12-01 18:44:04 +0100 | [diff] [blame] | 339 | else if (is_beyond_limit( addr, size, user_space_limit )) |
| 340 | add_reserved_area( addr, size ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 341 | else |
| 342 | munmap( addr, size ); |
| 343 | } |
| 344 | |
| 345 | |
| 346 | /*********************************************************************** |
| 347 | * delete_view |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 348 | * |
| 349 | * Deletes a view. The csVirtual section must be held by caller. |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 350 | */ |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 351 | static void delete_view( struct file_view *view ) /* [in] View */ |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 352 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 353 | if (!(view->flags & VFLAG_SYSTEM)) unmap_area( view->base, view->size ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 354 | list_remove( &view->entry ); |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 355 | if (view->mapping) NtClose( view->mapping ); |
| 356 | free( view ); |
| 357 | } |
| 358 | |
| 359 | |
| 360 | /*********************************************************************** |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 361 | * create_view |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 362 | * |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 363 | * Create a view. The csVirtual section must be held by caller. |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 364 | */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 365 | static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t size, BYTE vprot ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 366 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 367 | struct file_view *view; |
| 368 | struct list *ptr; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 369 | |
Alexandre Julliard | 261e376 | 2005-09-12 15:14:06 +0000 | [diff] [blame] | 370 | assert( !((UINT_PTR)base & page_mask) ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 371 | assert( !(size & page_mask) ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 372 | |
| 373 | /* Create the view structure */ |
| 374 | |
| 375 | if (!(view = malloc( sizeof(*view) + (size >> page_shift) - 1 ))) return STATUS_NO_MEMORY; |
| 376 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 377 | view->base = base; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 378 | view->size = size; |
| 379 | view->flags = 0; |
| 380 | view->mapping = 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 381 | view->protect = vprot; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 382 | memset( view->prot, vprot, size >> page_shift ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 383 | |
| 384 | /* Insert it in the linked list */ |
| 385 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 386 | LIST_FOR_EACH( ptr, &views_list ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 387 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 388 | struct file_view *next = LIST_ENTRY( ptr, struct file_view, entry ); |
| 389 | if (next->base > base) break; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 390 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 391 | list_add_before( ptr, &view->entry ); |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 392 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 393 | /* Check for overlapping views. This can happen if the previous view |
| 394 | * was a system view that got unmapped behind our back. In that case |
| 395 | * we recover by simply deleting it. */ |
| 396 | |
| 397 | if ((ptr = list_prev( &views_list, &view->entry )) != NULL) |
| 398 | { |
| 399 | struct file_view *prev = LIST_ENTRY( ptr, struct file_view, entry ); |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 400 | if ((char *)prev->base + prev->size > (char *)base) |
| 401 | { |
| 402 | TRACE( "overlapping prev view %p-%p for %p-%p\n", |
| 403 | prev->base, (char *)prev->base + prev->size, |
| 404 | base, (char *)base + view->size ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 405 | assert( prev->flags & VFLAG_SYSTEM ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 406 | delete_view( prev ); |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 407 | } |
| 408 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 409 | if ((ptr = list_next( &views_list, &view->entry )) != NULL) |
Alexandre Julliard | 94d5531 | 2004-01-16 04:52:17 +0000 | [diff] [blame] | 410 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 411 | struct file_view *next = LIST_ENTRY( ptr, struct file_view, entry ); |
| 412 | if ((char *)base + view->size > (char *)next->base) |
| 413 | { |
| 414 | TRACE( "overlapping next view %p-%p for %p-%p\n", |
| 415 | next->base, (char *)next->base + next->size, |
| 416 | base, (char *)base + view->size ); |
| 417 | assert( next->flags & VFLAG_SYSTEM ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 418 | delete_view( next ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 419 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 420 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 421 | |
| 422 | *view_ret = view; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 423 | VIRTUAL_DEBUG_DUMP_VIEW( view ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 424 | return STATUS_SUCCESS; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 425 | } |
| 426 | |
| 427 | |
| 428 | /*********************************************************************** |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 429 | * VIRTUAL_GetUnixProt |
| 430 | * |
| 431 | * Convert page protections to protection for mmap/mprotect. |
| 432 | */ |
| 433 | static int VIRTUAL_GetUnixProt( BYTE vprot ) |
| 434 | { |
| 435 | int prot = 0; |
| 436 | if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD)) |
| 437 | { |
| 438 | if (vprot & VPROT_READ) prot |= PROT_READ; |
| 439 | if (vprot & VPROT_WRITE) prot |= PROT_WRITE; |
| 440 | if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE; |
| 441 | if (vprot & VPROT_EXEC) prot |= PROT_EXEC; |
| 442 | } |
| 443 | return prot; |
| 444 | } |
| 445 | |
| 446 | |
| 447 | /*********************************************************************** |
| 448 | * VIRTUAL_GetWin32Prot |
| 449 | * |
| 450 | * Convert page protections to Win32 flags. |
| 451 | * |
| 452 | * RETURNS |
| 453 | * None |
| 454 | */ |
| 455 | static void VIRTUAL_GetWin32Prot( |
| 456 | BYTE vprot, /* [in] Page protection flags */ |
| 457 | DWORD *protect, /* [out] Location to store Win32 protection flags */ |
| 458 | DWORD *state ) /* [out] Location to store mem state flag */ |
| 459 | { |
| 460 | if (protect) { |
| 461 | *protect = VIRTUAL_Win32Flags[vprot & 0x0f]; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 462 | if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE; |
Alexandre Julliard | f724399 | 2005-06-21 20:23:02 +0000 | [diff] [blame] | 463 | if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS | PAGE_GUARD; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 464 | } |
| 465 | |
| 466 | if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; |
| 467 | } |
| 468 | |
| 469 | |
| 470 | /*********************************************************************** |
| 471 | * VIRTUAL_GetProt |
| 472 | * |
| 473 | * Build page protections from Win32 flags. |
| 474 | * |
Dimi Paun | 88fe1ff | 2005-05-18 09:45:12 +0000 | [diff] [blame] | 475 | * PARAMS |
| 476 | * protect [I] Win32 protection flags |
| 477 | * |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 478 | * RETURNS |
| 479 | * Value of page protection flags |
| 480 | */ |
Dimi Paun | 88fe1ff | 2005-05-18 09:45:12 +0000 | [diff] [blame] | 481 | static BYTE VIRTUAL_GetProt( DWORD protect ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 482 | { |
| 483 | BYTE vprot; |
| 484 | |
| 485 | switch(protect & 0xff) |
| 486 | { |
| 487 | case PAGE_READONLY: |
| 488 | vprot = VPROT_READ; |
| 489 | break; |
| 490 | case PAGE_READWRITE: |
| 491 | vprot = VPROT_READ | VPROT_WRITE; |
| 492 | break; |
| 493 | case PAGE_WRITECOPY: |
| 494 | /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given, |
| 495 | * that the hFile must have been opened with GENERIC_READ and |
| 496 | * GENERIC_WRITE access. This is WRONG as tests show that you |
| 497 | * only need GENERIC_READ access (at least for Win9x, |
| 498 | * FIXME: what about NT?). Thus, we don't put VPROT_WRITE in |
| 499 | * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY. |
| 500 | */ |
| 501 | vprot = VPROT_READ | VPROT_WRITECOPY; |
| 502 | break; |
| 503 | case PAGE_EXECUTE: |
| 504 | vprot = VPROT_EXEC; |
| 505 | break; |
| 506 | case PAGE_EXECUTE_READ: |
| 507 | vprot = VPROT_EXEC | VPROT_READ; |
| 508 | break; |
| 509 | case PAGE_EXECUTE_READWRITE: |
| 510 | vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE; |
| 511 | break; |
| 512 | case PAGE_EXECUTE_WRITECOPY: |
| 513 | /* See comment for PAGE_WRITECOPY above */ |
| 514 | vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; |
| 515 | break; |
| 516 | case PAGE_NOACCESS: |
| 517 | default: |
| 518 | vprot = 0; |
| 519 | break; |
| 520 | } |
| 521 | if (protect & PAGE_GUARD) vprot |= VPROT_GUARD; |
| 522 | if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE; |
| 523 | return vprot; |
| 524 | } |
| 525 | |
| 526 | |
| 527 | /*********************************************************************** |
| 528 | * VIRTUAL_SetProt |
| 529 | * |
| 530 | * Change the protection of a range of pages. |
| 531 | * |
| 532 | * RETURNS |
| 533 | * TRUE: Success |
| 534 | * FALSE: Failure |
| 535 | */ |
| 536 | static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */ |
| 537 | void *base, /* [in] Starting address */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 538 | size_t size, /* [in] Size in bytes */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 539 | BYTE vprot ) /* [in] Protections to use */ |
| 540 | { |
| 541 | TRACE("%p-%p %s\n", |
| 542 | base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) ); |
| 543 | |
| 544 | if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) )) |
| 545 | return FALSE; /* FIXME: last error */ |
| 546 | |
| 547 | memset( view->prot + (((char *)base - (char *)view->base) >> page_shift), |
| 548 | vprot, size >> page_shift ); |
| 549 | VIRTUAL_DEBUG_DUMP_VIEW( view ); |
| 550 | return TRUE; |
| 551 | } |
| 552 | |
| 553 | |
| 554 | /*********************************************************************** |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 555 | * unmap_extra_space |
| 556 | * |
| 557 | * Release the extra memory while keeping the range starting on the granularity boundary. |
| 558 | */ |
| 559 | static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t wanted_size, size_t mask ) |
| 560 | { |
| 561 | if ((ULONG_PTR)ptr & mask) |
| 562 | { |
| 563 | size_t extra = mask + 1 - ((ULONG_PTR)ptr & mask); |
| 564 | munmap( ptr, extra ); |
| 565 | ptr = (char *)ptr + extra; |
| 566 | total_size -= extra; |
| 567 | } |
| 568 | if (total_size > wanted_size) |
| 569 | munmap( (char *)ptr + wanted_size, total_size - wanted_size ); |
| 570 | return ptr; |
| 571 | } |
| 572 | |
| 573 | |
| 574 | /*********************************************************************** |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 575 | * map_view |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 576 | * |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 577 | * Create a view and mmap the corresponding memory area. |
| 578 | * The csVirtual section must be held by caller. |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 579 | */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 580 | static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, BYTE vprot ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 581 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 582 | void *ptr; |
| 583 | NTSTATUS status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 584 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 585 | if (base) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 586 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 587 | if (is_beyond_limit( base, size, ADDRESS_SPACE_LIMIT )) |
| 588 | return STATUS_WORKING_SET_LIMIT_RANGE; |
| 589 | |
| 590 | switch (wine_mmap_is_in_reserved_area( base, size )) |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 591 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 592 | case -1: /* partially in a reserved area */ |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 593 | return STATUS_CONFLICTING_ADDRESSES; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 594 | |
| 595 | case 0: /* not in a reserved area, do a normal allocation */ |
| 596 | if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) |
| 597 | { |
| 598 | if (errno == ENOMEM) return STATUS_NO_MEMORY; |
| 599 | return STATUS_INVALID_PARAMETER; |
| 600 | } |
| 601 | if (ptr != base) |
| 602 | { |
| 603 | /* We couldn't get the address we wanted */ |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 604 | if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 605 | else munmap( ptr, size ); |
| 606 | return STATUS_CONFLICTING_ADDRESSES; |
| 607 | } |
| 608 | break; |
| 609 | |
| 610 | default: |
| 611 | case 1: /* in a reserved area, make sure the address is available */ |
| 612 | if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES; |
| 613 | /* replace the reserved area by our mapping */ |
| 614 | if ((ptr = wine_anon_mmap( base, size, VIRTUAL_GetUnixProt(vprot), MAP_FIXED )) != base) |
| 615 | return STATUS_INVALID_PARAMETER; |
| 616 | break; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 617 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 618 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 619 | else |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 620 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 621 | size_t view_size = size + granularity_mask + 1; |
| 622 | |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 623 | for (;;) |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 624 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 625 | if ((ptr = wine_anon_mmap( NULL, view_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) |
| 626 | { |
| 627 | if (errno == ENOMEM) return STATUS_NO_MEMORY; |
| 628 | return STATUS_INVALID_PARAMETER; |
| 629 | } |
| 630 | /* if we got something beyond the user limit, unmap it and retry */ |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 631 | if (is_beyond_limit( ptr, view_size, user_space_limit )) add_reserved_area( ptr, view_size ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 632 | else break; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 633 | } |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 634 | ptr = unmap_extra_space( ptr, view_size, size, granularity_mask ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 635 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 636 | |
| 637 | status = create_view( view_ret, ptr, size, vprot ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 638 | if (status != STATUS_SUCCESS) unmap_area( ptr, size ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 639 | return status; |
| 640 | } |
| 641 | |
| 642 | |
| 643 | /*********************************************************************** |
| 644 | * unaligned_mmap |
| 645 | * |
| 646 | * Linux kernels before 2.4.x can support non page-aligned offsets, as |
| 647 | * long as the offset is aligned to the filesystem block size. This is |
| 648 | * a big performance gain so we want to take advantage of it. |
| 649 | * |
| 650 | * However, when we use 64-bit file support this doesn't work because |
| 651 | * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken |
| 652 | * in that it rounds unaligned offsets down to a page boundary. For |
| 653 | * these reasons we do a direct system call here. |
| 654 | */ |
| 655 | static void *unaligned_mmap( void *addr, size_t length, unsigned int prot, |
| 656 | unsigned int flags, int fd, off_t offset ) |
| 657 | { |
| 658 | #if defined(linux) && defined(__i386__) && defined(__GNUC__) |
| 659 | if (!(offset >> 32) && (offset & page_mask)) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 660 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 661 | int ret; |
| 662 | |
| 663 | struct |
| 664 | { |
| 665 | void *addr; |
| 666 | unsigned int length; |
| 667 | unsigned int prot; |
| 668 | unsigned int flags; |
| 669 | unsigned int fd; |
| 670 | unsigned int offset; |
| 671 | } args; |
| 672 | |
| 673 | args.addr = addr; |
| 674 | args.length = length; |
| 675 | args.prot = prot; |
| 676 | args.flags = flags; |
| 677 | args.fd = fd; |
| 678 | args.offset = offset; |
| 679 | |
| 680 | __asm__ __volatile__("push %%ebx\n\t" |
| 681 | "movl %2,%%ebx\n\t" |
| 682 | "int $0x80\n\t" |
| 683 | "popl %%ebx" |
| 684 | : "=a" (ret) |
| 685 | : "0" (90), /* SYS_mmap */ |
Peter Chapman | 505dfde | 2004-12-02 18:19:25 +0000 | [diff] [blame] | 686 | "q" (&args) |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 687 | : "memory" ); |
| 688 | if (ret < 0 && ret > -4096) |
| 689 | { |
| 690 | errno = -ret; |
| 691 | ret = -1; |
| 692 | } |
| 693 | return (void *)ret; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 694 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 695 | #endif |
| 696 | return mmap( addr, length, prot, flags, fd, offset ); |
| 697 | } |
| 698 | |
| 699 | |
| 700 | /*********************************************************************** |
| 701 | * map_file_into_view |
| 702 | * |
| 703 | * Wrapper for mmap() to map a file into a view, falling back to read if mmap fails. |
| 704 | * The csVirtual section must be held by caller. |
| 705 | */ |
| 706 | static NTSTATUS map_file_into_view( struct file_view *view, int fd, size_t start, size_t size, |
| 707 | off_t offset, BYTE vprot, BOOL removable ) |
| 708 | { |
| 709 | void *ptr; |
| 710 | int prot = VIRTUAL_GetUnixProt( vprot ); |
| 711 | BOOL shared_write = (vprot & VPROT_WRITE) != 0; |
| 712 | |
| 713 | assert( start < view->size ); |
| 714 | assert( start + size <= view->size ); |
| 715 | |
| 716 | /* only try mmap if media is not removable (or if we require write access) */ |
| 717 | if (!removable || shared_write) |
| 718 | { |
| 719 | int flags = MAP_FIXED | (shared_write ? MAP_SHARED : MAP_PRIVATE); |
| 720 | |
| 721 | if (unaligned_mmap( (char *)view->base + start, size, prot, flags, fd, offset ) != (void *)-1) |
| 722 | goto done; |
| 723 | |
| 724 | /* mmap() failed; if this is because the file offset is not */ |
| 725 | /* page-aligned (EINVAL), or because the underlying filesystem */ |
| 726 | /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */ |
| 727 | if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return FILE_GetNtStatus(); |
| 728 | if (shared_write) return FILE_GetNtStatus(); /* we cannot fake shared write mappings */ |
| 729 | } |
| 730 | |
| 731 | /* Reserve the memory with an anonymous mmap */ |
| 732 | ptr = wine_anon_mmap( (char *)view->base + start, size, PROT_READ | PROT_WRITE, MAP_FIXED ); |
| 733 | if (ptr == (void *)-1) return FILE_GetNtStatus(); |
| 734 | /* Now read in the file */ |
| 735 | pread( fd, ptr, size, offset ); |
| 736 | if (prot != (PROT_READ|PROT_WRITE)) mprotect( ptr, size, prot ); /* Set the right protection */ |
| 737 | done: |
| 738 | memset( view->prot + (start >> page_shift), vprot, size >> page_shift ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 739 | return STATUS_SUCCESS; |
| 740 | } |
| 741 | |
| 742 | |
| 743 | /*********************************************************************** |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 744 | * decommit_view |
| 745 | * |
| 746 | * Decommit some pages of a given view. |
| 747 | * The csVirtual section must be held by caller. |
| 748 | */ |
| 749 | static NTSTATUS decommit_pages( struct file_view *view, size_t start, size_t size ) |
| 750 | { |
| 751 | if (wine_anon_mmap( (char *)view->base + start, size, PROT_NONE, MAP_FIXED ) != (void *)-1) |
| 752 | { |
| 753 | BYTE *p = view->prot + (start >> page_shift); |
| 754 | size >>= page_shift; |
| 755 | while (size--) *p++ &= ~VPROT_COMMITTED; |
| 756 | return STATUS_SUCCESS; |
| 757 | } |
| 758 | return FILE_GetNtStatus(); |
| 759 | } |
| 760 | |
| 761 | |
| 762 | /*********************************************************************** |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 763 | * do_relocations |
| 764 | * |
| 765 | * Apply the relocations to a mapped PE image |
| 766 | */ |
| 767 | static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir, |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 768 | int delta, SIZE_T total_size ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 769 | { |
| 770 | IMAGE_BASE_RELOCATION *rel; |
| 771 | |
| 772 | TRACE_(module)( "relocating from %p-%p to %p-%p\n", |
| 773 | base - delta, base - delta + total_size, base, base + total_size ); |
| 774 | |
| 775 | for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress); |
| 776 | ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock; |
| 777 | rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) ) |
| 778 | { |
| 779 | char *page = base + rel->VirtualAddress; |
| 780 | WORD *TypeOffset = (WORD *)(rel + 1); |
| 781 | int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset); |
| 782 | |
| 783 | if (!count) continue; |
| 784 | |
| 785 | /* sanity checks */ |
Alexandre Julliard | 489c6b3 | 2005-09-21 09:47:12 +0000 | [diff] [blame] | 786 | if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 787 | { |
| 788 | ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n", |
| 789 | rel, rel->VirtualAddress, rel->SizeOfBlock, |
| 790 | base, dir->VirtualAddress, dir->Size ); |
| 791 | return 0; |
| 792 | } |
| 793 | |
Alexandre Julliard | 489c6b3 | 2005-09-21 09:47:12 +0000 | [diff] [blame] | 794 | if (page > base + total_size) |
| 795 | { |
| 796 | WARN_(module)("skipping %d relocations for page %p beyond module %p-%p\n", |
| 797 | count, page, base, base + total_size ); |
| 798 | continue; |
| 799 | } |
| 800 | |
| 801 | TRACE_(module)("%d relocations for page %lx\n", count, rel->VirtualAddress); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 802 | |
| 803 | /* patching in reverse order */ |
| 804 | for (i = 0 ; i < count; i++) |
| 805 | { |
| 806 | int offset = TypeOffset[i] & 0xFFF; |
| 807 | int type = TypeOffset[i] >> 12; |
| 808 | switch(type) |
| 809 | { |
| 810 | case IMAGE_REL_BASED_ABSOLUTE: |
| 811 | break; |
| 812 | case IMAGE_REL_BASED_HIGH: |
| 813 | *(short*)(page+offset) += HIWORD(delta); |
| 814 | break; |
| 815 | case IMAGE_REL_BASED_LOW: |
| 816 | *(short*)(page+offset) += LOWORD(delta); |
| 817 | break; |
| 818 | case IMAGE_REL_BASED_HIGHLOW: |
| 819 | *(int*)(page+offset) += delta; |
| 820 | /* FIXME: if this is an exported address, fire up enhanced logic */ |
| 821 | break; |
| 822 | default: |
| 823 | FIXME_(module)("Unknown/unsupported fixup type %d.\n", type); |
| 824 | break; |
| 825 | } |
| 826 | } |
| 827 | } |
| 828 | return 1; |
| 829 | } |
| 830 | |
| 831 | |
| 832 | /*********************************************************************** |
| 833 | * map_image |
| 834 | * |
| 835 | * Map an executable (PE format) image into memory. |
| 836 | */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 837 | static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_size, |
| 838 | SIZE_T header_size, int shared_fd, BOOL removable, PVOID *addr_ptr ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 839 | { |
| 840 | IMAGE_DOS_HEADER *dos; |
| 841 | IMAGE_NT_HEADERS *nt; |
| 842 | IMAGE_SECTION_HEADER *sec; |
| 843 | IMAGE_DATA_DIRECTORY *imports; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 844 | NTSTATUS status = STATUS_CONFLICTING_ADDRESSES; |
| 845 | int i; |
| 846 | off_t pos; |
| 847 | struct file_view *view = NULL; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 848 | char *ptr; |
| 849 | |
| 850 | /* zero-map the whole range */ |
| 851 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 852 | RtlEnterCriticalSection( &csVirtual ); |
| 853 | |
| 854 | if (base >= (char *)0x110000) /* make sure the DOS area remains free */ |
| 855 | status = map_view( &view, base, total_size, |
| 856 | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY | VPROT_IMAGE ); |
| 857 | |
| 858 | if (status == STATUS_CONFLICTING_ADDRESSES) |
| 859 | status = map_view( &view, NULL, total_size, |
| 860 | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY | VPROT_IMAGE ); |
| 861 | |
| 862 | if (status != STATUS_SUCCESS) goto error; |
| 863 | |
| 864 | ptr = view->base; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 865 | TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size ); |
| 866 | |
| 867 | /* map the header */ |
| 868 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 869 | status = STATUS_INVALID_IMAGE_FORMAT; /* generic error */ |
| 870 | if (map_file_into_view( view, fd, 0, header_size, 0, VPROT_COMMITTED | VPROT_READ, |
| 871 | removable ) != STATUS_SUCCESS) goto error; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 872 | dos = (IMAGE_DOS_HEADER *)ptr; |
| 873 | nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew); |
| 874 | if ((char *)(nt + 1) > ptr + header_size) goto error; |
| 875 | |
| 876 | sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); |
| 877 | if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error; |
| 878 | |
| 879 | imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT; |
| 880 | if (!imports->Size || !imports->VirtualAddress) imports = NULL; |
| 881 | |
| 882 | /* check the architecture */ |
| 883 | |
| 884 | if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) |
| 885 | { |
| 886 | MESSAGE("Trying to load PE image for unsupported architecture ("); |
| 887 | switch (nt->FileHeader.Machine) |
| 888 | { |
| 889 | case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break; |
| 890 | case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break; |
| 891 | case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break; |
| 892 | case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break; |
| 893 | case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break; |
| 894 | case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break; |
| 895 | case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break; |
Alexandre Julliard | 22a5332 | 2005-09-09 10:42:42 +0000 | [diff] [blame] | 896 | case IMAGE_FILE_MACHINE_IA64: MESSAGE("IA-64"); break; |
| 897 | case IMAGE_FILE_MACHINE_ALPHA64: MESSAGE("Alpha-64"); break; |
| 898 | case IMAGE_FILE_MACHINE_AMD64: MESSAGE("AMD-64"); break; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 899 | default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break; |
| 900 | } |
| 901 | MESSAGE(")\n"); |
| 902 | goto error; |
| 903 | } |
| 904 | |
Alexandre Julliard | 646ab89 | 2005-01-04 12:04:06 +0000 | [diff] [blame] | 905 | /* check for non page-aligned binary */ |
| 906 | |
| 907 | if (nt->OptionalHeader.SectionAlignment <= page_mask) |
| 908 | { |
| 909 | /* unaligned sections, this happens for native subsystem binaries */ |
| 910 | /* in that case Windows simply maps in the whole file */ |
| 911 | |
| 912 | if (map_file_into_view( view, fd, 0, total_size, 0, VPROT_COMMITTED | VPROT_READ, |
| 913 | removable ) != STATUS_SUCCESS) goto error; |
| 914 | |
| 915 | /* check that all sections are loaded at the right offset */ |
| 916 | for (i = 0; i < nt->FileHeader.NumberOfSections; i++) |
| 917 | { |
| 918 | if (sec[i].VirtualAddress != sec[i].PointerToRawData) |
| 919 | goto error; /* Windows refuses to load in that case too */ |
| 920 | } |
| 921 | |
| 922 | /* set the image protections */ |
| 923 | VIRTUAL_SetProt( view, ptr, total_size, |
| 924 | VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC ); |
| 925 | |
| 926 | /* perform relocations if necessary */ |
| 927 | /* FIXME: not 100% compatible, Windows doesn't do this for non page-aligned binaries */ |
| 928 | if (ptr != base) |
| 929 | { |
| 930 | const IMAGE_DATA_DIRECTORY *relocs; |
| 931 | relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; |
| 932 | if (relocs->VirtualAddress && relocs->Size) |
| 933 | do_relocations( ptr, relocs, ptr - base, total_size ); |
| 934 | } |
| 935 | |
| 936 | goto done; |
| 937 | } |
| 938 | |
| 939 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 940 | /* map all the sections */ |
| 941 | |
| 942 | for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) |
| 943 | { |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 944 | SIZE_T map_size, file_size, end; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 945 | |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 946 | if (!sec->Misc.VirtualSize) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 947 | { |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 948 | file_size = sec->SizeOfRawData; |
| 949 | map_size = ROUND_SIZE( 0, file_size ); |
| 950 | } |
| 951 | else |
| 952 | { |
| 953 | map_size = ROUND_SIZE( 0, sec->Misc.VirtualSize ); |
| 954 | file_size = min( sec->SizeOfRawData, map_size ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 955 | } |
| 956 | |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 957 | /* a few sanity checks */ |
| 958 | end = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, map_size ); |
| 959 | if (sec->VirtualAddress > total_size || end > total_size || end < sec->VirtualAddress) |
| 960 | { |
| 961 | ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n", |
| 962 | sec->Name, sec->VirtualAddress, map_size, total_size ); |
| 963 | goto error; |
| 964 | } |
Alexandre Julliard | 8c375c7 | 2005-08-12 11:21:45 +0000 | [diff] [blame] | 965 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 966 | if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) && |
| 967 | (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) |
| 968 | { |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 969 | TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n", |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 970 | sec->Name, ptr + sec->VirtualAddress, |
| 971 | sec->PointerToRawData, (int)pos, file_size, map_size, |
| 972 | sec->Characteristics ); |
| 973 | if (map_file_into_view( view, shared_fd, sec->VirtualAddress, map_size, pos, |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 974 | VPROT_COMMITTED | VPROT_READ | PROT_WRITE, |
| 975 | FALSE ) != STATUS_SUCCESS) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 976 | { |
| 977 | ERR_(module)( "Could not map shared section %.8s\n", sec->Name ); |
| 978 | goto error; |
| 979 | } |
| 980 | |
| 981 | /* check if the import directory falls inside this section */ |
| 982 | if (imports && imports->VirtualAddress >= sec->VirtualAddress && |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 983 | imports->VirtualAddress < sec->VirtualAddress + map_size) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 984 | { |
| 985 | UINT_PTR base = imports->VirtualAddress & ~page_mask; |
| 986 | UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size ); |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 987 | if (end > sec->VirtualAddress + map_size) end = sec->VirtualAddress + map_size; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 988 | if (end > base) |
| 989 | map_file_into_view( view, shared_fd, base, end - base, |
| 990 | pos + (base - sec->VirtualAddress), |
| 991 | VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, |
| 992 | FALSE ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 993 | } |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 994 | pos += map_size; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 995 | continue; |
| 996 | } |
| 997 | |
Alexandre Julliard | 8c375c7 | 2005-08-12 11:21:45 +0000 | [diff] [blame] | 998 | TRACE_(module)( "mapping section %.8s at %p off %lx size %lx virt %lx flags %lx\n", |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 999 | sec->Name, ptr + sec->VirtualAddress, |
| 1000 | sec->PointerToRawData, sec->SizeOfRawData, |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1001 | sec->Misc.VirtualSize, sec->Characteristics ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1002 | |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1003 | if (!sec->PointerToRawData || !file_size) continue; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1004 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1005 | /* Note: if the section is not aligned properly map_file_into_view will magically |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1006 | * fall back to read(), so we don't need to check anything here. |
| 1007 | */ |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1008 | if (map_file_into_view( view, fd, sec->VirtualAddress, file_size, sec->PointerToRawData, |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1009 | VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, |
| 1010 | removable ) != STATUS_SUCCESS) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1011 | { |
| 1012 | ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name ); |
| 1013 | goto error; |
| 1014 | } |
| 1015 | |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1016 | if (file_size & page_mask) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1017 | { |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1018 | end = ROUND_SIZE( 0, file_size ); |
| 1019 | if (end > map_size) end = map_size; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1020 | TRACE_(module)("clearing %p - %p\n", |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1021 | ptr + sec->VirtualAddress + file_size, |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1022 | ptr + sec->VirtualAddress + end ); |
Alexandre Julliard | 4ebd2fc | 2005-08-15 14:50:06 +0000 | [diff] [blame] | 1023 | memset( ptr + sec->VirtualAddress + file_size, 0, end - file_size ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1024 | } |
| 1025 | } |
| 1026 | |
| 1027 | |
| 1028 | /* perform base relocation, if necessary */ |
| 1029 | |
| 1030 | if (ptr != base) |
| 1031 | { |
| 1032 | const IMAGE_DATA_DIRECTORY *relocs; |
| 1033 | |
| 1034 | relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; |
| 1035 | if (!relocs->VirtualAddress || !relocs->Size) |
| 1036 | { |
Mike Hearn | 4d2cfee | 2004-03-15 20:06:50 +0000 | [diff] [blame] | 1037 | if (nt->OptionalHeader.ImageBase == 0x400000) { |
| 1038 | ERR("Image was mapped at %p: standard load address for a Win32 program (0x00400000) not available\n", ptr); |
| 1039 | ERR("Do you have exec-shield or prelink active?\n"); |
| 1040 | } else |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1041 | ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n", |
| 1042 | nt->OptionalHeader.ImageBase ); |
| 1043 | goto error; |
| 1044 | } |
| 1045 | |
| 1046 | /* FIXME: If we need to relocate a system DLL (base > 2GB) we should |
| 1047 | * really make sure that the *new* base address is also > 2GB. |
| 1048 | * Some DLLs really check the MSB of the module handle :-/ |
| 1049 | */ |
Alexandre Julliard | 261e376 | 2005-09-12 15:14:06 +0000 | [diff] [blame] | 1050 | if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((ULONG_PTR)base & 0x80000000)) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1051 | ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); |
| 1052 | |
| 1053 | if (!do_relocations( ptr, relocs, ptr - base, total_size )) |
| 1054 | { |
| 1055 | goto error; |
| 1056 | } |
| 1057 | } |
| 1058 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1059 | /* set the image protections */ |
| 1060 | |
| 1061 | sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); |
| 1062 | for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) |
| 1063 | { |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1064 | SIZE_T size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1065 | BYTE vprot = VPROT_COMMITTED; |
| 1066 | if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1067 | if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_READ|VPROT_WRITECOPY; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1068 | if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1069 | VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot ); |
| 1070 | } |
Alexandre Julliard | 646ab89 | 2005-01-04 12:04:06 +0000 | [diff] [blame] | 1071 | |
| 1072 | done: |
| 1073 | if (!removable) /* don't keep handle open on removable media */ |
Ivan Leo Puoti | d3edafe | 2005-02-22 19:33:50 +0000 | [diff] [blame] | 1074 | NtDuplicateObject( NtCurrentProcess(), hmapping, |
| 1075 | NtCurrentProcess(), &view->mapping, |
Alexandre Julliard | 646ab89 | 2005-01-04 12:04:06 +0000 | [diff] [blame] | 1076 | 0, 0, DUPLICATE_SAME_ACCESS ); |
| 1077 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1078 | RtlLeaveCriticalSection( &csVirtual ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1079 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1080 | *addr_ptr = ptr; |
| 1081 | return STATUS_SUCCESS; |
| 1082 | |
| 1083 | error: |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1084 | if (view) delete_view( view ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1085 | RtlLeaveCriticalSection( &csVirtual ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1086 | return status; |
| 1087 | } |
| 1088 | |
| 1089 | |
| 1090 | /*********************************************************************** |
| 1091 | * is_current_process |
| 1092 | * |
| 1093 | * Check whether a process handle is for the current process. |
| 1094 | */ |
Alexander Yaworsky | 8657ad8 | 2004-09-21 00:23:50 +0000 | [diff] [blame] | 1095 | BOOL is_current_process( HANDLE handle ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1096 | { |
| 1097 | BOOL ret = FALSE; |
| 1098 | |
Ivan Leo Puoti | d3edafe | 2005-02-22 19:33:50 +0000 | [diff] [blame] | 1099 | if (handle == NtCurrentProcess()) return TRUE; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1100 | SERVER_START_REQ( get_process_info ) |
| 1101 | { |
| 1102 | req->handle = handle; |
| 1103 | if (!wine_server_call( req )) |
| 1104 | ret = ((DWORD)reply->pid == GetCurrentProcessId()); |
| 1105 | } |
| 1106 | SERVER_END_REQ; |
| 1107 | return ret; |
| 1108 | } |
| 1109 | |
| 1110 | |
| 1111 | /*********************************************************************** |
Alexandre Julliard | af54207 | 2004-01-07 04:50:11 +0000 | [diff] [blame] | 1112 | * virtual_init |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1113 | */ |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1114 | static inline void virtual_init(void) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1115 | { |
Alexandre Julliard | af54207 | 2004-01-07 04:50:11 +0000 | [diff] [blame] | 1116 | #ifndef page_mask |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1117 | page_size = getpagesize(); |
| 1118 | page_mask = page_size - 1; |
| 1119 | /* Make sure we have a power of 2 */ |
| 1120 | assert( !(page_size & page_mask) ); |
| 1121 | page_shift = 0; |
| 1122 | while ((1 << page_shift) != page_size) page_shift++; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1123 | #endif /* page_mask */ |
Alexandre Julliard | af54207 | 2004-01-07 04:50:11 +0000 | [diff] [blame] | 1124 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1125 | |
| 1126 | |
| 1127 | /*********************************************************************** |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1128 | * VIRTUAL_alloc_teb |
| 1129 | * |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 1130 | * Allocate a memory view for a new TEB, properly aligned to a multiple of the size. |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1131 | */ |
| 1132 | NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first ) |
| 1133 | { |
| 1134 | void *ptr; |
| 1135 | NTSTATUS status; |
| 1136 | struct file_view *view; |
Alexandre Julliard | 06ea6e6 | 2005-09-16 18:54:19 +0000 | [diff] [blame] | 1137 | size_t align_size; |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1138 | BYTE vprot = VPROT_READ | VPROT_WRITE | VPROT_COMMITTED; |
| 1139 | |
| 1140 | if (first) virtual_init(); |
| 1141 | |
| 1142 | *ret = NULL; |
| 1143 | size = ROUND_SIZE( 0, size ); |
Alexandre Julliard | 06ea6e6 | 2005-09-16 18:54:19 +0000 | [diff] [blame] | 1144 | align_size = page_size; |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 1145 | while (align_size < size) align_size *= 2; |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1146 | |
| 1147 | for (;;) |
| 1148 | { |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 1149 | if ((ptr = wine_anon_mmap( NULL, 2 * align_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1150 | { |
| 1151 | if (errno == ENOMEM) return STATUS_NO_MEMORY; |
| 1152 | return STATUS_INVALID_PARAMETER; |
| 1153 | } |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 1154 | if (!is_beyond_limit( ptr, 2 * align_size, user_space_limit )) |
| 1155 | { |
| 1156 | ptr = unmap_extra_space( ptr, 2 * align_size, align_size, align_size - 1 ); |
| 1157 | break; |
| 1158 | } |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1159 | /* if we got something beyond the user limit, unmap it and retry */ |
Alexandre Julliard | fb9cead | 2005-09-14 10:36:58 +0000 | [diff] [blame] | 1160 | add_reserved_area( ptr, 2 * align_size ); |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1161 | } |
| 1162 | |
| 1163 | if (!first) RtlEnterCriticalSection( &csVirtual ); |
| 1164 | |
| 1165 | status = create_view( &view, ptr, size, vprot ); |
| 1166 | if (status == STATUS_SUCCESS) |
| 1167 | { |
| 1168 | view->flags |= VFLAG_VALLOC; |
| 1169 | *ret = ptr; |
| 1170 | } |
| 1171 | else unmap_area( ptr, size ); |
| 1172 | |
| 1173 | if (!first) RtlLeaveCriticalSection( &csVirtual ); |
| 1174 | |
| 1175 | return status; |
| 1176 | } |
| 1177 | |
| 1178 | |
| 1179 | /*********************************************************************** |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1180 | * VIRTUAL_HandleFault |
| 1181 | */ |
Dmitry Timoshkov | 40dd77b | 2005-07-15 11:43:09 +0000 | [diff] [blame] | 1182 | NTSTATUS VIRTUAL_HandleFault( LPCVOID addr ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1183 | { |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1184 | FILE_VIEW *view; |
Dmitry Timoshkov | 40dd77b | 2005-07-15 11:43:09 +0000 | [diff] [blame] | 1185 | NTSTATUS ret = STATUS_ACCESS_VIOLATION; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1186 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1187 | RtlEnterCriticalSection( &csVirtual ); |
| 1188 | if ((view = VIRTUAL_FindView( addr ))) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1189 | { |
Alexandre Julliard | 3b843d3 | 2005-04-20 16:26:23 +0000 | [diff] [blame] | 1190 | BYTE vprot = view->prot[((const char *)addr - (const char *)view->base) >> page_shift]; |
| 1191 | void *page = (void *)((UINT_PTR)addr & ~page_mask); |
| 1192 | char *stack = NtCurrentTeb()->Tib.StackLimit; |
| 1193 | if (vprot & VPROT_GUARD) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1194 | { |
Alexandre Julliard | 3b843d3 | 2005-04-20 16:26:23 +0000 | [diff] [blame] | 1195 | VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD ); |
| 1196 | ret = STATUS_GUARD_PAGE_VIOLATION; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1197 | } |
Alexandre Julliard | 3b843d3 | 2005-04-20 16:26:23 +0000 | [diff] [blame] | 1198 | /* is it inside the stack guard page? */ |
| 1199 | if (((const char *)addr >= stack) && ((const char *)addr < stack + (page_mask+1))) |
| 1200 | ret = STATUS_STACK_OVERFLOW; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1201 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1202 | RtlLeaveCriticalSection( &csVirtual ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1203 | return ret; |
| 1204 | } |
| 1205 | |
Alexandre Julliard | 670711e | 2004-04-06 23:13:47 +0000 | [diff] [blame] | 1206 | /*********************************************************************** |
| 1207 | * VIRTUAL_HasMapping |
| 1208 | * |
| 1209 | * Check if the specified view has an associated file mapping. |
| 1210 | */ |
| 1211 | BOOL VIRTUAL_HasMapping( LPCVOID addr ) |
| 1212 | { |
| 1213 | FILE_VIEW *view; |
| 1214 | BOOL ret = FALSE; |
| 1215 | |
| 1216 | RtlEnterCriticalSection( &csVirtual ); |
| 1217 | if ((view = VIRTUAL_FindView( addr ))) ret = (view->mapping != 0); |
| 1218 | RtlLeaveCriticalSection( &csVirtual ); |
| 1219 | return ret; |
| 1220 | } |
| 1221 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1222 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1223 | /*********************************************************************** |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 1224 | * VIRTUAL_UseLargeAddressSpace |
| 1225 | * |
| 1226 | * Increase the address space size for apps that support it. |
| 1227 | */ |
| 1228 | void VIRTUAL_UseLargeAddressSpace(void) |
| 1229 | { |
| 1230 | if (user_space_limit >= ADDRESS_SPACE_LIMIT) return; |
Alexandre Julliard | e3ef631 | 2005-12-01 18:42:39 +0100 | [diff] [blame] | 1231 | /* no large address space on win9x */ |
| 1232 | if (NtCurrentTeb()->Peb->OSPlatformId != VER_PLATFORM_WIN32_NT) return; |
| 1233 | |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 1234 | RtlEnterCriticalSection( &csVirtual ); |
| 1235 | remove_reserved_area( user_space_limit, (char *)ADDRESS_SPACE_LIMIT - (char *)user_space_limit ); |
| 1236 | user_space_limit = ADDRESS_SPACE_LIMIT; |
| 1237 | RtlLeaveCriticalSection( &csVirtual ); |
| 1238 | } |
| 1239 | |
| 1240 | |
| 1241 | /*********************************************************************** |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1242 | * NtAllocateVirtualMemory (NTDLL.@) |
| 1243 | * ZwAllocateVirtualMemory (NTDLL.@) |
| 1244 | */ |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1245 | NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_bits, |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1246 | SIZE_T *size_ptr, ULONG type, ULONG protect ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1247 | { |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1248 | void *base; |
| 1249 | BYTE vprot; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1250 | SIZE_T size = *size_ptr; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1251 | NTSTATUS status = STATUS_SUCCESS; |
| 1252 | struct file_view *view; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1253 | |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1254 | TRACE("%p %p %08lx %lx %08lx\n", process, *ret, size, type, protect ); |
Alexander Yaworsky | aadffd1 | 2004-09-22 04:03:10 +0000 | [diff] [blame] | 1255 | |
| 1256 | if (!size) return STATUS_INVALID_PARAMETER; |
| 1257 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1258 | if (!is_current_process( process )) |
| 1259 | { |
| 1260 | ERR("Unsupported on other process\n"); |
| 1261 | return STATUS_ACCESS_DENIED; |
| 1262 | } |
| 1263 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1264 | /* Round parameters to a page boundary */ |
| 1265 | |
| 1266 | if (size > 0x7fc00000) return STATUS_WORKING_SET_LIMIT_RANGE; /* 2Gb - 4Mb */ |
| 1267 | |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1268 | if (*ret) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1269 | { |
| 1270 | if (type & MEM_RESERVE) /* Round down to 64k boundary */ |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1271 | base = ROUND_ADDR( *ret, granularity_mask ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1272 | else |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1273 | base = ROUND_ADDR( *ret, page_mask ); |
| 1274 | size = (((UINT_PTR)*ret + size + page_mask) & ~page_mask) - (UINT_PTR)base; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1275 | |
| 1276 | /* disallow low 64k, wrap-around and kernel space */ |
| 1277 | if (((char *)base <= (char *)granularity_mask) || |
| 1278 | ((char *)base + size < (char *)base) || |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1279 | is_beyond_limit( base, size, ADDRESS_SPACE_LIMIT )) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1280 | return STATUS_INVALID_PARAMETER; |
| 1281 | } |
| 1282 | else |
| 1283 | { |
| 1284 | base = NULL; |
| 1285 | size = (size + page_mask) & ~page_mask; |
| 1286 | } |
| 1287 | |
| 1288 | if (type & MEM_TOP_DOWN) { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1289 | /* FIXME: MEM_TOP_DOWN allocates the largest possible address. */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1290 | WARN("MEM_TOP_DOWN ignored\n"); |
| 1291 | type &= ~MEM_TOP_DOWN; |
| 1292 | } |
| 1293 | |
Robert Shearman | 2050591 | 2004-10-11 20:59:06 +0000 | [diff] [blame] | 1294 | if (zero_bits) |
| 1295 | WARN("zero_bits %lu ignored\n", zero_bits); |
| 1296 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1297 | /* Compute the alloc type flags */ |
| 1298 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1299 | if (!(type & MEM_SYSTEM)) |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1300 | { |
| 1301 | if (!(type & (MEM_COMMIT | MEM_RESERVE)) || (type & ~(MEM_COMMIT | MEM_RESERVE))) |
| 1302 | { |
| 1303 | WARN("called with wrong alloc type flags (%08lx) !\n", type); |
| 1304 | return STATUS_INVALID_PARAMETER; |
| 1305 | } |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1306 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1307 | vprot = VIRTUAL_GetProt( protect ); |
| 1308 | if (type & MEM_COMMIT) vprot |= VPROT_COMMITTED; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1309 | |
| 1310 | /* Reserve the memory */ |
| 1311 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1312 | RtlEnterCriticalSection( &csVirtual ); |
| 1313 | |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1314 | if (type & MEM_SYSTEM) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1315 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1316 | if (type & MEM_IMAGE) vprot |= VPROT_IMAGE; |
| 1317 | status = create_view( &view, base, size, vprot | VPROT_COMMITTED ); |
| 1318 | if (status == STATUS_SUCCESS) |
| 1319 | { |
| 1320 | view->flags |= VFLAG_VALLOC | VFLAG_SYSTEM; |
| 1321 | base = view->base; |
| 1322 | } |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1323 | } |
| 1324 | else if ((type & MEM_RESERVE) || !base) |
| 1325 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1326 | status = map_view( &view, base, size, vprot ); |
| 1327 | if (status == STATUS_SUCCESS) |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1328 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1329 | view->flags |= VFLAG_VALLOC; |
| 1330 | base = view->base; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1331 | } |
| 1332 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1333 | else /* commit the pages */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1334 | { |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1335 | if (!(view = VIRTUAL_FindView( base )) || |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1336 | ((char *)base + size > (char *)view->base + view->size)) status = STATUS_NOT_MAPPED_VIEW; |
| 1337 | else if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1338 | } |
| 1339 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1340 | RtlLeaveCriticalSection( &csVirtual ); |
| 1341 | |
| 1342 | if (status == STATUS_SUCCESS) |
| 1343 | { |
| 1344 | *ret = base; |
| 1345 | *size_ptr = size; |
| 1346 | } |
| 1347 | return status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1348 | } |
| 1349 | |
| 1350 | |
| 1351 | /*********************************************************************** |
| 1352 | * NtFreeVirtualMemory (NTDLL.@) |
| 1353 | * ZwFreeVirtualMemory (NTDLL.@) |
| 1354 | */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1355 | NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, ULONG type ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1356 | { |
| 1357 | FILE_VIEW *view; |
| 1358 | char *base; |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1359 | NTSTATUS status = STATUS_SUCCESS; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1360 | LPVOID addr = *addr_ptr; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1361 | SIZE_T size = *size_ptr; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1362 | |
Alexander Yaworsky | aadffd1 | 2004-09-22 04:03:10 +0000 | [diff] [blame] | 1363 | TRACE("%p %p %08lx %lx\n", process, addr, size, type ); |
| 1364 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1365 | if (!is_current_process( process )) |
| 1366 | { |
| 1367 | ERR("Unsupported on other process\n"); |
| 1368 | return STATUS_ACCESS_DENIED; |
| 1369 | } |
| 1370 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1371 | /* Fix the parameters */ |
| 1372 | |
| 1373 | size = ROUND_SIZE( addr, size ); |
| 1374 | base = ROUND_ADDR( addr, page_mask ); |
| 1375 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1376 | RtlEnterCriticalSection(&csVirtual); |
| 1377 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1378 | if (!(view = VIRTUAL_FindView( base )) || |
| 1379 | (base + size > (char *)view->base + view->size) || |
| 1380 | !(view->flags & VFLAG_VALLOC)) |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1381 | { |
| 1382 | status = STATUS_INVALID_PARAMETER; |
| 1383 | } |
| 1384 | else if (type & MEM_SYSTEM) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1385 | { |
Alexandre Julliard | 7924f42 | 2003-11-04 04:50:18 +0000 | [diff] [blame] | 1386 | /* return the values that the caller should use to unmap the area */ |
| 1387 | *addr_ptr = view->base; |
| 1388 | *size_ptr = view->size; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1389 | view->flags |= VFLAG_SYSTEM; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1390 | delete_view( view ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1391 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1392 | else if (type == MEM_RELEASE) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1393 | { |
Dmitry Timoshkov | fcc2fe1 | 2004-02-11 23:56:52 +0000 | [diff] [blame] | 1394 | /* Free the pages */ |
| 1395 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1396 | if (size || (base != view->base)) status = STATUS_INVALID_PARAMETER; |
| 1397 | else |
| 1398 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1399 | delete_view( view ); |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1400 | *addr_ptr = base; |
| 1401 | *size_ptr = size; |
| 1402 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1403 | } |
Dmitry Timoshkov | fcc2fe1 | 2004-02-11 23:56:52 +0000 | [diff] [blame] | 1404 | else if (type == MEM_DECOMMIT) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1405 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1406 | status = decommit_pages( view, base - (char *)view->base, size ); |
| 1407 | if (status == STATUS_SUCCESS) |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1408 | { |
| 1409 | *addr_ptr = base; |
| 1410 | *size_ptr = size; |
| 1411 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1412 | } |
Dmitry Timoshkov | fcc2fe1 | 2004-02-11 23:56:52 +0000 | [diff] [blame] | 1413 | else |
| 1414 | { |
| 1415 | WARN("called with wrong free type flags (%08lx) !\n", type); |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1416 | status = STATUS_INVALID_PARAMETER; |
Dmitry Timoshkov | fcc2fe1 | 2004-02-11 23:56:52 +0000 | [diff] [blame] | 1417 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1418 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1419 | RtlLeaveCriticalSection(&csVirtual); |
| 1420 | return status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1421 | } |
| 1422 | |
| 1423 | |
| 1424 | /*********************************************************************** |
| 1425 | * NtProtectVirtualMemory (NTDLL.@) |
| 1426 | * ZwProtectVirtualMemory (NTDLL.@) |
| 1427 | */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1428 | NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1429 | ULONG new_prot, ULONG *old_prot ) |
| 1430 | { |
| 1431 | FILE_VIEW *view; |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1432 | NTSTATUS status = STATUS_SUCCESS; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1433 | char *base; |
| 1434 | UINT i; |
| 1435 | BYTE vprot, *p; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1436 | ULONG prot; |
| 1437 | SIZE_T size = *size_ptr; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1438 | LPVOID addr = *addr_ptr; |
| 1439 | |
Alexander Yaworsky | aadffd1 | 2004-09-22 04:03:10 +0000 | [diff] [blame] | 1440 | TRACE("%p %p %08lx %08lx\n", process, addr, size, new_prot ); |
| 1441 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1442 | if (!is_current_process( process )) |
| 1443 | { |
| 1444 | ERR("Unsupported on other process\n"); |
| 1445 | return STATUS_ACCESS_DENIED; |
| 1446 | } |
| 1447 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1448 | /* Fix the parameters */ |
| 1449 | |
| 1450 | size = ROUND_SIZE( addr, size ); |
| 1451 | base = ROUND_ADDR( addr, page_mask ); |
| 1452 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1453 | RtlEnterCriticalSection( &csVirtual ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1454 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1455 | if (!(view = VIRTUAL_FindView( base )) || (base + size > (char *)view->base + view->size)) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1456 | { |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1457 | status = STATUS_INVALID_PARAMETER; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1458 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1459 | else |
| 1460 | { |
| 1461 | /* Make sure all the pages are committed */ |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1462 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1463 | p = view->prot + ((base - (char *)view->base) >> page_shift); |
| 1464 | VIRTUAL_GetWin32Prot( *p, &prot, NULL ); |
| 1465 | for (i = size >> page_shift; i; i--, p++) |
| 1466 | { |
| 1467 | if (!(*p & VPROT_COMMITTED)) |
| 1468 | { |
| 1469 | status = STATUS_NOT_COMMITTED; |
| 1470 | break; |
| 1471 | } |
| 1472 | } |
| 1473 | if (!i) |
| 1474 | { |
| 1475 | if (old_prot) *old_prot = prot; |
| 1476 | vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED; |
| 1477 | if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED; |
| 1478 | } |
| 1479 | } |
| 1480 | RtlLeaveCriticalSection( &csVirtual ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1481 | |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1482 | if (status == STATUS_SUCCESS) |
| 1483 | { |
| 1484 | *addr_ptr = base; |
| 1485 | *size_ptr = size; |
| 1486 | } |
| 1487 | return status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1488 | } |
| 1489 | |
Felix Nawothnig | db6a238 | 2005-07-05 14:05:58 +0000 | [diff] [blame] | 1490 | #define UNIMPLEMENTED_INFO_CLASS(c) \ |
| 1491 | case c: \ |
| 1492 | FIXME("(process=%p,addr=%p) Unimplemented information class: " #c "\n", process, addr); \ |
| 1493 | return STATUS_INVALID_INFO_CLASS |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1494 | |
| 1495 | /*********************************************************************** |
| 1496 | * NtQueryVirtualMemory (NTDLL.@) |
| 1497 | * ZwQueryVirtualMemory (NTDLL.@) |
| 1498 | */ |
| 1499 | NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, |
| 1500 | MEMORY_INFORMATION_CLASS info_class, PVOID buffer, |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1501 | SIZE_T len, SIZE_T *res_len ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1502 | { |
| 1503 | FILE_VIEW *view; |
| 1504 | char *base, *alloc_base = 0; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1505 | struct list *ptr; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1506 | SIZE_T size = 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1507 | MEMORY_BASIC_INFORMATION *info = buffer; |
| 1508 | |
Hans Leidekker | fccfcbf | 2005-01-20 19:59:48 +0000 | [diff] [blame] | 1509 | if (info_class != MemoryBasicInformation) |
| 1510 | { |
Felix Nawothnig | db6a238 | 2005-07-05 14:05:58 +0000 | [diff] [blame] | 1511 | switch(info_class) |
| 1512 | { |
| 1513 | UNIMPLEMENTED_INFO_CLASS(MemoryWorkingSetList); |
| 1514 | UNIMPLEMENTED_INFO_CLASS(MemorySectionName); |
| 1515 | UNIMPLEMENTED_INFO_CLASS(MemoryBasicVlmInformation); |
| 1516 | |
| 1517 | default: |
| 1518 | FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", |
| 1519 | process, addr, info_class, buffer, len, res_len); |
| 1520 | return STATUS_INVALID_INFO_CLASS; |
| 1521 | } |
Hans Leidekker | fccfcbf | 2005-01-20 19:59:48 +0000 | [diff] [blame] | 1522 | } |
Alexandre Julliard | ac36f95 | 2002-11-06 22:33:17 +0000 | [diff] [blame] | 1523 | if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT) |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1524 | return STATUS_WORKING_SET_LIMIT_RANGE; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1525 | |
| 1526 | if (!is_current_process( process )) |
| 1527 | { |
| 1528 | ERR("Unsupported on other process\n"); |
| 1529 | return STATUS_ACCESS_DENIED; |
| 1530 | } |
| 1531 | |
| 1532 | base = ROUND_ADDR( addr, page_mask ); |
| 1533 | |
| 1534 | /* Find the view containing the address */ |
| 1535 | |
| 1536 | RtlEnterCriticalSection(&csVirtual); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1537 | ptr = list_head( &views_list ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1538 | for (;;) |
| 1539 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1540 | if (!ptr) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1541 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1542 | /* make the address space end at the user limit, except if |
| 1543 | * the last view was mapped beyond that */ |
Alexandre Julliard | 9f32a5c | 2005-08-09 10:43:47 +0000 | [diff] [blame] | 1544 | if (alloc_base <= (char *)user_space_limit) |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1545 | { |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 1546 | if (user_space_limit && base >= (char *)user_space_limit) |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1547 | { |
| 1548 | RtlLeaveCriticalSection( &csVirtual ); |
| 1549 | return STATUS_WORKING_SET_LIMIT_RANGE; |
| 1550 | } |
Alexandre Julliard | fd9792b | 2004-06-18 00:26:57 +0000 | [diff] [blame] | 1551 | size = (char *)user_space_limit - alloc_base; |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1552 | } |
| 1553 | else size = (char *)ADDRESS_SPACE_LIMIT - alloc_base; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1554 | view = NULL; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1555 | break; |
| 1556 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1557 | view = LIST_ENTRY( ptr, struct file_view, entry ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1558 | if ((char *)view->base > base) |
| 1559 | { |
| 1560 | size = (char *)view->base - alloc_base; |
| 1561 | view = NULL; |
| 1562 | break; |
| 1563 | } |
| 1564 | if ((char *)view->base + view->size > base) |
| 1565 | { |
| 1566 | alloc_base = view->base; |
| 1567 | size = view->size; |
| 1568 | break; |
| 1569 | } |
| 1570 | alloc_base = (char *)view->base + view->size; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1571 | ptr = list_next( &views_list, ptr ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1572 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1573 | |
| 1574 | /* Fill the info structure */ |
| 1575 | |
| 1576 | if (!view) |
| 1577 | { |
| 1578 | info->State = MEM_FREE; |
| 1579 | info->Protect = 0; |
| 1580 | info->AllocationProtect = 0; |
| 1581 | info->Type = 0; |
| 1582 | } |
| 1583 | else |
| 1584 | { |
| 1585 | BYTE vprot = view->prot[(base - alloc_base) >> page_shift]; |
| 1586 | VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State ); |
| 1587 | for (size = base - alloc_base; size < view->size; size += page_mask+1) |
| 1588 | if (view->prot[size >> page_shift] != vprot) break; |
Alexandre Julliard | 7fcc737 | 2003-11-03 22:21:55 +0000 | [diff] [blame] | 1589 | VIRTUAL_GetWin32Prot( view->protect, &info->AllocationProtect, NULL ); |
| 1590 | if (view->protect & VPROT_IMAGE) info->Type = MEM_IMAGE; |
| 1591 | else if (view->flags & VFLAG_VALLOC) info->Type = MEM_PRIVATE; |
| 1592 | else info->Type = MEM_MAPPED; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1593 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1594 | RtlLeaveCriticalSection(&csVirtual); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1595 | |
| 1596 | info->BaseAddress = (LPVOID)base; |
| 1597 | info->AllocationBase = (LPVOID)alloc_base; |
| 1598 | info->RegionSize = size - (base - alloc_base); |
Alexandre Julliard | c808e67 | 2003-05-08 03:50:32 +0000 | [diff] [blame] | 1599 | if (res_len) *res_len = sizeof(*info); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1600 | return STATUS_SUCCESS; |
| 1601 | } |
| 1602 | |
| 1603 | |
| 1604 | /*********************************************************************** |
| 1605 | * NtLockVirtualMemory (NTDLL.@) |
| 1606 | * ZwLockVirtualMemory (NTDLL.@) |
| 1607 | */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1608 | NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size, ULONG unknown ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1609 | { |
| 1610 | if (!is_current_process( process )) |
| 1611 | { |
| 1612 | ERR("Unsupported on other process\n"); |
| 1613 | return STATUS_ACCESS_DENIED; |
| 1614 | } |
| 1615 | return STATUS_SUCCESS; |
| 1616 | } |
| 1617 | |
| 1618 | |
| 1619 | /*********************************************************************** |
| 1620 | * NtUnlockVirtualMemory (NTDLL.@) |
| 1621 | * ZwUnlockVirtualMemory (NTDLL.@) |
| 1622 | */ |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1623 | NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size, ULONG unknown ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1624 | { |
| 1625 | if (!is_current_process( process )) |
| 1626 | { |
| 1627 | ERR("Unsupported on other process\n"); |
| 1628 | return STATUS_ACCESS_DENIED; |
| 1629 | } |
| 1630 | return STATUS_SUCCESS; |
| 1631 | } |
| 1632 | |
| 1633 | |
| 1634 | /*********************************************************************** |
| 1635 | * NtCreateSection (NTDLL.@) |
| 1636 | * ZwCreateSection (NTDLL.@) |
| 1637 | */ |
| 1638 | NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, |
| 1639 | const LARGE_INTEGER *size, ULONG protect, |
| 1640 | ULONG sec_flags, HANDLE file ) |
| 1641 | { |
| 1642 | NTSTATUS ret; |
| 1643 | BYTE vprot; |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1644 | DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1645 | |
| 1646 | /* Check parameters */ |
| 1647 | |
| 1648 | if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; |
| 1649 | |
| 1650 | vprot = VIRTUAL_GetProt( protect ); |
| 1651 | if (sec_flags & SEC_RESERVE) |
| 1652 | { |
| 1653 | if (file) return STATUS_INVALID_PARAMETER; |
| 1654 | } |
| 1655 | else vprot |= VPROT_COMMITTED; |
| 1656 | if (sec_flags & SEC_NOCACHE) vprot |= VPROT_NOCACHE; |
| 1657 | if (sec_flags & SEC_IMAGE) vprot |= VPROT_IMAGE; |
| 1658 | |
| 1659 | /* Create the server object */ |
| 1660 | |
| 1661 | SERVER_START_REQ( create_mapping ) |
| 1662 | { |
Vitaliy Margolen | a996000 | 2005-10-27 18:30:37 +0000 | [diff] [blame] | 1663 | req->access = access; |
| 1664 | req->attributes = (attr) ? attr->Attributes : 0; |
Vitaliy Margolen | 348a3d9 | 2005-12-02 16:13:13 +0100 | [diff] [blame^] | 1665 | req->rootdir = attr ? attr->RootDirectory : 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1666 | req->file_handle = file; |
Ge van Geldorp | 399901e | 2004-01-23 01:51:33 +0000 | [diff] [blame] | 1667 | req->size_high = size ? size->u.HighPart : 0; |
| 1668 | req->size_low = size ? size->u.LowPart : 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1669 | req->protect = vprot; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1670 | if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); |
| 1671 | ret = wine_server_call( req ); |
| 1672 | *handle = reply->handle; |
| 1673 | } |
| 1674 | SERVER_END_REQ; |
| 1675 | return ret; |
| 1676 | } |
| 1677 | |
| 1678 | |
| 1679 | /*********************************************************************** |
| 1680 | * NtOpenSection (NTDLL.@) |
| 1681 | * ZwOpenSection (NTDLL.@) |
| 1682 | */ |
| 1683 | NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) |
| 1684 | { |
| 1685 | NTSTATUS ret; |
| 1686 | DWORD len = attr->ObjectName->Length; |
| 1687 | |
| 1688 | if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; |
| 1689 | |
| 1690 | SERVER_START_REQ( open_mapping ) |
| 1691 | { |
| 1692 | req->access = access; |
Vitaliy Margolen | a996000 | 2005-10-27 18:30:37 +0000 | [diff] [blame] | 1693 | req->attributes = (attr) ? attr->Attributes : 0; |
Vitaliy Margolen | 348a3d9 | 2005-12-02 16:13:13 +0100 | [diff] [blame^] | 1694 | req->rootdir = attr ? attr->RootDirectory : 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1695 | wine_server_add_data( req, attr->ObjectName->Buffer, len ); |
| 1696 | if (!(ret = wine_server_call( req ))) *handle = reply->handle; |
| 1697 | } |
| 1698 | SERVER_END_REQ; |
| 1699 | return ret; |
| 1700 | } |
| 1701 | |
| 1702 | |
| 1703 | /*********************************************************************** |
| 1704 | * NtMapViewOfSection (NTDLL.@) |
| 1705 | * ZwMapViewOfSection (NTDLL.@) |
| 1706 | */ |
| 1707 | NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG zero_bits, |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1708 | SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1709 | SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect ) |
| 1710 | { |
Alexandre Julliard | 670711e | 2004-04-06 23:13:47 +0000 | [diff] [blame] | 1711 | FILE_FS_DEVICE_INFORMATION device_info; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1712 | NTSTATUS res; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1713 | SIZE_T size = 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1714 | int unix_handle = -1; |
| 1715 | int prot; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1716 | void *base; |
| 1717 | struct file_view *view; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1718 | DWORD size_low, size_high, header_size, shared_size; |
| 1719 | HANDLE shared_file; |
Alexandre Julliard | 670711e | 2004-04-06 23:13:47 +0000 | [diff] [blame] | 1720 | BOOL removable = FALSE; |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1721 | LARGE_INTEGER offset; |
| 1722 | |
| 1723 | offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1724 | |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1725 | TRACE("handle=%p process=%p addr=%p off=%lx%08lx size=%lx access=%lx\n", |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1726 | handle, process, *addr_ptr, offset.u.HighPart, offset.u.LowPart, size, protect ); |
Alexander Yaworsky | aadffd1 | 2004-09-22 04:03:10 +0000 | [diff] [blame] | 1727 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1728 | if (!is_current_process( process )) |
| 1729 | { |
| 1730 | ERR("Unsupported on other process\n"); |
| 1731 | return STATUS_ACCESS_DENIED; |
| 1732 | } |
| 1733 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1734 | /* Check parameters */ |
| 1735 | |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1736 | if ((offset.u.LowPart & granularity_mask) || |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1737 | (*addr_ptr && ((UINT_PTR)*addr_ptr & granularity_mask))) |
| 1738 | return STATUS_INVALID_PARAMETER; |
| 1739 | |
| 1740 | SERVER_START_REQ( get_mapping_info ) |
| 1741 | { |
| 1742 | req->handle = handle; |
| 1743 | res = wine_server_call( req ); |
| 1744 | prot = reply->protect; |
| 1745 | base = reply->base; |
| 1746 | size_low = reply->size_low; |
| 1747 | size_high = reply->size_high; |
| 1748 | header_size = reply->header_size; |
| 1749 | shared_file = reply->shared_file; |
| 1750 | shared_size = reply->shared_size; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1751 | } |
| 1752 | SERVER_END_REQ; |
Alexandre Julliard | f3f435f | 2003-12-01 23:01:12 +0000 | [diff] [blame] | 1753 | if (res) return res; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1754 | |
Alexandre Julliard | 6a27b48 | 2004-08-18 00:04:58 +0000 | [diff] [blame] | 1755 | if ((res = wine_server_handle_to_fd( handle, 0, &unix_handle, NULL ))) return res; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1756 | |
Alexandre Julliard | 0f41df1 | 2005-08-25 10:23:23 +0000 | [diff] [blame] | 1757 | if (FILE_GetDeviceInfo( unix_handle, &device_info ) == STATUS_SUCCESS) |
Alexandre Julliard | 670711e | 2004-04-06 23:13:47 +0000 | [diff] [blame] | 1758 | removable = device_info.Characteristics & FILE_REMOVABLE_MEDIA; |
| 1759 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1760 | if (prot & VPROT_IMAGE) |
| 1761 | { |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1762 | if (shared_file) |
| 1763 | { |
Alexandre Julliard | f3f435f | 2003-12-01 23:01:12 +0000 | [diff] [blame] | 1764 | int shared_fd; |
| 1765 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1766 | if ((res = wine_server_handle_to_fd( shared_file, GENERIC_READ, &shared_fd, |
Alexandre Julliard | 6a27b48 | 2004-08-18 00:04:58 +0000 | [diff] [blame] | 1767 | NULL ))) goto done; |
Alexandre Julliard | f3f435f | 2003-12-01 23:01:12 +0000 | [diff] [blame] | 1768 | res = map_image( handle, unix_handle, base, size_low, header_size, |
| 1769 | shared_fd, removable, addr_ptr ); |
| 1770 | wine_server_release_fd( shared_file, shared_fd ); |
| 1771 | NtClose( shared_file ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1772 | } |
Alexandre Julliard | f3f435f | 2003-12-01 23:01:12 +0000 | [diff] [blame] | 1773 | else |
| 1774 | { |
| 1775 | res = map_image( handle, unix_handle, base, size_low, header_size, |
| 1776 | -1, removable, addr_ptr ); |
| 1777 | } |
| 1778 | wine_server_release_fd( handle, unix_handle ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1779 | if (!res) *size_ptr = size_low; |
| 1780 | return res; |
| 1781 | } |
| 1782 | |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1783 | if (size_high) |
| 1784 | ERR("Sizes larger than 4Gb not supported\n"); |
| 1785 | |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1786 | if ((offset.u.LowPart >= size_low) || |
| 1787 | (*size_ptr > size_low - offset.u.LowPart)) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1788 | { |
| 1789 | res = STATUS_INVALID_PARAMETER; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1790 | goto done; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1791 | } |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1792 | if (*size_ptr) size = ROUND_SIZE( offset.u.LowPart, *size_ptr ); |
| 1793 | else size = size_low - offset.u.LowPart; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1794 | |
| 1795 | switch(protect) |
| 1796 | { |
| 1797 | case PAGE_NOACCESS: |
| 1798 | break; |
| 1799 | case PAGE_READWRITE: |
| 1800 | case PAGE_EXECUTE_READWRITE: |
| 1801 | if (!(prot & VPROT_WRITE)) |
| 1802 | { |
| 1803 | res = STATUS_INVALID_PARAMETER; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1804 | goto done; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1805 | } |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1806 | removable = FALSE; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1807 | /* fall through */ |
| 1808 | case PAGE_READONLY: |
| 1809 | case PAGE_WRITECOPY: |
| 1810 | case PAGE_EXECUTE: |
| 1811 | case PAGE_EXECUTE_READ: |
| 1812 | case PAGE_EXECUTE_WRITECOPY: |
| 1813 | if (prot & VPROT_READ) break; |
| 1814 | /* fall through */ |
| 1815 | default: |
| 1816 | res = STATUS_INVALID_PARAMETER; |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1817 | goto done; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1818 | } |
| 1819 | |
| 1820 | /* FIXME: If a mapping is created with SEC_RESERVE and a process, |
| 1821 | * which has a view of this mapping commits some pages, they will |
| 1822 | * appear commited in all other processes, which have the same |
| 1823 | * view created. Since we don`t support this yet, we create the |
| 1824 | * whole mapping commited. |
| 1825 | */ |
| 1826 | prot |= VPROT_COMMITTED; |
| 1827 | |
| 1828 | /* Reserve a properly aligned area */ |
| 1829 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1830 | RtlEnterCriticalSection( &csVirtual ); |
| 1831 | |
| 1832 | res = map_view( &view, *addr_ptr, size, prot ); |
| 1833 | if (res) |
| 1834 | { |
| 1835 | RtlLeaveCriticalSection( &csVirtual ); |
| 1836 | goto done; |
| 1837 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1838 | |
| 1839 | /* Map the file */ |
| 1840 | |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1841 | TRACE("handle=%p size=%lx offset=%lx%08lx\n", |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1842 | handle, size, offset.u.HighPart, offset.u.LowPart ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1843 | |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1844 | res = map_file_into_view( view, unix_handle, 0, size, offset.QuadPart, prot, removable ); |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1845 | if (res == STATUS_SUCCESS) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1846 | { |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1847 | if (!removable) /* don't keep handle open on removable media */ |
Ivan Leo Puoti | d3edafe | 2005-02-22 19:33:50 +0000 | [diff] [blame] | 1848 | NtDuplicateObject( NtCurrentProcess(), handle, |
| 1849 | NtCurrentProcess(), &view->mapping, |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1850 | 0, 0, DUPLICATE_SAME_ACCESS ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1851 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1852 | *addr_ptr = view->base; |
| 1853 | *size_ptr = size; |
| 1854 | } |
| 1855 | else |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1856 | { |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1857 | ERR( "map_file_into_view %p %lx %lx%08lx failed\n", |
Troy Rollo | 95fe6ab | 2005-04-19 10:31:28 +0000 | [diff] [blame] | 1858 | view->base, size, offset.u.HighPart, offset.u.LowPart ); |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1859 | delete_view( view ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1860 | } |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1861 | |
Alexandre Julliard | eb04fd2 | 2004-05-21 20:58:44 +0000 | [diff] [blame] | 1862 | RtlLeaveCriticalSection( &csVirtual ); |
| 1863 | |
| 1864 | done: |
Alexandre Julliard | f3f435f | 2003-12-01 23:01:12 +0000 | [diff] [blame] | 1865 | wine_server_release_fd( handle, unix_handle ); |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1866 | return res; |
| 1867 | } |
| 1868 | |
| 1869 | |
| 1870 | /*********************************************************************** |
| 1871 | * NtUnmapViewOfSection (NTDLL.@) |
| 1872 | * ZwUnmapViewOfSection (NTDLL.@) |
| 1873 | */ |
| 1874 | NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) |
| 1875 | { |
| 1876 | FILE_VIEW *view; |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1877 | NTSTATUS status = STATUS_INVALID_PARAMETER; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1878 | void *base = ROUND_ADDR( addr, page_mask ); |
| 1879 | |
| 1880 | if (!is_current_process( process )) |
| 1881 | { |
| 1882 | ERR("Unsupported on other process\n"); |
| 1883 | return STATUS_ACCESS_DENIED; |
| 1884 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1885 | RtlEnterCriticalSection( &csVirtual ); |
| 1886 | if ((view = VIRTUAL_FindView( base )) && (base == view->base)) |
| 1887 | { |
Alexandre Julliard | 94d74b5 | 2004-05-25 01:29:24 +0000 | [diff] [blame] | 1888 | delete_view( view ); |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1889 | status = STATUS_SUCCESS; |
| 1890 | } |
| 1891 | RtlLeaveCriticalSection( &csVirtual ); |
| 1892 | return status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1893 | } |
| 1894 | |
| 1895 | |
| 1896 | /*********************************************************************** |
| 1897 | * NtFlushVirtualMemory (NTDLL.@) |
| 1898 | * ZwFlushVirtualMemory (NTDLL.@) |
| 1899 | */ |
| 1900 | NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr, |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1901 | SIZE_T *size_ptr, ULONG unknown ) |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1902 | { |
| 1903 | FILE_VIEW *view; |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1904 | NTSTATUS status = STATUS_SUCCESS; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1905 | void *addr = ROUND_ADDR( *addr_ptr, page_mask ); |
| 1906 | |
| 1907 | if (!is_current_process( process )) |
| 1908 | { |
| 1909 | ERR("Unsupported on other process\n"); |
| 1910 | return STATUS_ACCESS_DENIED; |
| 1911 | } |
Alexandre Julliard | a2ce4ea | 2004-04-06 20:16:51 +0000 | [diff] [blame] | 1912 | RtlEnterCriticalSection( &csVirtual ); |
| 1913 | if (!(view = VIRTUAL_FindView( addr ))) status = STATUS_INVALID_PARAMETER; |
| 1914 | else |
| 1915 | { |
| 1916 | if (!*size_ptr) *size_ptr = view->size; |
| 1917 | *addr_ptr = addr; |
| 1918 | if (msync( addr, *size_ptr, MS_SYNC )) status = STATUS_NOT_MAPPED_DATA; |
| 1919 | } |
| 1920 | RtlLeaveCriticalSection( &csVirtual ); |
| 1921 | return status; |
Alexandre Julliard | 341b7dc | 2002-09-17 18:54:42 +0000 | [diff] [blame] | 1922 | } |
Alexandre Julliard | 4f4b980 | 2003-07-08 21:18:45 +0000 | [diff] [blame] | 1923 | |
| 1924 | |
| 1925 | /*********************************************************************** |
| 1926 | * NtReadVirtualMemory (NTDLL.@) |
| 1927 | * ZwReadVirtualMemory (NTDLL.@) |
| 1928 | */ |
| 1929 | NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buffer, |
| 1930 | SIZE_T size, SIZE_T *bytes_read ) |
| 1931 | { |
| 1932 | NTSTATUS status; |
| 1933 | |
| 1934 | SERVER_START_REQ( read_process_memory ) |
| 1935 | { |
| 1936 | req->handle = process; |
| 1937 | req->addr = (void *)addr; |
| 1938 | wine_server_set_reply( req, buffer, size ); |
| 1939 | if ((status = wine_server_call( req ))) size = 0; |
| 1940 | } |
| 1941 | SERVER_END_REQ; |
| 1942 | if (bytes_read) *bytes_read = size; |
| 1943 | return status; |
| 1944 | } |
| 1945 | |
| 1946 | |
| 1947 | /*********************************************************************** |
| 1948 | * NtWriteVirtualMemory (NTDLL.@) |
| 1949 | * ZwWriteVirtualMemory (NTDLL.@) |
| 1950 | */ |
| 1951 | NTSTATUS WINAPI NtWriteVirtualMemory( HANDLE process, void *addr, const void *buffer, |
| 1952 | SIZE_T size, SIZE_T *bytes_written ) |
| 1953 | { |
| 1954 | static const unsigned int zero; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1955 | SIZE_T first_offset, last_offset, first_mask, last_mask; |
Alexandre Julliard | 4f4b980 | 2003-07-08 21:18:45 +0000 | [diff] [blame] | 1956 | NTSTATUS status; |
| 1957 | |
| 1958 | if (!size) return STATUS_INVALID_PARAMETER; |
| 1959 | |
| 1960 | /* compute the mask for the first int */ |
| 1961 | first_mask = ~0; |
Dmitry Timoshkov | 1dc1895 | 2005-07-15 10:01:30 +0000 | [diff] [blame] | 1962 | first_offset = (ULONG_PTR)addr % sizeof(int); |
Alexandre Julliard | 4f4b980 | 2003-07-08 21:18:45 +0000 | [diff] [blame] | 1963 | memset( &first_mask, 0, first_offset ); |
| 1964 | |
| 1965 | /* compute the mask for the last int */ |
| 1966 | last_offset = (size + first_offset) % sizeof(int); |
| 1967 | last_mask = 0; |
| 1968 | memset( &last_mask, 0xff, last_offset ? last_offset : sizeof(int) ); |
| 1969 | |
| 1970 | SERVER_START_REQ( write_process_memory ) |
| 1971 | { |
| 1972 | req->handle = process; |
| 1973 | req->addr = (char *)addr - first_offset; |
| 1974 | req->first_mask = first_mask; |
| 1975 | req->last_mask = last_mask; |
| 1976 | if (first_offset) wine_server_add_data( req, &zero, first_offset ); |
| 1977 | wine_server_add_data( req, buffer, size ); |
| 1978 | if (last_offset) wine_server_add_data( req, &zero, sizeof(int) - last_offset ); |
| 1979 | |
| 1980 | if ((status = wine_server_call( req ))) size = 0; |
| 1981 | } |
| 1982 | SERVER_END_REQ; |
| 1983 | if (bytes_written) *bytes_written = size; |
| 1984 | return status; |
| 1985 | } |