- Add kdbreak.c with the following APIs: KdpLowWriteContent, KdpLowRestoreBreakpoint...
[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 KdpSetCommonState(IN ULONG NewState,
20 IN PCONTEXT Context,
21 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
22 {
23 USHORT InstructionCount;
24 BOOLEAN HadBreakpoints;
25
26 /* Setup common stuff available for all CPU architectures */
27 WaitStateChange->NewState = NewState;
28 WaitStateChange->ProcessorLevel = KeProcessorLevel;
29 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
30 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
31 WaitStateChange->Thread = (ULONG)KeGetCurrentThread();
32 WaitStateChange->ProgramCounter = (ULONG64)Context->Eip;
33
34 /* Zero out the Control Report */
35 RtlZeroMemory(&WaitStateChange->ControlReport,
36 sizeof(DBGKD_CONTROL_REPORT));
37
38 /* Now copy the instruction stream and set the count */
39 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
40 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
41 DBGKD_MAXSTREAM);
42 InstructionCount = DBGKD_MAXSTREAM;
43 WaitStateChange->ControlReport.InstructionCount = InstructionCount;
44
45 /* Clear all the breakpoints in this region */
46 HadBreakpoints = FALSE;
47 #if 0
48 KdpDeleteBreakpointRange((PVOID)WaitStateChange->ProgramCounter,
49 (PVOID)(WaitStateChange->ProgramCounter +
50 WaitStateChange->ControlReport.
51 InstructionCount - 1));
52 #endif
53 if (HadBreakpoints)
54 {
55 /* Copy the instruction stream again, this time without breakpoints */
56 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
57 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
58 WaitStateChange->ControlReport.InstructionCount);
59 }
60 }
61
62 VOID
63 NTAPI
64 KdpSetContextState(IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange,
65 IN PCONTEXT Context)
66 {
67 PKPRCB Prcb = KeGetCurrentPrcb();
68
69 /* Copy i386 specific debug registers */
70 WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.
71 KernelDr6;
72 WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.
73 KernelDr7;
74
75 /* Copy i386 specific segments */
76 WaitStateChange->ControlReport.SegCs = (USHORT)Context->SegCs;
77 WaitStateChange->ControlReport.SegDs = (USHORT)Context->SegDs;
78 WaitStateChange->ControlReport.SegEs = (USHORT)Context->SegEs;
79 WaitStateChange->ControlReport.SegFs = (USHORT)Context->SegFs;
80
81 /* Copy EFlags */
82 WaitStateChange->ControlReport.EFlags = Context->EFlags;
83
84 /* Set Report Flags */
85 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS;
86 if (WaitStateChange->ControlReport.SegCs == KGDT_R0_CODE)
87 {
88 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_CS;
89 }
90 }
91
92 VOID
93 NTAPI
94 KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
95 {
96 /* Copy the version block */
97 RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));
98 }
99
100 VOID
101 NTAPI
102 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
103 {
104 STRING Header;
105
106 /* Fill out the header */
107 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
108 Header.Buffer = (PCHAR)State;
109
110 /* Get the version block */
111 KdpSysGetVersion(&State->u.GetVersion64);
112
113 /* Fill out the state */
114 State->ApiNumber = DbgKdGetVersionApi;
115 State->ReturnStatus = STATUS_SUCCESS;
116
117 /* Send the packet */
118 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
119 &Header,
120 NULL,
121 &KdpContext);
122 }
123
124
125 BOOLEAN VirtCalled = FALSE;
126
127 VOID
128 NTAPI
129 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
130 IN PSTRING Data,
131 IN PCONTEXT Context)
132 {
133 STRING Header;
134 ULONG Length = State->u.ReadMemory.TransferCount;
135 NTSTATUS Status = STATUS_SUCCESS;
136
137 /* Validate length */
138 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
139 {
140 /* Overflow, set it to maximum possible */
141 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
142 }
143
144 #if 0
145 if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))
146 {
147 Ke386SetCr2(State->u.ReadMemory.TargetBaseAddress);
148 while (TRUE);
149 }
150 #endif
151
152 if ((ULONG_PTR)State->u.ReadMemory.TargetBaseAddress < KSEG0_BASE)
153 {
154 Length = 0;
155 Status = STATUS_UNSUCCESSFUL;
156 }
157 else if ((ULONG_PTR)State->u.ReadMemory.TargetBaseAddress >= (ULONG_PTR)SharedUserData)
158 {
159 Length = 0;
160 Status = STATUS_UNSUCCESSFUL;
161 }
162 else
163 {
164 RtlCopyMemory(Data->Buffer,
165 (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
166 Length);
167 }
168
169 /* Fill out the header */
170 Data->Length = Length;
171 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
172 Header.Buffer = (PCHAR)State;
173
174 /* Fill out the state */
175 State->ReturnStatus = Status;
176 State->u.ReadMemory.ActualBytesRead = Length;
177
178 /* Send the packet */
179 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
180 &Header,
181 Data,
182 &KdpContext);
183 }
184
185 VOID
186 NTAPI
187 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
188 IN PSTRING Data,
189 IN PCONTEXT Context)
190 {
191 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
192 STRING Header;
193 ULONG Length, RealLength;
194 PVOID ControlStart;
195
196 /* Setup the header */
197 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
198 Header.Buffer = (PCHAR)State;
199 ASSERT(Data->Length == 0);
200
201 /* Check the length requested */
202 Length = ReadMemory->TransferCount;
203 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
204 {
205 /* Use maximum allowed */
206 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
207 }
208
209 /* Make sure that this is a valid request */
210 if (((ULONG)ReadMemory->TargetBaseAddress < sizeof(KPROCESSOR_STATE)) &&
211 (State->Processor < KeNumberProcessors))
212 {
213 /* Get the actual length */
214 RealLength = sizeof(KPROCESSOR_STATE) -
215 (ULONG_PTR)ReadMemory->TargetBaseAddress;
216 if (RealLength < Length) Length = RealLength;
217
218 /* Set the proper address */
219 ControlStart = (PVOID)((ULONG_PTR)ReadMemory->TargetBaseAddress +
220 (ULONG_PTR)&KiProcessorBlock[State->Processor]->
221 ProcessorState);
222
223 /* Copy the memory */
224 RtlCopyMemory(Data->Buffer, ControlStart, Length);
225 Data->Length = Length;
226
227 /* Finish up */
228 State->ReturnStatus = STATUS_SUCCESS;
229 ReadMemory->ActualBytesRead = Data->Length;
230 }
231 else
232 {
233 /* Invalid request */
234 Data->Length = 0;
235 State->ReturnStatus = STATUS_UNSUCCESSFUL;
236 ReadMemory->ActualBytesRead = 0;
237 }
238
239 /* Send the reply */
240 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
241 &Header,
242 Data,
243 &KdpContext);
244 }
245
246 VOID
247 NTAPI
248 KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
249 IN PSTRING Data,
250 IN PCONTEXT Context)
251 {
252 PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
253 STRING Header;
254
255 /* Fill out the header */
256 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
257 Header.Buffer = (PCHAR)State;
258 ASSERT(Data->Length == 0);
259
260 /* Get the version block */
261 if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
262 {
263 /* We're all good */
264 State->ReturnStatus = STATUS_SUCCESS;
265 }
266 else
267 {
268 /* We failed */
269 State->ReturnStatus = STATUS_UNSUCCESSFUL;
270 }
271
272 /* Send the packet */
273 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
274 &Header,
275 NULL,
276 &KdpContext);
277 }
278
279 KCONTINUE_STATUS
280 NTAPI
281 KdpSendWaitContinue(IN ULONG PacketType,
282 IN PSTRING SendHeader,
283 IN PSTRING SendData OPTIONAL,
284 IN OUT PCONTEXT Context)
285 {
286 STRING Data, Header;
287 DBGKD_MANIPULATE_STATE64 ManipulateState;
288 ULONG Length;
289 KDSTATUS RecvCode;
290
291 /* Setup the Manipulate State structure */
292 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
293 Header.Buffer = (PCHAR)&ManipulateState;
294 Data.MaximumLength = sizeof(KdpMessageBuffer);
295 Data.Buffer = KdpMessageBuffer;
296 //KdpContextSent = FALSE;
297
298 SendPacket:
299 /* Send the Packet */
300 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
301
302 /* If the debugger isn't present anymore, just return success */
303 if (KdDebuggerNotPresent) return ContinueSuccess;
304
305 /* Main processing Loop */
306 for (;;)
307 {
308 /* Receive Loop */
309 do
310 {
311 /* Wait to get a reply to our packet */
312 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
313 &Header,
314 &Data,
315 &Length,
316 &KdpContext);
317
318 /* If we got a resend request, do it */
319 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
320 } while (RecvCode == KdPacketTimedOut);
321
322 /* Now check what API we got */
323 switch (ManipulateState.ApiNumber)
324 {
325 case DbgKdReadVirtualMemoryApi:
326
327 /* Read virtual memory */
328 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
329 VirtCalled = TRUE;
330 break;
331
332 case DbgKdWriteVirtualMemoryApi:
333
334 /* FIXME: TODO */
335 Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
336 while (TRUE);
337 break;
338
339 case DbgKdGetContextApi:
340
341 /* FIXME: TODO */
342 Ke386SetCr2(DbgKdGetContextApi);
343 while (TRUE);
344 break;
345
346 case DbgKdSetContextApi:
347
348 /* FIXME: TODO */
349 Ke386SetCr2(DbgKdSetContextApi);
350 while (TRUE);
351 break;
352
353 case DbgKdWriteBreakPointApi:
354
355 /* FIXME: TODO */
356 Ke386SetCr2(DbgKdWriteBreakPointApi);
357 while (TRUE);
358 break;
359
360 case DbgKdRestoreBreakPointApi:
361
362 /* FIXME: TODO */
363 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
364 break;
365
366 case DbgKdContinueApi:
367
368 /* FIXME: TODO */
369 Ke386SetCr2(DbgKdContinueApi);
370 while (TRUE);
371 break;
372
373 case DbgKdReadControlSpaceApi:
374
375 /* Read control space */
376 KdpReadControlSpace(&ManipulateState, &Data, Context);
377 break;
378
379 case DbgKdWriteControlSpaceApi:
380
381 /* FIXME: TODO */
382 Ke386SetCr2(DbgKdWriteControlSpaceApi);
383 while (TRUE);
384 break;
385
386 case DbgKdReadIoSpaceApi:
387
388 /* FIXME: TODO */
389 Ke386SetCr2(DbgKdReadIoSpaceApi);
390 while (TRUE);
391 break;
392
393 case DbgKdWriteIoSpaceApi:
394
395 /* FIXME: TODO */
396 Ke386SetCr2(DbgKdWriteIoSpaceApi);
397 while (TRUE);
398 break;
399
400 case DbgKdRebootApi:
401
402 /* FIXME: TODO */
403 Ke386SetCr2(DbgKdRebootApi);
404 while (TRUE);
405 break;
406
407 case DbgKdContinueApi2:
408
409 /* FIXME: TODO */
410 Ke386SetCr2(DbgKdContinueApi2);
411 while (TRUE);
412 break;
413
414 case DbgKdReadPhysicalMemoryApi:
415
416 /* FIXME: TODO */
417 Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
418 while (TRUE);
419 break;
420
421 case DbgKdWritePhysicalMemoryApi:
422
423 /* FIXME: TODO */
424 Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
425 while (TRUE);
426 break;
427
428 case DbgKdQuerySpecialCallsApi:
429
430 /* FIXME: TODO */
431 Ke386SetCr2(DbgKdQuerySpecialCallsApi);
432 while (TRUE);
433 break;
434
435 case DbgKdSetSpecialCallApi:
436
437 /* FIXME: TODO */
438 Ke386SetCr2(DbgKdSetSpecialCallApi);
439 while (TRUE);
440 break;
441
442 case DbgKdClearSpecialCallsApi:
443
444 /* FIXME: TODO */
445 Ke386SetCr2(DbgKdClearSpecialCallsApi);
446 while (TRUE);
447 break;
448
449 case DbgKdSetInternalBreakPointApi:
450
451 /* FIXME: TODO */
452 Ke386SetCr2(DbgKdSetInternalBreakPointApi);
453 while (TRUE);
454 break;
455
456 case DbgKdGetInternalBreakPointApi:
457
458 /* FIXME: TODO */
459 Ke386SetCr2(DbgKdGetInternalBreakPointApi);
460 while (TRUE);
461 break;
462
463 case DbgKdReadIoSpaceExtendedApi:
464
465 /* FIXME: TODO */
466 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
467 while (TRUE);
468 break;
469
470 case DbgKdWriteIoSpaceExtendedApi:
471
472 /* FIXME: TODO */
473 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
474 while (TRUE);
475 break;
476
477 case DbgKdGetVersionApi:
478
479 /* Get version data */
480 KdpGetVersion(&ManipulateState);
481 break;
482
483 case DbgKdWriteBreakPointExApi:
484
485 /* FIXME: TODO */
486 Ke386SetCr2(DbgKdWriteBreakPointExApi);
487 while (TRUE);
488 break;
489
490 case DbgKdRestoreBreakPointExApi:
491
492 /* FIXME: TODO */
493 Ke386SetCr2(DbgKdRestoreBreakPointExApi);
494 while (TRUE);
495 break;
496
497 case DbgKdCauseBugCheckApi:
498
499 /* FIXME: TODO */
500 Ke386SetCr2(DbgKdCauseBugCheckApi);
501 while (TRUE);
502 break;
503
504 case DbgKdSwitchProcessor:
505
506 /* FIXME: TODO */
507 Ke386SetCr2(DbgKdSwitchProcessor);
508 while (TRUE);
509 break;
510
511 case DbgKdPageInApi:
512
513 /* FIXME: TODO */
514 Ke386SetCr2(DbgKdPageInApi);
515 while (TRUE);
516 break;
517
518 case DbgKdReadMachineSpecificRegister:
519
520 /* FIXME: TODO */
521 Ke386SetCr2(DbgKdReadMachineSpecificRegister);
522 while (TRUE);
523 break;
524
525 case DbgKdWriteMachineSpecificRegister:
526
527 /* FIXME: TODO */
528 Ke386SetCr2(DbgKdWriteMachineSpecificRegister);
529 while (TRUE);
530 break;
531
532 case OldVlm1:
533
534 /* FIXME: TODO */
535 Ke386SetCr2(OldVlm1);
536 while (TRUE);
537 break;
538
539 case OldVlm2:
540
541 /* FIXME: TODO */
542 Ke386SetCr2(OldVlm2);
543 while (TRUE);
544 break;
545
546 case DbgKdSearchMemoryApi:
547
548 /* FIXME: TODO */
549 Ke386SetCr2(DbgKdSearchMemoryApi);
550 while (TRUE);
551 break;
552
553 case DbgKdGetBusDataApi:
554
555 /* FIXME: TODO */
556 Ke386SetCr2(DbgKdGetBusDataApi);
557 while (TRUE);
558 break;
559
560 case DbgKdSetBusDataApi:
561
562 /* FIXME: TODO */
563 Ke386SetCr2(DbgKdSetBusDataApi);
564 while (TRUE);
565 break;
566
567 case DbgKdCheckLowMemoryApi:
568
569 /* FIXME: TODO */
570 Ke386SetCr2(DbgKdCheckLowMemoryApi);
571 while (TRUE);
572 break;
573
574 case DbgKdClearAllInternalBreakpointsApi:
575
576 /* FIXME: TODO */
577 Ke386SetCr2(DbgKdClearAllInternalBreakpointsApi);
578 while (TRUE);
579 break;
580
581 case DbgKdFillMemoryApi:
582
583 /* FIXME: TODO */
584 Ke386SetCr2(DbgKdFillMemoryApi);
585 while (TRUE);
586 break;
587
588 case DbgKdQueryMemoryApi:
589
590 /* FIXME: TODO */
591 Ke386SetCr2(DbgKdQueryMemoryApi);
592 while (TRUE);
593 break;
594
595 case DbgKdSwitchPartition:
596
597 /* FIXME: TODO */
598 Ke386SetCr2(DbgKdSwitchPartition);
599 while (TRUE);
600 break;
601
602 /* Unsupported Message */
603 default:
604
605 /* Setup an empty message, with failure */
606 while (TRUE);
607 Data.Length = 0;
608 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
609
610 /* Send it */
611 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
612 &Header,
613 &Data,
614 &KdpContext);
615 break;
616 }
617 }
618 }
619
620 BOOLEAN
621 NTAPI
622 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
623 IN PKD_SYMBOLS_INFO SymbolInfo,
624 IN BOOLEAN Unload,
625 IN OUT PCONTEXT Context)
626 {
627 PSTRING ExtraData;
628 STRING Data, Header;
629 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
630 KCONTINUE_STATUS Status;
631
632 /* Start wait loop */
633 do
634 {
635 /* Build the architecture common parts of the message */
636 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
637 Context,
638 &WaitStateChange);
639
640 /* Now finish creating the structure */
641 KdpSetContextState(&WaitStateChange, Context);
642
643 /* Fill out load data */
644 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
645 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG)SymbolInfo->BaseOfDll;
646 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
647 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
648 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
649
650 /* Check if we have a symbol name */
651 if (PathName)
652 {
653 /* Setup the information */
654 WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
655 Data.Buffer = KdpPathBuffer;
656 Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
657 ExtraData = &Data;
658 }
659 else
660 {
661 /* No name */
662 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
663 ExtraData = NULL;
664 }
665
666 /* Setup the header */
667 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
668 Header.Buffer = (PCHAR)&WaitStateChange;
669
670 /* Send the packet */
671 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
672 &Header,
673 ExtraData,
674 Context);
675 } while(Status == ContinueProcessorReselected);
676
677 /* Return status */
678 while (TRUE);
679 return Status;
680 }
681
682 VOID
683 NTAPI
684 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
685 IN PVOID DeferredContext,
686 IN PVOID SystemArgument1,
687 IN PVOID SystemArgument2)
688 {
689 LONG OldSlip, NewSlip, PendingSlip;
690
691 /* Get the current pending slip */
692 PendingSlip = KdpTimeSlipPending;
693 do
694 {
695 /* Save the old value and either disable or enable it now. */
696 OldSlip = PendingSlip;
697 NewSlip = OldSlip > 1 ? 1 : 0;
698
699 /* Try to change the value */
700 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
701 NewSlip,
702 OldSlip) != OldSlip);
703
704 /* If the New Slip value is 1, then do the Time Slipping */
705 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
706 }
707
708 VOID
709 NTAPI
710 KdpTimeSlipWork(IN PVOID Context)
711 {
712 KIRQL OldIrql;
713 LARGE_INTEGER DueTime;
714
715 /* Update the System time from the CMOS */
716 ExAcquireTimeRefreshLock(FALSE);
717 ExUpdateSystemTimeFromCmos(FALSE, 0);
718 ExReleaseTimeRefreshLock();
719
720 /* Check if we have a registered Time Slip Event and signal it */
721 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
722 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
723 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
724
725 /* Delay the DPC until it runs next time */
726 DueTime.QuadPart = -1800000000;
727 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
728 }
729
730 BOOLEAN
731 NTAPI
732 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
733 IN OUT PCONTEXT ContextRecord,
734 IN BOOLEAN SecondChanceException)
735 {
736 BOOLEAN Status;
737
738 /* Save the port data */
739 KdSave(FALSE);
740
741 /* Report a state change */
742 #if 0
743 Status = KdpReportExceptionStateChange(ExceptionRecord,
744 ContextRecord,
745 SecondChanceException);
746 #else
747 Status = FALSE;
748 #endif
749
750 /* Restore the port data and return */
751 KdRestore(FALSE);
752 return Status;
753 }
754
755 LARGE_INTEGER
756 NTAPI
757 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
758 {
759 LARGE_INTEGER Null = {{0}};
760
761 /* Check if interrupts were disabled */
762 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
763 {
764 /* Nothing to return */
765 return Null;
766 }
767
768 /* Otherwise, do the call */
769 return KeQueryPerformanceCounter(NULL);
770 }
771
772 BOOLEAN
773 NTAPI
774 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
775 IN PKEXCEPTION_FRAME ExceptionFrame)
776 {
777 BOOLEAN Entered;
778
779 /* Check if we have a trap frame */
780 if (TrapFrame)
781 {
782 /* Calculate the time difference for the enter */
783 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
784 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
785 KdTimerStart.QuadPart;
786 }
787 else
788 {
789 /* No trap frame, so can't calculate */
790 KdTimerStop.QuadPart = 0;
791 }
792
793 /* Save the current IRQL */
794 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
795
796 /* Freeze all CPUs */
797 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
798
799 /* Lock the port, save the state and set debugger entered */
800 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
801 KdSave(FALSE);
802 KdEnteredDebugger = TRUE;
803
804 /* Check freeze flag */
805 if (KiFreezeFlag & 1)
806 {
807 /* Print out errror */
808 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
809 }
810
811 /* Check processor state */
812 if (KiFreezeFlag & 2)
813 {
814 /* Print out errror */
815 DbgPrint("Some processors not frozen in debugger!\n");
816 }
817
818 /* Make sure we acquired the port */
819 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
820
821 /* Return enter state */
822 return Entered;
823 }
824
825 VOID
826 NTAPI
827 KdExitDebugger(IN BOOLEAN Entered)
828 {
829 ULONG TimeSlip;
830
831 /* Restore the state and unlock the port */
832 KdRestore(FALSE);
833 if (KdpPortLocked) KdpPortUnlock();
834
835 /* Unfreeze the CPUs */
836 KeThawExecution(Entered);
837
838 /* Compare time with the one from KdEnterDebugger */
839 if (!KdTimerStop.QuadPart)
840 {
841 /* We didn't get a trap frame earlier in so never got the time */
842 KdTimerStart = KdTimerStop;
843 }
844 else
845 {
846 /* Query the timer */
847 KdTimerStart = KeQueryPerformanceCounter(NULL);
848 }
849
850 /* Check if a Time Slip was on queue */
851 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
852 if (TimeSlip == 1)
853 {
854 /* Queue a DPC for the time slip */
855 InterlockedIncrement(&KdpTimeSlipPending);
856 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
857 }
858 }
859
860 NTSTATUS
861 NTAPI
862 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
863 {
864 KIRQL OldIrql;
865
866 /* Check if we need to acquire the lock */
867 if (NeedLock)
868 {
869 /* Lock the port */
870 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
871 KdpPortLock();
872 }
873
874 /* Check if we're not disabled */
875 if (!KdDisableCount)
876 {
877 /* Check if we had locked the port before */
878 if (NeedLock)
879 {
880 /* Do the unlock */
881 KeLowerIrql(OldIrql);
882 KdpPortUnlock();
883 }
884
885 /* Fail: We're already enabled */
886 return STATUS_INVALID_PARAMETER;
887 }
888
889 /* Decrease the disable count */
890 if (!(--KdDisableCount))
891 {
892 /* We're now enabled again! Were we enabled before, too? */
893 if (KdPreviouslyEnabled)
894 {
895 /* Reinitialize the Debugger */
896 KdInitSystem(0, NULL) ;
897 KdpRestoreAllBreakpoints();
898 }
899 }
900
901 /* Check if we had locked the port before */
902 if (NeedLock)
903 {
904 /* Yes, now unlock it */
905 KeLowerIrql(OldIrql);
906 KdpPortUnlock();
907 }
908
909 /* We're done */
910 return STATUS_SUCCESS;
911 }
912
913 /* PUBLIC FUNCTIONS **********************************************************/
914
915 /*
916 * @implemented
917 */
918 NTSTATUS
919 NTAPI
920 KdEnableDebugger(VOID)
921 {
922 /* Use the internal routine */
923 while (TRUE);
924 return KdEnableDebuggerWithLock(TRUE);
925 }
926