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