xref: /reactos/ntoskrnl/mm/ARM3/ncache.c (revision c2c66aff)
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 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 /* GLOBALS ********************************************************************/
19 
20 /*
21  * @implemented
22  */
23 PVOID
24 NTAPI
MmAllocateNonCachedMemory(IN SIZE_T NumberOfBytes)25 MmAllocateNonCachedMemory(IN SIZE_T NumberOfBytes)
26 {
27     PFN_COUNT PageCount, MdlPageCount;
28     PFN_NUMBER 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 = (PFN_COUNT)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         ExFreePoolWithTag(Mdl, TAG_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         ExFreePoolWithTag(Mdl, TAG_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 = ValidKernelPte;
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         MI_WRITE_VALID_PTE(PointerPte++, TempPte);
158     } while (--PageCount);
159 
160     //
161     // Return the base address
162     //
163     return BaseAddress;
164 
165 }
166 
167 /*
168  * @implemented
169  */
170 VOID
171 NTAPI
MmFreeNonCachedMemory(IN PVOID BaseAddress,IN SIZE_T NumberOfBytes)172 MmFreeNonCachedMemory(IN PVOID BaseAddress,
173                       IN SIZE_T NumberOfBytes)
174 {
175     PMDL Mdl;
176     PMMPTE PointerPte;
177     PFN_COUNT PageCount;
178 
179     //
180     // Sanity checks
181     //
182     ASSERT(NumberOfBytes != 0);
183     ASSERT(PAGE_ALIGN(BaseAddress) == BaseAddress);
184 
185     //
186     // Get the page count
187     //
188     PageCount = (PFN_COUNT)BYTES_TO_PAGES(NumberOfBytes);
189 
190     //
191     // Get the first PTE
192     //
193     PointerPte = MiAddressToPte(BaseAddress);
194 
195     //
196     // Remember this is where we store the shadow MDL pointer
197     //
198     Mdl = *(PMDL*)(--PointerPte);
199 
200     //
201     // Kill the MDL (and underlying pages)
202     //
203     MmFreePagesFromMdl(Mdl);
204     ExFreePoolWithTag(Mdl, TAG_MDL);
205 
206     //
207     // Now free the system PTEs for the underlying VA
208     //
209     MiReleaseSystemPtes(PointerPte, PageCount + 1, SystemPteSpace);
210 }
211 
212 /* EOF */
213