Sync to trunk (r44371)
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / ncache.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/ncache.c
5 * PURPOSE: ARM Memory Manager Noncached Memory Allocator
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::NCACHE"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 /*
22 * @implemented
23 */
24 PVOID
25 NTAPI
26 MmAllocateNonCachedMemory(IN ULONG NumberOfBytes)
27 {
28 PFN_NUMBER PageCount, MdlPageCount, PageFrameIndex;
29 PHYSICAL_ADDRESS LowAddress, HighAddress, SkipBytes;
30 MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
31 PMDL Mdl;
32 PVOID BaseAddress;
33 PPFN_NUMBER MdlPages;
34 PMMPTE PointerPte;
35 MMPTE TempPte;
36
37 //
38 // Get the page count
39 //
40 ASSERT(NumberOfBytes != 0);
41 PageCount = BYTES_TO_PAGES(NumberOfBytes);
42
43 //
44 // Use the MDL allocator for simplicity, so setup the parameters
45 //
46 LowAddress.QuadPart = 0;
47 HighAddress.QuadPart = -1;
48 SkipBytes.QuadPart = 0;
49 CacheAttribute = MiPlatformCacheAttributes[0][MmNonCached];
50
51 //
52 // Now call the MDL allocator
53 //
54 Mdl = MiAllocatePagesForMdl(LowAddress,
55 HighAddress,
56 SkipBytes,
57 NumberOfBytes,
58 CacheAttribute,
59 0);
60 if (!Mdl) return NULL;
61
62 //
63 // Get the MDL VA and check how many pages we got (could be partial)
64 //
65 BaseAddress = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
66 MdlPageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Mdl->ByteCount);
67 if (PageCount != MdlPageCount)
68 {
69 //
70 // Unlike MDLs, partial isn't okay for a noncached allocation, so fail
71 //
72 ASSERT(PageCount > MdlPageCount);
73 MmFreePagesFromMdl(Mdl);
74 ExFreePool(Mdl);
75 return NULL;
76 }
77
78 //
79 // Allocate system PTEs for the base address
80 // We use an extra page to store the actual MDL pointer for the free later
81 //
82 PointerPte = MiReserveSystemPtes(PageCount + 1, SystemPteSpace);
83 if (!PointerPte)
84 {
85 //
86 // Out of memory...
87 //
88 MmFreePagesFromMdl(Mdl);
89 ExFreePool(Mdl);
90 return NULL;
91 }
92
93 //
94 // Store the MDL pointer
95 //
96 *(PMDL*)PointerPte++ = Mdl;
97
98 //
99 // Okay, now see what range we got
100 //
101 BaseAddress = MiPteToAddress(PointerPte);
102
103 //
104 // This is our array of pages
105 //
106 MdlPages = (PPFN_NUMBER)(Mdl + 1);
107
108 //
109 // Setup the template PTE
110 //
111 TempPte = HyperTemplatePte;
112
113 //
114 // Now check what kind of caching we should use
115 //
116 switch (CacheAttribute)
117 {
118 case MiNonCached:
119
120 //
121 // Disable caching
122 //
123 MI_PAGE_DISABLE_CACHE(&TempPte);
124 MI_PAGE_WRITE_THROUGH(&TempPte);
125 break;
126
127 case MiWriteCombined:
128
129 //
130 // Enable write combining
131 //
132 MI_PAGE_DISABLE_CACHE(&TempPte);
133 MI_PAGE_WRITE_COMBINED(&TempPte);
134 break;
135
136 default:
137 //
138 // Nothing to do
139 //
140 break;
141 }
142
143 //
144 // Now loop the MDL pages
145 //
146 do
147 {
148 //
149 // Get the PFN
150 //
151 PageFrameIndex = *MdlPages++;
152
153 //
154 // Set the PFN in the page and write it
155 //
156 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
157 ASSERT(PointerPte->u.Hard.Valid == 0);
158 ASSERT(TempPte.u.Hard.Valid == 1);
159 *PointerPte++ = TempPte;
160 } while (--PageCount);
161
162 //
163 // Return the base address
164 //
165 return BaseAddress;
166
167 }
168
169 /*
170 * @implemented
171 */
172 VOID
173 NTAPI
174 MmFreeNonCachedMemory(IN PVOID BaseAddress,
175 IN SIZE_T NumberOfBytes)
176 {
177 PMDL Mdl;
178 PMMPTE PointerPte;
179 PFN_NUMBER PageCount;
180
181 //
182 // Sanity checks
183 //
184 ASSERT(NumberOfBytes != 0);
185 ASSERT(PAGE_ALIGN(BaseAddress) == BaseAddress);
186
187 //
188 // Get the page count
189 //
190 PageCount = BYTES_TO_PAGES(NumberOfBytes);
191
192 //
193 // Get the first PTE
194 //
195 PointerPte = MiAddressToPte(BaseAddress);
196
197 //
198 // Remember this is where we store the shadow MDL pointer
199 //
200 Mdl = *(PMDL*)(--PointerPte);
201
202 //
203 // Kill the MDL (and underlying pages)
204 //
205 MmFreePagesFromMdl(Mdl);
206 ExFreePool(Mdl);
207
208 //
209 // Now free the system PTEs for the underlying VA
210 //
211 MiReleaseSystemPtes(PointerPte, PageCount + 1, SystemPteSpace);
212 }
213
214 /* EOF */