sync with trunk head (34904)
[reactos.git] / reactos / ntoskrnl / kd / i386 / kdmemsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/i386/kdmemsup.c
5 * PURPOSE: Kernel Debugger Safe Memory Support
6 *
7 * PROGRAMMERS: arty
8 */
9
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <internal/debug.h>
13
14 #define HIGH_PHYS_MASK 0x80000000
15 #define PAGE_TABLE_MASK 0x3ff
16 #define BIG_PAGE_SIZE (1<<22)
17 #define CR4_PAGE_SIZE_BIT 0x10
18 #define PDE_PRESENT_BIT 1
19 #define PDE_W_BIT 2
20 #define PDE_PS_BIT 0x80
21
22 /* VARIABLES ***************************************************************/
23
24 extern ULONG MmGlobalKernelPageDirectory[1024];
25 static BOOLEAN KdpPhysAccess = FALSE;
26 ULONG_PTR IdentityMapAddrHigh, IdentityMapAddrLow;
27 extern PFN_TYPE NTAPI MmAllocEarlyPage();
28
29 ULONGLONG
30 FASTCALL
31 KdpPhysRead(ULONG_PTR Addr, LONG Len)
32 {
33 ULONGLONG Result = 0;
34 ULONG_PTR OldCR3 = __readcr3(), OldCR4 = __readcr4();
35
36 if (Addr & HIGH_PHYS_MASK)
37 {
38 Addr &= ~HIGH_PHYS_MASK;
39 __writecr3(IdentityMapAddrHigh);
40 }
41 else
42 __writecr3(IdentityMapAddrLow);
43
44 __writecr4(OldCR4|CR4_PAGE_SIZE_BIT); // Turn on large page translation
45 __invlpg((PVOID)Addr);
46
47 switch (Len)
48 {
49 case 8:
50 Result = *((PULONGLONG)Addr);
51 break;
52 case 4:
53 Result = *((PULONG)Addr);
54 break;
55 case 2:
56 Result = *((PUSHORT)Addr);
57 break;
58 case 1:
59 Result = *((PUCHAR)Addr);
60 break;
61 }
62 __writecr4(OldCR4); // Turn off large page translation
63 __writecr3(OldCR3);
64 __invlpg((PVOID)Addr);
65
66 return Result;
67 }
68
69
70 VOID
71 NTAPI
72 KdpPhysWrite(ULONG_PTR Addr, LONG Len, ULONGLONG Value)
73 {
74 ULONG_PTR OldCR3 = __readcr3(), OldCR4 = __readcr4();
75
76 if (Addr & HIGH_PHYS_MASK)
77 {
78 Addr &= ~HIGH_PHYS_MASK;
79 __writecr3(IdentityMapAddrHigh);
80 }
81 else
82 __writecr3(IdentityMapAddrLow);
83
84 __writecr4(OldCR4|CR4_PAGE_SIZE_BIT); // Turn on large page translation
85 __invlpg((PVOID)Addr);
86
87 switch (Len)
88 {
89 case 8:
90 *((PULONGLONG)Addr) = Value;
91 break;
92 case 4:
93 *((PULONG)Addr) = Value;
94 break;
95 case 2:
96 *((PUSHORT)Addr) = Value;
97 break;
98 case 1:
99 *((PUCHAR)Addr) = Value;
100 break;
101 }
102 __writecr4(OldCR4); // Turn off large page translation
103 __writecr3(OldCR3);
104 __invlpg((PVOID)Addr);
105 }
106
107 BOOLEAN
108 NTAPI
109 KdpTranslateAddress(ULONG_PTR Addr, PULONG_PTR ResultAddr)
110 {
111 ULONG_PTR CR3Value = __readcr3();
112 ULONG_PTR CR4Value = __readcr4();
113 ULONG_PTR PageDirectory = (CR3Value & ~(PAGE_SIZE-1)) +
114 ((Addr >> 22) * sizeof(ULONG));
115 ULONG_PTR PageDirectoryEntry = KdpPhysRead(PageDirectory, sizeof(ULONG));
116
117 /* Not present -> fail */
118 if (!(PageDirectoryEntry & PDE_PRESENT_BIT))
119 {
120 return FALSE;
121 }
122
123 /* Big Page? */
124 if ((PageDirectoryEntry & PDE_PS_BIT) && (CR4Value & CR4_PAGE_SIZE_BIT))
125 {
126 *ResultAddr = (PageDirectoryEntry & ~(BIG_PAGE_SIZE-1)) +
127 (Addr & (BIG_PAGE_SIZE-1));
128 return TRUE;
129 }
130 else
131 {
132 ULONG_PTR PageTableAddr =
133 (PageDirectoryEntry & ~(PAGE_SIZE-1)) +
134 ((Addr >> PAGE_SHIFT) & PAGE_TABLE_MASK) * sizeof(ULONG);
135 ULONG_PTR PageTableEntry = KdpPhysRead(PageTableAddr, sizeof(ULONG));
136 if (PageTableEntry & PDE_PRESENT_BIT)
137 {
138 *ResultAddr = (PageTableEntry & ~(PAGE_SIZE-1)) +
139 (Addr & (PAGE_SIZE-1));
140 return TRUE;
141 }
142 }
143
144 return FALSE;
145 }
146
147 BOOLEAN
148 NTAPI
149 KdpSafeReadMemory(ULONG_PTR Addr, LONG Len, PVOID Value)
150 {
151 ULONG_PTR ResultPhysAddr;
152
153 if (!KdpPhysAccess)
154 {
155 memcpy(Value, (PVOID)Addr, Len);
156 return TRUE;
157 }
158
159 memset(Value, 0, Len);
160
161 if (!KdpTranslateAddress(Addr, &ResultPhysAddr))
162 return FALSE;
163
164 switch (Len)
165 {
166 case 8:
167 *((PULONGLONG)Value) = KdpPhysRead(ResultPhysAddr, Len);
168 break;
169 case 4:
170 *((PULONG)Value) = KdpPhysRead(ResultPhysAddr, Len);
171 break;
172 case 2:
173 *((PUSHORT)Value) = KdpPhysRead(ResultPhysAddr, Len);
174 break;
175 case 1:
176 *((PUCHAR)Value) = KdpPhysRead(ResultPhysAddr, Len);
177 break;
178 }
179
180 return TRUE;
181 }
182
183 BOOLEAN
184 NTAPI
185 KdpSafeWriteMemory(ULONG_PTR Addr, LONG Len, ULONGLONG Value)
186 {
187 ULONG_PTR ResultPhysAddr;
188
189 if (!KdpPhysAccess)
190 {
191 memcpy((PVOID)Addr, &Value, Len);
192 return TRUE;
193 }
194
195 if (!KdpTranslateAddress(Addr, &ResultPhysAddr))
196 return FALSE;
197
198 KdpPhysWrite(ResultPhysAddr, Len, Value);
199 return TRUE;
200 }
201
202 VOID
203 NTAPI
204 KdpEnableSafeMem()
205 {
206 int i;
207 PULONG IdentityMapVirt;
208 PHYSICAL_ADDRESS IdentityMapPhys, Highest = { };
209
210 if (KdpPhysAccess)
211 return;
212
213 Highest.LowPart = (ULONG)-1;
214 /* Allocate a physical page and map it to copy the phys copy code onto */
215 IdentityMapVirt = (PULONG)MmAllocateContiguousMemory(2 * PAGE_SIZE, Highest);
216 IdentityMapPhys = MmGetPhysicalAddress(IdentityMapVirt);
217 IdentityMapAddrHigh = IdentityMapPhys.LowPart;
218
219 /* Copy the kernel space */
220 memcpy(IdentityMapVirt,
221 MmGlobalKernelPageDirectory,
222 PAGE_SIZE);
223
224 /* Set up 512 4Mb pages (high 2Gig identity mapped) */
225 for (i = 0; i < 512; i++)
226 {
227 IdentityMapVirt[i] =
228 HIGH_PHYS_MASK | (i << 22) | PDE_PS_BIT | PDE_W_BIT | PDE_PRESENT_BIT;
229 }
230
231 /* Allocate a physical page and map it to copy the phys copy code onto */
232 IdentityMapAddrLow = IdentityMapAddrHigh + PAGE_SIZE;
233 IdentityMapVirt += PAGE_SIZE / sizeof(ULONG);
234
235 /* Copy the kernel space */
236 memcpy(IdentityMapVirt,
237 MmGlobalKernelPageDirectory,
238 PAGE_SIZE);
239
240 /* Set up 512 4Mb pages (low 2Gig identity mapped) */
241 for (i = 0; i < 512; i++)
242 {
243 IdentityMapVirt[i] = (i << 22) | PDE_PS_BIT | PDE_W_BIT | PDE_PRESENT_BIT;
244 }
245
246 KdpPhysAccess = TRUE;
247 }