1 /* 2 * ReactOS W32 Subsystem 3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #include <win32k.h> 21 22 #define NDEBUG 23 #include <debug.h> 24 25 HANDLE GlobalUserHeap = NULL; 26 PVOID GlobalUserHeapSection = NULL; 27 28 29 _Function_class_(RTL_HEAP_COMMIT_ROUTINE) 30 _IRQL_requires_same_ 31 static 32 NTSTATUS 33 NTAPI 34 IntUserHeapCommitRoutine( 35 _In_ PVOID Base, 36 _Inout_ PVOID *CommitAddress, 37 _Inout_ PSIZE_T CommitSize) 38 { 39 PPROCESSINFO W32Process; 40 PW32HEAP_USER_MAPPING Mapping; 41 PVOID UserBase = NULL; 42 NTSTATUS Status; 43 SIZE_T Delta; 44 PVOID UserCommitAddress; 45 46 W32Process = PsGetCurrentProcessWin32Process(); 47 48 if (W32Process != NULL) 49 { 50 /* Search for the mapping */ 51 Mapping = &W32Process->HeapMappings; 52 while (Mapping != NULL) 53 { 54 if (Mapping->KernelMapping == Base) 55 { 56 UserBase = Mapping->UserMapping; 57 break; 58 } 59 60 Mapping = Mapping->Next; 61 } 62 63 ASSERT(UserBase != NULL); 64 } 65 else 66 { 67 SIZE_T ViewSize = 0; 68 LARGE_INTEGER Offset; 69 70 /* HACK: This needs to be handled during startup only... */ 71 ASSERT(Base == (PVOID)GlobalUserHeap); 72 73 /* Temporarily map it into user space */ 74 Offset.QuadPart = 0; 75 Status = MmMapViewOfSection(GlobalUserHeapSection, 76 PsGetCurrentProcess(), 77 &UserBase, 78 0, 79 0, 80 &Offset, 81 &ViewSize, 82 ViewUnmap, 83 SEC_NO_CHANGE, 84 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */ 85 86 if (!NT_SUCCESS(Status)) 87 return Status; 88 } 89 90 /* Apply the commit address offset to the user base address */ 91 Delta = (SIZE_T)((ULONG_PTR)(*CommitAddress) - (ULONG_PTR)Base); 92 UserCommitAddress = (PVOID)((ULONG_PTR)UserBase + Delta); 93 94 /* Perform the actual commit */ 95 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 96 &UserCommitAddress, 97 0, 98 CommitSize, 99 MEM_COMMIT, 100 PAGE_EXECUTE_READ); 101 102 if (NT_SUCCESS(Status)) 103 { 104 /* Determine the address to return */ 105 Delta = (SIZE_T)((ULONG_PTR)UserCommitAddress - (ULONG_PTR)UserBase); 106 *CommitAddress = (PVOID)((ULONG_PTR)Base + Delta); 107 } 108 109 if (W32Process == NULL) 110 { 111 MmUnmapViewOfSection(PsGetCurrentProcess(), 112 UserBase); 113 } 114 115 return Status; 116 } 117 118 static PWIN32HEAP 119 IntUserHeapCreate(IN PVOID SectionObject, 120 IN PVOID *SystemMappedBase, 121 IN ULONG HeapSize) 122 { 123 PVOID MappedView = NULL; 124 LARGE_INTEGER Offset; 125 SIZE_T ViewSize = PAGE_SIZE; 126 RTL_HEAP_PARAMETERS Parameters = {0}; 127 PVOID pHeap; 128 NTSTATUS Status; 129 130 Offset.QuadPart = 0; 131 132 /* Commit the first page before creating the heap! */ 133 Status = MmMapViewOfSection(SectionObject, 134 PsGetCurrentProcess(), 135 &MappedView, 136 0, 137 0, 138 &Offset, 139 &ViewSize, 140 ViewUnmap, 141 SEC_NO_CHANGE, 142 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */ 143 if (!NT_SUCCESS(Status)) 144 return NULL; 145 146 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 147 &MappedView, 148 0, 149 &ViewSize, 150 MEM_COMMIT, 151 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */ 152 153 MmUnmapViewOfSection(PsGetCurrentProcess(), 154 MappedView); 155 156 if (!NT_SUCCESS(Status)) 157 return NULL; 158 159 /* Create the heap, don't serialize in kmode! The caller is responsible 160 to synchronize the heap! */ 161 Parameters.Length = sizeof(Parameters); 162 Parameters.InitialCommit = ViewSize; 163 Parameters.InitialReserve = (SIZE_T)HeapSize; 164 Parameters.CommitRoutine = IntUserHeapCommitRoutine; 165 166 pHeap = RtlCreateHeap( 167 #if DBG /* Enable checks on debug builds */ 168 HEAP_FREE_CHECKING_ENABLED | HEAP_TAIL_CHECKING_ENABLED | 169 #endif 170 HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, 171 *SystemMappedBase, 172 (SIZE_T)HeapSize, 173 ViewSize, 174 NULL, 175 &Parameters); 176 177 return pHeap; 178 } 179 180 PWIN32HEAP 181 UserCreateHeap(OUT PVOID *SectionObject, 182 IN OUT PVOID *SystemBase, 183 IN SIZE_T HeapSize) 184 { 185 LARGE_INTEGER SizeHeap; 186 PWIN32HEAP pHeap = NULL; 187 NTSTATUS Status; 188 189 SizeHeap.QuadPart = HeapSize; 190 191 /* Create the section and map it into session space */ 192 Status = MmCreateSection((PVOID*)SectionObject, 193 SECTION_ALL_ACCESS, 194 NULL, 195 &SizeHeap, 196 PAGE_EXECUTE_READWRITE, /* Would prefer PAGE_READWRITE, but thanks to RTL heaps... */ 197 SEC_RESERVE | 1, 198 NULL, 199 NULL); 200 201 if (!NT_SUCCESS(Status)) 202 { 203 SetLastNtError(Status); 204 return FALSE; 205 } 206 207 Status = MmMapViewInSessionSpace(*SectionObject, 208 SystemBase, 209 &HeapSize); 210 if (!NT_SUCCESS(Status)) 211 { 212 ObDereferenceObject(*SectionObject); 213 *SectionObject = NULL; 214 215 SetLastNtError(Status); 216 return FALSE; 217 } 218 219 /* Create the heap */ 220 pHeap = IntUserHeapCreate(*SectionObject, 221 SystemBase, 222 HeapSize); 223 224 if (pHeap == NULL) 225 { 226 ObDereferenceObject(*SectionObject); 227 *SectionObject = NULL; 228 229 SetLastNtError(STATUS_UNSUCCESSFUL); 230 } 231 232 return pHeap; 233 } 234 235 NTSTATUS 236 UnmapGlobalUserHeap(IN PEPROCESS Process) 237 { 238 NTSTATUS Status = STATUS_SUCCESS; 239 PPROCESSINFO W32Process; 240 PW32HEAP_USER_MAPPING HeapMapping; 241 242 TRACE_CH(UserProcess, "IntUnmapDesktopView called for process 0x%p\n", Process); 243 244 W32Process = PsGetProcessWin32Process(Process); 245 if (W32Process == NULL) 246 { 247 ERR_CH(UserProcess, "UnmapGlobalUserHeap - We don't have a Win32 process!\n"); 248 ASSERT(FALSE); 249 } 250 251 /* The first mapping entry must be the global user heap */ 252 HeapMapping = &W32Process->HeapMappings; 253 ASSERT(HeapMapping->KernelMapping == (PVOID)GlobalUserHeap); 254 255 /* Unmap if we're the last thread using the global user heap */ 256 if (--HeapMapping->Count == 0) 257 { 258 TRACE_CH(UserProcess, "UnmapGlobalUserHeap - Unmapping\n"); 259 Status = MmUnmapViewOfSection(Process, HeapMapping->UserMapping); 260 } 261 262 return Status; 263 } 264 265 NTSTATUS 266 MapGlobalUserHeap(IN PEPROCESS Process, 267 OUT PVOID* KernelMapping, 268 OUT PVOID* UserMapping) 269 { 270 NTSTATUS Status; 271 PPROCESSINFO W32Process; 272 PW32HEAP_USER_MAPPING HeapMapping; 273 PVOID UserBase = NULL; 274 275 SIZE_T ViewSize = 0; 276 LARGE_INTEGER Offset; 277 278 TRACE_CH(UserProcess, "MapGlobalUserHeap called for process 0x%p\n", Process); 279 280 W32Process = PsGetProcessWin32Process(Process); 281 if (W32Process == NULL) 282 { 283 ERR_CH(UserProcess, "MapGlobalUserHeap - We don't have a Win32 process!\n"); 284 ASSERT(FALSE); 285 } 286 287 TRACE_CH(UserProcess, "MapGlobalUserHeap - We got a Win32 process, find for existing global user heap mapping...\n"); 288 289 /* The first mapping entry must be the global user heap */ 290 HeapMapping = &W32Process->HeapMappings; 291 292 /* Find out if another thread already mapped the global user heap */ 293 if (HeapMapping->KernelMapping == (PVOID)GlobalUserHeap) 294 { 295 HeapMapping->Count++; 296 297 TRACE_CH(UserProcess, "MapGlobalUserHeap - A mapping was found, return it.\n"); 298 299 *KernelMapping = HeapMapping->KernelMapping; 300 *UserMapping = HeapMapping->UserMapping; 301 302 return STATUS_SUCCESS; 303 } 304 305 TRACE_CH(UserProcess, "MapGlobalUserHeap - No mapping was found, let's map...\n"); 306 307 /* We're the first, map the global heap into the process */ 308 Offset.QuadPart = 0; 309 Status = MmMapViewOfSection(GlobalUserHeapSection, 310 Process, 311 &UserBase, 312 0, 313 0, 314 &Offset, 315 &ViewSize, 316 ViewUnmap, 317 SEC_NO_CHANGE, 318 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */ 319 if (!NT_SUCCESS(Status)) 320 { 321 ERR_CH(UserProcess, "MapGlobalUserHeap - Failed to map the global heap! 0x%x\n", Status); 322 return Status; 323 } 324 325 TRACE_CH(UserProcess, "MapGlobalUserHeap -- Mapped kernel global heap 0x%p to user space at 0x%p\n", 326 GlobalUserHeap, UserBase); 327 328 /* Add the mapping */ 329 HeapMapping->Next = NULL; 330 HeapMapping->KernelMapping = (PVOID)GlobalUserHeap; 331 HeapMapping->UserMapping = UserBase; 332 HeapMapping->Limit = ViewSize; 333 HeapMapping->Count = 1; 334 335 *KernelMapping = HeapMapping->KernelMapping; 336 *UserMapping = HeapMapping->UserMapping; 337 338 return STATUS_SUCCESS; 339 } 340 341 /* EOF */ 342