f1e6ef0a97920c3af615879cd4eb449d978184a9
[reactos.git] / reactos / ntoskrnl / mm / i386 / page.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/i386/page.c
5 * PURPOSE: low level memory managment manipulation
6 * PROGRAMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 * 9/3/98: Created
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/mm.h>
15 #include <internal/mmhal.h>
16 #include <string.h>
17 #include <internal/string.h>
18 #include <internal/bitops.h>
19 #include <internal/ex.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* GLOBALS *****************************************************************/
25
26 extern ULONG MiNrFreePages;
27
28 #define PA_BIT_PRESENT (0)
29 #define PA_BIT_READWRITE (1)
30 #define PA_BIT_USER (2)
31
32 #define PA_PRESENT (1<<PA_BIT_PRESENT)
33
34 #define PAGETABLE_MAP (0xf0000000)
35 #define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
36
37 /* FUNCTIONS ***************************************************************/
38
39 static ULONG ProtectToPTE(ULONG flProtect)
40 {
41 ULONG Attributes = 0;
42
43 if (flProtect & PAGE_NOACCESS || flProtect & PAGE_GUARD)
44 {
45 Attributes = 0;
46 }
47 if (flProtect & PAGE_READWRITE || flProtect & PAGE_EXECUTE_READWRITE)
48 {
49 Attributes = PA_WRITE | PA_USER;
50 }
51 if (flProtect & PAGE_READONLY || flProtect & PAGE_EXECUTE ||
52 flProtect & PAGE_EXECUTE_READ)
53 {
54 Attributes = PA_READ | PA_USER;
55 }
56 return(Attributes);
57 }
58
59 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
60 (((ULONG)v / (1024 * 1024))&(~0x3)))
61 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((ULONG)v / 1024))
62
63 NTSTATUS Mmi386ReleaseMmInfo(PEPROCESS Process)
64 {
65 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process);
66
67 MmFreePage(Process->Pcb.PageTableDirectory, 1);
68 Process->Pcb.PageTableDirectory = NULL;
69
70 DPRINT("Finished Mmi386ReleaseMmInfo()\n");
71 return(STATUS_SUCCESS);
72 }
73
74 NTSTATUS MmCopyMmInfo(PEPROCESS Src, PEPROCESS Dest)
75 {
76 PULONG PhysPageDirectory;
77 PULONG PageDirectory;
78 PULONG CurrentPageDirectory;
79 PKPROCESS KProcess = &Dest->Pcb;
80 ULONG i;
81
82 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
83
84 PageDirectory = ExAllocatePage();
85 if (PageDirectory == NULL)
86 {
87 return(STATUS_UNSUCCESSFUL);
88 }
89 PhysPageDirectory = (PULONG)(MmGetPhysicalAddress(PageDirectory)).u.LowPart;
90 KProcess->PageTableDirectory = PhysPageDirectory;
91 CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
92
93 memset(PageDirectory,0,PAGESIZE);
94 for (i=768; i<896; i++)
95 {
96 PageDirectory[i] = CurrentPageDirectory[i];
97 }
98 DPRINT("Addr %x\n",0xf0000000 / (4*1024*1024));
99 PageDirectory[0xf0000000 / (4*1024*1024)] = (ULONG)PhysPageDirectory | 0x7;
100
101 ExUnmapPage(PageDirectory);
102
103 DPRINT("Finished MmCopyMmInfo()\n");
104 return(STATUS_SUCCESS);
105 }
106
107 VOID MmDeletePageTable(PEPROCESS Process, PVOID Address)
108 {
109 PEPROCESS CurrentProcess = PsGetCurrentProcess();
110
111 if (Process != NULL && Process != CurrentProcess)
112 {
113 KeAttachProcess(Process);
114 }
115 *(ADDR_TO_PDE(Address)) = 0;
116 FLUSH_TLB;
117 if (Process != NULL && Process != CurrentProcess)
118 {
119 KeDetachProcess();
120 }
121 }
122
123 ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
124 {
125 ULONG Entry;
126 PEPROCESS CurrentProcess = PsGetCurrentProcess();
127
128 if (Process != NULL && Process != CurrentProcess)
129 {
130 KeAttachProcess(Process);
131 }
132 Entry = *MmGetPageEntry(Address);
133 if (Process != NULL && Process != CurrentProcess)
134 {
135 KeDetachProcess();
136 }
137 return(Entry);
138 }
139
140 ULONG MmGetPhysicalAddressForProcess(PEPROCESS Process,
141 PVOID Address)
142 {
143 ULONG PageEntry;
144
145 PageEntry = MmGetPageEntryForProcess(Process, Address);
146
147 if (!(PageEntry & PA_PRESENT))
148 {
149 return(0);
150 }
151 return(PAGE_MASK(PageEntry));
152 }
153
154 VOID MmDeletePageEntry(PEPROCESS Process, PVOID Address, BOOL FreePage)
155 {
156 PULONG page_tlb;
157 PULONG page_dir;
158 PEPROCESS CurrentProcess = PsGetCurrentProcess();
159
160 if (Process != NULL && Process != CurrentProcess)
161 {
162 KeAttachProcess(Process);
163 }
164 page_dir = ADDR_TO_PDE(Address);
165 if ((*page_dir) == 0)
166 {
167 if (Process != NULL && Process != CurrentProcess)
168 {
169 KeDetachProcess();
170 }
171 return;
172 }
173 page_tlb = ADDR_TO_PTE(Address);
174 if (FreePage && PAGE_MASK(*page_tlb) != 0)
175 {
176 if (PAGE_MASK(*page_tlb) >= 0x400000)
177 {
178 DbgPrint("MmDeletePageEntry(Address %x) Physical %x Free %d, "
179 "Entry %x\n",
180 Address, PAGE_MASK(*page_tlb), MiNrFreePages,
181 *page_tlb);
182 KeBugCheck(0);
183 }
184 MmFreePage((PVOID)PAGE_MASK(*page_tlb),1);
185 }
186 *page_tlb = 0;
187 if (Process != NULL && Process != CurrentProcess)
188 {
189 KeDetachProcess();
190 }
191 }
192
193
194
195 PULONG MmGetPageEntry(PVOID PAddress)
196 /*
197 * FUNCTION: Get a pointer to the page table entry for a virtual address
198 */
199 {
200 PULONG page_tlb;
201 PULONG page_dir;
202 ULONG Address = (ULONG)PAddress;
203
204 DPRINT("MmGetPageEntry(Address %x)\n", Address);
205
206 page_dir = ADDR_TO_PDE(Address);
207 DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
208 if ((*page_dir) == 0)
209 {
210 (*page_dir) = ((ULONG)MmAllocPage()) | 0x7;
211 FLUSH_TLB;
212 }
213 page_tlb = ADDR_TO_PTE(Address);
214 DPRINT("page_tlb %x\n",page_tlb);
215 return(page_tlb);
216 }
217
218 BOOLEAN MmIsPagePresent(PEPROCESS Process, PVOID Address)
219 {
220 return((MmGetPageEntryForProcess(Process, Address)) & PA_PRESENT);
221 }
222
223
224 VOID MmSetPage(PEPROCESS Process,
225 PVOID Address,
226 ULONG flProtect,
227 ULONG PhysicalAddress)
228 {
229 PEPROCESS CurrentProcess = PsGetCurrentProcess();
230 ULONG Attributes = 0;
231
232 if (PAGE_ROUND_DOWN(Address) == 0x77631000)
233 {
234 DPRINT1("MmSetPage(Process %x, Address %x, flProtect %x, "
235 "PhysicalAddress %x)\n",Process,Address,flProtect,
236 PhysicalAddress);
237 }
238
239 if (((ULONG)PhysicalAddress) >= 0x400000)
240 {
241 DbgPrint("MmSetPage(Process %x, Address %x, PhysicalAddress %x)\n",
242 Process, Address, PhysicalAddress);
243 KeBugCheck(0);
244 }
245
246 Attributes = ProtectToPTE(flProtect);
247
248 if (Process != NULL && Process != CurrentProcess)
249 {
250 KeAttachProcess(Process);
251 }
252 (*MmGetPageEntry(Address)) = PhysicalAddress | Attributes;
253 FLUSH_TLB;
254 if (Process != NULL && Process != CurrentProcess)
255 {
256 KeDetachProcess();
257 }
258 }
259
260 VOID MmSetPageProtect(PEPROCESS Process,
261 PVOID Address,
262 ULONG flProtect)
263 {
264 ULONG Attributes = 0;
265 PULONG PageEntry;
266 PEPROCESS CurrentProcess = PsGetCurrentProcess();
267
268 Attributes = ProtectToPTE(flProtect);
269
270 if (Process != CurrentProcess)
271 {
272 KeAttachProcess(Process);
273 }
274 PageEntry = MmGetPageEntry(Address);
275 (*PageEntry) = PAGE_MASK(*PageEntry) | Attributes;
276 FLUSH_TLB;
277 if (Process != CurrentProcess)
278 {
279 KeDetachProcess();
280 }
281 }
282
283 PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID vaddr)
284 /*
285 * FUNCTION: Returns the physical address corresponding to a virtual address
286 */
287 {
288 PHYSICAL_ADDRESS p;
289
290 p.QuadPart = 0;
291
292 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
293
294 p.u.LowPart = PAGE_MASK(*MmGetPageEntry(vaddr));
295 p.u.HighPart = 0;
296
297 return p;
298 }