Corrected additional object manager issues pointed by Philip Susi
[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 MmDereferencePage(Process->Pcb.PageTableDirectory);
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",PAGETABLE_MAP / (4*1024*1024));
99 PageDirectory[PAGETABLE_MAP / (4*1024*1024)] =
100 (ULONG)PhysPageDirectory | 0x7;
101
102 ExUnmapPage(PageDirectory);
103
104 DPRINT("Finished MmCopyMmInfo()\n");
105 return(STATUS_SUCCESS);
106 }
107
108 VOID MmDeletePageTable(PEPROCESS Process, PVOID Address)
109 {
110 PEPROCESS CurrentProcess = PsGetCurrentProcess();
111
112 if (Process != NULL && Process != CurrentProcess)
113 {
114 KeAttachProcess(Process);
115 }
116 *(ADDR_TO_PDE(Address)) = 0;
117 FLUSH_TLB;
118 if (Process != NULL && Process != CurrentProcess)
119 {
120 KeDetachProcess();
121 }
122 }
123
124 ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
125 {
126 ULONG Entry;
127 PEPROCESS CurrentProcess = PsGetCurrentProcess();
128
129 if (Process != NULL && Process != CurrentProcess)
130 {
131 KeAttachProcess(Process);
132 }
133 Entry = *MmGetPageEntry(Address);
134 if (Process != NULL && Process != CurrentProcess)
135 {
136 KeDetachProcess();
137 }
138 return(Entry);
139 }
140
141 ULONG MmGetPhysicalAddressForProcess(PEPROCESS Process,
142 PVOID Address)
143 {
144 ULONG PageEntry;
145
146 PageEntry = MmGetPageEntryForProcess(Process, Address);
147
148 if (!(PageEntry & PA_PRESENT))
149 {
150 return(0);
151 }
152 return(PAGE_MASK(PageEntry));
153 }
154
155 VOID MmDeletePageEntry(PEPROCESS Process, PVOID Address, BOOL FreePage)
156 {
157 PULONG page_tlb;
158 PULONG page_dir;
159 PEPROCESS CurrentProcess = PsGetCurrentProcess();
160
161 if (Process != NULL && Process != CurrentProcess)
162 {
163 KeAttachProcess(Process);
164 }
165 page_dir = ADDR_TO_PDE(Address);
166 if ((*page_dir) == 0)
167 {
168 if (Process != NULL && Process != CurrentProcess)
169 {
170 KeDetachProcess();
171 }
172 return;
173 }
174 page_tlb = ADDR_TO_PTE(Address);
175 if (FreePage && PAGE_MASK(*page_tlb) != 0)
176 {
177 if (PAGE_MASK(*page_tlb) >= 0x400000)
178 {
179 DbgPrint("MmDeletePageEntry(Address %x) Physical %x Free %d, "
180 "Entry %x\n",
181 Address, PAGE_MASK(*page_tlb), MiNrFreePages,
182 *page_tlb);
183 KeBugCheck(0);
184 }
185 MmDereferencePage((PVOID)PAGE_MASK(*page_tlb));
186 }
187 *page_tlb = 0;
188 if (Process != NULL && Process != CurrentProcess)
189 {
190 KeDetachProcess();
191 }
192 }
193
194
195
196 PULONG MmGetPageEntry(PVOID PAddress)
197 /*
198 * FUNCTION: Get a pointer to the page table entry for a virtual address
199 */
200 {
201 PULONG page_tlb;
202 PULONG page_dir;
203 ULONG Address = (ULONG)PAddress;
204
205 DPRINT("MmGetPageEntry(Address %x)\n", Address);
206
207 page_dir = ADDR_TO_PDE(Address);
208 DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
209 if ((*page_dir) == 0)
210 {
211 (*page_dir) = ((ULONG)MmAllocPage()) | 0x7;
212 memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGESIZE);
213 FLUSH_TLB;
214 }
215 page_tlb = ADDR_TO_PTE(Address);
216 DPRINT("page_tlb %x\n",page_tlb);
217 return(page_tlb);
218 }
219
220 BOOLEAN MmIsPagePresent(PEPROCESS Process, PVOID Address)
221 {
222 return((MmGetPageEntryForProcess(Process, Address)) & PA_PRESENT);
223 }
224
225
226 VOID MmSetPage(PEPROCESS Process,
227 PVOID Address,
228 ULONG flProtect,
229 ULONG PhysicalAddress)
230 {
231 PEPROCESS CurrentProcess = PsGetCurrentProcess();
232 ULONG Attributes = 0;
233
234 if (PAGE_ROUND_DOWN(Address) == 0x77630000 ||
235 PAGE_ROUND_DOWN(Address) == 0x77631000 ||
236 PAGE_ROUND_DOWN(Address) == 0x77632000 ||
237 PAGE_ROUND_DOWN(Address) == 0x77633000)
238 {
239 DPRINT1("MmSetPage(Process %x, Address %x, flProtect %x, "
240 "PhysicalAddress %x)\n",Process,Address,flProtect,
241 PhysicalAddress);
242 }
243
244 if (((ULONG)PhysicalAddress) >= 0x400000)
245 {
246 DbgPrint("MmSetPage(Process %x, Address %x, PhysicalAddress %x)\n",
247 Process, Address, PhysicalAddress);
248 KeBugCheck(0);
249 }
250
251 Attributes = ProtectToPTE(flProtect);
252
253 if (Process != NULL && Process != CurrentProcess)
254 {
255 KeAttachProcess(Process);
256 }
257 (*MmGetPageEntry(Address)) = PhysicalAddress | Attributes;
258 FLUSH_TLB;
259 if (Process != NULL && Process != CurrentProcess)
260 {
261 KeDetachProcess();
262 }
263 }
264
265 VOID MmSetPageProtect(PEPROCESS Process,
266 PVOID Address,
267 ULONG flProtect)
268 {
269 ULONG Attributes = 0;
270 PULONG PageEntry;
271 PEPROCESS CurrentProcess = PsGetCurrentProcess();
272
273 Attributes = ProtectToPTE(flProtect);
274
275 if (Process != CurrentProcess)
276 {
277 KeAttachProcess(Process);
278 }
279 PageEntry = MmGetPageEntry(Address);
280 (*PageEntry) = PAGE_MASK(*PageEntry) | Attributes;
281 FLUSH_TLB;
282 if (Process != CurrentProcess)
283 {
284 KeDetachProcess();
285 }
286 }
287
288 PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID vaddr)
289 /*
290 * FUNCTION: Returns the physical address corresponding to a virtual address
291 */
292 {
293 PHYSICAL_ADDRESS p;
294
295 p.QuadPart = 0;
296
297 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
298
299 p.u.LowPart = PAGE_MASK(*MmGetPageEntry(vaddr));
300 p.u.HighPart = 0;
301
302 return p;
303 }