- Sync with trunk up to r46941.
[reactos.git] / ntoskrnl / mm / mmdbg.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/mmdbg.c
5 * PURPOSE: Memory Manager support routines for the Kernel Debugger
6 * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #include "ARM3/miarm.h"
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 PMMPTE MmDebugPte = MiAddressToPte(MI_DEBUG_MAPPING);
19 BOOLEAN MiDbgReadyForPhysical = FALSE;
20
21 /* FUNCTIONS ******************************************************************/
22
23 BOOLEAN
24 NTAPI
25 MmIsSessionAddress(IN PVOID Address)
26 {
27 //
28 // No session space support yet
29 //
30 return FALSE;
31 }
32
33 PVOID
34 NTAPI
35 MiDbgTranslatePhysicalAddress(IN ULONG64 PhysicalAddress,
36 IN ULONG Flags)
37 {
38 extern MMPTE ValidKernelPte;
39 PFN_NUMBER Pfn;
40 MMPTE TempPte;
41 PVOID MappingBaseAddress;
42
43 //
44 // Check if we are called too early
45 //
46 if (MiDbgReadyForPhysical == FALSE)
47 {
48 //
49 // The structures we require aren't initialized yet, fail
50 //
51 KdpDprintf("MiDbgTranslatePhysicalAddress called too early! "
52 "Address: 0x%I64x\n", PhysicalAddress);
53 return NULL;
54 }
55
56 //
57 // FIXME: No support for cache flags yet
58 //
59 if ((Flags & (MMDBG_COPY_CACHED |
60 MMDBG_COPY_UNCACHED |
61 MMDBG_COPY_WRITE_COMBINED)) != 0)
62 {
63 //
64 // Fail
65 //
66 KdpDprintf("MiDbgTranslatePhysicalAddress: Cache Flags not yet supported. "
67 "Flags: 0x%lx\n", Flags & (MMDBG_COPY_CACHED |
68 MMDBG_COPY_UNCACHED |
69 MMDBG_COPY_WRITE_COMBINED));
70 return NULL;
71 }
72
73 //
74 // Save the base address of our mapping page
75 //
76 MappingBaseAddress = MiPteToAddress(MmDebugPte);
77
78 //
79 //
80 //
81 TempPte = ValidKernelPte;
82
83 //
84 // Convert physical address to PFN
85 //
86 Pfn = (PFN_NUMBER)(PhysicalAddress >> PAGE_SHIFT);
87
88 //
89 // Check if this could be an I/O mapping
90 //
91 if (Pfn > MmHighestPhysicalPage)
92 {
93 //
94 // FIXME: We don't support this yet
95 //
96 KdpDprintf("MiDbgTranslatePhysicalAddress: I/O Space not yet supported. "
97 "PFN: 0x%I64x\n", (ULONG64)Pfn);
98 return NULL;
99 }
100 else
101 {
102 //
103 // Set the PFN in the PTE
104 //
105 TempPte.u.Hard.PageFrameNumber = Pfn;
106 }
107
108 //
109 // Map the PTE and invalidate its TLB entry
110 //
111 *MmDebugPte = TempPte;
112 KeInvalidateTlbEntry(MappingBaseAddress);
113
114 //
115 // Calculate and return the virtual offset into our mapping page
116 //
117 return (PVOID)((ULONG_PTR)MappingBaseAddress +
118 BYTE_OFFSET(PhysicalAddress));
119 }
120
121 VOID
122 NTAPI
123 MiDbgUnTranslatePhysicalAddress(VOID)
124 {
125 PVOID MappingBaseAddress = MiPteToAddress(MmDebugPte);
126
127 //
128 // The address must still be valid at this point
129 //
130 ASSERT(MmIsAddressValid(MappingBaseAddress));
131
132 //
133 // Clear the mapping PTE and invalidate its TLB entry
134 //
135 MmDebugPte->u.Long = 0;
136 KeInvalidateTlbEntry(MappingBaseAddress);
137 }
138
139 NTSTATUS
140 NTAPI
141 MmDbgCopyMemory(IN ULONG64 Address,
142 IN PVOID Buffer,
143 IN ULONG Size,
144 IN ULONG Flags)
145 {
146 NTSTATUS Status;
147 PVOID TargetAddress;
148
149 //
150 // No local kernel debugging support yet, so don't worry about locking
151 //
152 ASSERT(Flags & MMDBG_COPY_UNSAFE);
153
154 //
155 // We only handle 1, 2, 4 and 8 byte requests
156 //
157 if ((Size != 1) &&
158 (Size != 2) &&
159 (Size != 4) &&
160 (Size != MMDBG_COPY_MAX_SIZE))
161 {
162 //
163 // Invalid size, fail
164 //
165 KdpDprintf("MmDbgCopyMemory: Received Illegal Size 0x%lx\n", Size);
166 return STATUS_INVALID_PARAMETER_3;
167 }
168
169 //
170 // The copy must be aligned
171 //
172 if ((Address & (Size - 1)) != 0)
173 {
174 //
175 // Fail
176 //
177 KdpDprintf("MmDbgCopyMemory: Received Unaligned Address 0x%I64x Size %lx\n",
178 Address, Size);
179 return STATUS_INVALID_PARAMETER_3;
180 }
181
182 //
183 // Check if this is physical or virtual copy
184 //
185 if (Flags & MMDBG_COPY_PHYSICAL)
186 {
187 //
188 // Physical: translate and map it to our mapping space
189 //
190 TargetAddress = MiDbgTranslatePhysicalAddress(Address, Flags);
191
192 //
193 // Check if translation failed
194 //
195 if (!TargetAddress)
196 {
197 //
198 // Fail
199 //
200 KdpDprintf("MmDbgCopyMemory: Failed to Translate Physical Address "
201 "%I64x\n", Address);
202 return STATUS_UNSUCCESSFUL;
203 }
204
205 //
206 // The address we received must be valid!
207 //
208 ASSERT(MmIsAddressValid(TargetAddress));
209 }
210 else
211 {
212 //
213 // Virtual; truncate it to avoid casts later down
214 //
215 TargetAddress = (PVOID)(ULONG_PTR)Address;
216
217 //
218 // Check if the address is invalid
219 //
220 if (!MmIsAddressValid(TargetAddress))
221 {
222 //
223 // Fail
224 //
225 KdpDprintf("MmDbgCopyMemory: Failing %s for invalid "
226 "Virtual Address 0x%p\n",
227 Flags & MMDBG_COPY_WRITE ? "write" : "read",
228 TargetAddress);
229 return STATUS_UNSUCCESSFUL;
230 }
231
232 //
233 // No session space support yet
234 //
235 ASSERT(MmIsSessionAddress(TargetAddress) == FALSE);
236 }
237
238 //
239 // If we are going to write to the address then make sure it is writeable too
240 //
241 if ((Flags & MMDBG_COPY_WRITE) &&
242 (!MI_IS_PAGE_WRITEABLE(MiAddressToPte(TargetAddress))))
243 {
244 //
245 // Check if we mapped anything
246 //
247 if (Flags & MMDBG_COPY_PHYSICAL)
248 {
249 //
250 // Get rid of the mapping
251 //
252 MiDbgUnTranslatePhysicalAddress();
253 }
254
255 //
256 // Fail
257 //
258 // FIXME: We should attempt to override the write protection instead of
259 // failing here
260 //
261 KdpDprintf("MmDbgCopyMemory: Failing Write for Protected Address 0x%p\n",
262 TargetAddress);
263 return STATUS_UNSUCCESSFUL;
264 }
265
266 //
267 // Use SEH to try to catch anything else somewhat cleanly
268 //
269 _SEH2_TRY
270 {
271 //
272 // Check if this is read or write
273 //
274 if (Flags & MMDBG_COPY_WRITE)
275 {
276 //
277 // Do the write
278 //
279 RtlCopyMemory(TargetAddress,
280 Buffer,
281 Size);
282 }
283 else
284 {
285 //
286 // Do the read
287 //
288 RtlCopyMemory(Buffer,
289 TargetAddress,
290 Size);
291 }
292
293 //
294 // Copy succeeded
295 //
296 Status = STATUS_SUCCESS;
297 }
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
299 {
300 //
301 // Get the exception code
302 //
303 Status = _SEH2_GetExceptionCode();
304 }
305 _SEH2_END;
306
307 //
308 // Get rid of the mapping if this was a physical copy
309 //
310 if (Flags & MMDBG_COPY_PHYSICAL)
311 {
312 //
313 // Unmap and flush it
314 //
315 MiDbgUnTranslatePhysicalAddress();
316 }
317
318 //
319 // Return status to caller
320 //
321 return Status;
322 }