Make winkd somewhat portable.
[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 KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
20 IN PCONTEXT Context)
21 {
22 PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;
23 STRING Header;
24 NTSTATUS Status = STATUS_SUCCESS;
25
26 /* Validate the address space */
27 if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)
28 {
29 /* Check if this is process memory */
30 if ((PVOID)(LONG_PTR)Memory->Address < MmHighestUserAddress)
31 {
32 /* It is */
33 Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;
34 }
35 else
36 {
37 /* FIXME: Check if it's session space */
38 Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;
39 }
40
41 /* Set flags */
42 Memory->Flags = DBGKD_QUERY_MEMORY_READ |
43 DBGKD_QUERY_MEMORY_WRITE |
44 DBGKD_QUERY_MEMORY_EXECUTE;
45 }
46 else
47 {
48 /* Invalid */
49 Status = STATUS_INVALID_PARAMETER;
50 }
51
52 /* Return structure */
53 State->ReturnStatus = Status;
54 Memory->Reserved = 0;
55
56 /* Build header */
57 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
58 Header.Buffer = (PCHAR)State;
59
60 /* Send the packet */
61 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
62 &Header,
63 NULL,
64 &KdpContext);
65 }
66
67 VOID
68 NTAPI
69 KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
70 IN PSTRING Data,
71 IN PCONTEXT Context)
72 {
73 PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;
74 STRING Header;
75
76 /* Build header */
77 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
78 Header.Buffer = (PCHAR)State;
79 ASSERT(Data->Length == 0);
80
81 /* Create the breakpoint */
82 Breakpoint->BreakPointHandle =
83 KdpAddBreakpoint((PVOID)(LONG_PTR)Breakpoint->BreakPointAddress);
84 if (!Breakpoint->BreakPointHandle)
85 {
86 /* We failed */
87 State->ReturnStatus = STATUS_UNSUCCESSFUL;
88 }
89 else
90 {
91 /* Success! */
92 State->ReturnStatus = STATUS_SUCCESS;
93 }
94
95 /* Send the packet */
96 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
97 &Header,
98 NULL,
99 &KdpContext);
100 }
101
102 VOID
103 NTAPI
104 DumpTraceData(IN PSTRING TraceData)
105 {
106 /* Update the buffer */
107 TraceDataBuffer[0] = TraceDataBufferPosition;
108
109 /* Setup the trace data */
110 TraceData->Length = TraceDataBufferPosition * sizeof(ULONG);
111 TraceData->Buffer = (PCHAR)TraceDataBuffer;
112
113 /* Reset the buffer location */
114 TraceDataBufferPosition = 1;
115 }
116
117 VOID
118 NTAPI
119 KdpGetStateChange(IN PDBGKD_MANIPULATE_STATE64 State,
120 IN PCONTEXT Context)
121 {
122 PKPRCB Prcb;
123 ULONG i;
124
125 /* Check for success */
126 if (NT_SUCCESS(State->u.Continue2.ContinueStatus))
127 {
128 /* Check if we're tracing */
129 if (State->u.Continue2.ControlSet.TraceFlag)
130 {
131 /* Enable TF */
132 Context->EFlags |= EFLAGS_TF;
133 }
134 else
135 {
136 /* Remove it */
137 Context->EFlags &= ~EFLAGS_TF;
138 }
139
140 /* Loop all processors */
141 for (i = 0; i < KeNumberProcessors; i++)
142 {
143 /* Get the PRCB and update DR7 and DR6 */
144 Prcb = KiProcessorBlock[i];
145 Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
146 State->u.Continue2.ControlSet.Dr7;
147 Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0;
148 }
149
150 /* Check if we have new symbol information */
151 if (State->u.Continue2.ControlSet.CurrentSymbolStart != 1)
152 {
153 /* Update it */
154 KdpCurrentSymbolStart =
155 State->u.Continue2.ControlSet.CurrentSymbolStart;
156 KdpCurrentSymbolEnd= State->u.Continue2.ControlSet.CurrentSymbolEnd;
157 }
158 }
159 }
160
161 VOID
162 NTAPI
163 KdpSetCommonState(IN ULONG NewState,
164 IN PCONTEXT Context,
165 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
166 {
167 USHORT InstructionCount;
168 BOOLEAN HadBreakpoints;
169
170 /* Setup common stuff available for all CPU architectures */
171 WaitStateChange->NewState = NewState;
172 WaitStateChange->ProcessorLevel = KeProcessorLevel;
173 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
174 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
175 WaitStateChange->Thread = (ULONG)(LONG_PTR)KeGetCurrentThread();
176 #if defined(_M_X86_)
177 WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Eip;
178 #elif defined(_AMD64)
179 WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Rip;
180 #else
181 #error Unknown platform
182 #endif
183
184 /* Zero out the Control Report */
185 RtlZeroMemory(&WaitStateChange->ControlReport,
186 sizeof(DBGKD_CONTROL_REPORT));
187
188 /* Now copy the instruction stream and set the count */
189 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
190 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
191 DBGKD_MAXSTREAM);
192 InstructionCount = DBGKD_MAXSTREAM;
193 WaitStateChange->ControlReport.InstructionCount = InstructionCount;
194
195 /* Clear all the breakpoints in this region */
196 HadBreakpoints =
197 KdpDeleteBreakpointRange((PVOID)(LONG_PTR)WaitStateChange->ProgramCounter,
198 (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter +
199 WaitStateChange->ControlReport.InstructionCount - 1));
200 if (HadBreakpoints)
201 {
202 /* Copy the instruction stream again, this time without breakpoints */
203 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
204 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
205 WaitStateChange->ControlReport.InstructionCount);
206 }
207 }
208
209 VOID
210 NTAPI
211 KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
212 {
213 /* Copy the version block */
214 RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));
215 }
216
217 VOID
218 NTAPI
219 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
220 {
221 STRING Header;
222
223 /* Fill out the header */
224 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
225 Header.Buffer = (PCHAR)State;
226
227 /* Get the version block */
228 KdpSysGetVersion(&State->u.GetVersion64);
229
230 /* Fill out the state */
231 State->ApiNumber = DbgKdGetVersionApi;
232 State->ReturnStatus = STATUS_SUCCESS;
233
234 /* Send the packet */
235 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
236 &Header,
237 NULL,
238 &KdpContext);
239 }
240
241 VOID
242 NTAPI
243 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
244 IN PSTRING Data,
245 IN PCONTEXT Context)
246 {
247 STRING Header;
248 ULONG Length = State->u.ReadMemory.TransferCount;
249 NTSTATUS Status = STATUS_SUCCESS;
250
251 /* Validate length */
252 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
253 {
254 /* Overflow, set it to maximum possible */
255 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
256 }
257
258 #if 0
259 if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))
260 {
261 Ke386SetCr2(State->u.ReadMemory.TargetBaseAddress);
262 while (TRUE);
263 }
264 #endif
265
266 if (!State->u.ReadMemory.TargetBaseAddress)
267 {
268 Length = 0;
269 Status = STATUS_UNSUCCESSFUL;
270 }
271 else
272 {
273 RtlCopyMemory(Data->Buffer,
274 (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
275 Length);
276 }
277
278 /* Fill out the header */
279 Data->Length = Length;
280 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
281 Header.Buffer = (PCHAR)State;
282
283 /* Fill out the state */
284 State->ReturnStatus = Status;
285 State->u.ReadMemory.ActualBytesRead = Length;
286
287 /* Send the packet */
288 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
289 &Header,
290 Data,
291 &KdpContext);
292 }
293
294 VOID
295 NTAPI
296 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
297 IN PSTRING Data,
298 IN PCONTEXT Context)
299 {
300 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
301 STRING Header;
302 ULONG Length, RealLength;
303 PVOID ControlStart;
304
305 /* Setup the header */
306 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
307 Header.Buffer = (PCHAR)State;
308 ASSERT(Data->Length == 0);
309
310 /* Check the length requested */
311 Length = ReadMemory->TransferCount;
312 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
313 {
314 /* Use maximum allowed */
315 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
316 }
317
318 /* Make sure that this is a valid request */
319 if (((ULONG)ReadMemory->TargetBaseAddress < sizeof(KPROCESSOR_STATE)) &&
320 (State->Processor < KeNumberProcessors))
321 {
322 /* Get the actual length */
323 RealLength = sizeof(KPROCESSOR_STATE) -
324 (ULONG_PTR)ReadMemory->TargetBaseAddress;
325 if (RealLength < Length) Length = RealLength;
326
327 /* Set the proper address */
328 ControlStart = (PVOID)((ULONG_PTR)ReadMemory->TargetBaseAddress +
329 (ULONG_PTR)&KiProcessorBlock[State->Processor]->
330 ProcessorState);
331
332 /* Copy the memory */
333 RtlCopyMemory(Data->Buffer, ControlStart, Length);
334 Data->Length = Length;
335
336 /* Finish up */
337 State->ReturnStatus = STATUS_SUCCESS;
338 ReadMemory->ActualBytesRead = Data->Length;
339 }
340 else
341 {
342 /* Invalid request */
343 Data->Length = 0;
344 State->ReturnStatus = STATUS_UNSUCCESSFUL;
345 ReadMemory->ActualBytesRead = 0;
346 }
347
348 /* Send the reply */
349 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
350 &Header,
351 Data,
352 &KdpContext);
353 }
354
355 VOID
356 NTAPI
357 KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
358 IN PSTRING Data,
359 IN PCONTEXT Context)
360 {
361 PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
362 STRING Header;
363 ULONG Length;
364 PVOID ControlStart;
365
366 /* Setup the header */
367 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
368 Header.Buffer = (PCHAR)State;
369
370 /* Make sure that this is a valid request */
371 Length = WriteMemory->TransferCount;
372 if ((((ULONG)WriteMemory->TargetBaseAddress + Length) <=
373 sizeof(KPROCESSOR_STATE)) &&
374 (State->Processor < KeNumberProcessors))
375 {
376 /* Set the proper address */
377 ControlStart = (PVOID)((ULONG_PTR)WriteMemory->TargetBaseAddress +
378 (ULONG_PTR)&KiProcessorBlock[State->Processor]->
379 ProcessorState);
380
381 /* Copy the memory */
382 RtlCopyMemory(ControlStart, Data->Buffer, Data->Length);
383 Length = Data->Length;
384
385 /* Finish up */
386 State->ReturnStatus = STATUS_SUCCESS;
387 WriteMemory->ActualBytesWritten = Length;
388 }
389 else
390 {
391 /* Invalid request */
392 Data->Length = 0;
393 State->ReturnStatus = STATUS_UNSUCCESSFUL;
394 WriteMemory->ActualBytesWritten = 0;
395 }
396
397 /* Send the reply */
398 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
399 &Header,
400 Data,
401 &KdpContext);
402 }
403
404 VOID
405 NTAPI
406 KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
407 IN PSTRING Data,
408 IN PCONTEXT Context)
409 {
410 PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
411 STRING Header;
412
413 /* Fill out the header */
414 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
415 Header.Buffer = (PCHAR)State;
416 ASSERT(Data->Length == 0);
417
418 /* Get the version block */
419 if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
420 {
421 /* We're all good */
422 State->ReturnStatus = STATUS_SUCCESS;
423 }
424 else
425 {
426 /* We failed */
427 State->ReturnStatus = STATUS_UNSUCCESSFUL;
428 }
429
430 /* Send the packet */
431 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
432 &Header,
433 NULL,
434 &KdpContext);
435 }
436
437 VOID
438 NTAPI
439 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
440 IN PSTRING Data,
441 IN PCONTEXT Context)
442 {
443 STRING Header;
444 PVOID ControlStart;
445
446 /* Setup the header */
447 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
448 Header.Buffer = (PCHAR)State;
449 ASSERT(Data->Length == 0);
450
451 /* Make sure that this is a valid request */
452 if (State->Processor < KeNumberProcessors)
453 {
454 /* Check if the request is for this CPU */
455 if (State->Processor == KeGetCurrentPrcb()->Number)
456 {
457 /* We're just copying our own context */
458 ControlStart = Context;
459 }
460 else
461 {
462 /* SMP not yet handled */
463 ControlStart = NULL;
464 while (TRUE);
465 }
466
467 /* Copy the memory */
468 RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));
469 Data->Length = sizeof(CONTEXT);
470
471 /* Finish up */
472 State->ReturnStatus = STATUS_SUCCESS;
473 }
474 else
475 {
476 /* Invalid request */
477 State->ReturnStatus = STATUS_UNSUCCESSFUL;
478 }
479
480 /* Send the reply */
481 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
482 &Header,
483 Data,
484 &KdpContext);
485 }
486
487 VOID
488 NTAPI
489 KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
490 IN PSTRING Data,
491 IN PCONTEXT Context)
492 {
493 STRING Header;
494 PVOID ControlStart;
495
496 /* Setup the header */
497 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
498 Header.Buffer = (PCHAR)State;
499 ASSERT(Data->Length == sizeof(CONTEXT));
500
501 /* Make sure that this is a valid request */
502 if (State->Processor < KeNumberProcessors)
503 {
504 /* Check if the request is for this CPU */
505 if (State->Processor == KeGetCurrentPrcb()->Number)
506 {
507 /* We're just copying our own context */
508 ControlStart = Context;
509 }
510 else
511 {
512 /* SMP not yet handled */
513 ControlStart = NULL;
514 while (TRUE);
515 }
516
517 /* Copy the memory */
518 RtlCopyMemory(ControlStart, Data->Buffer, sizeof(CONTEXT));
519
520 /* Finish up */
521 State->ReturnStatus = STATUS_SUCCESS;
522 }
523 else
524 {
525 /* Invalid request */
526 State->ReturnStatus = STATUS_UNSUCCESSFUL;
527 }
528
529 /* Send the reply */
530 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
531 &Header,
532 Data,
533 &KdpContext);
534 }
535
536 KCONTINUE_STATUS
537 NTAPI
538 KdpSendWaitContinue(IN ULONG PacketType,
539 IN PSTRING SendHeader,
540 IN PSTRING SendData OPTIONAL,
541 IN OUT PCONTEXT Context)
542 {
543 STRING Data, Header;
544 DBGKD_MANIPULATE_STATE64 ManipulateState;
545 ULONG Length;
546 KDSTATUS RecvCode;
547
548 /* Setup the Manipulate State structure */
549 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
550 Header.Buffer = (PCHAR)&ManipulateState;
551 Data.MaximumLength = sizeof(KdpMessageBuffer);
552 Data.Buffer = KdpMessageBuffer;
553 //KdpContextSent = FALSE;
554
555 SendPacket:
556 /* Send the Packet */
557 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
558
559 /* If the debugger isn't present anymore, just return success */
560 if (KdDebuggerNotPresent) return ContinueSuccess;
561
562 /* Main processing Loop */
563 for (;;)
564 {
565 /* Receive Loop */
566 do
567 {
568 /* Wait to get a reply to our packet */
569 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
570 &Header,
571 &Data,
572 &Length,
573 &KdpContext);
574
575 /* If we got a resend request, do it */
576 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
577 } while (RecvCode == KdPacketTimedOut);
578
579 /* Now check what API we got */
580 switch (ManipulateState.ApiNumber)
581 {
582 case DbgKdReadVirtualMemoryApi:
583
584 /* Read virtual memory */
585 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
586 break;
587
588 case DbgKdWriteVirtualMemoryApi:
589
590 /* FIXME: TODO */
591 Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
592 while (TRUE);
593 break;
594
595 case DbgKdGetContextApi:
596
597 /* Get the current context */
598 KdpGetContext(&ManipulateState, &Data, Context);
599 break;
600
601 case DbgKdSetContextApi:
602
603 /* Set a new context */
604 KdpSetContext(&ManipulateState, &Data, Context);
605 break;
606
607 case DbgKdWriteBreakPointApi:
608
609 /* Write the breakpoint */
610 KdpWriteBreakpoint(&ManipulateState, &Data, Context);
611 break;
612
613 case DbgKdRestoreBreakPointApi:
614
615 /* FIXME: TODO */
616 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
617 break;
618
619 case DbgKdContinueApi:
620
621 /* Simply continue */
622 return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
623
624 case DbgKdReadControlSpaceApi:
625
626 /* Read control space */
627 KdpReadControlSpace(&ManipulateState, &Data, Context);
628 break;
629
630 case DbgKdWriteControlSpaceApi:
631
632 /* FIXME: TODO */
633 KdpWriteControlSpace(&ManipulateState, &Data, Context);
634 break;
635
636 case DbgKdReadIoSpaceApi:
637
638 /* FIXME: TODO */
639 Ke386SetCr2(DbgKdReadIoSpaceApi);
640 while (TRUE);
641 break;
642
643 case DbgKdWriteIoSpaceApi:
644
645 /* FIXME: TODO */
646 Ke386SetCr2(DbgKdWriteIoSpaceApi);
647 while (TRUE);
648 break;
649
650 case DbgKdRebootApi:
651
652 /* FIXME: TODO */
653 Ke386SetCr2(DbgKdRebootApi);
654 while (TRUE);
655 break;
656
657 case DbgKdContinueApi2:
658
659 /* Check if caller reports success */
660 if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
661 {
662 /* Update the state */
663 KdpGetStateChange(&ManipulateState, Context);
664 return ContinueSuccess;
665 }
666 else
667 {
668 /* Return an error */
669 return ContinueError;
670 }
671 break;
672
673 case DbgKdReadPhysicalMemoryApi:
674
675 /* FIXME: TODO */
676 goto fail;
677 Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
678 while (TRUE);
679 break;
680
681 case DbgKdWritePhysicalMemoryApi:
682
683 /* FIXME: TODO */
684 Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
685 while (TRUE);
686 break;
687
688 case DbgKdQuerySpecialCallsApi:
689
690 /* FIXME: TODO */
691 Ke386SetCr2(DbgKdQuerySpecialCallsApi);
692 while (TRUE);
693 break;
694
695 case DbgKdSetSpecialCallApi:
696
697 /* FIXME: TODO */
698 Ke386SetCr2(DbgKdSetSpecialCallApi);
699 while (TRUE);
700 break;
701
702 case DbgKdClearSpecialCallsApi:
703
704 /* FIXME: TODO */
705 Ke386SetCr2(DbgKdClearSpecialCallsApi);
706 while (TRUE);
707 break;
708
709 case DbgKdSetInternalBreakPointApi:
710
711 /* FIXME: TODO */
712 Ke386SetCr2(DbgKdSetInternalBreakPointApi);
713 while (TRUE);
714 break;
715
716 case DbgKdGetInternalBreakPointApi:
717
718 /* FIXME: TODO */
719 Ke386SetCr2(DbgKdGetInternalBreakPointApi);
720 while (TRUE);
721 break;
722
723 case DbgKdReadIoSpaceExtendedApi:
724
725 /* FIXME: TODO */
726 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
727 while (TRUE);
728 break;
729
730 case DbgKdWriteIoSpaceExtendedApi:
731
732 /* FIXME: TODO */
733 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
734 while (TRUE);
735 break;
736
737 case DbgKdGetVersionApi:
738
739 /* Get version data */
740 KdpGetVersion(&ManipulateState);
741 break;
742
743 case DbgKdWriteBreakPointExApi:
744
745 /* FIXME: TODO */
746 Ke386SetCr2(DbgKdWriteBreakPointExApi);
747 while (TRUE);
748 break;
749
750 case DbgKdRestoreBreakPointExApi:
751
752 /* FIXME: TODO */
753 Ke386SetCr2(DbgKdRestoreBreakPointExApi);
754 while (TRUE);
755 break;
756
757 case DbgKdCauseBugCheckApi:
758
759 /* FIXME: TODO */
760 Ke386SetCr2(DbgKdCauseBugCheckApi);
761 while (TRUE);
762 break;
763
764 case DbgKdSwitchProcessor:
765
766 /* FIXME: TODO */
767 Ke386SetCr2(DbgKdSwitchProcessor);
768 while (TRUE);
769 break;
770
771 case DbgKdPageInApi:
772
773 /* FIXME: TODO */
774 Ke386SetCr2(DbgKdPageInApi);
775 while (TRUE);
776 break;
777
778 case DbgKdReadMachineSpecificRegister:
779
780 /* FIXME: TODO */
781 Ke386SetCr2(DbgKdReadMachineSpecificRegister);
782 while (TRUE);
783 break;
784
785 case DbgKdWriteMachineSpecificRegister:
786
787 /* FIXME: TODO */
788 Ke386SetCr2(DbgKdWriteMachineSpecificRegister);
789 while (TRUE);
790 break;
791
792 case OldVlm1:
793
794 /* FIXME: TODO */
795 Ke386SetCr2(OldVlm1);
796 while (TRUE);
797 break;
798
799 case OldVlm2:
800
801 /* FIXME: TODO */
802 Ke386SetCr2(OldVlm2);
803 while (TRUE);
804 break;
805
806 case DbgKdSearchMemoryApi:
807
808 /* FIXME: TODO */
809 Ke386SetCr2(DbgKdSearchMemoryApi);
810 while (TRUE);
811 break;
812
813 case DbgKdGetBusDataApi:
814
815 /* FIXME: TODO */
816 Ke386SetCr2(DbgKdGetBusDataApi);
817 while (TRUE);
818 break;
819
820 case DbgKdSetBusDataApi:
821
822 /* FIXME: TODO */
823 Ke386SetCr2(DbgKdSetBusDataApi);
824 while (TRUE);
825 break;
826
827 case DbgKdCheckLowMemoryApi:
828
829 /* FIXME: TODO */
830 Ke386SetCr2(DbgKdCheckLowMemoryApi);
831 while (TRUE);
832 break;
833
834 case DbgKdClearAllInternalBreakpointsApi:
835
836 /* Just clear the counter */
837 KdpNumInternalBreakpoints = 0;
838 break;
839
840 case DbgKdFillMemoryApi:
841
842 /* FIXME: TODO */
843 Ke386SetCr2(DbgKdFillMemoryApi);
844 while (TRUE);
845 break;
846
847 case DbgKdQueryMemoryApi:
848
849 /* Query memory */
850 KdpQueryMemory(&ManipulateState, Context);
851 break;
852
853 case DbgKdSwitchPartition:
854
855 /* FIXME: TODO */
856 Ke386SetCr2(DbgKdSwitchPartition);
857 while (TRUE);
858 break;
859
860 /* Unsupported Message */
861 default:
862
863 /* Setup an empty message, with failure */
864 while (TRUE);
865 fail:
866 Data.Length = 0;
867 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
868
869 /* Send it */
870 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
871 &Header,
872 &Data,
873 &KdpContext);
874 break;
875 }
876 }
877 }
878
879 BOOLEAN
880 NTAPI
881 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
882 IN PKD_SYMBOLS_INFO SymbolInfo,
883 IN BOOLEAN Unload,
884 IN OUT PCONTEXT Context)
885 {
886 PSTRING ExtraData;
887 STRING Data, Header;
888 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
889 KCONTINUE_STATUS Status;
890
891 /* Start wait loop */
892 do
893 {
894 /* Build the architecture common parts of the message */
895 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
896 Context,
897 &WaitStateChange);
898
899 /* Now finish creating the structure */
900 KdpSetContextState(&WaitStateChange, Context);
901
902 /* Fill out load data */
903 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
904 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONGLONG)(LONG_PTR)SymbolInfo->BaseOfDll;
905 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
906 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
907 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
908
909 /* Check if we have a symbol name */
910 if (PathName)
911 {
912 /* Setup the information */
913 WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
914 RtlCopyMemory(KdpPathBuffer, PathName->Buffer, PathName->Length);
915 Data.Buffer = KdpPathBuffer;
916 Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
917 ExtraData = &Data;
918 }
919 else
920 {
921 /* No name */
922 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
923 ExtraData = NULL;
924 }
925
926 /* Setup the header */
927 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
928 Header.Buffer = (PCHAR)&WaitStateChange;
929
930 /* Send the packet */
931 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
932 &Header,
933 ExtraData,
934 Context);
935 } while(Status == ContinueProcessorReselected);
936
937 /* Return status */
938 return Status;
939 }
940
941 BOOLEAN
942 NTAPI
943 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
944 IN OUT PCONTEXT Context,
945 IN BOOLEAN SecondChanceException)
946 {
947 STRING Header, Data;
948 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
949 BOOLEAN Status;
950
951 /* Start report loop */
952 do
953 {
954 /* Build the architecture common parts of the message */
955 KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
956
957 /* Convert the exception record to 64-bits and set First Chance flag */
958 ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
959 &WaitStateChange.u.Exception.ExceptionRecord);
960 WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
961
962 /* Now finish creating the structure */
963 KdpSetContextState(&WaitStateChange, Context);
964
965 /* Setup the actual header to send to KD */
966 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
967 Header.Buffer = (PCHAR)&WaitStateChange;
968
969 /* Setup the trace data */
970 DumpTraceData(&Data);
971
972 /* Send State Change packet and wait for a reply */
973 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
974 &Header,
975 &Data,
976 Context);
977 } while (Status == KdPacketNeedsResend);
978
979 /* Return */
980 return Status;
981 }
982
983 VOID
984 NTAPI
985 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
986 IN PVOID DeferredContext,
987 IN PVOID SystemArgument1,
988 IN PVOID SystemArgument2)
989 {
990 LONG OldSlip, NewSlip, PendingSlip;
991
992 /* Get the current pending slip */
993 PendingSlip = KdpTimeSlipPending;
994 do
995 {
996 /* Save the old value and either disable or enable it now. */
997 OldSlip = PendingSlip;
998 NewSlip = OldSlip > 1 ? 1 : 0;
999
1000 /* Try to change the value */
1001 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1002 NewSlip,
1003 OldSlip) != OldSlip);
1004
1005 /* If the New Slip value is 1, then do the Time Slipping */
1006 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1007 }
1008
1009 VOID
1010 NTAPI
1011 KdpTimeSlipWork(IN PVOID Context)
1012 {
1013 KIRQL OldIrql;
1014 LARGE_INTEGER DueTime;
1015
1016 /* Update the System time from the CMOS */
1017 ExAcquireTimeRefreshLock(FALSE);
1018 ExUpdateSystemTimeFromCmos(FALSE, 0);
1019 ExReleaseTimeRefreshLock();
1020
1021 /* Check if we have a registered Time Slip Event and signal it */
1022 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1023 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1024 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1025
1026 /* Delay the DPC until it runs next time */
1027 DueTime.QuadPart = -1800000000;
1028 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1029 }
1030
1031 BOOLEAN
1032 NTAPI
1033 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
1034 IN OUT PCONTEXT ContextRecord,
1035 IN BOOLEAN SecondChanceException)
1036 {
1037 BOOLEAN Status;
1038
1039 /* Save the port data */
1040 KdSave(FALSE);
1041
1042 /* Report a state change */
1043 Status = KdpReportExceptionStateChange(ExceptionRecord,
1044 ContextRecord,
1045 SecondChanceException);
1046
1047 /* Restore the port data and return */
1048 KdRestore(FALSE);
1049 return Status;
1050 }
1051
1052 LARGE_INTEGER
1053 NTAPI
1054 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1055 {
1056 LARGE_INTEGER Null = {{0}};
1057
1058 /* Check if interrupts were disabled */
1059 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1060 {
1061 /* Nothing to return */
1062 return Null;
1063 }
1064
1065 /* Otherwise, do the call */
1066 return KeQueryPerformanceCounter(NULL);
1067 }
1068
1069 BOOLEAN
1070 NTAPI
1071 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1072 IN PKEXCEPTION_FRAME ExceptionFrame)
1073 {
1074 BOOLEAN Entered;
1075
1076 /* Check if we have a trap frame */
1077 if (TrapFrame)
1078 {
1079 /* Calculate the time difference for the enter */
1080 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1081 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1082 KdTimerStart.QuadPart;
1083 }
1084 else
1085 {
1086 /* No trap frame, so can't calculate */
1087 KdTimerStop.QuadPart = 0;
1088 }
1089
1090 /* Save the current IRQL */
1091 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1092
1093 /* Freeze all CPUs */
1094 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
1095
1096 /* Lock the port, save the state and set debugger entered */
1097 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1098 KdSave(FALSE);
1099 KdEnteredDebugger = TRUE;
1100
1101 /* Check freeze flag */
1102 if (KiFreezeFlag & 1)
1103 {
1104 /* Print out errror */
1105 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
1106 }
1107
1108 /* Check processor state */
1109 if (KiFreezeFlag & 2)
1110 {
1111 /* Print out errror */
1112 DbgPrint("Some processors not frozen in debugger!\n");
1113 }
1114
1115 /* Make sure we acquired the port */
1116 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
1117
1118 /* Return enter state */
1119 return Entered;
1120 }
1121
1122 VOID
1123 NTAPI
1124 KdExitDebugger(IN BOOLEAN Entered)
1125 {
1126 ULONG TimeSlip;
1127
1128 /* Restore the state and unlock the port */
1129 KdRestore(FALSE);
1130 if (KdpPortLocked) KdpPortUnlock();
1131
1132 /* Unfreeze the CPUs */
1133 KeThawExecution(Entered);
1134
1135 /* Compare time with the one from KdEnterDebugger */
1136 if (!KdTimerStop.QuadPart)
1137 {
1138 /* We didn't get a trap frame earlier in so never got the time */
1139 KdTimerStart = KdTimerStop;
1140 }
1141 else
1142 {
1143 /* Query the timer */
1144 KdTimerStart = KeQueryPerformanceCounter(NULL);
1145 }
1146
1147 /* Check if a Time Slip was on queue */
1148 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1149 if (TimeSlip == 1)
1150 {
1151 /* Queue a DPC for the time slip */
1152 InterlockedIncrement(&KdpTimeSlipPending);
1153 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
1154 }
1155 }
1156
1157 NTSTATUS
1158 NTAPI
1159 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
1160 {
1161 KIRQL OldIrql = PASSIVE_LEVEL;
1162
1163 /* Check if we need to acquire the lock */
1164 if (NeedLock)
1165 {
1166 /* Lock the port */
1167 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1168 KdpPortLock();
1169 }
1170
1171 /* Check if we're not disabled */
1172 if (!KdDisableCount)
1173 {
1174 /* Check if we had locked the port before */
1175 if (NeedLock)
1176 {
1177 /* Do the unlock */
1178 KeLowerIrql(OldIrql);
1179 KdpPortUnlock();
1180 }
1181
1182 /* Fail: We're already enabled */
1183 return STATUS_INVALID_PARAMETER;
1184 }
1185
1186 /* Decrease the disable count */
1187 if (!(--KdDisableCount))
1188 {
1189 /* We're now enabled again! Were we enabled before, too? */
1190 if (KdPreviouslyEnabled)
1191 {
1192 /* Reinitialize the Debugger */
1193 KdInitSystem(0, NULL) ;
1194 KdpRestoreAllBreakpoints();
1195 }
1196 }
1197
1198 /* Check if we had locked the port before */
1199 if (NeedLock)
1200 {
1201 /* Yes, now unlock it */
1202 KeLowerIrql(OldIrql);
1203 KdpPortUnlock();
1204 }
1205
1206 /* We're done */
1207 return STATUS_SUCCESS;
1208 }
1209
1210 /* PUBLIC FUNCTIONS **********************************************************/
1211
1212 /*
1213 * @implemented
1214 */
1215 NTSTATUS
1216 NTAPI
1217 KdEnableDebugger(VOID)
1218 {
1219 /* Use the internal routine */
1220 while (TRUE);
1221 return KdEnableDebuggerWithLock(TRUE);
1222 }
1223
1224 /*
1225 * @unimplemented
1226 */
1227 NTSTATUS
1228 NTAPI
1229 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
1230 IN PVOID InputBuffer,
1231 IN ULONG InputBufferLength,
1232 OUT PVOID OutputBuffer,
1233 IN ULONG OutputBufferLength,
1234 IN OUT PULONG ReturnLength,
1235 IN KPROCESSOR_MODE PreviousMode)
1236 {
1237 /* HACK */
1238 return STATUS_SUCCESS;
1239 }
1240
1241 /*
1242 * @unimplemented
1243 */
1244 NTSTATUS
1245 NTAPI
1246 KdChangeOption(IN KD_OPTION Option,
1247 IN ULONG InBufferBytes OPTIONAL,
1248 IN PVOID InBuffer,
1249 IN ULONG OutBufferBytes OPTIONAL,
1250 OUT PVOID OutBuffer,
1251 OUT PULONG OutBufferNeeded OPTIONAL)
1252 {
1253 /* HACK */
1254 return STATUS_SUCCESS;
1255 }
1256
1257 /*
1258 * @unimplemented
1259 */
1260 NTSTATUS
1261 NTAPI
1262 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
1263 {
1264 /* HACK */
1265 return STATUS_SUCCESS;
1266 }
1267
1268 /*
1269 * @unimplemented
1270 */
1271 NTSTATUS
1272 NTAPI
1273 KdDisableDebugger(VOID)
1274 {
1275 /* HACK */
1276 return STATUS_SUCCESS;
1277 }
1278
1279 /*
1280 * @unimplemented
1281 */
1282 BOOLEAN
1283 NTAPI
1284 KdRefreshDebuggerNotPresent(VOID)
1285 {
1286 /* HACK */
1287 return KdDebuggerNotPresent;
1288 }
1289
1290 NTSTATUS
1291 NTAPI
1292 NtQueryDebugFilterState(ULONG ComponentId,
1293 ULONG Level)
1294 {
1295 /* HACK */
1296 return STATUS_SUCCESS;
1297 }
1298
1299 NTSTATUS
1300 NTAPI
1301 NtSetDebugFilterState(ULONG ComponentId,
1302 ULONG Level,
1303 BOOLEAN State)
1304 {
1305 /* HACK */
1306 return STATUS_SUCCESS;
1307 }
1308