Sync to trunk head (r42241)
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
index 0241dd2..4c04759 100644 (file)
@@ -20,8 +20,7 @@
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-static
-int
+LONG
 MiGetExceptionInfo(EXCEPTION_POINTERS *ExceptionInfo, BOOLEAN * HaveBadAddress, ULONG_PTR * BadAddress)
 {
     PEXCEPTION_RECORD ExceptionRecord;
@@ -556,6 +555,7 @@ MiQueryVirtualMemory(IN HANDLE ProcessHandle,
 
         default:
         {
+            DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass);
             Status = STATUS_INVALID_INFO_CLASS;
             *ResultLength = 0;
             break;
@@ -622,6 +622,115 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
     return Status;
 }
 
+PVOID
+NTAPI
+MiMapLockedPagesInUserSpace(IN PMDL Mdl,
+                            IN PVOID BaseVa,
+                            IN MEMORY_CACHING_TYPE CacheType,
+                            IN PVOID BaseAddress)
+{
+    PVOID Base;
+    PPFN_NUMBER MdlPages;
+    ULONG PageCount;   
+    PEPROCESS CurrentProcess;
+    NTSTATUS Status;
+    ULONG Protect;
+    MEMORY_AREA *Result;
+    LARGE_INTEGER BoundaryAddressMultiple;
+    
+    /* Calculate the number of pages required. */
+    MdlPages = (PPFN_NUMBER)(Mdl + 1);
+    PageCount = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
+    
+    /* Set default page protection */
+    Protect = PAGE_READWRITE;
+    if (CacheType == MmNonCached) Protect |= PAGE_NOCACHE;
+    
+    BoundaryAddressMultiple.QuadPart = 0;
+    Base = BaseAddress;
+    
+    CurrentProcess = PsGetCurrentProcess();
+    
+    MmLockAddressSpace(&CurrentProcess->Vm);
+    Status = MmCreateMemoryArea(&CurrentProcess->Vm,
+                                MEMORY_AREA_MDL_MAPPING,
+                                &Base,
+                                PageCount * PAGE_SIZE,
+                                Protect,
+                                &Result,
+                                (Base != NULL),
+                                0,
+                                BoundaryAddressMultiple);
+    MmUnlockAddressSpace(&CurrentProcess->Vm);
+    if (!NT_SUCCESS(Status))
+    {
+        if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL)
+        {
+            return NULL;
+        }
+        
+        /* Throw exception */
+        ExRaiseStatus(STATUS_ACCESS_VIOLATION);
+        ASSERT(0);
+    }
+    
+    /* Set the virtual mappings for the MDL pages. */
+    if (Mdl->MdlFlags & MDL_IO_SPACE)
+    {
+        /* Map the pages */
+        Status = MmCreateVirtualMappingUnsafe(CurrentProcess,
+                                              Base,
+                                              Protect,
+                                              MdlPages,
+                                              PageCount);
+    }
+    else
+    {
+        /* Map the pages */
+        Status = MmCreateVirtualMapping(CurrentProcess,
+                                        Base,
+                                        Protect,
+                                        MdlPages,
+                                        PageCount);
+    }
+    
+    /* Check if the mapping suceeded */
+    if (!NT_SUCCESS(Status))
+    {
+        /* If it can fail, return NULL */
+        if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL) return NULL;
+        
+        /* Throw exception */
+        ExRaiseStatus(STATUS_ACCESS_VIOLATION);
+    }
+    
+    /* Return the base */
+    Base = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset);
+    return Base;
+}
+
+VOID
+NTAPI
+MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress,
+                              IN PMDL Mdl)
+{
+    PMEMORY_AREA MemoryArea;
+    
+    /* Sanity check */
+    ASSERT(Mdl->Process == PsGetCurrentProcess());
+    
+    /* Find the memory area */
+    MemoryArea = MmLocateMemoryAreaByAddress(&Mdl->Process->Vm,
+                                             BaseAddress);
+    ASSERT(MemoryArea);
+    
+    /* Free it */
+    MmFreeMemoryArea(&Mdl->Process->Vm,
+                     MemoryArea,
+                     NULL,
+                     NULL);    
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 /*
@@ -758,7 +867,7 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     PEPROCESS Process;
     NTSTATUS Status = STATUS_SUCCESS;
-    ULONG BytesWritten = 0;
+    SIZE_T BytesWritten = 0;
     PAGED_CODE();
 
     /* Check if we came from user mode */
@@ -849,6 +958,7 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
     SIZE_T NumberOfBytesToProtect = 0;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
 
     /* Check for valid protection flags */
     Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
@@ -961,6 +1071,7 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
     WCHAR ModuleFileNameBuffer[MAX_PATH] = {0};
     UNICODE_STRING ModuleFileName;
     PMEMORY_SECTION_NAME SectionName = NULL;
+    PEPROCESS Process;
     union
     {
         MEMORY_BASIC_INFORMATION BasicInfo;
@@ -975,11 +1086,15 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
 
     PreviousMode =  ExGetPreviousMode();
 
-    if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
+    if (PreviousMode != KernelMode)
     {
         _SEH2_TRY
         {
-            ProbeForWriteSize_t(UnsafeResultLength);
+            ProbeForWrite(VirtualMemoryInformation,
+                          Length,
+                          sizeof(ULONG_PTR));
+
+            if (UnsafeResultLength) ProbeForWriteSize_t(UnsafeResultLength);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -1002,6 +1117,19 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
     /* FIXME: Move this inside MiQueryVirtualMemory */
     if (VirtualMemoryInformationClass == MemorySectionName)
     {
+        Status = ObReferenceObjectByHandle(ProcessHandle,
+                                           PROCESS_QUERY_INFORMATION,
+                                           NULL,
+                                           PreviousMode,
+                                           (PVOID*)(&Process),
+                                           NULL);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("NtQueryVirtualMemory() = %x\n",Status);
+            return(Status);
+        }
+
         RtlInitEmptyUnicodeString(&ModuleFileName, ModuleFileNameBuffer, sizeof(ModuleFileNameBuffer));
         Status = MmGetFileNameForAddress(Address, &ModuleFileName);
 
@@ -1039,6 +1167,7 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
                 }
             }
         }
+        ObDereferenceObject(Process);
         return Status;
     }
     else
@@ -1131,4 +1260,57 @@ NtFlushVirtualMemory(IN HANDLE ProcessHandle,
     return STATUS_SUCCESS;
 }
 
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtGetWriteWatch(IN HANDLE ProcessHandle,
+                IN ULONG Flags,
+                IN PVOID BaseAddress,
+                IN ULONG RegionSize,
+                IN PVOID *UserAddressArray,
+                OUT PULONG EntriesInUserAddressArray,
+                OUT PULONG Granularity)
+{
+    if (!EntriesInUserAddressArray || !Granularity)
+    {
+        return STATUS_ACCESS_VIOLATION;
+    }
+    
+    if (!*EntriesInUserAddressArray || !RegionSize)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    if (!UserAddressArray)
+    {
+        return STATUS_ACCESS_VIOLATION;
+    }
+    
+    /* HACK: Set granularity to PAGE_SIZE */
+    *Granularity = PAGE_SIZE;
+    
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtResetWriteWatch(IN HANDLE ProcessHandle,
+                  IN PVOID BaseAddress,
+                  IN ULONG RegionSize)
+{
+    if (!RegionSize)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 /* EOF */