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
_Function_class_(RTL_HEAP_COMMIT_ROUTINE)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_READONLY);
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_READONLY);
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
IntUserHeapCreate(IN PVOID SectionObject,IN PVOID * SystemMappedBase,IN ULONG HeapSize)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_READONLY);
143 if (!NT_SUCCESS(Status))
144 return NULL;
145
146 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
147 &MappedView,
148 0,
149 &ViewSize,
150 MEM_COMMIT,
151 PAGE_READONLY);
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
UserCreateHeap(OUT PVOID * SectionObject,IN OUT PVOID * SystemBase,IN SIZE_T HeapSize)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_READWRITE,
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
UnmapGlobalUserHeap(IN PEPROCESS Process)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
MapGlobalUserHeap(IN PEPROCESS Process,OUT PVOID * KernelMapping,OUT PVOID * UserMapping)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_READONLY);
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