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