reactos/win32ss/gdi/eng/mapping.c

593 lines
15 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Functions for mapping files and sections
* FILE: win32ss/gdi/eng/mapping.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
HANDLE ghSystem32Directory;
HANDLE ghRootDirectory;
PVOID
NTAPI
EngMapSectionView(
_In_ HANDLE hSection,
_In_ SIZE_T cjSize,
_In_ ULONG cjOffset,
_Out_ PHANDLE phSecure)
{
LARGE_INTEGER liSectionOffset;
PVOID pvBaseAddress;
NTSTATUS Status;
/* Check if the size is ok (for 64 bit) */
if (cjSize > ULONG_MAX)
{
DPRINT1("chSize out of range: 0x%Id\n", cjSize);
return NULL;
}
/* Align the offset at allocation granularity and compensate for the size */
liSectionOffset.QuadPart = cjOffset & ~(MM_ALLOCATION_GRANULARITY - 1);
cjSize += cjOffset & (MM_ALLOCATION_GRANULARITY - 1);
/* Map the section */
Status = ZwMapViewOfSection(hSection,
NtCurrentProcess(),
&pvBaseAddress,
0,
cjSize,
&liSectionOffset,
&cjSize,
ViewShare,
0,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
return NULL;
}
/* Secure the section memory */
*phSecure = EngSecureMem(pvBaseAddress, (ULONG)cjSize);
if (!*phSecure)
{
ZwUnmapViewOfSection(NtCurrentProcess(), pvBaseAddress);
return NULL;
}
/* Return the address where the requested data starts */
return (PUCHAR)pvBaseAddress + (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
}
VOID
NTAPI
EngUnmapSectionView(
_In_ PVOID pvBits,
_In_ ULONG cjOffset,
_In_ HANDLE hSecure)
{
NTSTATUS Status;
/* Unsecure the memory */
EngUnsecureMem(hSecure);
/* Calculate the real start of the section view */
pvBits = (PUCHAR)pvBits - (cjOffset & (MM_ALLOCATION_GRANULARITY - 1));
/* Unmap the section view */
Status = MmUnmapViewOfSection(PsGetCurrentProcess(), pvBits);
ASSERT(NT_SUCCESS(Status));
}
PVOID
NTAPI
EngCreateSection(
_In_ ULONG fl,
_In_ SIZE_T cjSize,
_In_ ULONG ulTag)
{
NTSTATUS Status;
PENGSECTION pSection;
PVOID pvSectionObject;
LARGE_INTEGER liSize;
/* Allocate a section object */
pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
if (!pSection) return NULL;
liSize.QuadPart = cjSize;
Status = MmCreateSection(&pvSectionObject,
SECTION_ALL_ACCESS,
NULL,
&liSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create a section Status=0x%x\n", Status);
EngFreeMem(pSection);
return NULL;
}
/* Set the fields of the section */
pSection->ulTag = ulTag;
pSection->pvSectionObject = pvSectionObject;
pSection->pvMappedBase = NULL;
pSection->cjViewSize = cjSize;
return pSection;
}
PVOID
NTAPI
EngCreateSectionHack(
_In_ ULONG fl,
_In_ SIZE_T cjSize,
_In_ ULONG ulTag)
{
NTSTATUS Status;
PENGSECTION pSection;
PVOID pvSectionObject;
LARGE_INTEGER liSize;
/* Allocate a section object */
pSection = EngAllocMem(0, sizeof(ENGSECTION), 'stsU');
if (!pSection) return NULL;
liSize.QuadPart = cjSize;
Status = MmCreateSection(&pvSectionObject,
SECTION_ALL_ACCESS,
NULL,
&liSize,
PAGE_READWRITE,
SEC_COMMIT | 1,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create a section Status=0x%x\n", Status);
EngFreeMem(pSection);
return NULL;
}
/* Set the fields of the section */
pSection->ulTag = ulTag;
pSection->pvSectionObject = pvSectionObject;
pSection->pvMappedBase = NULL;
pSection->cjViewSize = cjSize;
return pSection;
}
_Success_(return!=FALSE)
BOOL
APIENTRY
EngMapSection(
_In_ PVOID pvSection,
_In_ BOOL bMap,
_In_ HANDLE hProcess,
_When_(bMap, _Outptr_) PVOID* pvBaseAddress)
{
NTSTATUS Status;
PENGSECTION pSection = pvSection;
PEPROCESS pepProcess;
/* Get a pointer to the process */
Status = ObReferenceObjectByHandle(hProcess,
PROCESS_VM_OPERATION,
NULL,
KernelMode,
(PVOID*)&pepProcess,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Could not access process %p, Status=0x%lx\n", hProcess, Status);
return FALSE;
}
if (bMap)
{
/* Make sure the section isn't already mapped */
ASSERT(pSection->pvMappedBase == NULL);
/* Map the section into the process address space */
Status = MmMapViewOfSection(pSection->pvSectionObject,
pepProcess,
&pSection->pvMappedBase,
0,
pSection->cjViewSize,
NULL,
&pSection->cjViewSize,
0,
0,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to map a section Status=0x%x\n", Status);
}
}
else
{
/* Make sure the section is mapped */
ASSERT(pSection->pvMappedBase);
/* Unmap the section from the process address space */
Status = MmUnmapViewOfSection(pepProcess, pSection->pvMappedBase);
if (NT_SUCCESS(Status))
{
pSection->pvMappedBase = NULL;
}
else
{
DPRINT1("Failed to unmap a section @ %p Status=0x%x\n",
pSection->pvMappedBase, Status);
}
}
/* Dereference the process */
ObDereferenceObject(pepProcess);
/* Set the new mapping base and return bool status */
*pvBaseAddress = pSection->pvMappedBase;
return NT_SUCCESS(Status);
}
BOOL
APIENTRY
EngFreeSectionMem(
_In_opt_ PVOID pvSection,
_In_opt_ PVOID pvMappedBase)
{
NTSTATUS Status;
PENGSECTION pSection = pvSection;
BOOL bResult = TRUE;
/* Did the caller give us a mapping base? */
if (pvMappedBase)
{
Status = MmUnmapViewInSessionSpace(pvMappedBase);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
bResult = FALSE;
}
}
/* Check if we should free the section as well */
if (pSection)
{
/* Dereference the kernel section */
ObDereferenceObject(pSection->pvSectionObject);
/* Finally free the section memory itself */
EngFreeMem(pSection);
}
return bResult;
}
_Check_return_
_Success_(return!=NULL)
__drv_allocatesMem(Mem)
_Post_writable_byte_size_(cjSize)
PVOID
APIENTRY
EngAllocSectionMem(
_Outptr_ PVOID *ppvSection,
_In_ ULONG fl,
_In_ SIZE_T cjSize,
_In_ ULONG ulTag)
{
NTSTATUS Status;
PENGSECTION pSection;
/* Check parameter */
if (cjSize == 0) return NULL;
/* Allocate a section object */
pSection = EngCreateSectionHack(fl, cjSize, ulTag);
if (!pSection)
{
*ppvSection = NULL;
return NULL;
}
/* Map the section in session space */
Status = MmMapViewInSessionSpace(pSection->pvSectionObject,
&pSection->pvMappedBase,
&pSection->cjViewSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to map a section Status=0x%x\n", Status);
*ppvSection = NULL;
EngFreeSectionMem(pSection, NULL);
return NULL;
}
if (fl & FL_ZERO_MEMORY)
{
RtlZeroMemory(pSection->pvMappedBase, cjSize);
}
/* Set section pointer and return base address */
*ppvSection = pSection;
return pSection->pvMappedBase;
}
_Check_return_
PFILEVIEW
NTAPI
EngLoadModuleEx(
_In_z_ LPWSTR pwsz,
_In_ ULONG cjSizeOfModule,
_In_ FLONG fl)
{
PFILEVIEW pFileView = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hRootDir;
UNICODE_STRING ustrFileName;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION FileInformation;
HANDLE hFile;
NTSTATUS Status;
LARGE_INTEGER liSize;
if (fl & FVF_FONTFILE)
{
pFileView = EngAllocMem(0, sizeof(FONTFILEVIEW), 'vffG');
}
else
{
pFileView = EngAllocMem(0, sizeof(FILEVIEW), 'liFg');
}
/* Check for success */
if (!pFileView) return NULL;
/* Check if the file is relative to system32 */
if (fl & FVF_SYSTEMROOT)
{
hRootDir = ghSystem32Directory;
}
else
{
hRootDir = ghRootDirectory;
}
/* Initialize unicode string and object attributes */
RtlInitUnicodeString(&ustrFileName, pwsz);
InitializeObjectAttributes(&ObjectAttributes,
&ustrFileName,
OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
hRootDir,
NULL);
/* Now open the file */
Status = ZwCreateFile(&hFile,
FILE_READ_DATA,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open file, hFile=%p, Status=0x%x\n", hFile, Status);
EngFreeMem(pFileView);
return NULL;
}
Status = ZwQueryInformationFile(hFile,
&IoStatusBlock,
&FileInformation,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (NT_SUCCESS(Status))
{
pFileView->LastWriteTime = FileInformation.LastWriteTime;
}
/* Create a section from the file */
liSize.QuadPart = cjSizeOfModule;
Status = MmCreateSection(&pFileView->pSection,
SECTION_ALL_ACCESS,
NULL,
&liSize,
fl & FVF_READONLY ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
SEC_COMMIT,
hFile,
NULL);
/* Close the file handle */
ZwClose(hFile);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create a section Status=0x%x\n", Status);
EngFreeMem(pFileView);
return NULL;
}
pFileView->pvKView = NULL;
pFileView->pvViewFD = NULL;
pFileView->cjView = 0;
return pFileView;
}
HANDLE
APIENTRY
EngLoadModule(
_In_ LPWSTR pwsz)
{
/* Forward to EngLoadModuleEx */
return (HANDLE)EngLoadModuleEx(pwsz, 0, FVF_READONLY | FVF_SYSTEMROOT);
}
HANDLE
APIENTRY
EngLoadModuleForWrite(
_In_ LPWSTR pwsz,
_In_ ULONG cjSizeOfModule)
{
/* Forward to EngLoadModuleEx */
return (HANDLE)EngLoadModuleEx(pwsz, cjSizeOfModule, FVF_SYSTEMROOT);
}
_Check_return_
_Success_(return!=NULL)
_Post_writable_byte_size_(*pulSize)
PVOID
APIENTRY
EngMapModule(
_In_ HANDLE h,
_Out_ PULONG pulSize)
{
PFILEVIEW pFileView = (PFILEVIEW)h;
NTSTATUS Status;
pFileView->cjView = 0;
/* FIXME: Use system space because ARM3 doesn't support executable sections yet */
Status = MmMapViewInSystemSpace(pFileView->pSection,
&pFileView->pvKView,
&pFileView->cjView);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to map a section Status=0x%x\n", Status);
*pulSize = 0;
return NULL;
}
*pulSize = (ULONG)pFileView->cjView;
return pFileView->pvKView;
}
VOID
APIENTRY
EngFreeModule(
_In_ _Post_invalid_ HANDLE h)
{
PFILEVIEW pFileView = (PFILEVIEW)h;
NTSTATUS Status;
/* FIXME: Use system space because ARM3 doesn't support executable sections yet */
Status = MmUnmapViewInSystemSpace(pFileView->pvKView);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmUnmapViewInSessionSpace failed: 0x%lx\n", Status);
ASSERT(FALSE);
}
/* Dereference the section */
ObDereferenceObject(pFileView->pSection);
/* Free the file view memory */
EngFreeMem(pFileView);
}
_Success_(return != 0)
_When_(cjSize != 0, _At_(return, _Out_writes_bytes_(cjSize)))
PVOID
APIENTRY
EngMapFile(
_In_ LPWSTR pwsz,
_In_ ULONG cjSize,
_Out_ ULONG_PTR *piFile)
{
HANDLE hModule;
PVOID pvBase;
/* Load the file */
hModule = EngLoadModuleEx(pwsz, 0, 0);
if (!hModule)
{
*piFile = 0;
return NULL;
}
/* Map the file */
pvBase = EngMapModule(hModule, &cjSize);
if (!pvBase)
{
EngFreeModule(hModule);
hModule = NULL;
}
/* Set iFile and return mapped base */
*piFile = (ULONG_PTR)hModule;
return pvBase;
}
BOOL
APIENTRY
EngUnmapFile(
_In_ ULONG_PTR iFile)
{
HANDLE hModule = (HANDLE)iFile;
EngFreeModule(hModule);
return TRUE;
}
_Check_return_
_Success_(return!=FALSE)
BOOL
APIENTRY
EngMapFontFileFD(
_In_ ULONG_PTR iFile,
_Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
_Out_ ULONG *pcjBuf)
{
// www.osr.com/ddk/graphics/gdifncs_0co7.htm
UNIMPLEMENTED;
return FALSE;
}
VOID
APIENTRY
EngUnmapFontFileFD(
_In_ ULONG_PTR iFile)
{
// http://www.osr.com/ddk/graphics/gdifncs_6wbr.htm
UNIMPLEMENTED;
}
__drv_preferredFunction("EngMapFontFileFD", "Obsolete")
_Check_return_
_Success_(return!=FALSE)
BOOL
APIENTRY
EngMapFontFile(
_In_ ULONG_PTR iFile,
_Outptr_result_bytebuffer_(*pcjBuf) PULONG *ppjBuf,
_Out_ ULONG *pcjBuf)
{
// www.osr.com/ddk/graphics/gdifncs_3up3.htm
return EngMapFontFileFD(iFile, ppjBuf, pcjBuf);
}
VOID
APIENTRY
EngUnmapFontFile(
_In_ ULONG_PTR iFile)
{
// www.osr.com/ddk/graphics/gdifncs_09wn.htm
EngUnmapFontFileFD(iFile);
}