[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / misc / usrheap.c
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
26 static NTSTATUS APIENTRY
27 IntUserHeapCommitRoutine(IN PVOID Base,
28 IN OUT PVOID *CommitAddress,
29 IN OUT PSIZE_T CommitSize)
30 {
31 PPROCESSINFO W32Process;
32 PW32HEAP_USER_MAPPING Mapping;
33 PVOID UserBase = NULL;
34 NTSTATUS Status;
35 SIZE_T Delta;
36 PVOID UserCommitAddress;
37
38 W32Process = PsGetCurrentProcessWin32Process();
39
40 if (W32Process != NULL)
41 {
42 /* Search for the mapping */
43 Mapping = &W32Process->HeapMappings;
44 while (Mapping != NULL)
45 {
46 if (Mapping->KernelMapping == Base)
47 {
48 UserBase = Mapping->UserMapping;
49 break;
50 }
51
52 Mapping = Mapping->Next;
53 }
54
55 ASSERT(UserBase != NULL);
56 }
57 else
58 {
59 SIZE_T ViewSize = 0;
60 LARGE_INTEGER Offset;
61 extern PSECTION_OBJECT GlobalUserHeapSection;
62
63 /* HACK: This needs to be handled during startup only... */
64 ASSERT(Base == (PVOID)GlobalUserHeap);
65
66 /* Temporarily map it into user space */
67 Offset.QuadPart = 0;
68 Status = MmMapViewOfSection(GlobalUserHeapSection,
69 PsGetCurrentProcess(),
70 &UserBase,
71 0,
72 0,
73 &Offset,
74 &ViewSize,
75 ViewUnmap,
76 SEC_NO_CHANGE,
77 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
78
79 if (!NT_SUCCESS(Status))
80 return Status;
81 }
82
83 /* Apply the commit address offset to the user base address */
84 Delta = (SIZE_T) ((ULONG_PTR) (*CommitAddress) - (ULONG_PTR) (Base));
85 UserCommitAddress = (PVOID) ((ULONG_PTR) (UserBase) + Delta);
86
87 /* Perform the actual commit */
88 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
89 &UserCommitAddress,
90 0,
91 CommitSize,
92 MEM_COMMIT,
93 PAGE_EXECUTE_READ);
94
95 if (NT_SUCCESS(Status))
96 {
97 /* Determine the address to return */
98 Delta = (SIZE_T) ((ULONG_PTR) (UserCommitAddress) - (ULONG_PTR) (UserBase));
99 *CommitAddress = (PVOID) ((ULONG_PTR) (Base) + Delta);
100 }
101
102 if (W32Process == NULL)
103 {
104 MmUnmapViewOfSection(PsGetCurrentProcess(),
105 UserBase);
106 }
107
108 return Status;
109 }
110
111 static PWIN32HEAP
112 IntUserHeapCreate(IN PSECTION_OBJECT SectionObject,
113 IN PVOID *SystemMappedBase,
114 IN ULONG HeapSize)
115 {
116 PVOID MappedView = NULL;
117 LARGE_INTEGER Offset;
118 SIZE_T ViewSize = PAGE_SIZE;
119 RTL_HEAP_PARAMETERS Parameters = {0};
120 PVOID pHeap;
121 NTSTATUS Status;
122
123 Offset.QuadPart = 0;
124
125 /* Commit the first page before creating the heap! */
126 Status = MmMapViewOfSection(SectionObject,
127 PsGetCurrentProcess(),
128 &MappedView,
129 0,
130 0,
131 &Offset,
132 &ViewSize,
133 ViewUnmap,
134 SEC_NO_CHANGE,
135 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
136 if (!NT_SUCCESS(Status))
137 return NULL;
138
139 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
140 &MappedView,
141 0,
142 &ViewSize,
143 MEM_COMMIT,
144 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
145
146 MmUnmapViewOfSection(PsGetCurrentProcess(),
147 MappedView);
148
149 if (!NT_SUCCESS(Status))
150 return NULL;
151
152 /* Create the heap, don't serialize in kmode! The caller is responsible
153 to synchronize the heap! */
154 Parameters.Length = sizeof(Parameters);
155 Parameters.InitialCommit = ViewSize;
156 Parameters.InitialReserve = (SIZE_T)HeapSize;
157 Parameters.CommitRoutine = IntUserHeapCommitRoutine;
158
159 pHeap = RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
160 *SystemMappedBase,
161 (SIZE_T)HeapSize,
162 ViewSize,
163 NULL,
164 &Parameters);
165
166 return pHeap;
167 }
168
169 PWIN32HEAP
170 UserCreateHeap(OUT PSECTION_OBJECT *SectionObject,
171 IN OUT PVOID *SystemBase,
172 IN SIZE_T HeapSize)
173 {
174 LARGE_INTEGER SizeHeap;
175 PWIN32HEAP pHeap = NULL;
176 NTSTATUS Status;
177
178 SizeHeap.QuadPart = HeapSize;
179
180 /* Create the section and map it into session space */
181 Status = MmCreateSection((PVOID*)SectionObject,
182 SECTION_ALL_ACCESS,
183 NULL,
184 &SizeHeap,
185 PAGE_EXECUTE_READWRITE, /* Would prefer PAGE_READWRITE, but thanks to RTL heaps... */
186 SEC_RESERVE,
187 NULL,
188 NULL);
189
190 if (!NT_SUCCESS(Status))
191 {
192 SetLastNtError(Status);
193 return FALSE;
194 }
195
196 Status = MmMapViewInSystemSpace(*SectionObject,
197 SystemBase,
198 &HeapSize);
199 if (!NT_SUCCESS(Status))
200 {
201 ObDereferenceObject(*SectionObject);
202 *SectionObject = NULL;
203
204 SetLastNtError(Status);
205 return FALSE;
206 }
207
208 /* Create the heap */
209 pHeap = IntUserHeapCreate(*SectionObject,
210 SystemBase,
211 HeapSize);
212
213 if (pHeap == NULL)
214 {
215 ObDereferenceObject(*SectionObject);
216 *SectionObject = NULL;
217
218 SetLastNtError(STATUS_UNSUCCESSFUL);
219 }
220
221 return pHeap;
222 }