Sync with trunk r43000
[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(OUT 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 OUT 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 = (LONG_PTR)KeGetCurrentThread();
176 #if defined(_M_X86_)
177 WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Eip;
178 #elif defined(_M_AMD64)
179 WaitStateChange->ProgramCounter = (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 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
212 {
213 STRING Header;
214
215 /* Fill out the header */
216 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
217 Header.Buffer = (PCHAR)State;
218
219 /* Get the version block */
220 KdpSysGetVersion(&State->u.GetVersion64);
221
222 /* Fill out the state */
223 State->ApiNumber = DbgKdGetVersionApi;
224 State->ReturnStatus = STATUS_SUCCESS;
225
226 /* Send the packet */
227 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
228 &Header,
229 NULL,
230 &KdpContext);
231 }
232
233 VOID
234 NTAPI
235 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
236 IN PSTRING Data,
237 IN PCONTEXT Context)
238 {
239 STRING Header;
240 ULONG Length = State->u.ReadMemory.TransferCount;
241 NTSTATUS Status = STATUS_SUCCESS;
242 ULONG64 TargetBaseAddress = State->u.ReadMemory.TargetBaseAddress;
243
244 /* Validate length */
245 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
246 {
247 /* Overflow, set it to maximum possible */
248 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
249 }
250
251 #if 0
252 if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))
253 {
254 Ke386SetCr2(State->u.ReadMemory.TargetBaseAddress);
255 while (TRUE);
256 }
257 #endif
258
259 // HACK for x64, until KD stops sending bogus addresses to WinDbg
260 if (TargetBaseAddress < (ULONG_PTR)MM_LOWEST_SYSTEM_ADDRESS)
261 {
262 FrLdrDbgPrint("Trying to read memory at 0x%p\n", TargetBaseAddress);
263 // DPRINT1("Trying to read memory at 0x%p\n", TargetBaseAddress);
264 TargetBaseAddress = 0;
265 }
266
267 if (!TargetBaseAddress)
268 {
269 Length = 0;
270 Status = STATUS_UNSUCCESSFUL;
271 }
272 else
273 {
274 RtlCopyMemory(Data->Buffer,
275 (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
276 Length);
277 }
278
279 /* Fill out the header */
280 Data->Length = Length;
281 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
282 Header.Buffer = (PCHAR)State;
283
284 /* Fill out the state */
285 State->ReturnStatus = Status;
286 State->u.ReadMemory.ActualBytesRead = Length;
287
288 /* Send the packet */
289 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
290 &Header,
291 Data,
292 &KdpContext);
293 }
294
295 VOID
296 NTAPI
297 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
298 IN PSTRING Data,
299 IN PCONTEXT Context)
300 {
301 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
302 STRING Header;
303 ULONG Length, RealLength;
304 PVOID ControlStart;
305
306 /* Setup the header */
307 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
308 Header.Buffer = (PCHAR)State;
309 ASSERT(Data->Length == 0);
310
311 /* Check the length requested */
312 Length = ReadMemory->TransferCount;
313 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
314 {
315 /* Use maximum allowed */
316 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
317 }
318
319 #if defined (_M_AMD64)
320 if ((ULONG)ReadMemory->TargetBaseAddress <= 2)
321 {
322 PKPRCB Prcb = KiProcessorBlock[State->Processor];
323 PKIPCR Pcr = CONTAINING_RECORD(Prcb, KIPCR, Prcb);
324
325 switch ((ULONG_PTR)ReadMemory->TargetBaseAddress)
326 {
327 case 0:
328 /* Copy a pointer to the Pcr */
329 ControlStart = &Pcr;
330 RealLength = sizeof(PVOID);
331 break;
332
333 case 1:
334 /* Copy a pointer to the Prcb */
335 ControlStart = &Prcb;
336 RealLength = sizeof(PVOID);
337 break;
338
339 case 2:
340 /* Copy SpecialRegisters */
341 ControlStart = &Prcb->ProcessorState.SpecialRegisters;
342 RealLength = sizeof(KSPECIAL_REGISTERS);
343 break;
344
345 default:
346 RealLength = 0;
347 ControlStart = NULL;
348 ASSERT(FALSE);
349 }
350
351 if (RealLength < Length) Length = RealLength;
352
353 /* Copy the memory */
354 RtlCopyMemory(Data->Buffer, ControlStart, Length);
355 Data->Length = Length;
356
357 /* Finish up */
358 State->ReturnStatus = STATUS_SUCCESS;
359 ReadMemory->ActualBytesRead = Data->Length;
360 }
361 #else
362 /* Make sure that this is a valid request */
363 if (((ULONG)ReadMemory->TargetBaseAddress < sizeof(KPROCESSOR_STATE)) &&
364 (State->Processor < KeNumberProcessors))
365 {
366 /* Get the actual length */
367 RealLength = sizeof(KPROCESSOR_STATE) -
368 (ULONG_PTR)ReadMemory->TargetBaseAddress;
369 if (RealLength < Length) Length = RealLength;
370
371 /* Set the proper address */
372 ControlStart = (PVOID)((ULONG_PTR)ReadMemory->TargetBaseAddress +
373 (ULONG_PTR)&KiProcessorBlock[State->Processor]->
374 ProcessorState);
375
376 /* Copy the memory */
377 RtlCopyMemory(Data->Buffer, ControlStart, Length);
378 Data->Length = Length;
379
380 /* Finish up */
381 State->ReturnStatus = STATUS_SUCCESS;
382 ReadMemory->ActualBytesRead = Data->Length;
383 }
384 #endif
385 else
386 {
387 /* Invalid request */
388 Data->Length = 0;
389 State->ReturnStatus = STATUS_UNSUCCESSFUL;
390 ReadMemory->ActualBytesRead = 0;
391 }
392
393 /* Send the reply */
394 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
395 &Header,
396 Data,
397 &KdpContext);
398 }
399
400 VOID
401 NTAPI
402 KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
403 IN PSTRING Data,
404 IN PCONTEXT Context)
405 {
406 PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
407 STRING Header;
408 ULONG Length;
409 PVOID ControlStart;
410
411 /* Setup the header */
412 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
413 Header.Buffer = (PCHAR)State;
414
415 /* Make sure that this is a valid request */
416 Length = WriteMemory->TransferCount;
417 if ((((ULONG)WriteMemory->TargetBaseAddress + Length) <=
418 sizeof(KPROCESSOR_STATE)) &&
419 (State->Processor < KeNumberProcessors))
420 {
421 /* Set the proper address */
422 ControlStart = (PVOID)((ULONG_PTR)WriteMemory->TargetBaseAddress +
423 (ULONG_PTR)&KiProcessorBlock[State->Processor]->
424 ProcessorState);
425
426 /* Copy the memory */
427 RtlCopyMemory(ControlStart, Data->Buffer, Data->Length);
428 Length = Data->Length;
429
430 /* Finish up */
431 State->ReturnStatus = STATUS_SUCCESS;
432 WriteMemory->ActualBytesWritten = Length;
433 }
434 else
435 {
436 /* Invalid request */
437 Data->Length = 0;
438 State->ReturnStatus = STATUS_UNSUCCESSFUL;
439 WriteMemory->ActualBytesWritten = 0;
440 }
441
442 /* Send the reply */
443 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
444 &Header,
445 Data,
446 &KdpContext);
447 }
448
449 VOID
450 NTAPI
451 KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
452 IN PSTRING Data,
453 IN PCONTEXT Context)
454 {
455 PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
456 STRING Header;
457
458 /* Fill out the header */
459 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
460 Header.Buffer = (PCHAR)State;
461 ASSERT(Data->Length == 0);
462
463 /* Get the version block */
464 if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
465 {
466 /* We're all good */
467 State->ReturnStatus = STATUS_SUCCESS;
468 }
469 else
470 {
471 /* We failed */
472 State->ReturnStatus = STATUS_UNSUCCESSFUL;
473 }
474
475 /* Send the packet */
476 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
477 &Header,
478 NULL,
479 &KdpContext);
480 }
481
482 VOID
483 NTAPI
484 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
485 IN PSTRING Data,
486 IN PCONTEXT Context)
487 {
488 STRING Header;
489 PVOID ControlStart;
490
491 /* Setup the header */
492 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
493 Header.Buffer = (PCHAR)State;
494 ASSERT(Data->Length == 0);
495
496 /* Make sure that this is a valid request */
497 if (State->Processor < KeNumberProcessors)
498 {
499 /* Check if the request is for this CPU */
500 if (State->Processor == KeGetCurrentPrcb()->Number)
501 {
502 /* We're just copying our own context */
503 ControlStart = Context;
504 }
505 else
506 {
507 /* SMP not yet handled */
508 ControlStart = NULL;
509 while (TRUE);
510 }
511
512 /* Copy the memory */
513 RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));
514 Data->Length = sizeof(CONTEXT);
515
516 /* Finish up */
517 State->ReturnStatus = STATUS_SUCCESS;
518 }
519 else
520 {
521 /* Invalid request */
522 State->ReturnStatus = STATUS_UNSUCCESSFUL;
523 }
524
525 /* Send the reply */
526 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
527 &Header,
528 Data,
529 &KdpContext);
530 }
531
532 VOID
533 NTAPI
534 KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
535 IN PSTRING Data,
536 IN PCONTEXT Context)
537 {
538 STRING Header;
539 PVOID ControlStart;
540
541 /* Setup the header */
542 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
543 Header.Buffer = (PCHAR)State;
544 ASSERT(Data->Length == sizeof(CONTEXT));
545
546 /* Make sure that this is a valid request */
547 if (State->Processor < KeNumberProcessors)
548 {
549 /* Check if the request is for this CPU */
550 if (State->Processor == KeGetCurrentPrcb()->Number)
551 {
552 /* We're just copying our own context */
553 ControlStart = Context;
554 }
555 else
556 {
557 /* SMP not yet handled */
558 ControlStart = NULL;
559 while (TRUE);
560 }
561
562 /* Copy the memory */
563 RtlCopyMemory(ControlStart, Data->Buffer, sizeof(CONTEXT));
564
565 /* Finish up */
566 State->ReturnStatus = STATUS_SUCCESS;
567 }
568 else
569 {
570 /* Invalid request */
571 State->ReturnStatus = STATUS_UNSUCCESSFUL;
572 }
573
574 /* Send the reply */
575 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
576 &Header,
577 Data,
578 &KdpContext);
579 }
580
581 VOID
582 NTAPI
583 KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
584 IN PSTRING Data,
585 IN PCONTEXT Context)
586 {
587 STRING Header;
588 PDBGKD_READ_WRITE_MSR ReadMsr;
589 LARGE_INTEGER Value;
590
591 /* Setup the header */
592 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
593 Header.Buffer = (PCHAR)State;
594
595 /* Get a shortcut */
596 ReadMsr = &State->u.ReadWriteMsr;
597
598 /* Read the msr */
599 Value.QuadPart = __readmsr(ReadMsr->Msr);
600
601 /* Set fields */
602 ReadMsr->DataValueLow = Value.LowPart;
603 ReadMsr->DataValueHigh = Value.HighPart;
604
605 /* Send the reply */
606 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
607 &Header,
608 Data,
609 &KdpContext);
610 }
611
612 VOID
613 NTAPI
614 KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
615 IN PSTRING Data,
616 IN PCONTEXT Context)
617 {
618 STRING Header;
619 PDBGKD_READ_WRITE_MSR WriteMsr;
620 LARGE_INTEGER Value;
621
622 /* Setup the header */
623 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
624 Header.Buffer = (PCHAR)State;
625
626 /* Get a shortcut */
627 WriteMsr = &State->u.ReadWriteMsr;
628
629 /* Set fields */
630 Value.LowPart = WriteMsr->DataValueLow;
631 Value.HighPart = WriteMsr->DataValueHigh;
632
633 /* Write the msr */
634 __writemsr(WriteMsr->Msr, Value.QuadPart);
635
636 /* Send the reply */
637 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
638 &Header,
639 Data,
640 &KdpContext);
641 }
642
643 KCONTINUE_STATUS
644 NTAPI
645 KdpSendWaitContinue(IN ULONG PacketType,
646 IN PSTRING SendHeader,
647 IN PSTRING SendData OPTIONAL,
648 IN OUT PCONTEXT Context)
649 {
650 STRING Data, Header;
651 DBGKD_MANIPULATE_STATE64 ManipulateState;
652 ULONG Length;
653 KDSTATUS RecvCode;
654
655 /* Setup the Manipulate State structure */
656 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
657 Header.Buffer = (PCHAR)&ManipulateState;
658 Data.MaximumLength = sizeof(KdpMessageBuffer);
659 Data.Buffer = KdpMessageBuffer;
660 //KdpContextSent = FALSE;
661
662 SendPacket:
663 /* Send the Packet */
664 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
665
666 /* If the debugger isn't present anymore, just return success */
667 if (KdDebuggerNotPresent) return ContinueSuccess;
668
669 /* Main processing Loop */
670 for (;;)
671 {
672 /* Receive Loop */
673 do
674 {
675 /* Wait to get a reply to our packet */
676 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
677 &Header,
678 &Data,
679 &Length,
680 &KdpContext);
681
682 /* If we got a resend request, do it */
683 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
684 } while (RecvCode == KdPacketTimedOut);
685
686 /* Now check what API we got */
687 switch (ManipulateState.ApiNumber)
688 {
689 case DbgKdReadVirtualMemoryApi:
690
691 /* Read virtual memory */
692 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
693 break;
694
695 case DbgKdWriteVirtualMemoryApi:
696
697 /* FIXME: TODO */
698 Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
699 while (TRUE);
700 break;
701
702 case DbgKdGetContextApi:
703
704 /* Get the current context */
705 KdpGetContext(&ManipulateState, &Data, Context);
706 break;
707
708 case DbgKdSetContextApi:
709
710 /* Set a new context */
711 KdpSetContext(&ManipulateState, &Data, Context);
712 break;
713
714 case DbgKdWriteBreakPointApi:
715
716 /* Write the breakpoint */
717 KdpWriteBreakpoint(&ManipulateState, &Data, Context);
718 break;
719
720 case DbgKdRestoreBreakPointApi:
721
722 /* FIXME: TODO */
723 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
724 break;
725
726 case DbgKdContinueApi:
727
728 /* Simply continue */
729 return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
730
731 case DbgKdReadControlSpaceApi:
732
733 /* Read control space */
734 KdpReadControlSpace(&ManipulateState, &Data, Context);
735 break;
736
737 case DbgKdWriteControlSpaceApi:
738
739 /* FIXME: TODO */
740 KdpWriteControlSpace(&ManipulateState, &Data, Context);
741 break;
742
743 case DbgKdReadIoSpaceApi:
744
745 /* FIXME: TODO */
746 Ke386SetCr2(DbgKdReadIoSpaceApi);
747 while (TRUE);
748 break;
749
750 case DbgKdWriteIoSpaceApi:
751
752 /* FIXME: TODO */
753 Ke386SetCr2(DbgKdWriteIoSpaceApi);
754 while (TRUE);
755 break;
756
757 case DbgKdRebootApi:
758
759 /* FIXME: TODO */
760 Ke386SetCr2(DbgKdRebootApi);
761 while (TRUE);
762 break;
763
764 case DbgKdContinueApi2:
765
766 /* Check if caller reports success */
767 if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
768 {
769 /* Update the state */
770 KdpGetStateChange(&ManipulateState, Context);
771 return ContinueSuccess;
772 }
773 else
774 {
775 /* Return an error */
776 return ContinueError;
777 }
778 break;
779
780 case DbgKdReadPhysicalMemoryApi:
781
782 /* FIXME: TODO */
783 goto fail;
784 Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
785 while (TRUE);
786 break;
787
788 case DbgKdWritePhysicalMemoryApi:
789
790 /* FIXME: TODO */
791 Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
792 while (TRUE);
793 break;
794
795 case DbgKdQuerySpecialCallsApi:
796
797 /* FIXME: TODO */
798 Ke386SetCr2(DbgKdQuerySpecialCallsApi);
799 while (TRUE);
800 break;
801
802 case DbgKdSetSpecialCallApi:
803
804 /* FIXME: TODO */
805 Ke386SetCr2(DbgKdSetSpecialCallApi);
806 while (TRUE);
807 break;
808
809 case DbgKdClearSpecialCallsApi:
810
811 /* FIXME: TODO */
812 Ke386SetCr2(DbgKdClearSpecialCallsApi);
813 while (TRUE);
814 break;
815
816 case DbgKdSetInternalBreakPointApi:
817
818 /* FIXME: TODO */
819 Ke386SetCr2(DbgKdSetInternalBreakPointApi);
820 while (TRUE);
821 break;
822
823 case DbgKdGetInternalBreakPointApi:
824
825 /* FIXME: TODO */
826 Ke386SetCr2(DbgKdGetInternalBreakPointApi);
827 while (TRUE);
828 break;
829
830 case DbgKdReadIoSpaceExtendedApi:
831
832 /* FIXME: TODO */
833 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
834 while (TRUE);
835 break;
836
837 case DbgKdWriteIoSpaceExtendedApi:
838
839 /* FIXME: TODO */
840 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
841 while (TRUE);
842 break;
843
844 case DbgKdGetVersionApi:
845
846 /* Get version data */
847 KdpGetVersion(&ManipulateState);
848 break;
849
850 case DbgKdWriteBreakPointExApi:
851
852 /* FIXME: TODO */
853 Ke386SetCr2(DbgKdWriteBreakPointExApi);
854 while (TRUE);
855 break;
856
857 case DbgKdRestoreBreakPointExApi:
858
859 /* FIXME: TODO */
860 Ke386SetCr2(DbgKdRestoreBreakPointExApi);
861 while (TRUE);
862 break;
863
864 case DbgKdCauseBugCheckApi:
865
866 /* FIXME: TODO */
867 Ke386SetCr2(DbgKdCauseBugCheckApi);
868 while (TRUE);
869 break;
870
871 case DbgKdSwitchProcessor:
872
873 /* FIXME: TODO */
874 Ke386SetCr2(DbgKdSwitchProcessor);
875 while (TRUE);
876 break;
877
878 case DbgKdPageInApi:
879
880 /* FIXME: TODO */
881 Ke386SetCr2(DbgKdPageInApi);
882 while (TRUE);
883 break;
884
885 case DbgKdReadMachineSpecificRegister:
886
887 /* Read the specified MSR */
888 KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
889 break;
890
891 case DbgKdWriteMachineSpecificRegister:
892
893 /* Write the specified MSR */
894 KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
895 break;
896
897 case OldVlm1:
898
899 /* FIXME: TODO */
900 Ke386SetCr2(OldVlm1);
901 while (TRUE);
902 break;
903
904 case OldVlm2:
905
906 /* FIXME: TODO */
907 Ke386SetCr2(OldVlm2);
908 while (TRUE);
909 break;
910
911 case DbgKdSearchMemoryApi:
912
913 /* FIXME: TODO */
914 Ke386SetCr2(DbgKdSearchMemoryApi);
915 while (TRUE);
916 break;
917
918 case DbgKdGetBusDataApi:
919
920 /* FIXME: TODO */
921 Ke386SetCr2(DbgKdGetBusDataApi);
922 while (TRUE);
923 break;
924
925 case DbgKdSetBusDataApi:
926
927 /* FIXME: TODO */
928 Ke386SetCr2(DbgKdSetBusDataApi);
929 while (TRUE);
930 break;
931
932 case DbgKdCheckLowMemoryApi:
933
934 /* FIXME: TODO */
935 Ke386SetCr2(DbgKdCheckLowMemoryApi);
936 while (TRUE);
937 break;
938
939 case DbgKdClearAllInternalBreakpointsApi:
940
941 /* Just clear the counter */
942 KdpNumInternalBreakpoints = 0;
943 break;
944
945 case DbgKdFillMemoryApi:
946
947 /* FIXME: TODO */
948 Ke386SetCr2(DbgKdFillMemoryApi);
949 while (TRUE);
950 break;
951
952 case DbgKdQueryMemoryApi:
953
954 /* Query memory */
955 KdpQueryMemory(&ManipulateState, Context);
956 break;
957
958 case DbgKdSwitchPartition:
959
960 /* FIXME: TODO */
961 Ke386SetCr2(DbgKdSwitchPartition);
962 while (TRUE);
963 break;
964
965 /* Unsupported Message */
966 default:
967
968 /* Setup an empty message, with failure */
969 while (TRUE);
970 fail:
971 Data.Length = 0;
972 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
973
974 /* Send it */
975 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
976 &Header,
977 &Data,
978 &KdpContext);
979 break;
980 }
981 }
982 }
983
984 BOOLEAN
985 NTAPI
986 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
987 IN PKD_SYMBOLS_INFO SymbolInfo,
988 IN BOOLEAN Unload,
989 IN OUT PCONTEXT Context)
990 {
991 PSTRING ExtraData;
992 STRING Data, Header;
993 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
994 KCONTINUE_STATUS Status;
995
996 /* Start wait loop */
997 do
998 {
999 /* Build the architecture common parts of the message */
1000 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1001 Context,
1002 &WaitStateChange);
1003
1004 /* Now finish creating the structure */
1005 KdpSetContextState(&WaitStateChange, Context);
1006
1007 /* Fill out load data */
1008 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1009 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONGLONG)(LONG_PTR)SymbolInfo->BaseOfDll;
1010 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1011 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1012 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1013
1014 /* Check if we have a symbol name */
1015 if (PathName)
1016 {
1017 /* Setup the information */
1018 WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
1019 RtlCopyMemory(KdpPathBuffer, PathName->Buffer, PathName->Length);
1020 Data.Buffer = KdpPathBuffer;
1021 Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
1022 ExtraData = &Data;
1023 }
1024 else
1025 {
1026 /* No name */
1027 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1028 ExtraData = NULL;
1029 }
1030
1031 /* Setup the header */
1032 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
1033 Header.Buffer = (PCHAR)&WaitStateChange;
1034
1035 /* Send the packet */
1036 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1037 &Header,
1038 ExtraData,
1039 Context);
1040 } while(Status == ContinueProcessorReselected);
1041
1042 /* Return status */
1043 return Status;
1044 }
1045
1046 BOOLEAN
1047 NTAPI
1048 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1049 IN OUT PCONTEXT Context,
1050 IN BOOLEAN SecondChanceException)
1051 {
1052 STRING Header, Data;
1053 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
1054 BOOLEAN Status;
1055
1056 /* Start report loop */
1057 do
1058 {
1059 /* Build the architecture common parts of the message */
1060 KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1061
1062 /* Convert the exception record to 64-bits and set First Chance flag */
1063 ExceptionRecordTo64(ExceptionRecord,
1064 &WaitStateChange.u.Exception.ExceptionRecord);
1065 WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1066
1067 /* Now finish creating the structure */
1068 KdpSetContextState(&WaitStateChange, Context);
1069
1070 /* Setup the actual header to send to KD */
1071 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64) - sizeof(CONTEXT);
1072 Header.Buffer = (PCHAR)&WaitStateChange;
1073
1074 /* Setup the trace data */
1075 DumpTraceData(&Data);
1076
1077 /* Send State Change packet and wait for a reply */
1078 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1079 &Header,
1080 &Data,
1081 Context);
1082 } while (Status == KdPacketNeedsResend);
1083
1084 /* Return */
1085 return Status;
1086 }
1087
1088 VOID
1089 NTAPI
1090 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1091 IN PVOID DeferredContext,
1092 IN PVOID SystemArgument1,
1093 IN PVOID SystemArgument2)
1094 {
1095 LONG OldSlip, NewSlip, PendingSlip;
1096
1097 /* Get the current pending slip */
1098 PendingSlip = KdpTimeSlipPending;
1099 do
1100 {
1101 /* Save the old value and either disable or enable it now. */
1102 OldSlip = PendingSlip;
1103 NewSlip = OldSlip > 1 ? 1 : 0;
1104
1105 /* Try to change the value */
1106 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1107 NewSlip,
1108 OldSlip) != OldSlip);
1109
1110 /* If the New Slip value is 1, then do the Time Slipping */
1111 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1112 }
1113
1114 VOID
1115 NTAPI
1116 KdpTimeSlipWork(IN PVOID Context)
1117 {
1118 KIRQL OldIrql;
1119 LARGE_INTEGER DueTime;
1120
1121 /* Update the System time from the CMOS */
1122 ExAcquireTimeRefreshLock(FALSE);
1123 ExUpdateSystemTimeFromCmos(FALSE, 0);
1124 ExReleaseTimeRefreshLock();
1125
1126 /* Check if we have a registered Time Slip Event and signal it */
1127 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1128 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1129 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1130
1131 /* Delay the DPC until it runs next time */
1132 DueTime.QuadPart = -1800000000;
1133 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1134 }
1135
1136 BOOLEAN
1137 NTAPI
1138 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
1139 IN OUT PCONTEXT ContextRecord,
1140 IN BOOLEAN SecondChanceException)
1141 {
1142 BOOLEAN Status;
1143
1144 /* Save the port data */
1145 KdSave(FALSE);
1146
1147 /* Report a state change */
1148 Status = KdpReportExceptionStateChange(ExceptionRecord,
1149 ContextRecord,
1150 SecondChanceException);
1151
1152 /* Restore the port data and return */
1153 KdRestore(FALSE);
1154 return Status;
1155 }
1156
1157 LARGE_INTEGER
1158 NTAPI
1159 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1160 {
1161 LARGE_INTEGER Null = {{0}};
1162
1163 /* Check if interrupts were disabled */
1164 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1165 {
1166 /* Nothing to return */
1167 return Null;
1168 }
1169
1170 /* Otherwise, do the call */
1171 return KeQueryPerformanceCounter(NULL);
1172 }
1173
1174 BOOLEAN
1175 NTAPI
1176 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1177 IN PKEXCEPTION_FRAME ExceptionFrame)
1178 {
1179 BOOLEAN Entered;
1180
1181 /* Check if we have a trap frame */
1182 if (TrapFrame)
1183 {
1184 /* Calculate the time difference for the enter */
1185 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1186 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1187 KdTimerStart.QuadPart;
1188 }
1189 else
1190 {
1191 /* No trap frame, so can't calculate */
1192 KdTimerStop.QuadPart = 0;
1193 }
1194
1195 /* Save the current IRQL */
1196 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1197
1198 /* Freeze all CPUs */
1199 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
1200
1201 /* Lock the port, save the state and set debugger entered */
1202 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1203 KdSave(FALSE);
1204 KdEnteredDebugger = TRUE;
1205
1206 /* Check freeze flag */
1207 if (KiFreezeFlag & 1)
1208 {
1209 /* Print out errror */
1210 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
1211 }
1212
1213 /* Check processor state */
1214 if (KiFreezeFlag & 2)
1215 {
1216 /* Print out errror */
1217 DbgPrint("Some processors not frozen in debugger!\n");
1218 }
1219
1220 /* Make sure we acquired the port */
1221 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
1222
1223 /* Return enter state */
1224 return Entered;
1225 }
1226
1227 VOID
1228 NTAPI
1229 KdExitDebugger(IN BOOLEAN Entered)
1230 {
1231 ULONG TimeSlip;
1232
1233 /* Restore the state and unlock the port */
1234 KdRestore(FALSE);
1235 if (KdpPortLocked) KdpPortUnlock();
1236
1237 /* Unfreeze the CPUs */
1238 KeThawExecution(Entered);
1239
1240 /* Compare time with the one from KdEnterDebugger */
1241 if (!KdTimerStop.QuadPart)
1242 {
1243 /* We didn't get a trap frame earlier in so never got the time */
1244 KdTimerStart = KdTimerStop;
1245 }
1246 else
1247 {
1248 /* Query the timer */
1249 KdTimerStart = KeQueryPerformanceCounter(NULL);
1250 }
1251
1252 /* Check if a Time Slip was on queue */
1253 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1254 if (TimeSlip == 1)
1255 {
1256 /* Queue a DPC for the time slip */
1257 InterlockedIncrement(&KdpTimeSlipPending);
1258 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
1259 }
1260 }
1261
1262 NTSTATUS
1263 NTAPI
1264 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
1265 {
1266 KIRQL OldIrql = PASSIVE_LEVEL;
1267
1268 /* Check if we need to acquire the lock */
1269 if (NeedLock)
1270 {
1271 /* Lock the port */
1272 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1273 KdpPortLock();
1274 }
1275
1276 /* Check if we're not disabled */
1277 if (!KdDisableCount)
1278 {
1279 /* Check if we had locked the port before */
1280 if (NeedLock)
1281 {
1282 /* Do the unlock */
1283 KeLowerIrql(OldIrql);
1284 KdpPortUnlock();
1285 }
1286
1287 /* Fail: We're already enabled */
1288 return STATUS_INVALID_PARAMETER;
1289 }
1290
1291 /* Decrease the disable count */
1292 if (!(--KdDisableCount))
1293 {
1294 /* We're now enabled again! Were we enabled before, too? */
1295 if (KdPreviouslyEnabled)
1296 {
1297 /* Reinitialize the Debugger */
1298 KdInitSystem(0, NULL) ;
1299 KdpRestoreAllBreakpoints();
1300 }
1301 }
1302
1303 /* Check if we had locked the port before */
1304 if (NeedLock)
1305 {
1306 /* Yes, now unlock it */
1307 KeLowerIrql(OldIrql);
1308 KdpPortUnlock();
1309 }
1310
1311 /* We're done */
1312 return STATUS_SUCCESS;
1313 }
1314
1315 /* PUBLIC FUNCTIONS **********************************************************/
1316
1317 /*
1318 * @implemented
1319 */
1320 NTSTATUS
1321 NTAPI
1322 KdEnableDebugger(VOID)
1323 {
1324 /* Use the internal routine */
1325 while (TRUE);
1326 return KdEnableDebuggerWithLock(TRUE);
1327 }
1328
1329 /*
1330 * @unimplemented
1331 */
1332 NTSTATUS
1333 NTAPI
1334 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
1335 IN PVOID InputBuffer,
1336 IN ULONG InputBufferLength,
1337 OUT PVOID OutputBuffer,
1338 IN ULONG OutputBufferLength,
1339 IN OUT PULONG ReturnLength,
1340 IN KPROCESSOR_MODE PreviousMode)
1341 {
1342 /* HACK */
1343 return STATUS_SUCCESS;
1344 }
1345
1346 /*
1347 * @unimplemented
1348 */
1349 NTSTATUS
1350 NTAPI
1351 KdChangeOption(IN KD_OPTION Option,
1352 IN ULONG InBufferBytes OPTIONAL,
1353 IN PVOID InBuffer,
1354 IN ULONG OutBufferBytes OPTIONAL,
1355 OUT PVOID OutBuffer,
1356 OUT PULONG OutBufferNeeded OPTIONAL)
1357 {
1358 /* HACK */
1359 return STATUS_SUCCESS;
1360 }
1361
1362 /*
1363 * @unimplemented
1364 */
1365 NTSTATUS
1366 NTAPI
1367 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
1368 {
1369 /* HACK */
1370 return STATUS_SUCCESS;
1371 }
1372
1373 /*
1374 * @unimplemented
1375 */
1376 NTSTATUS
1377 NTAPI
1378 KdDisableDebugger(VOID)
1379 {
1380 /* HACK */
1381 return STATUS_SUCCESS;
1382 }
1383
1384 /*
1385 * @unimplemented
1386 */
1387 BOOLEAN
1388 NTAPI
1389 KdRefreshDebuggerNotPresent(VOID)
1390 {
1391 /* HACK */
1392 return KdDebuggerNotPresent;
1393 }
1394
1395 NTSTATUS
1396 NTAPI
1397 NtQueryDebugFilterState(ULONG ComponentId,
1398 ULONG Level)
1399 {
1400 /* HACK */
1401 return STATUS_SUCCESS;
1402 }
1403
1404 NTSTATUS
1405 NTAPI
1406 NtSetDebugFilterState(ULONG ComponentId,
1407 ULONG Level,
1408 BOOLEAN State)
1409 {
1410 /* HACK */
1411 return STATUS_SUCCESS;
1412 }
1413