Skip to content

Commit e0759a5

Browse files
authored
[NTOS:MM] Finish MmAllocateMappingAddress and MmFreeMappingAddress and fix test failures. (reactos#7491)
* [NTOS:MM] Fix MmAllocateMappingAddress and MmFreeMappingAddress and their regression test failures. Follow up of reactos#7260. This fixes kmtest:MmReservedMapping failures and hang. Based on mm-implement-mappingaddress.patch by Thomas Faber and some changes by Oleg Dubinskiy. kmtest:MmReservedMapping revisions and updates to Vista+ method by Timo Kreuzer. Signed-off-by: Oleg Dubinskiy <[email protected]> Signed-off-by: Timo Kreuzer <[email protected]> CORE-10147, CORE-14635, CORE-17409, CORE-19318
1 parent 31334eb commit e0759a5

File tree

6 files changed

+251
-22
lines changed

6 files changed

+251
-22
lines changed

modules/rostests/kmtests/ntos_mm/MmReservedMapping.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <kmt_test.h>
1010

1111
static BOOLEAN g_IsPae;
12+
static ULONG g_OsVersion;
13+
static BOOLEAN g_IsReactOS;
1214

1315
#ifdef _M_IX86
1416

@@ -76,7 +78,7 @@ ValidateMapping(
7678
BOOLEAN Valid = TRUE;
7779
#if defined(_M_IX86) || defined(_M_AMD64)
7880
PUCHAR CurrentAddress;
79-
ULONGLONG PteValue;
81+
ULONGLONG PteValue, ExpectedValue;
8082
ULONG i;
8183

8284
for (i = 0; i < ValidPtes; i++)
@@ -110,10 +112,26 @@ ValidateMapping(
110112
CurrentAddress, PteValue, PoolTag & ~1);
111113
CurrentAddress = (PUCHAR)BaseAddress - 2 * PAGE_SIZE;
112114
PteValue = GET_PTE_VALUE(CurrentAddress);
115+
116+
if (g_IsReactOS || g_OsVersion >= 0x0600)
117+
{
118+
/* On ReactOS and on Vista+ the size is stored in
119+
* the NextEntry field of a MMPTE_LIST structure */
120+
#ifdef _M_IX86
121+
ExpectedValue = (TotalPtes + 2) << 12;
122+
#elif defined(_M_AMD64)
123+
ExpectedValue = ((ULONG64)TotalPtes + 2) << 32;
124+
#endif
125+
}
126+
else
127+
{
128+
/* On Windows 2003 the size is shifted by 1 bit only */
129+
ExpectedValue = (TotalPtes + 2) * 2;
130+
}
113131
Valid = Valid &&
114-
ok(PteValue == (TotalPtes + 2) * 2,
132+
ok(PteValue == ExpectedValue,
115133
"PTE for %p contains 0x%I64x, expected %x\n",
116-
CurrentAddress, PteValue, (TotalPtes + 2) * 2);
134+
CurrentAddress, PteValue, ExpectedValue);
117135
#endif
118136

119137
return Valid;
@@ -281,6 +299,9 @@ START_TEST(MmReservedMapping)
281299
PVOID Mapping;
282300

283301
g_IsPae = ExIsProcessorFeaturePresent(PF_PAE_ENABLED);
302+
g_OsVersion = SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion;
303+
g_IsReactOS = *(PULONG)(KI_USER_SHARED_DATA + PAGE_SIZE - sizeof(ULONG)) == 0x8eac705;
304+
ok(g_IsReactOS == 1, "Not reactos\n");
284305

285306
pMmAllocatePagesForMdlEx = KmtGetSystemRoutineAddress(L"MmAllocatePagesForMdlEx");
286307

ntoskrnl/ex/init.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,9 @@ ExpInitializeExecutive(IN ULONG Cpu,
13301330
/* Set the machine type */
13311331
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_NATIVE;
13321332
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_NATIVE;
1333+
1334+
/* ReactOS magic */
1335+
*(PULONG)(KI_USER_SHARED_DATA + PAGE_SIZE - sizeof(ULONG)) = 0x8eac705;
13331336
}
13341337

13351338
VOID

ntoskrnl/mm/ARM3/mdlsup.c

Lines changed: 208 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ MmAllocatePagesForMdlEx(IN PHYSICAL_ADDRESS LowAddress,
529529
else
530530
{
531531
//
532-
// Conver to internal caching attribute
532+
// Convert to internal caching attribute
533533
//
534534
CacheAttribute = MiPlatformCacheAttributes[FALSE][CacheType];
535535
}
@@ -1622,29 +1622,224 @@ MmAdvanceMdl(IN PMDL Mdl,
16221622
}
16231623

16241624
/*
1625-
* @unimplemented
1625+
* @implemented
16261626
*/
16271627
PVOID
16281628
NTAPI
1629-
MmMapLockedPagesWithReservedMapping(IN PVOID MappingAddress,
1630-
IN ULONG PoolTag,
1631-
IN PMDL MemoryDescriptorList,
1632-
IN MEMORY_CACHING_TYPE CacheType)
1629+
MmMapLockedPagesWithReservedMapping(
1630+
_In_ PVOID MappingAddress,
1631+
_In_ ULONG PoolTag,
1632+
_In_ PMDL Mdl,
1633+
_In_ MEMORY_CACHING_TYPE CacheType)
16331634
{
1634-
UNIMPLEMENTED;
1635-
return 0;
1635+
PPFN_NUMBER MdlPages, LastPage;
1636+
PFN_COUNT PageCount;
1637+
BOOLEAN IsIoMapping;
1638+
MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
1639+
PMMPTE PointerPte;
1640+
MMPTE TempPte;
1641+
1642+
ASSERT(Mdl->ByteCount != 0);
1643+
1644+
// Get the list of pages and count
1645+
MdlPages = MmGetMdlPfnArray(Mdl);
1646+
PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Mdl),
1647+
Mdl->ByteCount);
1648+
LastPage = MdlPages + PageCount;
1649+
1650+
// Sanity checks
1651+
ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA |
1652+
MDL_SOURCE_IS_NONPAGED_POOL |
1653+
MDL_PARTIAL_HAS_BEEN_MAPPED)) == 0);
1654+
ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | MDL_PARTIAL)) != 0);
1655+
1656+
// Get the correct cache type
1657+
IsIoMapping = (Mdl->MdlFlags & MDL_IO_SPACE) != 0;
1658+
CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType];
1659+
1660+
// Get the first PTE we reserved
1661+
ASSERT(MappingAddress);
1662+
PointerPte = MiAddressToPte(MappingAddress) - 2;
1663+
ASSERT(!PointerPte[0].u.Hard.Valid &&
1664+
!PointerPte[1].u.Hard.Valid);
1665+
1666+
// Verify that the pool tag matches
1667+
TempPte.u.Long = PoolTag;
1668+
TempPte.u.Hard.Valid = 0;
1669+
if (PointerPte[1].u.Long != TempPte.u.Long)
1670+
{
1671+
KeBugCheckEx(SYSTEM_PTE_MISUSE,
1672+
PTE_MAPPING_ADDRESS_NOT_OWNED, /* Trying to map an address it does not own */
1673+
(ULONG_PTR)MappingAddress,
1674+
PoolTag,
1675+
PointerPte[1].u.Long);
1676+
}
1677+
1678+
// We must have a size, and our helper PTEs must be invalid
1679+
if (PointerPte[0].u.List.NextEntry < 3)
1680+
{
1681+
KeBugCheckEx(SYSTEM_PTE_MISUSE,
1682+
PTE_MAPPING_ADDRESS_INVALID, /* Trying to map an invalid address */
1683+
(ULONG_PTR)MappingAddress,
1684+
PoolTag,
1685+
(ULONG_PTR)_ReturnAddress());
1686+
}
1687+
1688+
// If the mapping isn't big enough, fail
1689+
if (PointerPte[0].u.List.NextEntry - 2 < PageCount)
1690+
{
1691+
DPRINT1("Reserved mapping too small. Need %Iu pages, have %Iu\n",
1692+
PageCount,
1693+
PointerPte[0].u.List.NextEntry - 2);
1694+
return NULL;
1695+
}
1696+
// Skip our two helper PTEs
1697+
PointerPte += 2;
1698+
1699+
// Get the template
1700+
TempPte = ValidKernelPte;
1701+
switch (CacheAttribute)
1702+
{
1703+
case MiNonCached:
1704+
// Disable caching
1705+
MI_PAGE_DISABLE_CACHE(&TempPte);
1706+
MI_PAGE_WRITE_THROUGH(&TempPte);
1707+
break;
1708+
1709+
case MiWriteCombined:
1710+
// Enable write combining
1711+
MI_PAGE_DISABLE_CACHE(&TempPte);
1712+
MI_PAGE_WRITE_COMBINED(&TempPte);
1713+
break;
1714+
1715+
default:
1716+
// Nothing to do
1717+
break;
1718+
}
1719+
1720+
// Loop all PTEs
1721+
for (; (MdlPages < LastPage) && (*MdlPages != LIST_HEAD); ++MdlPages)
1722+
{
1723+
// Write the PTE
1724+
TempPte.u.Hard.PageFrameNumber = *MdlPages;
1725+
MI_WRITE_VALID_PTE(PointerPte++, TempPte);
1726+
}
1727+
1728+
// Mark it as mapped
1729+
ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0);
1730+
Mdl->MappedSystemVa = MappingAddress;
1731+
Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
1732+
1733+
// Check if it was partial
1734+
if (Mdl->MdlFlags & MDL_PARTIAL)
1735+
{
1736+
// Write the appropriate flag here too
1737+
Mdl->MdlFlags |= MDL_PARTIAL_HAS_BEEN_MAPPED;
1738+
}
1739+
1740+
// Return the mapped address
1741+
return (PVOID)((ULONG_PTR)MappingAddress + Mdl->ByteOffset);
16361742
}
16371743

