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