- KPROCESSOR_STATE is not 4-byte aligned.
[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 VOID
280 NTAPI
281 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
282 IN PSTRING Data,
283 IN PCONTEXT Context)
284 {
285 STRING Header;
286 PVOID ControlStart;
287
288 /* Setup the header */
289 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
290 Header.Buffer = (PCHAR)State;
291 ASSERT(Data->Length == 0);
292
293 /* Make sure that this is a valid request */
294 if (State->Processor < KeNumberProcessors)
295 {
296 /* Check if the request is for this CPU */
297 if (State->Processor == KeGetCurrentPrcb()->Number)
298 {
299 /* We're just copying our own context */
300 ControlStart = Context;
301 }
302 else
303 {
304 /* SMP not yet handled */
305 ControlStart = NULL;
306 while (TRUE);
307 }
308
309 /* Copy the memory */
310 RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));
311 Data->Length = sizeof(CONTEXT);
312
313 /* Finish up */
314 State->ReturnStatus = STATUS_SUCCESS;
315 }
316 else
317 {
318 /* Invalid request */
319 State->ReturnStatus = STATUS_UNSUCCESSFUL;
320 }
321
322 /* Send the reply */
323 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
324 &Header,
325 Data,
326 &KdpContext);
327 }
328
329
330 KCONTINUE_STATUS
331 NTAPI
332 KdpSendWaitContinue(IN ULONG PacketType,
333 IN PSTRING SendHeader,
334 IN PSTRING SendData OPTIONAL,
335 IN OUT PCONTEXT Context)
336 {
337 STRING Data, Header;
338 DBGKD_MANIPULATE_STATE64 ManipulateState;
339 ULONG Length;
340 KDSTATUS RecvCode;
341
342 /* Setup the Manipulate State structure */
343 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
344 Header.Buffer = (PCHAR)&ManipulateState;
345 Data.MaximumLength = sizeof(KdpMessageBuffer);
346 Data.Buffer = KdpMessageBuffer;
347 //KdpContextSent = FALSE;
348
349 SendPacket:
350 /* Send the Packet */
351 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
352
353 /* If the debugger isn't present anymore, just return success */
354 if (KdDebuggerNotPresent) return ContinueSuccess;
355
356 /* Main processing Loop */
357 for (;;)
358 {
359 /* Receive Loop */
360 do
361 {
362 /* Wait to get a reply to our packet */
363 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
364 &Header,
365 &Data,
366 &Length,
367 &KdpContext);
368
369 /* If we got a resend request, do it */
370 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
371 } while (RecvCode == KdPacketTimedOut);
372
373 /* Now check what API we got */
374 switch (ManipulateState.ApiNumber)
375 {
376 case DbgKdReadVirtualMemoryApi:
377
378 /* Read virtual memory */
379 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
380 VirtCalled = TRUE;
381 break;
382
383 case DbgKdWriteVirtualMemoryApi:
384
385 /* FIXME: TODO */
386 Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
387 while (TRUE);
388 break;
389
390 case DbgKdGetContextApi:
391
392 /* FIXME: TODO */
393 KdpGetContext(&ManipulateState, &Data, Context);
394 break;
395
396 case DbgKdSetContextApi:
397
398 /* FIXME: TODO */
399 Ke386SetCr2(DbgKdSetContextApi);
400 while (TRUE);
401 break;
402
403 case DbgKdWriteBreakPointApi:
404
405 /* FIXME: TODO */
406 Ke386SetCr2(DbgKdWriteBreakPointApi);
407 while (TRUE);
408 break;
409
410 case DbgKdRestoreBreakPointApi:
411
412 /* FIXME: TODO */
413 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
414 break;
415
416 case DbgKdContinueApi:
417
418 /* FIXME: TODO */
419 Ke386SetCr2(DbgKdContinueApi);
420 while (TRUE);
421 break;
422
423 case DbgKdReadControlSpaceApi:
424
425 /* Read control space */
426 KdpReadControlSpace(&ManipulateState, &Data, Context);
427 break;
428
429 case DbgKdWriteControlSpaceApi:
430
431 /* FIXME: TODO */
432 Ke386SetCr2(DbgKdWriteControlSpaceApi);
433 while (TRUE);
434 break;
435
436 case DbgKdReadIoSpaceApi:
437
438 /* FIXME: TODO */
439 Ke386SetCr2(DbgKdReadIoSpaceApi);
440 while (TRUE);
441 break;
442
443 case DbgKdWriteIoSpaceApi:
444
445 /* FIXME: TODO */
446 Ke386SetCr2(DbgKdWriteIoSpaceApi);
447 while (TRUE);
448 break;
449
450 case DbgKdRebootApi:
451
452 /* FIXME: TODO */
453 Ke386SetCr2(DbgKdRebootApi);
454 while (TRUE);
455 break;
456
457 case DbgKdContinueApi2:
458
459 /* FIXME: TODO */
460 Ke386SetCr2(DbgKdContinueApi2);
461 while (TRUE);
462 break;
463
464 case DbgKdReadPhysicalMemoryApi:
465
466 /* FIXME: TODO */
467 goto fail;
468 Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
469 while (TRUE);
470 break;
471
472 case DbgKdWritePhysicalMemoryApi:
473
474 /* FIXME: TODO */
475 Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
476 while (TRUE);
477 break;
478
479 case DbgKdQuerySpecialCallsApi:
480
481 /* FIXME: TODO */
482 Ke386SetCr2(DbgKdQuerySpecialCallsApi);
483 while (TRUE);
484 break;
485
486 case DbgKdSetSpecialCallApi:
487
488 /* FIXME: TODO */
489 Ke386SetCr2(DbgKdSetSpecialCallApi);
490 while (TRUE);
491 break;
492
493 case DbgKdClearSpecialCallsApi:
494
495 /* FIXME: TODO */
496 Ke386SetCr2(DbgKdClearSpecialCallsApi);
497 while (TRUE);
498 break;
499
500 case DbgKdSetInternalBreakPointApi:
501
502 /* FIXME: TODO */
503 Ke386SetCr2(DbgKdSetInternalBreakPointApi);
504 while (TRUE);
505 break;
506
507 case DbgKdGetInternalBreakPointApi:
508
509 /* FIXME: TODO */
510 Ke386SetCr2(DbgKdGetInternalBreakPointApi);
511 while (TRUE);
512 break;
513
514 case DbgKdReadIoSpaceExtendedApi:
515
516 /* FIXME: TODO */
517 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
518 while (TRUE);
519 break;
520
521 case DbgKdWriteIoSpaceExtendedApi:
522
523 /* FIXME: TODO */
524 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
525 while (TRUE);
526 break;
527
528 case DbgKdGetVersionApi:
529
530 /* Get version data */
531 KdpGetVersion(&ManipulateState);
532 break;
533
534 case DbgKdWriteBreakPointExApi:
535
536 /* FIXME: TODO */
537 Ke386SetCr2(DbgKdWriteBreakPointExApi);
538 while (TRUE);
539 break;
540
541 case DbgKdRestoreBreakPointExApi:
542
543 /* FIXME: TODO */
544 Ke386SetCr2(DbgKdRestoreBreakPointExApi);
545 while (TRUE);
546 break;
547
548 case DbgKdCauseBugCheckApi:
549
550 /* FIXME: TODO */
551 Ke386SetCr2(DbgKdCauseBugCheckApi);
552 while (TRUE);
553 break;
554
555 case DbgKdSwitchProcessor:
556
557 /* FIXME: TODO */
558 Ke386SetCr2(DbgKdSwitchProcessor);
559 while (TRUE);
560 break;
561
562 case DbgKdPageInApi:
563
564 /* FIXME: TODO */
565 Ke386SetCr2(DbgKdPageInApi);
566 while (TRUE);
567 break;
568
569 case DbgKdReadMachineSpecificRegister:
570
571 /* FIXME: TODO */
572 Ke386SetCr2(DbgKdReadMachineSpecificRegister);
573 while (TRUE);
574 break;
575
576 case DbgKdWriteMachineSpecificRegister:
577
578 /* FIXME: TODO */
579 Ke386SetCr2(DbgKdWriteMachineSpecificRegister);
580 while (TRUE);
581 break;
582
583 case OldVlm1:
584
585 /* FIXME: TODO */
586 Ke386SetCr2(OldVlm1);
587 while (TRUE);
588 break;
589
590 case OldVlm2:
591
592 /* FIXME: TODO */
593 Ke386SetCr2(OldVlm2);
594 while (TRUE);
595 break;
596
597 case DbgKdSearchMemoryApi:
598
599 /* FIXME: TODO */
600 Ke386SetCr2(DbgKdSearchMemoryApi);
601 while (TRUE);
602 break;
603
604 case DbgKdGetBusDataApi:
605
606 /* FIXME: TODO */
607 Ke386SetCr2(DbgKdGetBusDataApi);
608 while (TRUE);
609 break;
610
611 case DbgKdSetBusDataApi:
612
613 /* FIXME: TODO */
614 Ke386SetCr2(DbgKdSetBusDataApi);
615 while (TRUE);
616 break;
617
618 case DbgKdCheckLowMemoryApi:
619
620 /* FIXME: TODO */
621 Ke386SetCr2(DbgKdCheckLowMemoryApi);
622 while (TRUE);
623 break;
624
625 case DbgKdClearAllInternalBreakpointsApi:
626
627 /* Just clear the counter */
628 KdpNumInternalBreakpoints = 0;
629 break;
630
631 case DbgKdFillMemoryApi:
632
633 /* FIXME: TODO */
634 Ke386SetCr2(DbgKdFillMemoryApi);
635 while (TRUE);
636 break;
637
638 case DbgKdQueryMemoryApi:
639
640 /* FIXME: TODO */
641 Ke386SetCr2(DbgKdQueryMemoryApi);
642 while (TRUE);
643 break;
644
645 case DbgKdSwitchPartition:
646
647 /* FIXME: TODO */
648 Ke386SetCr2(DbgKdSwitchPartition);
649 while (TRUE);
650 break;
651
652 /* Unsupported Message */
653 default:
654
655 /* Setup an empty message, with failure */
656 while (TRUE);
657 fail:
658 Data.Length = 0;
659 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
660
661 /* Send it */
662 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
663 &Header,
664 &Data,
665 &KdpContext);
666 break;
667 }
668 }
669 }
670
671 BOOLEAN
672 NTAPI
673 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
674 IN PKD_SYMBOLS_INFO SymbolInfo,
675 IN BOOLEAN Unload,
676 IN OUT PCONTEXT Context)
677 {
678 PSTRING ExtraData;
679 STRING Data, Header;
680 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
681 KCONTINUE_STATUS Status;
682
683 /* Start wait loop */
684 do
685 {
686 /* Build the architecture common parts of the message */
687 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
688 Context,
689 &WaitStateChange);
690
691 /* Now finish creating the structure */
692 KdpSetContextState(&WaitStateChange, Context);
693
694 /* Fill out load data */
695 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
696 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG)SymbolInfo->BaseOfDll;
697 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
698 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
699 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
700
701 /* Check if we have a symbol name */
702 if (PathName)
703 {
704 /* Setup the information */
705 WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
706 Data.Buffer = KdpPathBuffer;
707 Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
708 ExtraData = &Data;
709 }
710 else
711 {
712 /* No name */
713 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
714 ExtraData = NULL;
715 }
716
717 /* Setup the header */
718 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
719 Header.Buffer = (PCHAR)&WaitStateChange;
720
721 /* Send the packet */
722 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
723 &Header,
724 ExtraData,
725 Context);
726 } while(Status == ContinueProcessorReselected);
727
728 /* Return status */
729 while (TRUE);
730 return Status;
731 }
732
733 VOID
734 NTAPI
735 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
736 IN PVOID DeferredContext,
737 IN PVOID SystemArgument1,
738 IN PVOID SystemArgument2)
739 {
740 LONG OldSlip, NewSlip, PendingSlip;
741
742 /* Get the current pending slip */
743 PendingSlip = KdpTimeSlipPending;
744 do
745 {
746 /* Save the old value and either disable or enable it now. */
747 OldSlip = PendingSlip;
748 NewSlip = OldSlip > 1 ? 1 : 0;
749
750 /* Try to change the value */
751 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
752 NewSlip,
753 OldSlip) != OldSlip);
754
755 /* If the New Slip value is 1, then do the Time Slipping */
756 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
757 }
758
759 VOID
760 NTAPI
761 KdpTimeSlipWork(IN PVOID Context)
762 {
763 KIRQL OldIrql;
764 LARGE_INTEGER DueTime;
765
766 /* Update the System time from the CMOS */
767 ExAcquireTimeRefreshLock(FALSE);
768 ExUpdateSystemTimeFromCmos(FALSE, 0);
769 ExReleaseTimeRefreshLock();
770
771 /* Check if we have a registered Time Slip Event and signal it */
772 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
773 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
774 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
775
776 /* Delay the DPC until it runs next time */
777 DueTime.QuadPart = -1800000000;
778 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
779 }
780
781 BOOLEAN
782 NTAPI
783 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
784 IN OUT PCONTEXT ContextRecord,
785 IN BOOLEAN SecondChanceException)
786 {
787 BOOLEAN Status;
788
789 /* Save the port data */
790 KdSave(FALSE);
791
792 /* Report a state change */
793 #if 0
794 Status = KdpReportExceptionStateChange(ExceptionRecord,
795 ContextRecord,
796 SecondChanceException);
797 #else
798 Status = FALSE;
799 #endif
800
801 /* Restore the port data and return */
802 KdRestore(FALSE);
803 return Status;
804 }
805
806 LARGE_INTEGER
807 NTAPI
808 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
809 {
810 LARGE_INTEGER Null = {{0}};
811
812 /* Check if interrupts were disabled */
813 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
814 {
815 /* Nothing to return */
816 return Null;
817 }
818
819 /* Otherwise, do the call */
820 return KeQueryPerformanceCounter(NULL);
821 }
822
823 BOOLEAN
824 NTAPI
825 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
826 IN PKEXCEPTION_FRAME ExceptionFrame)
827 {
828 BOOLEAN Entered;
829
830 /* Check if we have a trap frame */
831 if (TrapFrame)
832 {
833 /* Calculate the time difference for the enter */
834 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
835 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
836 KdTimerStart.QuadPart;
837 }
838 else
839 {
840 /* No trap frame, so can't calculate */
841 KdTimerStop.QuadPart = 0;
842 }
843
844 /* Save the current IRQL */
845 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
846
847 /* Freeze all CPUs */
848 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
849
850 /* Lock the port, save the state and set debugger entered */
851 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
852 KdSave(FALSE);
853 KdEnteredDebugger = TRUE;
854
855 /* Check freeze flag */
856 if (KiFreezeFlag & 1)
857 {
858 /* Print out errror */
859 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
860 }
861
862 /* Check processor state */
863 if (KiFreezeFlag & 2)
864 {
865 /* Print out errror */
866 DbgPrint("Some processors not frozen in debugger!\n");
867 }
868
869 /* Make sure we acquired the port */
870 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
871
872 /* Return enter state */
873 return Entered;
874 }
875
876 VOID
877 NTAPI
878 KdExitDebugger(IN BOOLEAN Entered)
879 {
880 ULONG TimeSlip;
881
882 /* Restore the state and unlock the port */
883 KdRestore(FALSE);
884 if (KdpPortLocked) KdpPortUnlock();
885
886 /* Unfreeze the CPUs */
887 KeThawExecution(Entered);
888
889 /* Compare time with the one from KdEnterDebugger */
890 if (!KdTimerStop.QuadPart)
891 {
892 /* We didn't get a trap frame earlier in so never got the time */
893 KdTimerStart = KdTimerStop;
894 }
895 else
896 {
897 /* Query the timer */
898 KdTimerStart = KeQueryPerformanceCounter(NULL);
899 }
900
901 /* Check if a Time Slip was on queue */
902 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
903 if (TimeSlip == 1)
904 {
905 /* Queue a DPC for the time slip */
906 InterlockedIncrement(&KdpTimeSlipPending);
907 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
908 }
909 }
910
911 NTSTATUS
912 NTAPI
913 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
914 {
915 KIRQL OldIrql;
916
917 /* Check if we need to acquire the lock */
918 if (NeedLock)
919 {
920 /* Lock the port */
921 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
922 KdpPortLock();
923 }
924
925 /* Check if we're not disabled */
926 if (!KdDisableCount)
927 {
928 /* Check if we had locked the port before */
929 if (NeedLock)
930 {
931 /* Do the unlock */
932 KeLowerIrql(OldIrql);
933 KdpPortUnlock();
934 }
935
936 /* Fail: We're already enabled */
937 return STATUS_INVALID_PARAMETER;
938 }
939
940 /* Decrease the disable count */
941 if (!(--KdDisableCount))
942 {
943 /* We're now enabled again! Were we enabled before, too? */
944 if (KdPreviouslyEnabled)
945 {
946 /* Reinitialize the Debugger */
947 KdInitSystem(0, NULL) ;
948 KdpRestoreAllBreakpoints();
949 }
950 }
951
952 /* Check if we had locked the port before */
953 if (NeedLock)
954 {
955 /* Yes, now unlock it */
956 KeLowerIrql(OldIrql);
957 KdpPortUnlock();
958 }
959
960 /* We're done */
961 return STATUS_SUCCESS;
962 }
963
964 /* PUBLIC FUNCTIONS **********************************************************/
965
966 /*
967 * @implemented
968 */
969 NTSTATUS
970 NTAPI
971 KdEnableDebugger(VOID)
972 {
973 /* Use the internal routine */
974 while (TRUE);
975 return KdEnableDebuggerWithLock(TRUE);
976 }
977