16381744
/*
1639-
* @unimplemented
1745+
* @implemented
16401746
*/
16411747
VOID
16421748
NTAPI
1643-
MmUnmapReservedMapping(IN PVOID BaseAddress,
1644-
IN ULONG PoolTag,
1645-
IN PMDL MemoryDescriptorList)
1749+
MmUnmapReservedMapping(
1750+
_In_ PVOID BaseAddress,
1751+
_In_ ULONG PoolTag,
1752+
_In_ PMDL Mdl)
16461753
{
1647-
UNIMPLEMENTED;
1754+
PVOID Base;
1755+
PFN_COUNT PageCount, ExtraPageCount;
1756+
PPFN_NUMBER MdlPages;
1757+
PMMPTE PointerPte;
1758+
MMPTE TempPte;
1759+
1760+
// Sanity check
1761+
ASSERT(Mdl->ByteCount != 0);
1762+
ASSERT(BaseAddress > MM_HIGHEST_USER_ADDRESS);
1763+
1764+
// Get base and count information
1765+
Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
1766+
PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount);
1767+
1768+
// Sanity checks
1769+
ASSERT((Mdl->MdlFlags & MDL_PARENT_MAPPED_SYSTEM_VA) == 0);
1770+
ASSERT(PageCount != 0);
1771+
ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
1772+
1773+
// Get the first PTE we reserved
1774+
PointerPte = MiAddressToPte(BaseAddress) - 2;
1775+
ASSERT(!PointerPte[0].u.Hard.Valid &&
1776+
!PointerPte[1].u.Hard.Valid);
1777+
1778+
// Verify that the pool tag matches
1779+
TempPte.u.Long = PoolTag;
1780+
TempPte.u.Hard.Valid = 0;
1781+
if (PointerPte[1].u.Long != TempPte.u.Long)
1782+
{
1783+
KeBugCheckEx(SYSTEM_PTE_MISUSE,
1784+
PTE_UNMAPPING_ADDRESS_NOT_OWNED, /* Trying to unmap an address it does not own */
1785+
(ULONG_PTR)BaseAddress,
1786+
PoolTag,
1787+
PointerPte[1].u.Long);
1788+
}
1789+
1790+
// We must have a size
1791+
if (PointerPte[0].u.List.NextEntry < 3)
1792+
{
1793+
KeBugCheckEx(SYSTEM_PTE_MISUSE,
1794+
PTE_MAPPING_ADDRESS_EMPTY, /* Mapping apparently empty */
1795+
(ULONG_PTR)BaseAddress,
1796+
PoolTag,
1797+
(ULONG_PTR)_ReturnAddress());
1798+
}
1799+
1800+
// Skip our two helper PTEs
1801+
PointerPte += 2;
1802+
1803+
// This should be a resident system PTE
1804+
ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]);
1805+
ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]);
1806+
ASSERT(PointerPte->u.Hard.Valid == 1);
1807+
1808+
// TODO: check the MDL range makes sense with regard to the mapping range
1809+
// TODO: check if any of them are already zero
1810+
// TODO: check if any outside the MDL range are nonzero
1811+
// TODO: find out what to do with extra PTEs
1812+
1813+
// Check if the caller wants us to free advanced pages
1814+
if (Mdl->MdlFlags & MDL_FREE_EXTRA_PTES)
1815+
{
1816+
// Get the MDL page array
1817+
MdlPages = MmGetMdlPfnArray(Mdl);
1818+
1819+
/* Number of extra pages stored after the PFN array */
1820+
ExtraPageCount = MdlPages[PageCount];
1821+
1822+
// Do the math
1823+
PageCount += ExtraPageCount;
1824+
PointerPte -= ExtraPageCount;
1825+
ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]);
1826+
ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]);
1827+
1828+
// Get the new base address
1829+
BaseAddress = (PVOID)((ULONG_PTR)BaseAddress -
1830+
(ExtraPageCount << PAGE_SHIFT));
1831+
}
1832+
1833+
// Zero the PTEs
1834+
RtlZeroMemory(PointerPte, PageCount * sizeof(MMPTE));
1835+
1836+
// Flush the TLB
1837+
KeFlushEntireTb(TRUE, TRUE);
1838+
1839+
// Remove flags
1840+
Mdl->MdlFlags &= ~(MDL_MAPPED_TO_SYSTEM_VA |
1841+
MDL_PARTIAL_HAS_BEEN_MAPPED |
1842+
MDL_FREE_EXTRA_PTES);
16481843
}
16491844

