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