Synchronize with trunk r58457.
[reactos.git] / win32ss / gdi / eng / mapping.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for mapping files and sections
5 * FILE: subsys/win32k/eng/device.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 HANDLE ghSystem32Directory;
15 HANDLE ghRootDirectory;
16
17 PVOID
18 NTAPI
19 EngMapSectionView(
20 _In_ HANDLE hSection,
21 _In_ SIZE_T cjSize,
22 _In_ ULONG cjOffset,
23 _Out_ PHANDLE phSecure)
24 {
25 LARGE_INTEGER liSectionOffset;
26 PVOID pvBaseAddress;
27 NTSTATUS Status;
28
29 /* Align the offset at allocation granularity and compensate for the size */
30 liSectionOffset.QuadPart = cjOffset & ~(MM_ALLOCATION_GRANULARITY - 1);
31 cjSize += cjOffset & (MM_ALLOCATION_GRANULARITY - 1);
32
33 /* Map the section */
34 Status = ZwMapViewOfSection(hSection,
35 NtCurrentProcess(),
36 &pvBaseAddress,
37 0,
38 cjSize,
39 &liSectionOffset,
40 &cjSize,
41 ViewShare,
42 0,
43 PAGE_READWRITE);
44 if (!NT_SUCCESS(Status))
45 {
46 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
47 return NULL;
48 }
49
50 /* Secure the section memory */
51 *phSecure = EngSecureMem(pvBaseAddress, cjSize);
52 if (!*phSecure)
53 {
54 ZwUnmapViewOfSection(NtCurrentProcess(), pvBaseAddress);
55 return NULL;
56 }
57
58 /* Return the address where the requested data starts */
59 return (PUCHAR)pvBaseAddress + (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
60 }
61
62 VOID
63 NTAPI
64 EngUnmapSectionView(
65 _In_ PVOID pvBits,
66 _In_ ULONG cjOffset,
67 _In_ HANDLE hSecure)
68 {
69 NTSTATUS Status;
70
71 /* Unsecure the memory */
72 EngUnsecureMem(hSecure);
73
74 /* Calculate the real start of the section view */
75 pvBits = (PUCHAR)pvBits - (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
76
77 /* Unmap the section view */
78 Status = MmUnmapViewOfSection(PsGetCurrentProcess(), pvBits);
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT1("Could not unmap section view!\n");
82 }
83 }
84
85
86 PVOID
87 NTAPI
88 EngCreateSection(
89 IN ULONG fl,
90 IN SIZE_T cjSize,
91 IN ULONG ulTag)
92 {
93 NTSTATUS Status;
94 PENGSECTION pSection;
95 PVOID pvSectionObject;
96 LARGE_INTEGER liSize;
97
98 /* Allocate a section object */
99 pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
100 if (!pSection) return NULL;
101
102 liSize.QuadPart = cjSize;
103 Status = MmCreateSection(&pvSectionObject,
104 SECTION_ALL_ACCESS,
105 NULL,
106 &liSize,
107 PAGE_READWRITE,
108 SEC_COMMIT,
109 NULL,
110 NULL);
111 if (!NT_SUCCESS(Status))
112 {
113 DPRINT1("Failed to create a section Status=0x%x\n", Status);
114 EngFreeMem(pSection);
115 return NULL;
116 }
117
118 /* Set the fields of the section */
119 pSection->ulTag = ulTag;
120 pSection->pvSectionObject = pvSectionObject;
121 pSection->pvMappedBase = NULL;
122 pSection->cjViewSize = cjSize;
123
124 return pSection;
125 }
126
127 PVOID
128 NTAPI
129 EngCreateSectionHack(
130 IN ULONG fl,
131 IN SIZE_T cjSize,
132 IN ULONG ulTag)
133 {
134 NTSTATUS Status;
135 PENGSECTION pSection;
136 PVOID pvSectionObject;
137 LARGE_INTEGER liSize;
138
139 /* Allocate a section object */
140 pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
141 if (!pSection) return NULL;
142
143 liSize.QuadPart = cjSize;
144 Status = MmCreateSection(&pvSectionObject,
145 SECTION_ALL_ACCESS,
146 NULL,
147 &liSize,
148 PAGE_READWRITE,
149 SEC_COMMIT | 1,
150 NULL,
151 NULL);
152 if (!NT_SUCCESS(Status))
153 {
154 DPRINT1("Failed to create a section Status=0x%x\n", Status);
155 EngFreeMem(pSection);
156 return NULL;
157 }
158
159 /* Set the fields of the section */
160 pSection->ulTag = ulTag;
161 pSection->pvSectionObject = pvSectionObject;
162 pSection->pvMappedBase = NULL;
163 pSection->cjViewSize = cjSize;
164
165 return pSection;
166 }
167
168
169
170 BOOL
171 APIENTRY
172 EngMapSection(
173 IN PVOID pvSection,
174 IN BOOL bMap,
175 IN HANDLE hProcess,
176 OUT PVOID* pvBaseAddress)
177 {
178 NTSTATUS Status;
179 PENGSECTION pSection = pvSection;
180 PEPROCESS pepProcess;
181
182 /* Get a pointer to the process */
183 Status = ObReferenceObjectByHandle(hProcess,
184 PROCESS_VM_OPERATION,
185 NULL,
186 KernelMode,
187 (PVOID*)&pepProcess,
188 NULL);
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT1("Could not access process %p, Status=0x%lx\n", hProcess, Status);
192 return FALSE;
193 }
194
195 if (bMap)
196 {
197 /* Make sure the section isn't already mapped */
198 ASSERT(pSection->pvMappedBase == NULL);
199
200 /* Map the section into the process address space */
201 Status = MmMapViewOfSection(pSection->pvSectionObject,
202 pepProcess,
203 &pSection->pvMappedBase,
204 0,
205 pSection->cjViewSize,
206 NULL,
207 &pSection->cjViewSize,
208 0,
209 0,
210 PAGE_READWRITE);
211 if (!NT_SUCCESS(Status))
212 {
213 DPRINT1("Failed to map a section Status=0x%x\n", Status);
214 }
215 }
216 else
217 {
218 /* Make sure the section is mapped */
219 ASSERT(pSection->pvMappedBase);
220
221 /* Unmap the section from the process address space */
222 Status = MmUnmapViewOfSection(pepProcess, pSection->pvMappedBase);
223 if (NT_SUCCESS(Status))
224 {
225 pSection->pvMappedBase = NULL;
226 }
227 else
228 {
229 DPRINT1("Failed to unmap a section @ %p Status=0x%x\n",
230 pSection->pvMappedBase, Status);
231 }
232 }
233
234 /* Dereference the process */
235 ObDereferenceObject(pepProcess);
236
237 /* Set the new mapping base and return bool status */
238 *pvBaseAddress = pSection->pvMappedBase;
239 return NT_SUCCESS(Status);
240 }
241
242 BOOL
243 APIENTRY
244 EngFreeSectionMem(
245 IN PVOID pvSection OPTIONAL,
246 IN PVOID pvMappedBase OPTIONAL)
247 {
248 NTSTATUS Status;
249 PENGSECTION pSection = pvSection;
250 BOOL bResult = TRUE;
251
252 /* Did the caller give us a mapping base? */
253 if (pvMappedBase)
254 {
255 Status = MmUnmapViewInSessionSpace(pvMappedBase);
256 if (!NT_SUCCESS(Status))
257 {
258 DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
259 bResult = FALSE;
260 }
261 }
262
263 /* Check if we should free the section as well */
264 if (pSection)
265 {
266 /* Dereference the kernel section */
267 ObDereferenceObject(pSection->pvSectionObject);
268
269 /* Finally free the section memory itself */
270 EngFreeMem(pSection);
271 }
272
273 return bResult;
274 }
275
276 PVOID
277 APIENTRY
278 EngAllocSectionMem(
279 OUT PVOID *ppvSection,
280 IN ULONG fl,
281 IN SIZE_T cjSize,
282 IN ULONG ulTag)
283 {
284 NTSTATUS Status;
285 PENGSECTION pSection;
286
287 /* Check parameter */
288 if (cjSize == 0) return NULL;
289
290 /* Allocate a section object */
291 pSection = EngCreateSectionHack(fl, cjSize, ulTag);
292 if (!pSection)
293 {
294 *ppvSection = NULL;
295 return NULL;
296 }
297
298 /* Map the section in session space */
299 Status = MmMapViewInSessionSpace(pSection->pvSectionObject,
300 &pSection->pvMappedBase,
301 &pSection->cjViewSize);
302 if (!NT_SUCCESS(Status))
303 {
304 DPRINT1("Failed to map a section Status=0x%x\n", Status);
305 *ppvSection = NULL;
306 EngFreeSectionMem(pSection, NULL);
307 return NULL;
308 }
309
310 if (fl & FL_ZERO_MEMORY)
311 {
312 RtlZeroMemory(pSection->pvMappedBase, cjSize);
313 }
314
315 /* Set section pointer and return base address */
316 *ppvSection = pSection;
317 return pSection->pvMappedBase;
318 }
319
320
321 PFILEVIEW
322 NTAPI
323 EngLoadModuleEx(
324 LPWSTR pwsz,
325 ULONG cjSizeOfModule,
326 FLONG fl)
327 {
328 PFILEVIEW pFileView = NULL;
329 OBJECT_ATTRIBUTES ObjectAttributes;
330 HANDLE hRootDir;
331 UNICODE_STRING ustrFileName;
332 IO_STATUS_BLOCK IoStatusBlock;
333 FILE_BASIC_INFORMATION FileInformation;
334 HANDLE hFile;
335 NTSTATUS Status;
336 LARGE_INTEGER liSize;
337
338 if (fl & FVF_FONTFILE)
339 {
340 pFileView = EngAllocMem(0, sizeof(FONTFILEVIEW), 'vffG');
341 }
342 else
343 {
344 pFileView = EngAllocMem(0, sizeof(FILEVIEW), 'liFg');
345 }
346
347 /* Check for success */
348 if (!pFileView) return NULL;
349
350 /* Check if the file is relative to system32 */
351 if (fl & FVF_SYSTEMROOT)
352 {
353 hRootDir = ghSystem32Directory;
354 }
355 else
356 {
357 hRootDir = ghRootDirectory;
358 }
359
360 /* Initialize unicode string and object attributes */
361 RtlInitUnicodeString(&ustrFileName, pwsz);
362 InitializeObjectAttributes(&ObjectAttributes,
363 &ustrFileName,
364 OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
365 hRootDir,
366 NULL);
367
368 /* Now open the file */
369 Status = ZwCreateFile(&hFile,
370 FILE_READ_DATA,
371 &ObjectAttributes,
372 &IoStatusBlock,
373 NULL,
374 FILE_ATTRIBUTE_NORMAL,
375 0,
376 FILE_OPEN,
377 FILE_NON_DIRECTORY_FILE,
378 NULL,
379 0);
380
381 Status = ZwQueryInformationFile(hFile,
382 &IoStatusBlock,
383 &FileInformation,
384 sizeof(FILE_BASIC_INFORMATION),
385 FileBasicInformation);
386 if (NT_SUCCESS(Status))
387 {
388 pFileView->LastWriteTime = FileInformation.LastWriteTime;
389 }
390
391 /* Create a section from the file */
392 liSize.QuadPart = cjSizeOfModule;
393 Status = MmCreateSection(&pFileView->pSection,
394 SECTION_ALL_ACCESS,
395 NULL,
396 &liSize,
397 fl & FVF_READONLY ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
398 SEC_COMMIT,
399 hFile,
400 NULL);
401
402 /* Close the file handle */
403 ZwClose(hFile);
404
405 if (!NT_SUCCESS(Status))
406 {
407 DPRINT1("Failed to create a section Status=0x%x\n", Status);
408 EngFreeMem(pFileView);
409 return NULL;
410 }
411
412
413 pFileView->pvKView = NULL;
414 pFileView->pvViewFD = NULL;
415 pFileView->cjView = 0;
416
417 return pFileView;
418 }
419
420 HANDLE
421 APIENTRY
422 EngLoadModule(
423 _In_ LPWSTR pwsz)
424 {
425 /* Forward to EngLoadModuleEx */
426 return (HANDLE)EngLoadModuleEx(pwsz, 0, FVF_READONLY | FVF_SYSTEMROOT);
427 }
428
429 HANDLE
430 APIENTRY
431 EngLoadModuleForWrite(
432 _In_ LPWSTR pwsz,
433 _In_ ULONG cjSizeOfModule)
434 {
435 /* Forward to EngLoadModuleEx */
436 return (HANDLE)EngLoadModuleEx(pwsz, cjSizeOfModule, FVF_SYSTEMROOT);
437 }
438
439 PVOID
440 APIENTRY
441 EngMapModule(
442 _In_ HANDLE h,
443 _Out_ PULONG pulSize)
444 {
445 PFILEVIEW pFileView = (PFILEVIEW)h;
446 NTSTATUS Status;
447
448 pFileView->cjView = 0;
449
450 /* FIXME: Use system space because ARM3 doesn't support executable sections yet */
451 Status = MmMapViewInSystemSpace(pFileView->pSection,
452 &pFileView->pvKView,
453 &pFileView->cjView);
454 if (!NT_SUCCESS(Status))
455 {
456 DPRINT1("Failed to map a section Status=0x%x\n", Status);
457 *pulSize = 0;
458 return NULL;
459 }
460
461 *pulSize = (ULONG)pFileView->cjView;
462 return pFileView->pvKView;
463 }
464
465 VOID
466 APIENTRY
467 EngFreeModule(
468 _In_ HANDLE h)
469 {
470 PFILEVIEW pFileView = (PFILEVIEW)h;
471 NTSTATUS Status;
472
473 /* FIXME: Use system space because ARM3 doesn't support executable sections yet */
474 Status = MmUnmapViewInSystemSpace(pFileView->pvKView);
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
478 ASSERT(FALSE);
479 }
480
481 /* Dereference the section */
482 ObDereferenceObject(pFileView->pSection);
483
484 /* Free the file view memory */
485 EngFreeMem(pFileView);
486 }
487
488 _Success_(return != 0)
489 _When_(cjSize != 0, _At_(return, _Out_writes_bytes_(cjSize)))
490 PVOID
491 APIENTRY
492 EngMapFile(
493 _In_ LPWSTR pwsz,
494 _In_ ULONG cjSize,
495 _Out_ ULONG_PTR *piFile)
496 {
497 HANDLE hModule;
498 PVOID pvBase;
499
500 /* Load the file */
501 hModule = EngLoadModuleEx(pwsz, 0, 0);
502 if (!hModule)
503 {
504 *piFile = 0;
505 return NULL;
506 }
507
508 /* Map the file */
509 pvBase = EngMapModule(hModule, &cjSize);
510 if (!pvBase)
511 {
512 EngFreeModule(hModule);
513 hModule = NULL;
514 }
515
516 /* Set iFile and return mapped base */
517 *piFile = (ULONG_PTR)hModule;
518 return pvBase;
519 }
520
521 BOOL
522 APIENTRY
523 EngUnmapFile(
524 _In_ ULONG_PTR iFile)
525 {
526 HANDLE hModule = (HANDLE)iFile;
527
528 EngFreeModule(hModule);
529
530 return TRUE;
531 }
532
533
534 BOOL
535 APIENTRY
536 EngMapFontFileFD(
537 _In_ ULONG_PTR iFile,
538 _Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
539 _Out_ ULONG *pcjBuf)
540 {
541 // www.osr.com/ddk/graphics/gdifncs_0co7.htm
542 UNIMPLEMENTED;
543 return FALSE;
544 }
545
546 VOID
547 APIENTRY
548 EngUnmapFontFileFD(
549 _In_ ULONG_PTR iFile)
550 {
551 // http://www.osr.com/ddk/graphics/gdifncs_6wbr.htm
552 UNIMPLEMENTED;
553 }
554
555 BOOL
556 APIENTRY
557 EngMapFontFile(
558 _In_ ULONG_PTR iFile,
559 _Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
560 _Out_ ULONG *pcjBuf)
561 {
562 // www.osr.com/ddk/graphics/gdifncs_3up3.htm
563 return EngMapFontFileFD(iFile, ppjBuf, pcjBuf);
564 }
565
566 VOID
567 APIENTRY
568 EngUnmapFontFile(
569 _In_ ULONG_PTR iFile)
570 {
571 // www.osr.com/ddk/graphics/gdifncs_09wn.htm
572 EngUnmapFontFileFD(iFile);
573 }