16501845
/*

ntoskrnl/mm/ARM3/miarm.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,17 @@ C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE);
156156

157157
//
158158
// Some internal SYSTEM_PTE_MISUSE bugcheck subcodes
159+
// These names were created by Oleg Dubinskiy and Doug Lyons for ReactOS. For reference, see
160+
// https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-0xda--system-pte-misuse
159161
//
160-
#define PTE_MAPPING_NONE 0x100
161-
#define PTE_MAPPING_NOT_OWNED 0x101
162-
#define PTE_MAPPING_EMPTY 0x102
163-
#define PTE_MAPPING_RESERVED 0x103
162+
#define PTE_MAPPING_NONE 0x100
163+
#define PTE_MAPPING_NOT_OWNED 0x101
164+
#define PTE_MAPPING_EMPTY 0x102
165+
#define PTE_MAPPING_RESERVED 0x103
166+
#define PTE_MAPPING_ADDRESS_NOT_OWNED 0x104
167+
#define PTE_MAPPING_ADDRESS_INVALID 0x105
168+
#define PTE_UNMAPPING_ADDRESS_NOT_OWNED 0x108
169+
#define PTE_MAPPING_ADDRESS_EMPTY 0x109
164170

165171
//
166172
// Mask for image section page protection
@@ -1002,7 +1008,6 @@ MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte,
10021008
{
10031009
/* Write the invalid PTE */
10041010
ASSERT(InvalidPte.u.Hard.Valid == 0);
1005-
ASSERT(InvalidPte.u.Long != 0);
10061011
*PointerPte = InvalidPte;
10071012
}
10081013

ntoskrnl/mm/ARM3/pool.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,10 @@ MmAllocateMappingAddress(
15801580
PMMPTE PointerPte;
15811581
MMPTE TempPte;
15821582

1583+
/* Fast exit if PoolTag is NULL */
1584+
if (!PoolTag)
1585+
return NULL;
1586+
15831587
/* How many PTEs does the caller want? */
15841588
SizeInPages = BYTES_TO_PAGES(NumberOfBytes);
15851589
if (SizeInPages == 0)

ntoskrnl/mm/freelist.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
192192
KIRQL OldIrql;
193193
PMMPFN Pfn1;
194194
INT LookForZeroedPages;
195+
195196
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
196-
DPRINT1("ARM3-DEBUG: Being called with %I64x %I64x %I64x %lx %d %lu\n", LowAddress, HighAddress, SkipBytes, TotalBytes, CacheAttribute, MdlFlags);
197+
DPRINT("ARM3-DEBUG: Being called with %I64x %I64x %I64x %lx %d %lu\n", LowAddress, HighAddress, SkipBytes, TotalBytes, CacheAttribute, MdlFlags);
197198

198199
//
199200
// Convert the low address into a PFN

0 commit comments

Comments
 (0)