- Sync with trunk up to r46941.
[reactos.git] / ntoskrnl / mm / procsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/procsup.c
5 * PURPOSE: Memory functions related to Processes
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 PVOID
19 NTAPI
20 MiCreatePebOrTeb(PEPROCESS Process,
21 PVOID BaseAddress)
22 {
23 NTSTATUS Status;
24 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
25 PMEMORY_AREA MemoryArea;
26 PHYSICAL_ADDRESS BoundaryAddressMultiple;
27 PVOID AllocatedBase = BaseAddress;
28 BoundaryAddressMultiple.QuadPart = 0;
29
30 /* Acquire the Lock */
31 MmLockAddressSpace(ProcessAddressSpace);
32
33 /*
34 * Create a Peb or Teb.
35 * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
36 * is that a PEB allocation should never fail since the address is free,
37 * while TEB allocation can fail, and we should simply try the address
38 * below. Is there a nicer way of doing this automagically? (ie: findning)
39 * a gap region? -- Alex
40 */
41 do {
42 DPRINT("Trying to allocate: %x\n", AllocatedBase);
43 Status = MmCreateMemoryArea(ProcessAddressSpace,
44 MEMORY_AREA_PEB_OR_TEB,
45 &AllocatedBase,
46 PAGE_SIZE,
47 PAGE_READWRITE,
48 &MemoryArea,
49 TRUE,
50 0,
51 BoundaryAddressMultiple);
52 AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
53 } while (Status != STATUS_SUCCESS);
54
55 /* Initialize the Region */
56 MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
57 PAGE_SIZE,
58 MEM_COMMIT,
59 PAGE_READWRITE);
60
61 /* Reserve the pages */
62 MmReserveSwapPages(PAGE_SIZE);
63
64 /* Unlock Address Space */
65 DPRINT("Returning\n");
66 MmUnlockAddressSpace(ProcessAddressSpace);
67 return RVA(AllocatedBase, PAGE_SIZE);
68 }
69
70 VOID
71 NTAPI
72 MmDeleteTeb(PEPROCESS Process,
73 PTEB Teb)
74 {
75 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
76 PMEMORY_AREA MemoryArea;
77
78 /* Lock the Address Space */
79 MmLockAddressSpace(ProcessAddressSpace);
80
81 MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
82 if (MemoryArea)
83 {
84 /* Delete the Teb */
85 MmFreeVirtualMemory(Process, MemoryArea);
86 }
87
88 /* Unlock the Address Space */
89 MmUnlockAddressSpace(ProcessAddressSpace);
90 }
91
92 NTSTATUS
93 NTAPI
94 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
95 {
96 PVOID BaseAddress;
97 PMEMORY_AREA MemoryArea;
98 PHYSICAL_ADDRESS BoundaryAddressMultiple;
99 NTSTATUS Status;
100 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
101 BoundaryAddressMultiple.QuadPart = 0;
102
103 /* Create the shared data page */
104 BaseAddress = (PVOID)USER_SHARED_DATA;
105 Status = MmCreateMemoryArea(ProcessAddressSpace,
106 MEMORY_AREA_SHARED_DATA,
107 &BaseAddress,
108 PAGE_SIZE,
109 PAGE_EXECUTE_READ,
110 &MemoryArea,
111 FALSE,
112 0,
113 BoundaryAddressMultiple);
114 return Status;
115 }
116
117 NTSTATUS
118 NTAPI
119 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
120 IN PEPROCESS ProcessClone OPTIONAL,
121 IN PVOID Section OPTIONAL,
122 IN OUT PULONG Flags,
123 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
124 {
125 NTSTATUS Status;
126 PMMSUPPORT ProcessAddressSpace = &Process->Vm;
127 PVOID BaseAddress;
128 PMEMORY_AREA MemoryArea;
129 PHYSICAL_ADDRESS BoundaryAddressMultiple;
130 SIZE_T ViewSize = 0;
131 PVOID ImageBase = 0;
132 PROS_SECTION_OBJECT SectionObject = Section;
133 BoundaryAddressMultiple.QuadPart = 0;
134
135 /* Initialize the Addresss Space lock */
136 KeInitializeGuardedMutex(&Process->AddressCreationLock);
137 Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
138
139 /* Initialize AVL tree */
140 ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
141 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
142
143 /* Acquire the Lock */
144 MmLockAddressSpace(ProcessAddressSpace);
145
146 /* Protect the highest 64KB of the process address space */
147 BaseAddress = (PVOID)MmUserProbeAddress;
148 Status = MmCreateMemoryArea(ProcessAddressSpace,
149 MEMORY_AREA_NO_ACCESS,
150 &BaseAddress,
151 0x10000,
152 PAGE_NOACCESS,
153 &MemoryArea,
154 FALSE,
155 0,
156 BoundaryAddressMultiple);
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT1("Failed to protect last 64KB\n");
160 goto exit;
161 }
162
163 /* Protect the 60KB above the shared user page */
164 BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
165 Status = MmCreateMemoryArea(ProcessAddressSpace,
166 MEMORY_AREA_NO_ACCESS,
167 &BaseAddress,
168 0x10000 - PAGE_SIZE,
169 PAGE_NOACCESS,
170 &MemoryArea,
171 FALSE,
172 0,
173 BoundaryAddressMultiple);
174 if (!NT_SUCCESS(Status))
175 {
176 DPRINT1("Failed to protect the memory above the shared user page\n");
177 goto exit;
178 }
179
180 /* Create the shared data page */
181 BaseAddress = (PVOID)USER_SHARED_DATA;
182 Status = MmCreateMemoryArea(ProcessAddressSpace,
183 MEMORY_AREA_SHARED_DATA,
184 &BaseAddress,
185 PAGE_SIZE,
186 PAGE_EXECUTE_READ,
187 &MemoryArea,
188 FALSE,
189 0,
190 BoundaryAddressMultiple);
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT1("Failed to create Shared User Data\n");
194 goto exit;
195 }
196
197 /* The process now has an address space */
198 Process->HasAddressSpace = TRUE;
199
200 /* Check if there's a Section Object */
201 if (SectionObject)
202 {
203 UNICODE_STRING FileName;
204 PWCHAR szSrc;
205 PCHAR szDest;
206 USHORT lnFName = 0;
207
208 /* Unlock the Address Space */
209 DPRINT("Unlocking\n");
210 MmUnlockAddressSpace(ProcessAddressSpace);
211
212 DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
213 SectionObject, Process, &ImageBase);
214 Status = MmMapViewOfSection(Section,
215 (PEPROCESS)Process,
216 (PVOID*)&ImageBase,
217 0,
218 0,
219 NULL,
220 &ViewSize,
221 0,
222 MEM_COMMIT,
223 PAGE_READWRITE);
224 if (!NT_SUCCESS(Status))
225 {
226 DPRINT1("Failed to map process Image\n");
227 return Status;
228 }
229
230 /* Save the pointer */
231 Process->SectionBaseAddress = ImageBase;
232
233 /* Determine the image file name and save it to EPROCESS */
234 DPRINT("Getting Image name\n");
235 FileName = SectionObject->FileObject->FileName;
236 szSrc = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
237 if (FileName.Buffer)
238 {
239 /* Loop the file name*/
240 while (szSrc > FileName.Buffer)
241 {
242 /* Make sure this isn't a backslash */
243 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
244 {
245 /* If so, stop it here */
246 szSrc++;
247 break;
248 }
249 else
250 {
251 /* Otherwise, keep going */
252 lnFName++;
253 }
254 }
255 }
256
257 /* Copy the to the process and truncate it to 15 characters if necessary */
258 szDest = Process->ImageFileName;
259 lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
260 while (lnFName--) *szDest++ = (UCHAR)*szSrc++;
261 *szDest = ANSI_NULL;
262
263 /* Check if caller wants an audit name */
264 if (AuditName)
265 {
266 /* Setup the audit name */
267 SeInitializeProcessAuditName(SectionObject->FileObject,
268 FALSE,
269 AuditName);
270 }
271
272 /* Return status to caller */
273 return Status;
274 }
275
276 exit:
277 /* Unlock the Address Space */
278 DPRINT("Unlocking\n");
279 MmUnlockAddressSpace(ProcessAddressSpace);
280
281 /* Return status to caller */
282 return Status;
283 }
284
285 VOID
286 NTAPI
287 MmCleanProcessAddressSpace(IN PEPROCESS Process)
288 {
289 /* FIXME: Add part of MmDeleteProcessAddressSpace here */
290 }
291
292 NTSTATUS
293 NTAPI
294 MmDeleteProcessAddressSpace(PEPROCESS Process)
295 {
296 PVOID Address;
297 PMEMORY_AREA MemoryArea;
298
299 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
300 Process->ImageFileName);
301
302 MmLockAddressSpace(&Process->Vm);
303
304 while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
305 {
306 switch (MemoryArea->Type)
307 {
308 case MEMORY_AREA_SECTION_VIEW:
309 Address = (PVOID)MemoryArea->StartingAddress;
310 MmUnlockAddressSpace(&Process->Vm);
311 MmUnmapViewOfSection(Process, Address);
312 MmLockAddressSpace(&Process->Vm);
313 break;
314
315 case MEMORY_AREA_VIRTUAL_MEMORY:
316 case MEMORY_AREA_PEB_OR_TEB:
317 MmFreeVirtualMemory(Process, MemoryArea);
318 break;
319
320 case MEMORY_AREA_SHARED_DATA:
321 case MEMORY_AREA_NO_ACCESS:
322 MmFreeMemoryArea(&Process->Vm,
323 MemoryArea,
324 NULL,
325 NULL);
326 break;
327
328 case MEMORY_AREA_MDL_MAPPING:
329 KeBugCheck(PROCESS_HAS_LOCKED_PAGES);
330 break;
331
332 default:
333 KeBugCheck(MEMORY_MANAGEMENT);
334 }
335 }
336
337 Mmi386ReleaseMmInfo(Process);
338
339 MmUnlockAddressSpace(&Process->Vm);
340
341 DPRINT("Finished MmReleaseMmInfo()\n");
342 return(STATUS_SUCCESS);
343 }
344