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