* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: virtual.c,v 1.77 2004/07/09 20:14:49 navaraf Exp $
+/* $Id: virtual.c,v 1.86 2004/12/22 05:17:44 royce Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/virtual.c
/* INCLUDE *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/mm.h>
-#include <internal/ob.h>
-#include <internal/io.h>
-#include <internal/ps.h>
-#include <internal/pool.h>
-#include <internal/safe.h>
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/*
* FUNCTION: Flushes virtual memory to file
* ARGUMENTS:
- * ProcessHandle = Points to the process that allocated the virtual
+ * ProcessHandle = Points to the process that allocated the virtual
* memory
* BaseAddress = Points to the memory address
* NumberOfBytesToFlush = Limits the range to flush,
* NumberOfBytesFlushed = Actual number of bytes flushed
- * RETURNS: Status
+ * RETURNS: Status
*/
{
UNIMPLEMENTED;
return(STATUS_NOT_IMPLEMENTED);
}
-/* (tMk 2004.II.4)
- * FUNCTION: Locks range of process virtual memory.
- * Called from VirtualLock (lib\kernel32\mem\virtual.c)
- *
- * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
- */
+
NTSTATUS STDCALL
-NtLockVirtualMemory(HANDLE ProcessHandle,
- PVOID BaseAddress,
- ULONG NumberOfBytesToLock,
- PULONG NumberOfBytesLocked) // ULONG LockOption?
+MiLockVirtualMemory(HANDLE ProcessHandle,
+ PVOID BaseAddress,
+ ULONG NumberOfBytesToLock,
+ PULONG NumberOfBytesLocked,
+ PObReferenceObjectByHandle pObReferenceObjectByHandle,
+ PMmCreateMdl pMmCreateMdl,
+ PObDereferenceObject pObDereferenceObject,
+ PMmProbeAndLockPages pMmProbeAndLockPages,
+ PExFreePool pExFreePool)
{
- // AG [08-20-03] : I have *no* idea if this is correct, I just used the
- // other functions as a template and made a few intelligent guesses...
+ PEPROCESS Process;
+ NTSTATUS Status;
+ PMDL Mdl;
+
+ Status = pObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_WRITE,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return(Status);
+
+ Mdl = pMmCreateMdl(NULL,
+ BaseAddress,
+ NumberOfBytesToLock);
+ if (Mdl == NULL)
+ {
+ pObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
- NTSTATUS Status;
- PMDL Mdl;
- PEPROCESS Process;
+ pMmProbeAndLockPages(Mdl,
+ UserMode,
+ IoWriteAccess);
- DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
- "NumberOfBytesToLock %d), NumberOfBytesLocked %x\n",ProcessHandle,BaseAddress,
- NumberOfBytesToLock, NumberOfBytesLocked);
+ pExFreePool(Mdl);
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_WRITE,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Mdl = MmCreateMdl(NULL,
- BaseAddress,
- NumberOfBytesToLock);
- if(Mdl == NULL)
- {
- ObDereferenceObject(Process);
- return(STATUS_NO_MEMORY);
- }
- MmProbeAndLockPages(Mdl,
- UserMode,
- IoWriteAccess);
+ pObDereferenceObject(Process);
- ExFreePool(Mdl); // Are we supposed to do this here?
+ *NumberOfBytesLocked = NumberOfBytesToLock;
+ return(STATUS_SUCCESS);
+}
- ObDereferenceObject(Process);
- *NumberOfBytesLocked = NumberOfBytesToLock;
- return(STATUS_SUCCESS);
+NTSTATUS STDCALL
+NtLockVirtualMemory(HANDLE ProcessHandle,
+ PVOID BaseAddress,
+ ULONG NumberOfBytesToLock,
+ PULONG NumberOfBytesLocked)
+{
+ DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+ "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
+ ProcessHandle,
+ BaseAddress,
+ NumberOfBytesToLock,
+ NumberOfBytesLocked);
+
+ return MiLockVirtualMemory(ProcessHandle,
+ BaseAddress,
+ NumberOfBytesToLock,
+ NumberOfBytesLocked,
+ ObReferenceObjectByHandle,
+ MmCreateMdl,
+ ObfDereferenceObject,
+ MmProbeAndLockPages,
+ ExFreePool);
}
-/* (tMk 2004.II.4)
- * FUNCTION:
- * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
- *
- */
-NTSTATUS STDCALL
-NtQueryVirtualMemory (IN HANDLE ProcessHandle,
+NTSTATUS FASTCALL
+MiQueryVirtualMemory (IN HANDLE ProcessHandle,
IN PVOID Address,
IN CINT VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN ULONG Length,
- OUT PULONG UnsafeResultLength)
+ OUT PULONG ResultLength)
{
NTSTATUS Status;
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
- ULONG ResultLength = 0;
PMADDRESS_SPACE AddressSpace;
- DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
- "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
- "Length %lu ResultLength %x)\n",ProcessHandle,Address,
- VirtualMemoryInformationClass,VirtualMemoryInformation,
- Length,ResultLength);
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_QUERY_INFORMATION,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
-
- if (!NT_SUCCESS(Status))
+ if (Address < (PVOID)KERNEL_BASE)
{
- DPRINT("NtQueryVirtualMemory() = %x\n",Status);
- return(Status);
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("NtQueryVirtualMemory() = %x\n",Status);
+ return(Status);
+ }
+ AddressSpace = &Process->AddressSpace;
+ }
+ else
+ {
+ AddressSpace = MmGetKernelAddressSpace();
}
-
- AddressSpace = &Process->AddressSpace;
MmLockAddressSpace(AddressSpace);
MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
Address);
{
case MemoryBasicInformation:
{
- PMEMORY_BASIC_INFORMATION Info =
- (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
-
+ PMEMORY_BASIC_INFORMATION Info =
+ (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
if (Length != sizeof(MEMORY_BASIC_INFORMATION))
{
MmUnlockAddressSpace(AddressSpace);
if (MemoryArea == NULL)
{
+ Info->Type = 0;
Info->State = MEM_FREE;
+ Info->Protect = PAGE_NOACCESS;
+ Info->AllocationProtect = 0;
Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
- Info->AllocationBase = 0;
- Info->AllocationProtect = 0;
- /* TODO: Find the next memory area and set RegionSize! */
- /* Since programs might depend on RegionSize for
- * iteration, we for now just make up a value.
- */
- Info->RegionSize = (Address > (PVOID)0x80000000) ? 0 : 0x10000;
- Info->Protect = PAGE_NOACCESS;
- Info->Type = 0;
+ Info->AllocationBase = NULL;
+ Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
Status = STATUS_SUCCESS;
- ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
- }
- else if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
- {
- Status = MmQueryAnonMem(MemoryArea, Address, Info,
- &ResultLength);
- }
- else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
- {
- Status = MmQuerySectionView(MemoryArea, Address, Info,
- &ResultLength);
- }
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ }
else
- {
- Status = STATUS_UNSUCCESSFUL;
- ResultLength = 0;
- }
+ {
+ switch(MemoryArea->Type)
+ {
+ case MEMORY_AREA_VIRTUAL_MEMORY:
+ Status = MmQueryAnonMem(MemoryArea, Address, Info,
+ ResultLength);
+ break;
+ case MEMORY_AREA_SECTION_VIEW:
+ Status = MmQuerySectionView(MemoryArea, Address, Info,
+ ResultLength);
+ break;
+ case MEMORY_AREA_NO_ACCESS:
+ Info->Type = 0;
+ Info->State = MEM_FREE;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->BaseAddress;
+ Info->AllocationBase = MemoryArea->BaseAddress;
+ Info->RegionSize = MemoryArea->Length;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_SHARED_DATA:
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->BaseAddress;
+ Info->AllocationBase = MemoryArea->BaseAddress;
+ Info->RegionSize = MemoryArea->Length;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_SYSTEM:
+ {
+ static int warned = 0;
+ if ( !warned )
+ {
+ DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
+ warned = 1;
+ }
+ }
+ /* FIXME - don't have a clue if this is right, but it's better than nothing */
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->BaseAddress;
+ Info->AllocationBase = MemoryArea->BaseAddress;
+ Info->RegionSize = MemoryArea->Length;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_KERNEL_STACK:
+ {
+ static int warned = 0;
+ if ( !warned )
+ {
+ DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
+ warned = 1;
+ }
+ }
+ /* FIXME - don't have a clue if this is right, but it's better than nothing */
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->BaseAddress;
+ Info->AllocationBase = MemoryArea->BaseAddress;
+ Info->RegionSize = MemoryArea->Length;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ default:
+ DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
+ Status = STATUS_UNSUCCESSFUL;
+ *ResultLength = 0;
+ }
+ }
break;
}
default:
{
Status = STATUS_INVALID_INFO_CLASS;
- ResultLength = 0;
+ *ResultLength = 0;
break;
}
}
MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
+ if (Address < (PVOID)KERNEL_BASE)
+ {
+ ObDereferenceObject(Process);
+ }
+
+ return Status;
+}
+
+/* (tMk 2004.II.4)
+ * FUNCTION:
+ * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
+ *
+ */
+NTSTATUS STDCALL
+NtQueryVirtualMemory (IN HANDLE ProcessHandle,
+ IN PVOID Address,
+ IN CINT VirtualMemoryInformationClass,
+ OUT PVOID VirtualMemoryInformation,
+ IN ULONG Length,
+ OUT PULONG UnsafeResultLength)
+{
+ NTSTATUS Status;
+ ULONG ResultLength = 0;
+ KPROCESSOR_MODE PrevMode;
+ union
+ {
+ MEMORY_BASIC_INFORMATION BasicInfo;
+ }
+ VirtualMemoryInfo;
+
+ DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
+ "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
+ "Length %lu ResultLength %x)\n",ProcessHandle,Address,
+ VirtualMemoryInformationClass,VirtualMemoryInformation,
+ Length,ResultLength);
+
+ PrevMode = ExGetPreviousMode();
+
+ if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
+ {
+ DPRINT1("Invalid parameter\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = MiQueryVirtualMemory ( ProcessHandle,
+ Address,
+ VirtualMemoryInformationClass,
+ &VirtualMemoryInfo,
+ Length,
+ &ResultLength );
+
+ if (NT_SUCCESS(Status) && ResultLength > 0)
+ {
+ Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
+ if (!NT_SUCCESS(Status))
+ {
+ ResultLength = 0;
+ }
+ }
+
if (UnsafeResultLength != NULL)
{
MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
/* (tMk 2004.II.5)
- * FUNCTION:
+ * FUNCTION:
* Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
*
*/
if (!NT_SUCCESS(Status))
return Status;
- // (tMk 2004.II.5) in Microsoft SDK I read:
+ // (tMk 2004.II.5) in Microsoft SDK I read:
// 'if this parameter is NULL or does not point to a valid variable, the function fails'
- if(UnsafeOldAccessProtection == NULL)
+ if(UnsafeOldAccessProtection == NULL)
{
return(STATUS_INVALID_PARAMETER);
}
-
+
NumberOfBytesToProtect =
PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
PAGE_ROUND_DOWN(BaseAddress);
/* (tMk 2004.II.05)
- * FUNCTION:
+ * FUNCTION:
* Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
*
* NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
NTSTATUS Status;
PMDL Mdl;
PVOID SystemAddress;
- PEPROCESS Process;
+ PEPROCESS Process, CurrentProcess;
+
DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
"Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
return(Status);
}
- Mdl = MmCreateMdl(NULL,
- Buffer,
- NumberOfBytesToRead);
- if(Mdl == NULL)
+ CurrentProcess = PsGetCurrentProcess();
+
+ if (Process == CurrentProcess)
{
- ObDereferenceObject(Process);
- return(STATUS_NO_MEMORY);
+ memcpy(Buffer, BaseAddress, NumberOfBytesToRead);
}
- MmProbeAndLockPages(Mdl,
- UserMode,
- IoWriteAccess);
-
- KeAttachProcess(Process);
-
- SystemAddress = MmGetSystemAddressForMdl(Mdl);
- memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
-
- KeDetachProcess();
-
- if (Mdl->MappedSystemVa != NULL)
+ else
{
- MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ Mdl = MmCreateMdl(NULL,
+ Buffer,
+ NumberOfBytesToRead);
+ if(Mdl == NULL)
+ {
+ ObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+ MmProbeAndLockPages(Mdl,
+ UserMode,
+ IoWriteAccess);
+
+ KeAttachProcess(&Process->Pcb);
+
+ SystemAddress = MmGetSystemAddressForMdl(Mdl);
+ memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
+
+ KeDetachProcess();
+
+ if (Mdl->MappedSystemVa != NULL)
+ {
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ }
+ MmUnlockPages(Mdl);
+ ExFreePool(Mdl);
}
- MmUnlockPages(Mdl);
- ExFreePool(Mdl);
ObDereferenceObject(Process);
Mdl = MmCreateMdl(NULL,
BaseAddress,
NumberOfBytesToUnlock);
- if(Mdl == NULL)
+ if(Mdl == NULL)
{
ObDereferenceObject(Process);
return(STATUS_NO_MEMORY);
/* (tMk 2004.II.05)
* FUNCTION:
* Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
- *
+ *
* NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
*/
NTSTATUS STDCALL
return(Status);
}
- Mdl = MmCreateMdl(NULL,
- Buffer,
- NumberOfBytesToWrite);
- MmProbeAndLockPages(Mdl,
- UserMode,
- IoReadAccess);
- if(Mdl == NULL)
+ if (Process == PsGetCurrentProcess())
{
- ObDereferenceObject(Process);
- return(STATUS_NO_MEMORY);
+ memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
}
- KeAttachProcess(Process);
-
- SystemAddress = MmGetSystemAddressForMdl(Mdl);
- memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
-
- KeDetachProcess();
-
- ObDereferenceObject(Process);
-
- if (Mdl->MappedSystemVa != NULL)
+ else
{
- MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ Mdl = MmCreateMdl(NULL,
+ Buffer,
+ NumberOfBytesToWrite);
+ MmProbeAndLockPages(Mdl,
+ UserMode,
+ IoReadAccess);
+ if(Mdl == NULL)
+ {
+ ObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+ KeAttachProcess(&Process->Pcb);
+
+ SystemAddress = MmGetSystemAddressForMdl(Mdl);
+ memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
+
+ KeDetachProcess();
+
+ if (Mdl->MappedSystemVa != NULL)
+ {
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ }
+ MmUnlockPages(Mdl);
+ ExFreePool(Mdl);
}
- MmUnlockPages(Mdl);
- ExFreePool(Mdl);
+
+ ObDereferenceObject(Process);
*NumberOfBytesWritten = NumberOfBytesToWrite;
return(STATUS_SUCCESS);
}
+/*
+ * @unimplemented
+ */
+
+PVOID
+STDCALL
+MmGetVirtualForPhysical (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ UNIMPLEMENTED;
+ return 0;
+}
+
/* FUNCTION:
* Called from EngSecureMem (subsys\win32k\eng\mem.c)
* @unimplemented
IN ULONG Length,
IN ULONG Alignment)
{
- assert (Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+ ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
if (Length == 0)
return;
ULONG x;
ULONG i;
- assert (Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+ ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
if (Length == 0)
return;