- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / kd64 / kdapi.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdapi.c
5 * PURPOSE: KD64 Public Routines and Internal Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 VOID
18 NTAPI
19 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
20 IN PVOID DeferredContext,
21 IN PVOID SystemArgument1,
22 IN PVOID SystemArgument2)
23 {
24 LONG OldSlip, NewSlip, PendingSlip;
25
26 /* Get the current pending slip */
27 PendingSlip = KdpTimeSlipPending;
28 do
29 {
30 /* Save the old value and either disable or enable it now. */
31 OldSlip = PendingSlip;
32 NewSlip = OldSlip > 1 ? 1 : 0;
33
34 /* Try to change the value */
35 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
36 NewSlip,
37 OldSlip) != OldSlip);
38
39 /* If the New Slip value is 1, then do the Time Slipping */
40 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
41 }
42
43 VOID
44 NTAPI
45 KdpTimeSlipWork(IN PVOID Context)
46 {
47 KIRQL OldIrql;
48 LARGE_INTEGER DueTime;
49
50 /* Update the System time from the CMOS */
51 ExAcquireTimeRefreshLock(FALSE);
52 ExUpdateSystemTimeFromCmos(FALSE, 0);
53 ExReleaseTimeRefreshLock();
54
55 /* Check if we have a registered Time Slip Event and signal it */
56 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
57 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
58 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
59
60 /* Delay the DPC until it runs next time */
61 DueTime.QuadPart = -1800000000;
62 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
63 }
64
65 BOOLEAN
66 NTAPI
67 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
68 IN OUT PCONTEXT ContextRecord,
69 IN BOOLEAN SecondChanceException)
70 {
71 BOOLEAN Status;
72
73 /* Save the port data */
74 KdSave(FALSE);
75
76 /* Report a state change */
77 #if 0
78 Status = KdpReportExceptionStateChange(ExceptionRecord,
79 ContextRecord,
80 SecondChanceException);
81 #else
82 Status = FALSE;
83 #endif
84
85 /* Restore the port data and return */
86 KdRestore(FALSE);
87 return Status;
88 }
89
90 LARGE_INTEGER
91 NTAPI
92 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
93 {
94 LARGE_INTEGER Null = {{0}};
95
96 /* Check if interrupts were disabled */
97 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
98 {
99 /* Nothing to return */
100 return Null;
101 }
102
103 /* Otherwise, do the call */
104 return KeQueryPerformanceCounter(NULL);
105 }
106
107 BOOLEAN
108 NTAPI
109 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
110 IN PKEXCEPTION_FRAME ExceptionFrame)
111 {
112 BOOLEAN Entered;
113
114 /* Check if we have a trap frame */
115 if (TrapFrame)
116 {
117 /* Calculate the time difference for the enter */
118 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
119 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
120 KdTimerStart.QuadPart;
121 }
122 else
123 {
124 /* No trap frame, so can't calculate */
125 KdTimerStop.QuadPart = 0;
126 }
127
128 /* Save the current IRQL */
129 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
130
131 /* Freeze all CPUs */
132 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
133
134 /* Lock the port, save the state and set debugger entered */
135 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
136 KdSave(FALSE);
137 KdEnteredDebugger = TRUE;
138
139 /* Check freeze flag */
140 if (KiFreezeFlag & 1)
141 {
142 /* Print out errror */
143 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
144 }
145
146 /* Check processor state */
147 if (KiFreezeFlag & 2)
148 {
149 /* Print out errror */
150 DbgPrint("Some processors not frozen in debugger!\n");
151 }
152
153 /* Make sure we acquired the port */
154 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
155
156 /* Return enter state */
157 return Entered;
158 }
159
160 VOID
161 NTAPI
162 KdExitDebugger(IN BOOLEAN Entered)
163 {
164 ULONG TimeSlip;
165
166 /* Restore the state and unlock the port */
167 KdRestore(FALSE);
168 if (KdpPortLocked) KdpPortUnlock();
169
170 /* Unfreeze the CPUs */
171 KeThawExecution(Entered);
172
173 /* Compare time with the one from KdEnterDebugger */
174 if (!KdTimerStop.QuadPart)
175 {
176 /* We didn't get a trap frame earlier in so never got the time */
177 KdTimerStart = KdTimerStop;
178 }
179 else
180 {
181 /* Query the timer */
182 KdTimerStart = KeQueryPerformanceCounter(NULL);
183 }
184
185 /* Check if a Time Slip was on queue */
186 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
187 if (TimeSlip == 1)
188 {
189 /* Queue a DPC for the time slip */
190 InterlockedIncrement(&KdpTimeSlipPending);
191 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
192 }
193 }
194
195 NTSTATUS
196 NTAPI
197 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
198 {
199 KIRQL OldIrql;
200
201 /* Check if we need to acquire the lock */
202 if (NeedLock)
203 {
204 /* Lock the port */
205 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
206 KdpPortLock();
207 }
208
209 /* Check if we're not disabled */
210 if (!KdDisableCount)
211 {
212 /* Check if we had locked the port before */
213 if (NeedLock)
214 {
215 /* Do the unlock */
216 KeLowerIrql(OldIrql);
217 KdpPortUnlock();
218 }
219
220 /* Fail: We're already enabled */
221 return STATUS_INVALID_PARAMETER;
222 }
223
224 /* Decrease the disable count */
225 if (!(--KdDisableCount))
226 {
227 /* We're now enabled again! Were we enabled before, too? */
228 if (KdPreviouslyEnabled)
229 {
230 /* Reinitialize the Debugger */
231 KdInitSystem(0, NULL) ;
232 //KdpRestoreAllBreakpoints();
233 }
234 }
235
236 /* Check if we had locked the port before */
237 if (NeedLock)
238 {
239 /* Yes, now unlock it */
240 KeLowerIrql(OldIrql);
241 KdpPortUnlock();
242 }
243
244 /* We're done */
245 return STATUS_SUCCESS;
246 }
247
248 /* PUBLIC FUNCTIONS **********************************************************/
249
250 /*
251 * @implemented
252 */
253 NTSTATUS
254 NTAPI
255 KdEnableDebugger(VOID)
256 {
257 /* Use the internal routine */
258 while (TRUE);
259 return KdEnableDebuggerWithLock(TRUE);
260 }
261