xref: /reactos/ntoskrnl/mm/ARM3/mmdbg.c (revision 20bd5e8a)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/mm/ARM3/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 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 #ifdef NDEBUG
19 #define KdpDprintf(...)
20 #endif
21 
22 BOOLEAN
23 NTAPI
24 MmIsSessionAddress(
25     IN PVOID Address
26 );
27 
28 /* GLOBALS ********************************************************************/
29 
30 PVOID MiDebugMapping = MI_DEBUG_MAPPING;
31 PMMPTE MmDebugPte = NULL;
32 
33 /* FUNCTIONS ******************************************************************/
34 
35 PVOID
36 NTAPI
MiDbgTranslatePhysicalAddress(IN ULONG64 PhysicalAddress,IN ULONG Flags)37 MiDbgTranslatePhysicalAddress(IN ULONG64 PhysicalAddress,
38                               IN ULONG Flags)
39 {
40     PFN_NUMBER Pfn;
41     MMPTE TempPte;
42     PVOID MappingBaseAddress;
43 
44     /* Check if we are called too early */
45     if (MmDebugPte == NULL)
46     {
47         /* The structures we require aren't initialized yet, fail */
48         KdpDprintf("MiDbgTranslatePhysicalAddress called too early! "
49                    "Address: 0x%I64x\n",
50                    PhysicalAddress);
51         return NULL;
52     }
53 
54     /* FIXME: No support for cache flags yet */
55     if ((Flags & (MMDBG_COPY_CACHED |
56                   MMDBG_COPY_UNCACHED |
57                   MMDBG_COPY_WRITE_COMBINED)) != 0)
58     {
59         /* Fail */
60         KdpDprintf("MiDbgTranslatePhysicalAddress: Cache flags not yet supported. "
61                    "Flags: 0x%lx\n",
62                    Flags & (MMDBG_COPY_CACHED |
63                             MMDBG_COPY_UNCACHED |
64                             MMDBG_COPY_WRITE_COMBINED));
65         return NULL;
66     }
67 
68     /* Save the base address of our mapping page */
69     MappingBaseAddress = MiPteToAddress(MmDebugPte);
70 
71     /* Get the template */
72     TempPte = ValidKernelPte;
73 
74     /* Convert physical address to PFN */
75     Pfn = (PFN_NUMBER)(PhysicalAddress >> PAGE_SHIFT);
76 
77     /* Check if this could be an I/O mapping */
78     if (!MiGetPfnEntry(Pfn))
79     {
80         /* FIXME: We don't support this yet */
81         KdpDprintf("MiDbgTranslatePhysicalAddress: I/O Space not yet supported. "
82                    "PFN: 0x%I64x\n",
83                    (ULONG64)Pfn);
84         return NULL;
85     }
86     else
87     {
88         /* Set the PFN in the PTE */
89         TempPte.u.Hard.PageFrameNumber = Pfn;
90     }
91 
92     /* Map the PTE and invalidate its TLB entry */
93     *MmDebugPte = TempPte;
94     KeInvalidateTlbEntry(MappingBaseAddress);
95 
96     /* Calculate and return the virtual offset into our mapping page */
97     return (PVOID)((ULONG_PTR)MappingBaseAddress +
98                     BYTE_OFFSET(PhysicalAddress));
99 }
100 
101 VOID
102 NTAPI
MiDbgUnTranslatePhysicalAddress(VOID)103 MiDbgUnTranslatePhysicalAddress(VOID)
104 {
105     PVOID MappingBaseAddress;
106 
107     /* The address must still be valid at this point */
108     MappingBaseAddress = MiPteToAddress(MmDebugPte);
109     ASSERT(MmIsAddressValid(MappingBaseAddress));
110 
111     /* Clear the mapping PTE and invalidate its TLB entry */
112     MmDebugPte->u.Long = 0;
113     KeInvalidateTlbEntry(MappingBaseAddress);
114 }
115 
116 
117 //
118 // We handle 8-byte requests at most
119 //
120 C_ASSERT(MMDBG_COPY_MAX_SIZE == 8);
121 
122 NTSTATUS
123 NTAPI
MmDbgCopyMemory(IN ULONG64 Address,IN PVOID Buffer,IN ULONG Size,IN ULONG Flags)124 MmDbgCopyMemory(IN ULONG64 Address,
125                 IN PVOID Buffer,
126                 IN ULONG Size,
127                 IN ULONG Flags)
128 {
129     PVOID TargetAddress;
130     ULONG64 PhysicalAddress;
131     PMMPTE PointerPte;
132     PVOID CopyDestination, CopySource;
133 
134     /* No local kernel debugging support yet, so don't worry about locking */
135     if (!(Flags & MMDBG_COPY_UNSAFE))
136     {
137         static BOOLEAN Warned = FALSE;
138         if (!Warned)
139         {
140             KdpDprintf("MmDbgCopyMemory: not providing MMDBG_COPY_UNSAFE is UNIMPLEMENTED\n");
141             Warned = TRUE;
142         }
143     }
144 
145     /* We only handle 1, 2, 4 and 8 byte requests */
146     if ((Size != 1) &&
147         (Size != 2) &&
148         (Size != 4) &&
149         (Size != 8))
150     {
151         /* Invalid size, fail */
152         KdpDprintf("MmDbgCopyMemory: Received Illegal Size 0x%lx\n",
153                    Size);
154         return STATUS_INVALID_PARAMETER_3;
155     }
156 
157     /* The copy must be aligned */
158     if ((Address & (Size - 1)) != 0)
159     {
160         /* Not allowing unaligned access */
161         KdpDprintf("MmDbgCopyMemory: Received Unaligned Address 0x%I64x Size %lx\n",
162                    Address,
163                    Size);
164         return STATUS_INVALID_PARAMETER_3;
165     }
166 
167     /* Check for physical or virtual copy */
168     if (Flags & MMDBG_COPY_PHYSICAL)
169     {
170         /* Physical: translate and map it to our mapping space */
171         TargetAddress = MiDbgTranslatePhysicalAddress(Address,
172                                                       Flags);
173 
174         /* Check if translation failed */
175         if (!TargetAddress)
176         {
177             /* Fail */
178             KdpDprintf("MmDbgCopyMemory: Failed to Translate Physical Address %I64x\n",
179                        Address);
180             return STATUS_UNSUCCESSFUL;
181         }
182 
183         /* The address we received must be valid! */
184         ASSERT(MmIsAddressValid(TargetAddress));
185     }
186     else
187     {
188         /* Virtual; truncate it to avoid casts later down */
189         TargetAddress = (PVOID)(ULONG_PTR)Address;
190 
191         /* Make sure address is valid */
192         if (!MmIsAddressValid(TargetAddress))
193         {
194             /* Fail */
195             KdpDprintf("MmDbgCopyMemory: Failing %s for invalid Virtual Address 0x%p\n",
196                        Flags & MMDBG_COPY_WRITE ? "write" : "read",
197                        TargetAddress);
198             return STATUS_UNSUCCESSFUL;
199         }
200 
201         /* Not handling session space correctly yet */
202         if (MmIsSessionAddress(TargetAddress))
203         {
204             /* FIXME */
205         }
206 
207         /* If we are going to write to the address, then check if its writable */
208         PointerPte = MiAddressToPte(TargetAddress);
209         if ((Flags & MMDBG_COPY_WRITE) &&
210             (!MI_IS_PAGE_WRITEABLE(PointerPte)))
211         {
212             /* Not writable, we need to do a physical copy */
213             Flags |= MMDBG_COPY_PHYSICAL;
214 
215             /* Calculate the physical address */
216             PhysicalAddress = PointerPte->u.Hard.PageFrameNumber << PAGE_SHIFT;
217             PhysicalAddress += BYTE_OFFSET(Address);
218 
219             /* Translate the physical address */
220             TargetAddress = MiDbgTranslatePhysicalAddress(PhysicalAddress,
221                                                           Flags);
222 
223             /* Check if translation failed */
224             if (!TargetAddress)
225             {
226                 /* Fail */
227                 KdpDprintf("MmDbgCopyMemory: Failed to translate for write %I64x (%I64x)\n",
228                            PhysicalAddress,
229                            Address);
230                 return STATUS_UNSUCCESSFUL;
231             }
232         }
233     }
234 
235     /* Check what kind of operation this is */
236     if (Flags & MMDBG_COPY_WRITE)
237     {
238         /* Write */
239         CopyDestination = TargetAddress;
240         CopySource = Buffer;
241     }
242     else
243     {
244         /* Read */
245         CopyDestination = Buffer;
246         CopySource = TargetAddress;
247     }
248 
249     /* Do the copy  */
250     switch (Size)
251     {
252         case 1:
253 
254             /* 1 byte */
255             *(PUCHAR)CopyDestination = *(PUCHAR)CopySource;
256             break;
257 
258         case 2:
259 
260             /* 2 bytes */
261             *(PUSHORT)CopyDestination = *(PUSHORT)CopySource;
262             break;
263 
264         case 4:
265 
266             /* 4 bytes */
267             *(PULONG)CopyDestination = *(PULONG)CopySource;
268             break;
269 
270         case 8:
271 
272             /* 8 bytes */
273             *(PULONGLONG)CopyDestination = *(PULONGLONG)CopySource;
274             break;
275 
276         /* Size is sanitized above */
277         DEFAULT_UNREACHABLE;
278     }
279 
280     /* Get rid of the mapping if this was a physical copy */
281     if (Flags & MMDBG_COPY_PHYSICAL)
282     {
283         /* Unmap and flush it */
284         MiDbgUnTranslatePhysicalAddress();
285     }
286 
287     /* And we are done */
288     return STATUS_SUCCESS;
289 }
290