ok_eq_hex(Status, ExpectAtBase ? STATUS_SUCCESS : STATUS_IMAGE_NOT_AT_BASE);\
if (!skip(NT_SUCCESS(Status), "Section not mapped\n")) \
{ \
+ ok((LONG_PTR)BaseAddress > 0, "BaseAddress = %p\n", BaseAddress); \
+ ok_eq_uint(*(PUCHAR)BaseAddress, ExpectM ? 'M' : 0); \
+ Status = MmUnmapViewOfSection(PsGetCurrentProcess(), BaseAddress); \
+ ok_eq_hex(Status, STATUS_SUCCESS); \
+ } \
+ BaseAddress = NULL; \
+ ViewSize = 0; \
+ Status = MmMapViewOfSection(SectionObject, PsGetCurrentProcess(), \
+ &BaseAddress, 0, 1, &SectionOffset, \
+ &ViewSize, ViewUnmap, 0, \
+ PAGE_READONLY | PAGE_NOCACHE); \
+ ok_eq_hex(Status, ExpectAtBase ? STATUS_SUCCESS : STATUS_IMAGE_NOT_AT_BASE);\
+ if (!skip(NT_SUCCESS(Status), "Section not mapped\n")) \
+ { \
+ ok((LONG_PTR)BaseAddress > 0, "BaseAddress = %p\n", BaseAddress); \
ok_eq_uint(*(PUCHAR)BaseAddress, ExpectM ? 'M' : 0); \
Status = MmUnmapViewOfSection(PsGetCurrentProcess(), BaseAddress); \
ok_eq_hex(Status, STATUS_SUCCESS); \
}
}
+static
+VOID
+TestPhysicalMemorySection(VOID)
+{
+ NTSTATUS Status;
+ UNICODE_STRING SectionName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE SectionHandle;
+ PVOID SectionObject;
+ PUCHAR MyPage;
+ PHYSICAL_ADDRESS MyPagePhysical;
+ PUCHAR ZeroPageContents;
+ PHYSICAL_ADDRESS ZeroPagePhysical;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ PVOID Mapping;
+ SYSTEM_BASIC_INFORMATION BasicInfo;
+ PUCHAR MappingBytes;
+ SIZE_T ViewSize;
+ SIZE_T EqualBytes;
+ struct
+ {
+ PVOID Mapping;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ SIZE_T ViewSize;
+ } *UserStruct;
+ PVOID UserMem;
+ SIZE_T UserSize;
+
+ MyPage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'MPmK');
+ if (skip(MyPage != NULL, "Out of memory\n"))
+ return;
+ MyPagePhysical = MmGetPhysicalAddress(MyPage);
+ RtlFillMemory(MyPage + 0 * PAGE_SIZE / 4, PAGE_SIZE / 4, 0x23);
+ RtlFillMemory(MyPage + 1 * PAGE_SIZE / 4, PAGE_SIZE / 4, 0x67);
+ RtlFillMemory(MyPage + 2 * PAGE_SIZE / 4, PAGE_SIZE / 4, 0xab);
+ RtlFillMemory(MyPage + 3 * PAGE_SIZE / 4, PAGE_SIZE / 4, 0xef);
+
+ ZeroPageContents = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 'ZPmK');
+ if (skip(ZeroPageContents != NULL, "Out of memory\n"))
+ {
+ ExFreePoolWithTag(MyPage, 'MPmK');
+ return;
+ }
+ ZeroPagePhysical.QuadPart = 0;
+
+ Mapping = MmMapIoSpace(ZeroPagePhysical, PAGE_SIZE, MmCached);
+ if (skip(Mapping != NULL, "Failed to map zero page\n"))
+ {
+ ExFreePoolWithTag(ZeroPageContents, 'ZPmK');
+ ExFreePoolWithTag(MyPage, 'MPmK');
+ return;
+ }
+
+ RtlCopyMemory(ZeroPageContents, Mapping, PAGE_SIZE);
+ MmUnmapIoSpace(Mapping, PAGE_SIZE);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SectionName,
+ 0,
+ NULL,
+ NULL);
+ Status = ZwOpenSection(&SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (!skip(NT_SUCCESS(Status), "No section\n"))
+ {
+ /* Map zero page and compare */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &ZeroPagePhysical,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (!skip(NT_SUCCESS(Status), "No view\n"))
+ {
+ ok((LONG_PTR)Mapping > 0, "Mapping = %p\n", Mapping);
+ EqualBytes = RtlCompareMemory(Mapping,
+ ZeroPageContents,
+ PAGE_SIZE);
+ ok_eq_size(EqualBytes, PAGE_SIZE);
+ Status = ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ /* Map the zero page non-cached */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &ZeroPagePhysical,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE | PAGE_NOCACHE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (!skip(NT_SUCCESS(Status), "No view\n"))
+ {
+ ok((LONG_PTR)Mapping > 0, "Mapping = %p\n", Mapping);
+ EqualBytes = RtlCompareMemory(Mapping,
+ ZeroPageContents,
+ PAGE_SIZE);
+ ok_eq_size(EqualBytes, PAGE_SIZE);
+ Status = ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ /* Map our NP page, compare, and check that modifications are reflected */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &MyPagePhysical,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (!skip(NT_SUCCESS(Status), "No view\n"))
+ {
+ ok((LONG_PTR)Mapping > 0, "Mapping = %p\n", Mapping);
+ EqualBytes = RtlCompareMemory(Mapping,
+ MyPage,
+ PAGE_SIZE);
+ ok_eq_size(EqualBytes, PAGE_SIZE);
+
+ MappingBytes = Mapping;
+ ok(MappingBytes[5] == 0x23, "Mapping[5] = 0x%x\n", MappingBytes[5]);
+ ok(MyPage[5] == 0x23, "MyPage[5] = 0x%x\n", MyPage[5]);
+
+ MyPage[5] = 0x44;
+ ok(MappingBytes[5] == 0x44, "Mapping[5] = 0x%x\n", MappingBytes[5]);
+ ok(MyPage[5] == 0x44, "MyPage[5] = 0x%x\n", MyPage[5]);
+
+ MappingBytes[5] = 0x88;
+ ok(MappingBytes[5] == 0x88, "Mapping[5] = 0x%x\n", MappingBytes[5]);
+ ok(MyPage[5] == 0x88, "MyPage[5] = 0x%x\n", MyPage[5]);
+
+ Status = ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ /* Unaligned mapping will get aligned automatically */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE - 4;
+ PhysicalAddress.QuadPart = MyPagePhysical.QuadPart + 4;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &PhysicalAddress,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (!skip(NT_SUCCESS(Status), "No view\n"))
+ {
+ ok((LONG_PTR)Mapping > 0, "Mapping = %p\n", Mapping);
+ ok(((ULONG_PTR)Mapping % PAGE_SIZE) == 0, "Mapping = %p\n", Mapping);
+ ok_eq_ulong(ViewSize, PAGE_SIZE);
+
+ EqualBytes = RtlCompareMemory(Mapping,
+ MyPage,
+ PAGE_SIZE);
+ ok_eq_size(EqualBytes, PAGE_SIZE);
+
+ Status = ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ /* The following tests need to pass parameters in user mode */
+ UserStruct = NULL;
+ UserMem = NULL;
+ UserSize = PAGE_SIZE;
+ Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
+ &UserMem,
+ 0,
+ &UserSize,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ UserStruct = UserMem;
+
+ /* Find highest physical page -- only kernel can map beyond this */
+ Status = ZwQuerySystemInformation(SystemBasicInformation,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ trace("HighestPhysicalPageNumber: %lx\n", BasicInfo.HighestPhysicalPageNumber);
+
+ /* Start one page before highest physical -- succeeds for user/kernel */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE;
+ PhysicalAddress.QuadPart = (ULONGLONG)(BasicInfo.HighestPhysicalPageNumber - 1) << PAGE_SHIFT;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &PhysicalAddress,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+
+ /* Repeat from user mode */
+ if (!skip(UserStruct != NULL, "No user memory\n"))
+ {
+ KmtStartSeh()
+ UserStruct->Mapping = NULL;
+ UserStruct->PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
+ UserStruct->ViewSize = PAGE_SIZE;
+ KmtEndSeh(STATUS_SUCCESS);
+
+ Status = NtMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &UserStruct->Mapping,
+ 0,
+ 0,
+ &UserStruct->PhysicalAddress,
+ &UserStruct->ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ {
+ KmtStartSeh()
+ ZwUnmapViewOfSection(ZwCurrentProcess(), UserStruct->Mapping);
+ KmtEndSeh(STATUS_SUCCESS);
+ }
+ }
+
+ /* Now start at highest physical -- fails for user */
+ Mapping = NULL;
+ ViewSize = PAGE_SIZE;
+ PhysicalAddress.QuadPart = (ULONGLONG)BasicInfo.HighestPhysicalPageNumber << PAGE_SHIFT;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &PhysicalAddress,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+
+ /* Repeat from user mode */
+ if (!skip(UserStruct != NULL, "No user memory\n"))
+ {
+ KmtStartSeh()
+ UserStruct->Mapping = NULL;
+ UserStruct->PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
+ UserStruct->ViewSize = PAGE_SIZE;
+ KmtEndSeh(STATUS_SUCCESS);
+
+ Status = NtMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &UserStruct->Mapping,
+ 0,
+ 0,
+ &UserStruct->PhysicalAddress,
+ &UserStruct->ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER_6);
+ if (NT_SUCCESS(Status))
+ {
+ KmtStartSeh()
+ ZwUnmapViewOfSection(ZwCurrentProcess(), UserStruct->Mapping);
+ KmtEndSeh(STATUS_SUCCESS);
+ }
+ }
+
+ /* End of view crosses highest physical -- fails for user */
+ Mapping = NULL;
+ ViewSize = 2 * PAGE_SIZE;
+ PhysicalAddress.QuadPart = (ULONGLONG)(BasicInfo.HighestPhysicalPageNumber - 1) << PAGE_SHIFT;
+ Status = ZwMapViewOfSection(SectionHandle,
+ ZwCurrentProcess(),
+ &Mapping,
+ 0,
+ 0,
+ &PhysicalAddress,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ ZwUnmapViewOfSection(ZwCurrentProcess(), Mapping);
+
+ /* Repeat from user mode */
+ if (!skip(UserStruct != NULL, "No user memory\n"))
+ {
+ KmtStartSeh()
+ UserStruct->Mapping = NULL;
+ UserStruct->PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
+ UserStruct->ViewSize = 2 * PAGE_SIZE;
+ KmtEndSeh(STATUS_SUCCESS);
+
+ Status = NtMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &UserStruct->Mapping,
+ 0,
+ 0,
+ &UserStruct->PhysicalAddress,
+ &UserStruct->ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER_6);
+ if (NT_SUCCESS(Status))
+ {
+ KmtStartSeh()
+ ZwUnmapViewOfSection(ZwCurrentProcess(), UserStruct->Mapping);
+ KmtEndSeh(STATUS_SUCCESS);
+ }
+ }
+
+ /* Free user memory and close section */
+ if (!skip(UserStruct != NULL, "No user memory\n"))
+ {
+ UserSize = 0;
+ Status = ZwFreeVirtualMemory(ZwCurrentProcess(),
+ &UserMem,
+ &UserSize,
+ MEM_RELEASE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ Status = ObCloseHandle(SectionHandle, UserMode);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ }
+
+ /* Try flag 0x80000000, which ROS calls SEC_PHYSICALMEMORY */
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+ Status = ZwCreateSection(&SectionHandle,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes,
+ NULL,
+ PAGE_READWRITE,
+ 0x80000000,
+ NULL);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER_6);
+ if (NT_SUCCESS(Status))
+ ZwClose(SectionHandle);
+
+ /* Assertion failure: AllocationAttributes & SEC_IMAGE | SEC_RESERVE | SEC_COMMIT */
+ if (!KmtIsCheckedBuild)
+ {
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+ Status = MmCreateSection(&SectionObject,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes,
+ NULL,
+ PAGE_READWRITE,
+ 0x80000000,
+ NULL,
+ NULL);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER_6);
+ if (NT_SUCCESS(Status))
+ ObDereferenceObject(SectionObject);
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+ Status = MmCreateSection(&SectionObject,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes,
+ NULL,
+ PAGE_READWRITE,
+ SEC_RESERVE | 0x80000000,
+ NULL,
+ NULL);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER_6);
+ if (NT_SUCCESS(Status))
+ ObDereferenceObject(SectionObject);
+
+ ExFreePoolWithTag(ZeroPageContents, 'ZPmK');
+ ExFreePoolWithTag(MyPage, 'MPmK');
+}
+
START_TEST(MmSection)
{
NTSTATUS Status;
ZwClose(FileHandle2);
if (FileHandle1)
ZwClose(FileHandle1);
+
+ TestPhysicalMemorySection();
}