Sync to trunk head (r42241)
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
index ddeb3fb..4c04759 100644 (file)
@@ -20,8 +20,7 @@
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-static
-int
+LONG
 MiGetExceptionInfo(EXCEPTION_POINTERS *ExceptionInfo, BOOLEAN * HaveBadAddress, ULONG_PTR * BadAddress)
 {
     PEXCEPTION_RECORD ExceptionRecord;
@@ -65,9 +64,9 @@ MiDoMappedCopy(IN PEPROCESS SourceProcess,
     PMDL Mdl = (PMDL)MdlBuffer;
     SIZE_T TotalSize, CurrentSize, RemainingSize;
     volatile BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
-    BOOLEAN PagesLocked;
+    volatile BOOLEAN PagesLocked;
     PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
-    PVOID MdlAddress;
+    volatile PVOID MdlAddress;
     KAPC_STATE ApcState;
     BOOLEAN HaveBadAddress;
     ULONG_PTR BadAddress;
@@ -421,7 +420,7 @@ MiQueryVirtualMemory(IN HANDLE ProcessHandle,
     NTSTATUS Status;
     PEPROCESS Process;
     MEMORY_AREA* MemoryArea;
-    PMM_AVL_TABLE AddressSpace;
+    PMMSUPPORT AddressSpace;
 
     Status = ObReferenceObjectByHandle(ProcessHandle,
                                        PROCESS_QUERY_INFORMATION,
@@ -436,7 +435,7 @@ MiQueryVirtualMemory(IN HANDLE ProcessHandle,
         return(Status);
     }
 
-    AddressSpace = &Process->VadRoot;
+    AddressSpace = &Process->Vm;
 
     MmLockAddressSpace(AddressSpace);
     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
@@ -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;
@@ -576,7 +576,7 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
                        OUT PULONG OldAccessProtection  OPTIONAL)
 {
     PMEMORY_AREA MemoryArea;
-    PMM_AVL_TABLE AddressSpace;
+    PMMSUPPORT AddressSpace;
     ULONG OldAccessProtection_;
     NTSTATUS Status;
 
@@ -585,7 +585,7 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
     PAGE_ROUND_DOWN(*BaseAddress);
     *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
 
-    AddressSpace = &Process->VadRoot;
+    AddressSpace = &Process->Vm;
 
     MmLockAddressSpace(AddressSpace);
     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
@@ -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 */
@@ -844,10 +953,26 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
 {
     PEPROCESS Process;
     ULONG OldAccessProtection;
+    ULONG Protection;
     PVOID BaseAddress = NULL;
     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);
+    if (Protection != PAGE_NOACCESS &&
+        Protection != PAGE_READONLY &&
+        Protection != PAGE_READWRITE &&
+        Protection != PAGE_WRITECOPY &&
+        Protection != PAGE_EXECUTE &&
+        Protection != PAGE_EXECUTE_READ &&
+        Protection != PAGE_EXECUTE_READWRITE &&
+        Protection != PAGE_EXECUTE_WRITECOPY)
+    {
+        return STATUS_INVALID_PAGE_PROTECTION;
+    }
 
     /* Check if we came from user mode */
     if (PreviousMode != KernelMode)
@@ -946,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;
@@ -960,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)
         {
@@ -987,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);
 
@@ -1024,6 +1167,7 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
                 }
             }
         }
+        ObDereferenceObject(Process);
         return Status;
     }
     else
@@ -1116,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 */