xref: /reactos/ntoskrnl/kd64/kdapi.c (revision 92dfec21)
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  *                  Stefan Ginsberg (stefan.ginsberg@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
17 
18 /* PRIVATE FUNCTIONS *********************************************************/
19 
20 VOID
21 NTAPI
22 KdpMoveMemory(
23     _In_ PVOID Destination,
24     _In_ PVOID Source,
25     _In_ SIZE_T Length)
26 {
27     PCHAR DestinationBytes, SourceBytes;
28 
29     /* Copy the buffers 1 byte at a time */
30     DestinationBytes = Destination;
31     SourceBytes = Source;
32     while (Length--) *DestinationBytes++ = *SourceBytes++;
33 }
34 
35 VOID
36 NTAPI
37 KdpZeroMemory(
38     _In_ PVOID Destination,
39     _In_ SIZE_T Length)
40 {
41     PCHAR DestinationBytes;
42 
43     /* Zero the buffer 1 byte at a time */
44     DestinationBytes = Destination;
45     while (Length--) *DestinationBytes++ = 0;
46 }
47 
48 NTSTATUS
49 NTAPI
50 KdpCopyMemoryChunks(
51     _In_ ULONG64 Address,
52     _In_ PVOID Buffer,
53     _In_ ULONG TotalSize,
54     _In_ ULONG ChunkSize,
55     _In_ ULONG Flags,
56     _Out_opt_ PULONG ActualSize)
57 {
58     NTSTATUS Status;
59     ULONG RemainingLength, CopyChunk;
60 
61     /* Check if we didn't get a chunk size or if it is too big */
62     if (ChunkSize == 0)
63     {
64         /* Default to 4 byte chunks */
65         ChunkSize = 4;
66     }
67     else if (ChunkSize > MMDBG_COPY_MAX_SIZE)
68     {
69         /* Normalize to maximum size */
70         ChunkSize = MMDBG_COPY_MAX_SIZE;
71     }
72 
73     /* Copy the whole range in aligned chunks */
74     RemainingLength = TotalSize;
75     CopyChunk = 1;
76     while (RemainingLength > 0)
77     {
78         /*
79          * Determine the best chunk size for this round.
80          * The ideal size is aligned, isn't larger than the
81          * the remaining length and respects the chunk limit.
82          */
83         while (((CopyChunk * 2) <= RemainingLength) &&
84                (CopyChunk < ChunkSize) &&
85                ((Address & ((CopyChunk * 2) - 1)) == 0))
86         {
87             /* Increase it */
88             CopyChunk *= 2;
89         }
90 
91         /*
92          * The chunk size can be larger than the remaining size if this
93          * isn't the first round, so check if we need to shrink it back.
94          */
95         while (CopyChunk > RemainingLength)
96         {
97             /* Shrink it */
98             CopyChunk /= 2;
99         }
100 
101         /* Do the copy */
102         Status = MmDbgCopyMemory(Address, Buffer, CopyChunk, Flags);
103         if (!NT_SUCCESS(Status))
104         {
105             /* Copy failed, break out */
106             break;
107         }
108 
109         /* Update pointers and length for the next run */
110         Address = Address + CopyChunk;
111         Buffer = (PVOID)((ULONG_PTR)Buffer + CopyChunk);
112         RemainingLength = RemainingLength - CopyChunk;
113     }
114 
115     /* We may have modified executable code, flush the instruction cache */
116     KeSweepICache((PVOID)(ULONG_PTR)Address, TotalSize);
117 
118     /*
119      * Return the size we managed to copy and return
120      * success if we could copy the whole range.
121      */
122     if (ActualSize) *ActualSize = TotalSize - RemainingLength;
123     return RemainingLength == 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
124 }
125 
126 #ifdef _WINKD_
127 
128 VOID
129 NTAPI
130 KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
131                IN PCONTEXT Context)
132 {
133     PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;
134     STRING Header;
135     NTSTATUS Status = STATUS_SUCCESS;
136 
137     /* Validate the address space */
138     if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)
139     {
140         /* Check if this is process memory */
141         if ((PVOID)(ULONG_PTR)Memory->Address < MmHighestUserAddress)
142         {
143             /* It is */
144             Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;
145         }
146         else
147         {
148             /* Check if it's session space */
149             if (MmIsSessionAddress((PVOID)(ULONG_PTR)Memory->Address))
150             {
151                 /* It is */
152                 Memory->AddressSpace = DBGKD_QUERY_MEMORY_SESSION;
153             }
154             else
155             {
156                 /* Not session space but some other kernel memory */
157                 Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;
158             }
159         }
160 
161         /* Set flags */
162         Memory->Flags = DBGKD_QUERY_MEMORY_READ |
163                         DBGKD_QUERY_MEMORY_WRITE |
164                         DBGKD_QUERY_MEMORY_EXECUTE;
165     }
166     else
167     {
168         /* Invalid */
169         Status = STATUS_INVALID_PARAMETER;
170     }
171 
172     /* Return structure */
173     State->ReturnStatus = Status;
174     Memory->Reserved = 0;
175 
176     /* Build header */
177     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
178     Header.Buffer = (PCHAR)State;
179 
180     /* Send the packet */
181     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
182                  &Header,
183                  NULL,
184                  &KdpContext);
185 }
186 
187 VOID
188 NTAPI
189 KdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State,
190                 IN PSTRING Data,
191                 IN PCONTEXT Context)
192 {
193     //PDBGKD_SEARCH_MEMORY SearchMemory = &State->u.SearchMemory;
194     STRING Header;
195 
196     /* TODO */
197     KdpDprintf("Memory Search support is unimplemented!\n");
198 
199     /* Send a failure packet */
200     State->ReturnStatus = STATUS_UNSUCCESSFUL;
201     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
202     Header.Buffer = (PCHAR)State;
203     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
204                  &Header,
205                  NULL,
206                  &KdpContext);
207 }
208 
209 VOID
210 NTAPI
211 KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,
212               IN PSTRING Data,
213               IN PCONTEXT Context)
214 {
215     //PDBGKD_FILL_MEMORY FillMemory = &State->u.FillMemory;
216     STRING Header;
217 
218     /* TODO */
219     KdpDprintf("Memory Fill support is unimplemented!\n");
220 
221     /* Send a failure packet */
222     State->ReturnStatus = STATUS_UNSUCCESSFUL;
223     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
224     Header.Buffer = (PCHAR)State;
225     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
226                  &Header,
227                  NULL,
228                  &KdpContext);
229 }
230 
231 VOID
232 NTAPI
233 KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
234                    IN PSTRING Data,
235                    IN PCONTEXT Context)
236 {
237     PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;
238     STRING Header;
239 
240     /* Build header */
241     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
242     Header.Buffer = (PCHAR)State;
243     ASSERT(Data->Length == 0);
244 
245     /* Create the breakpoint */
246     Breakpoint->BreakPointHandle =
247         KdpAddBreakpoint((PVOID)(ULONG_PTR)Breakpoint->BreakPointAddress);
248     if (!Breakpoint->BreakPointHandle)
249     {
250         /* We failed */
251         State->ReturnStatus = STATUS_UNSUCCESSFUL;
252     }
253     else
254     {
255         /* Success! */
256         State->ReturnStatus = STATUS_SUCCESS;
257     }
258 
259     /* Send the packet */
260     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
261                  &Header,
262                  NULL,
263                  &KdpContext);
264 }
265 
266 VOID
267 NTAPI
268 KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
269                      IN PSTRING Data,
270                      IN PCONTEXT Context)
271 {
272     PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
273     STRING Header;
274 
275     /* Fill out the header */
276     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
277     Header.Buffer = (PCHAR)State;
278     ASSERT(Data->Length == 0);
279 
280     /* Get the version block */
281     if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
282     {
283         /* We're all good */
284         State->ReturnStatus = STATUS_SUCCESS;
285     }
286     else
287     {
288         /* We failed */
289         State->ReturnStatus = STATUS_UNSUCCESSFUL;
290     }
291 
292     /* Send the packet */
293     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
294                  &Header,
295                  NULL,
296                  &KdpContext);
297 }
298 
299 NTSTATUS
300 NTAPI
301 KdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
302                      IN PSTRING Data,
303                      IN PCONTEXT Context)
304 {
305     //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
306     STRING Header;
307 
308     /* TODO */
309     KdpDprintf("Extended Breakpoint Write support is unimplemented!\n");
310 
311     /* Send a failure packet */
312     State->ReturnStatus = STATUS_UNSUCCESSFUL;
313     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
314     Header.Buffer = (PCHAR)State;
315     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
316                  &Header,
317                  Data,
318                  &KdpContext);
319     return STATUS_UNSUCCESSFUL;
320 }
321 
322 VOID
323 NTAPI
324 KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
325                        IN PSTRING Data,
326                        IN PCONTEXT Context)
327 {
328     //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
329     STRING Header;
330 
331     /* TODO */
332     KdpDprintf("Extended Breakpoint Restore support is unimplemented!\n");
333 
334     /* Send a failure packet */
335     State->ReturnStatus = STATUS_UNSUCCESSFUL;
336     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
337     Header.Buffer = (PCHAR)State;
338     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
339                  &Header,
340                  Data,
341                  &KdpContext);
342 }
343 
344 VOID
345 NTAPI
346 KdpWriteCustomBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
347                          IN PSTRING Data,
348                          IN PCONTEXT Context)
349 {
350     //PDBGKD_WRITE_CUSTOM_BREAKPOINT = &State->u.WriteCustomBreakpoint;
351     STRING Header;
352 
353     /* Not supported */
354     KdpDprintf("Custom Breakpoint Write is unimplemented\n");
355 
356     /* Send a failure packet */
357     State->ReturnStatus = STATUS_UNSUCCESSFUL;
358     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
359     Header.Buffer = (PCHAR)State;
360     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
361                  &Header,
362                  NULL,
363                  &KdpContext);
364 }
365 
366 VOID
367 NTAPI
368 DumpTraceData(IN PSTRING TraceData)
369 {
370     /* Update the buffer */
371     TraceDataBuffer[0] = TraceDataBufferPosition;
372 
373     /* Setup the trace data */
374     TraceData->Length = (USHORT)(TraceDataBufferPosition * sizeof(ULONG));
375     TraceData->Buffer = (PCHAR)TraceDataBuffer;
376 
377     /* Reset the buffer location */
378     TraceDataBufferPosition = 1;
379 }
380 
381 VOID
382 NTAPI
383 KdpSetCommonState(IN ULONG NewState,
384                   IN PCONTEXT Context,
385                   IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)
386 {
387     ULONG InstructionCount;
388     BOOLEAN HadBreakpoints;
389 
390     /* Setup common stuff available for all CPU architectures */
391     WaitStateChange->NewState = NewState;
392     WaitStateChange->ProcessorLevel = KeProcessorLevel;
393     WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
394     WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
395     WaitStateChange->Thread = (ULONG64)(LONG_PTR)KeGetCurrentThread();
396     WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context);
397 
398     /* Zero out the entire Control Report */
399     KdpZeroMemory(&WaitStateChange->AnyControlReport,
400                   sizeof(DBGKD_ANY_CONTROL_REPORT));
401 
402     /* Now copy the instruction stream and set the count */
403     KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
404                         &WaitStateChange->ControlReport.InstructionStream[0],
405                         DBGKD_MAXSTREAM,
406                         0,
407                         MMDBG_COPY_UNSAFE,
408                         &InstructionCount);
409     WaitStateChange->ControlReport.InstructionCount = (USHORT)InstructionCount;
410 
411     /* Clear all the breakpoints in this region */
412     HadBreakpoints =
413         KdpDeleteBreakpointRange((PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
414                                  (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter +
415                                          WaitStateChange->ControlReport.InstructionCount - 1));
416     if (HadBreakpoints)
417     {
418         /* Copy the instruction stream again, this time without breakpoints */
419         KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
420                             &WaitStateChange->ControlReport.InstructionStream[0],
421                             InstructionCount,
422                             0,
423                             MMDBG_COPY_UNSAFE,
424                             NULL);
425     }
426 }
427 
428 VOID
429 NTAPI
430 KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
431 {
432     /* Copy the version block */
433     KdpMoveMemory(Version,
434                   &KdVersionBlock,
435                   sizeof(DBGKD_GET_VERSION64));
436 }
437 
438 VOID
439 NTAPI
440 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
441 {
442     STRING Header;
443 
444     /* Fill out the header */
445     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
446     Header.Buffer = (PCHAR)State;
447 
448     /* Get the version block */
449     KdpSysGetVersion(&State->u.GetVersion64);
450 
451     /* Fill out the state */
452     State->ApiNumber = DbgKdGetVersionApi;
453     State->ReturnStatus = STATUS_SUCCESS;
454 
455     /* Send the packet */
456     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
457                  &Header,
458                  NULL,
459                  &KdpContext);
460 }
461 
462 VOID
463 NTAPI
464 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
465                      IN PSTRING Data,
466                      IN PCONTEXT Context)
467 {
468     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
469     STRING Header;
470     ULONG Length = ReadMemory->TransferCount;
471 
472     /* Setup the header */
473     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
474     Header.Buffer = (PCHAR)State;
475     ASSERT(Data->Length == 0);
476 
477     /* Validate length */
478     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
479     {
480         /* Overflow, set it to maximum possible */
481         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
482     }
483 
484     /* Do the read */
485     State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
486                                               Data->Buffer,
487                                               Length,
488                                               0,
489                                               MMDBG_COPY_UNSAFE,
490                                               &Length);
491 
492     /* Return the actual length read */
493     ReadMemory->ActualBytesRead = Length;
494     Data->Length = (USHORT)Length;
495 
496     /* Send the packet */
497     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
498                  &Header,
499                  Data,
500                  &KdpContext);
501 }
502 
503 VOID
504 NTAPI
505 KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
506                       IN PSTRING Data,
507                       IN PCONTEXT Context)
508 {
509     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
510     STRING Header;
511 
512     /* Setup the header */
513     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
514     Header.Buffer = (PCHAR)State;
515 
516     /* Do the write */
517     State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
518                                               Data->Buffer,
519                                               Data->Length,
520                                               0,
521                                               MMDBG_COPY_UNSAFE |
522                                               MMDBG_COPY_WRITE,
523                                               &WriteMemory->ActualBytesWritten);
524 
525     /* Send the packet */
526     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
527                  &Header,
528                  NULL,
529                  &KdpContext);
530 }
531 
532 VOID
533 NTAPI
534 KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
535                       IN PSTRING Data,
536                       IN PCONTEXT Context)
537 {
538     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
539     STRING Header;
540     ULONG Length = ReadMemory->TransferCount;
541     ULONG Flags, CacheFlags;
542 
543     /* Setup the header */
544     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
545     Header.Buffer = (PCHAR)State;
546     ASSERT(Data->Length == 0);
547 
548     /* Validate length */
549     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
550     {
551         /* Overflow, set it to maximum possible */
552         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
553     }
554 
555     /* Start with the default flags */
556     Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL;
557 
558     /* Get the caching flags and check if a type is specified */
559     CacheFlags = ReadMemory->ActualBytesRead;
560     if (CacheFlags == DBGKD_CACHING_CACHED)
561     {
562         /* Cached */
563         Flags |= MMDBG_COPY_CACHED;
564     }
565     else if (CacheFlags == DBGKD_CACHING_UNCACHED)
566     {
567         /* Uncached */
568         Flags |= MMDBG_COPY_UNCACHED;
569     }
570     else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
571     {
572         /* Write Combined */
573         Flags |= MMDBG_COPY_WRITE_COMBINED;
574     }
575 
576     /* Do the read */
577     State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
578                                               Data->Buffer,
579                                               Length,
580                                               0,
581                                               Flags,
582                                               &Length);
583 
584     /* Return the actual length read */
585     ReadMemory->ActualBytesRead = Length;
586     Data->Length = (USHORT)Length;
587 
588     /* Send the packet */
589     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
590                  &Header,
591                  Data,
592                  &KdpContext);
593 }
594 
595 VOID
596 NTAPI
597 KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
598                        IN PSTRING Data,
599                        IN PCONTEXT Context)
600 {
601     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
602     STRING Header;
603     ULONG Flags, CacheFlags;
604 
605     /* Setup the header */
606     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
607     Header.Buffer = (PCHAR)State;
608 
609     /* Start with the default flags */
610     Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL;
611 
612     /* Get the caching flags and check if a type is specified */
613     CacheFlags = WriteMemory->ActualBytesWritten;
614     if (CacheFlags == DBGKD_CACHING_CACHED)
615     {
616         /* Cached */
617         Flags |= MMDBG_COPY_CACHED;
618     }
619     else if (CacheFlags == DBGKD_CACHING_UNCACHED)
620     {
621         /* Uncached */
622         Flags |= MMDBG_COPY_UNCACHED;
623     }
624     else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
625     {
626         /* Write Combined */
627         Flags |= MMDBG_COPY_WRITE_COMBINED;
628     }
629 
630     /* Do the write */
631     State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
632                                               Data->Buffer,
633                                               Data->Length,
634                                               0,
635                                               Flags,
636                                               &WriteMemory->ActualBytesWritten);
637 
638     /* Send the packet */
639     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
640                  &Header,
641                  NULL,
642                  &KdpContext);
643 }
644 
645 VOID
646 NTAPI
647 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
648                     IN PSTRING Data,
649                     IN PCONTEXT Context)
650 {
651     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
652     STRING Header;
653     ULONG Length;
654 
655     /* Setup the header */
656     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
657     Header.Buffer = (PCHAR)State;
658     ASSERT(Data->Length == 0);
659 
660     /* Check the length requested */
661     Length = ReadMemory->TransferCount;
662     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
663     {
664         /* Use maximum allowed */
665         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
666     }
667 
668     /* Call the internal routine */
669     State->ReturnStatus = KdpSysReadControlSpace(State->Processor,
670                                                  ReadMemory->TargetBaseAddress,
671                                                  Data->Buffer,
672                                                  Length,
673                                                  &Length);
674 
675     /* Return the actual length read */
676     ReadMemory->ActualBytesRead = Length;
677     Data->Length = (USHORT)Length;
678 
679     /* Send the reply */
680     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
681                  &Header,
682                  Data,
683                  &KdpContext);
684 }
685 
686 VOID
687 NTAPI
688 KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
689                      IN PSTRING Data,
690                      IN PCONTEXT Context)
691 {
692     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
693     STRING Header;
694 
695     /* Setup the header */
696     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
697     Header.Buffer = (PCHAR)State;
698 
699     /* Call the internal routine */
700     State->ReturnStatus = KdpSysWriteControlSpace(State->Processor,
701                                                   WriteMemory->TargetBaseAddress,
702                                                   Data->Buffer,
703                                                   Data->Length,
704                                                   &WriteMemory->ActualBytesWritten);
705 
706     /* Send the reply */
707     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
708                  &Header,
709                  Data,
710                  &KdpContext);
711 }
712 
713 VOID
714 NTAPI
715 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
716               IN PSTRING Data,
717               IN PCONTEXT Context)
718 {
719     STRING Header;
720     PCONTEXT TargetContext;
721 
722     /* Setup the header */
723     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
724     Header.Buffer = (PCHAR)State;
725     ASSERT(Data->Length == 0);
726 
727     /* Make sure that this is a valid request */
728     if (State->Processor < KeNumberProcessors)
729     {
730         /* Check if the request is for this CPU */
731         if (State->Processor == KeGetCurrentPrcb()->Number)
732         {
733             /* We're just copying our own context */
734             TargetContext = Context;
735         }
736         else
737         {
738             /* Get the context from the PRCB array */
739             TargetContext = &KiProcessorBlock[State->Processor]->
740                             ProcessorState.ContextFrame;
741         }
742 
743         /* Copy it over to the debugger */
744         KdpMoveMemory(Data->Buffer,
745                       TargetContext,
746                       sizeof(CONTEXT));
747         Data->Length = sizeof(CONTEXT);
748 
749         /* Let the debugger set the context now */
750         KdpContextSent = TRUE;
751 
752         /* Finish up */
753         State->ReturnStatus = STATUS_SUCCESS;
754     }
755     else
756     {
757         /* Invalid request */
758         State->ReturnStatus = STATUS_UNSUCCESSFUL;
759     }
760 
761     /* Send the reply */
762     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
763                  &Header,
764                  Data,
765                  &KdpContext);
766 }
767 
768 VOID
769 NTAPI
770 KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
771               IN PSTRING Data,
772               IN PCONTEXT Context)
773 {
774     STRING Header;
775     PCONTEXT TargetContext;
776 
777     /* Setup the header */
778     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
779     Header.Buffer = (PCHAR)State;
780     ASSERT(Data->Length == sizeof(CONTEXT));
781 
782     /* Make sure that this is a valid request */
783     if ((State->Processor < KeNumberProcessors) &&
784         (KdpContextSent))
785     {
786         /* Check if the request is for this CPU */
787         if (State->Processor == KeGetCurrentPrcb()->Number)
788         {
789             /* We're just copying our own context */
790             TargetContext = Context;
791         }
792         else
793         {
794             /* Get the context from the PRCB array */
795             TargetContext = &KiProcessorBlock[State->Processor]->
796                             ProcessorState.ContextFrame;
797         }
798 
799         /* Copy the new context to it */
800         KdpMoveMemory(TargetContext,
801                       Data->Buffer,
802                       sizeof(CONTEXT));
803 
804         /* Finish up */
805         State->ReturnStatus = STATUS_SUCCESS;
806     }
807     else
808     {
809         /* Invalid request */
810         State->ReturnStatus = STATUS_UNSUCCESSFUL;
811     }
812 
813     /* Send the reply */
814     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
815                  &Header,
816                  NULL,
817                  &KdpContext);
818 }
819 
820 VOID
821 NTAPI
822 KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
823                 IN PSTRING Data,
824                 IN PCONTEXT Context)
825 {
826     STRING Header;
827     PDBGKD_CONTEXT_EX ContextEx;
828     PCONTEXT TargetContext;
829     ASSERT(Data->Length == 0);
830 
831     /* Get our struct */
832     ContextEx = &State->u.ContextEx;
833 
834     /* Set up the header */
835     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
836     Header.Buffer = (PCHAR)State;
837 
838     /* Make sure that this is a valid request */
839     if ((State->Processor < KeNumberProcessors) &&
840         (ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT))
841     {
842         /* Check if the request is for this CPU */
843         if (State->Processor == KeGetCurrentPrcb()->Number)
844         {
845             /* We're just copying our own context */
846             TargetContext = Context;
847         }
848         else
849         {
850             /* Get the context from the PRCB array */
851             TargetContext = &KiProcessorBlock[State->Processor]->
852                             ProcessorState.ContextFrame;
853         }
854 
855         /* Copy what is requested */
856         KdpMoveMemory(Data->Buffer,
857                       (PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
858                       ContextEx->ByteCount);
859 
860         /* KD copies all */
861         Data->Length = ContextEx->BytesCopied = ContextEx->ByteCount;
862 
863         /* Let the debugger set the context now */
864         KdpContextSent = TRUE;
865 
866         /* Finish up */
867         State->ReturnStatus = STATUS_SUCCESS;
868     }
869     else
870     {
871         /* Invalid request */
872         ContextEx->BytesCopied = 0;
873         State->ReturnStatus = STATUS_UNSUCCESSFUL;
874     }
875 
876     /* Send the reply */
877     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
878                  &Header,
879                  Data,
880                  &KdpContext);
881 }
882 
883 VOID
884 NTAPI
885 KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
886                 IN PSTRING Data,
887                 IN PCONTEXT Context)
888 {
889     STRING Header;
890     PDBGKD_CONTEXT_EX ContextEx;
891     PCONTEXT TargetContext;
892 
893     /* Get our struct */
894     ContextEx = &State->u.ContextEx;
895     ASSERT(Data->Length == ContextEx->ByteCount);
896 
897     /* Set up the header */
898     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
899     Header.Buffer = (PCHAR)State;
900 
901     /* Make sure that this is a valid request */
902     if ((State->Processor < KeNumberProcessors) &&
903         ((ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT)) &&
904         (KdpContextSent))
905     {
906         /* Check if the request is for this CPU */
907         if (State->Processor == KeGetCurrentPrcb()->Number)
908         {
909             /* We're just copying our own context */
910             TargetContext = Context;
911         }
912         else
913         {
914             /* Get the context from the PRCB array */
915             TargetContext = &KiProcessorBlock[State->Processor]->
916                             ProcessorState.ContextFrame;
917         }
918 
919         /* Copy what is requested */
920         KdpMoveMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
921                       Data->Buffer,
922                       ContextEx->ByteCount);
923 
924         /* KD copies all */
925         ContextEx->BytesCopied = ContextEx->ByteCount;
926 
927         /* Finish up */
928         State->ReturnStatus = STATUS_SUCCESS;
929     }
930     else
931     {
932         /* Invalid request */
933         ContextEx->BytesCopied = 0;
934         State->ReturnStatus = STATUS_UNSUCCESSFUL;
935     }
936 
937     /* Send the reply */
938     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
939                  &Header,
940                  NULL,
941                  &KdpContext);
942 }
943 
944 VOID
945 NTAPI
946 KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)
947 {
948     /* Crash with the special code */
949     KeBugCheck(MANUALLY_INITIATED_CRASH);
950 }
951 
952 VOID
953 NTAPI
954 KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
955                                IN PSTRING Data,
956                                IN PCONTEXT Context)
957 {
958     STRING Header;
959     PDBGKD_READ_WRITE_MSR ReadMsr = &State->u.ReadWriteMsr;
960     LARGE_INTEGER MsrValue;
961 
962     /* Setup the header */
963     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
964     Header.Buffer = (PCHAR)State;
965     ASSERT(Data->Length == 0);
966 
967     /* Call the internal routine */
968     State->ReturnStatus = KdpSysReadMsr(ReadMsr->Msr,
969                                         &MsrValue);
970 
971     /* Return the data */
972     ReadMsr->DataValueLow = MsrValue.LowPart;
973     ReadMsr->DataValueHigh = MsrValue.HighPart;
974 
975     /* Send the reply */
976     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
977                  &Header,
978                  NULL,
979                  &KdpContext);
980 }
981 
982 VOID
983 NTAPI
984 KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
985                                 IN PSTRING Data,
986                                 IN PCONTEXT Context)
987 {
988     STRING Header;
989     PDBGKD_READ_WRITE_MSR WriteMsr = &State->u.ReadWriteMsr;
990     LARGE_INTEGER MsrValue;
991 
992     /* Setup the header */
993     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
994     Header.Buffer = (PCHAR)State;
995     ASSERT(Data->Length == 0);
996 
997     /* Call the internal routine */
998     MsrValue.LowPart = WriteMsr->DataValueLow;
999     MsrValue.HighPart = WriteMsr->DataValueHigh;
1000     State->ReturnStatus = KdpSysWriteMsr(WriteMsr->Msr,
1001                                          &MsrValue);
1002 
1003     /* Send the reply */
1004     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1005                  &Header,
1006                  NULL,
1007                  &KdpContext);
1008 }
1009 
1010 VOID
1011 NTAPI
1012 KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1013               IN PSTRING Data,
1014               IN PCONTEXT Context)
1015 {
1016     STRING Header;
1017     PDBGKD_GET_SET_BUS_DATA GetBusData = &State->u.GetSetBusData;
1018     ULONG Length;
1019 
1020     /* Setup the header */
1021     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1022     Header.Buffer = (PCHAR)State;
1023     ASSERT(Data->Length == 0);
1024 
1025     /* Check the length requested */
1026     Length = GetBusData->Length;
1027     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
1028     {
1029         /* Use maximum allowed */
1030         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
1031     }
1032 
1033     /* Call the internal routine */
1034     State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType,
1035                                             GetBusData->BusNumber,
1036                                             GetBusData->SlotNumber,
1037                                             GetBusData->Offset,
1038                                             Data->Buffer,
1039                                             Length,
1040                                             &Length);
1041 
1042     /* Return the actual length read */
1043     GetBusData->Length = Length;
1044     Data->Length = (USHORT)Length;
1045 
1046     /* Send the reply */
1047     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1048                  &Header,
1049                  Data,
1050                  &KdpContext);
1051 }
1052 
1053 VOID
1054 NTAPI
1055 KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1056               IN PSTRING Data,
1057               IN PCONTEXT Context)
1058 {
1059     STRING Header;
1060     PDBGKD_GET_SET_BUS_DATA SetBusData = &State->u.GetSetBusData;
1061     ULONG Length;
1062 
1063     /* Setup the header */
1064     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1065     Header.Buffer = (PCHAR)State;
1066 
1067     /* Call the internal routine */
1068     State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType,
1069                                              SetBusData->BusNumber,
1070                                              SetBusData->SlotNumber,
1071                                              SetBusData->Offset,
1072                                              Data->Buffer,
1073                                              SetBusData->Length,
1074                                              &Length);
1075 
1076     /* Return the actual length written */
1077     SetBusData->Length = Length;
1078 
1079     /* Send the reply */
1080     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1081                  &Header,
1082                  NULL,
1083                  &KdpContext);
1084 }
1085 
1086 VOID
1087 NTAPI
1088 KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1089                IN PSTRING Data,
1090                IN PCONTEXT Context)
1091 {
1092     STRING Header;
1093     PDBGKD_READ_WRITE_IO64 ReadIo = &State->u.ReadWriteIo;
1094 
1095     /* Setup the header */
1096     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1097     Header.Buffer = (PCHAR)State;
1098     ASSERT(Data->Length == 0);
1099 
1100     /*
1101      * Clear the value so 1 or 2 byte reads
1102      * don't leave the higher bits unmodified
1103      */
1104     ReadIo->DataValue = 0;
1105 
1106     /* Call the internal routine */
1107     State->ReturnStatus = KdpSysReadIoSpace(Isa,
1108                                             0,
1109                                             1,
1110                                             ReadIo->IoAddress,
1111                                             &ReadIo->DataValue,
1112                                             ReadIo->DataSize,
1113                                             &ReadIo->DataSize);
1114 
1115     /* Send the reply */
1116     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1117                  &Header,
1118                  NULL,
1119                  &KdpContext);
1120 }
1121 
1122 VOID
1123 NTAPI
1124 KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1125                 IN PSTRING Data,
1126                 IN PCONTEXT Context)
1127 {
1128     STRING Header;
1129     PDBGKD_READ_WRITE_IO64 WriteIo = &State->u.ReadWriteIo;
1130 
1131     /* Setup the header */
1132     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1133     Header.Buffer = (PCHAR)State;
1134     ASSERT(Data->Length == 0);
1135 
1136     /* Call the internal routine */
1137     State->ReturnStatus = KdpSysWriteIoSpace(Isa,
1138                                              0,
1139                                              1,
1140                                              WriteIo->IoAddress,
1141                                              &WriteIo->DataValue,
1142                                              WriteIo->DataSize,
1143                                              &WriteIo->DataSize);
1144 
1145     /* Send the reply */
1146     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1147                  &Header,
1148                  NULL,
1149                  &KdpContext);
1150 }
1151 
1152 VOID
1153 NTAPI
1154 KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1155                        IN PSTRING Data,
1156                        IN PCONTEXT Context)
1157 {
1158     STRING Header;
1159     PDBGKD_READ_WRITE_IO_EXTENDED64 ReadIoExtended = &State->u.
1160                                                       ReadWriteIoExtended;
1161 
1162     /* Setup the header */
1163     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1164     Header.Buffer = (PCHAR)State;
1165     ASSERT(Data->Length == 0);
1166 
1167     /*
1168      * Clear the value so 1 or 2 byte reads
1169      * don't leave the higher bits unmodified
1170      */
1171     ReadIoExtended->DataValue = 0;
1172 
1173     /* Call the internal routine */
1174     State->ReturnStatus = KdpSysReadIoSpace(ReadIoExtended->InterfaceType,
1175                                             ReadIoExtended->BusNumber,
1176                                             ReadIoExtended->AddressSpace,
1177                                             ReadIoExtended->IoAddress,
1178                                             &ReadIoExtended->DataValue,
1179                                             ReadIoExtended->DataSize,
1180                                             &ReadIoExtended->DataSize);
1181 
1182     /* Send the reply */
1183     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1184                  &Header,
1185                  NULL,
1186                  &KdpContext);
1187 }
1188 
1189 VOID
1190 NTAPI
1191 KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1192                         IN PSTRING Data,
1193                         IN PCONTEXT Context)
1194 {
1195     STRING Header;
1196     PDBGKD_READ_WRITE_IO_EXTENDED64 WriteIoExtended = &State->u.
1197                                                        ReadWriteIoExtended;
1198 
1199     /* Setup the header */
1200     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1201     Header.Buffer = (PCHAR)State;
1202     ASSERT(Data->Length == 0);
1203 
1204     /* Call the internal routine */
1205     State->ReturnStatus = KdpSysWriteIoSpace(WriteIoExtended->InterfaceType,
1206                                              WriteIoExtended->BusNumber,
1207                                              WriteIoExtended->AddressSpace,
1208                                              WriteIoExtended->IoAddress,
1209                                              &WriteIoExtended->DataValue,
1210                                              WriteIoExtended->DataSize,
1211                                              &WriteIoExtended->DataSize);
1212 
1213     /* Send the reply */
1214     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1215                  &Header,
1216                  NULL,
1217                  &KdpContext);
1218 }
1219 
1220 VOID
1221 NTAPI
1222 KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)
1223 {
1224     STRING Header;
1225 
1226     /* Setup the header */
1227     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1228     Header.Buffer = (PCHAR)State;
1229 
1230     /* Call the internal routine */
1231     State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
1232 
1233     /* Send the reply */
1234     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1235                  &Header,
1236                  NULL,
1237                  &KdpContext);
1238 }
1239 
1240 VOID
1241 NTAPI
1242 KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)
1243 {
1244     STRING Header;
1245 
1246     /* Set failure */
1247     State->ReturnStatus = STATUS_UNSUCCESSFUL;
1248 
1249     /* Setup the packet */
1250     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1251     Header.Buffer = (PCHAR)State;
1252 
1253     /* Send it */
1254     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1255                  &Header,
1256                  NULL,
1257                  &KdpContext);
1258 }
1259 
1260 KCONTINUE_STATUS
1261 NTAPI
1262 KdpSendWaitContinue(IN ULONG PacketType,
1263                     IN PSTRING SendHeader,
1264                     IN PSTRING SendData OPTIONAL,
1265                     IN OUT PCONTEXT Context)
1266 {
1267     STRING Data, Header;
1268     DBGKD_MANIPULATE_STATE64 ManipulateState;
1269     ULONG Length;
1270     KDSTATUS RecvCode;
1271 
1272     /* Setup the Manipulate State structure */
1273     Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
1274     Header.Buffer = (PCHAR)&ManipulateState;
1275     Data.MaximumLength = sizeof(KdpMessageBuffer);
1276     Data.Buffer = KdpMessageBuffer;
1277 
1278     /*
1279      * Reset the context state to ensure the debugger has received
1280      * the current context before it sets it.
1281      */
1282     KdpContextSent = FALSE;
1283 
1284 SendPacket:
1285     /* Send the Packet */
1286     KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
1287 
1288     /* If the debugger isn't present anymore, just return success */
1289     if (KdDebuggerNotPresent) return ContinueSuccess;
1290 
1291     /* Main processing Loop */
1292     for (;;)
1293     {
1294         /* Receive Loop */
1295         do
1296         {
1297             /* Wait to get a reply to our packet */
1298             RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1299                                        &Header,
1300                                        &Data,
1301                                        &Length,
1302                                        &KdpContext);
1303 
1304             /* If we got a resend request, do it */
1305             if (RecvCode == KdPacketNeedsResend) goto SendPacket;
1306         } while (RecvCode == KdPacketTimedOut);
1307 
1308         /* Now check what API we got */
1309         switch (ManipulateState.ApiNumber)
1310         {
1311             case DbgKdReadVirtualMemoryApi:
1312 
1313                 /* Read virtual memory */
1314                 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
1315                 break;
1316 
1317             case DbgKdWriteVirtualMemoryApi:
1318 
1319                 /* Write virtual memory */
1320                 KdpWriteVirtualMemory(&ManipulateState, &Data, Context);
1321                 break;
1322 
1323             case DbgKdGetContextApi:
1324 
1325                 /* Get the current context */
1326                 KdpGetContext(&ManipulateState, &Data, Context);
1327                 break;
1328 
1329             case DbgKdSetContextApi:
1330 
1331                 /* Set a new context */
1332                 KdpSetContext(&ManipulateState, &Data, Context);
1333                 break;
1334 
1335             case DbgKdWriteBreakPointApi:
1336 
1337                 /* Write the breakpoint */
1338                 KdpWriteBreakpoint(&ManipulateState, &Data, Context);
1339                 break;
1340 
1341             case DbgKdRestoreBreakPointApi:
1342 
1343                 /* Restore the breakpoint */
1344                 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
1345                 break;
1346 
1347             case DbgKdContinueApi:
1348 
1349                 /* Simply continue */
1350                 return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
1351 
1352             case DbgKdReadControlSpaceApi:
1353 
1354                 /* Read control space */
1355                 KdpReadControlSpace(&ManipulateState, &Data, Context);
1356                 break;
1357 
1358             case DbgKdWriteControlSpaceApi:
1359 
1360                 /* Write control space */
1361                 KdpWriteControlSpace(&ManipulateState, &Data, Context);
1362                 break;
1363 
1364             case DbgKdReadIoSpaceApi:
1365 
1366                 /* Read I/O Space */
1367                 KdpReadIoSpace(&ManipulateState, &Data, Context);
1368                 break;
1369 
1370             case DbgKdWriteIoSpaceApi:
1371 
1372                 /* Write I/O Space */
1373                 KdpWriteIoSpace(&ManipulateState, &Data, Context);
1374                 break;
1375 
1376             case DbgKdRebootApi:
1377 
1378                 /* Reboot the system */
1379                 HalReturnToFirmware(HalRebootRoutine);
1380                 break;
1381 
1382             case DbgKdContinueApi2:
1383 
1384                 /* Check if caller reports success */
1385                 if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
1386                 {
1387                     /* Update the state */
1388                     KdpGetStateChange(&ManipulateState, Context);
1389                     return ContinueSuccess;
1390                 }
1391                 else
1392                 {
1393                     /* Return an error */
1394                     return ContinueError;
1395                 }
1396 
1397             case DbgKdReadPhysicalMemoryApi:
1398 
1399                 /* Read  physical memory */
1400                 KdpReadPhysicalMemory(&ManipulateState, &Data, Context);
1401                 break;
1402 
1403             case DbgKdWritePhysicalMemoryApi:
1404 
1405                 /* Write  physical memory */
1406                 KdpWritePhysicalMemory(&ManipulateState, &Data, Context);
1407                 break;
1408 
1409             case DbgKdQuerySpecialCallsApi:
1410             case DbgKdSetSpecialCallApi:
1411             case DbgKdClearSpecialCallsApi:
1412 
1413                 /* TODO */
1414                 KdpDprintf("Special Call support is unimplemented!\n");
1415                 KdpNotSupported(&ManipulateState);
1416                 break;
1417 
1418             case DbgKdSetInternalBreakPointApi:
1419             case DbgKdGetInternalBreakPointApi:
1420 
1421                 /* TODO */
1422                 KdpDprintf("Internal Breakpoint support is unimplemented!\n");
1423                 KdpNotSupported(&ManipulateState);
1424                 break;
1425 
1426             case DbgKdReadIoSpaceExtendedApi:
1427 
1428                 /* Read I/O Space */
1429                 KdpReadIoSpaceExtended(&ManipulateState, &Data, Context);
1430                 break;
1431 
1432             case DbgKdWriteIoSpaceExtendedApi:
1433 
1434                 /* Write I/O Space */
1435                 KdpWriteIoSpaceExtended(&ManipulateState, &Data, Context);
1436                 break;
1437 
1438             case DbgKdGetVersionApi:
1439 
1440                 /* Get version data */
1441                 KdpGetVersion(&ManipulateState);
1442                 break;
1443 
1444             case DbgKdWriteBreakPointExApi:
1445 
1446                 /* Write the breakpoint and check if it failed */
1447                 if (!NT_SUCCESS(KdpWriteBreakPointEx(&ManipulateState,
1448                                                      &Data,
1449                                                      Context)))
1450                 {
1451                     /* Return an error */
1452                     return ContinueError;
1453                 }
1454                 break;
1455 
1456             case DbgKdRestoreBreakPointExApi:
1457 
1458                 /* Restore the breakpoint */
1459                 KdpRestoreBreakPointEx(&ManipulateState, &Data, Context);
1460                 break;
1461 
1462             case DbgKdCauseBugCheckApi:
1463 
1464                 /* Crash the system */
1465                 KdpCauseBugCheck(&ManipulateState);
1466                 break;
1467 
1468             case DbgKdSwitchProcessor:
1469 
1470                 /* TODO */
1471                 KdpDprintf("Processor Switch support is unimplemented!\n");
1472                 KdpNotSupported(&ManipulateState);
1473                 break;
1474 
1475             case DbgKdPageInApi:
1476 
1477                 /* TODO */
1478                 KdpDprintf("Page-In support is unimplemented!\n");
1479                 KdpNotSupported(&ManipulateState);
1480                 break;
1481 
1482             case DbgKdReadMachineSpecificRegister:
1483 
1484                 /* Read from the specified MSR */
1485                 KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
1486                 break;
1487 
1488             case DbgKdWriteMachineSpecificRegister:
1489 
1490                 /* Write to the specified MSR */
1491                 KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
1492                 break;
1493 
1494             case DbgKdSearchMemoryApi:
1495 
1496                 /* Search memory */
1497                 KdpSearchMemory(&ManipulateState, &Data, Context);
1498                 break;
1499 
1500             case DbgKdGetBusDataApi:
1501 
1502                 /* Read from the bus */
1503                 KdpGetBusData(&ManipulateState, &Data, Context);
1504                 break;
1505 
1506             case DbgKdSetBusDataApi:
1507 
1508                 /* Write to the bus */
1509                 KdpSetBusData(&ManipulateState, &Data, Context);
1510                 break;
1511 
1512             case DbgKdCheckLowMemoryApi:
1513 
1514                 /* Check for memory corruption in the lower 4 GB */
1515                 KdpCheckLowMemory(&ManipulateState);
1516                 break;
1517 
1518             case DbgKdClearAllInternalBreakpointsApi:
1519 
1520                 /* Just clear the counter */
1521                 KdpNumInternalBreakpoints = 0;
1522                 break;
1523 
1524             case DbgKdFillMemoryApi:
1525 
1526                 /* Fill memory */
1527                 KdpFillMemory(&ManipulateState, &Data, Context);
1528                 break;
1529 
1530             case DbgKdQueryMemoryApi:
1531 
1532                 /* Query memory */
1533                 KdpQueryMemory(&ManipulateState, Context);
1534                 break;
1535 
1536             case DbgKdSwitchPartition:
1537 
1538                 /* TODO */
1539                 KdpDprintf("Partition Switch support is unimplemented!\n");
1540                 KdpNotSupported(&ManipulateState);
1541                 break;
1542 
1543             case DbgKdWriteCustomBreakpointApi:
1544 
1545                 /* Write the customized breakpoint */
1546                 KdpWriteCustomBreakpoint(&ManipulateState, &Data, Context);
1547                 break;
1548 
1549             case DbgKdGetContextExApi:
1550 
1551                 /* Extended Context Get */
1552                 KdpGetContextEx(&ManipulateState, &Data, Context);
1553                 break;
1554 
1555             case DbgKdSetContextExApi:
1556 
1557                 /* Extended Context Set */
1558                 KdpSetContextEx(&ManipulateState, &Data, Context);
1559                 break;
1560 
1561             /* Unsupported Messages */
1562             default:
1563 
1564                 /* Send warning */
1565                 KdpDprintf("Received Unrecognized API 0x%lx\n", ManipulateState.ApiNumber);
1566 
1567                 /* Setup an empty message, with failure */
1568                 Data.Length = 0;
1569                 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1570 
1571                 /* Send it */
1572                 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1573                              &Header,
1574                              &Data,
1575                              &KdpContext);
1576                 break;
1577         }
1578     }
1579 }
1580 
1581 VOID
1582 NTAPI
1583 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
1584                                 IN PKD_SYMBOLS_INFO SymbolInfo,
1585                                 IN BOOLEAN Unload,
1586                                 IN OUT PCONTEXT Context)
1587 {
1588     PSTRING ExtraData;
1589     STRING Data, Header;
1590     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1591     ULONG PathNameLength;
1592     KCONTINUE_STATUS Status;
1593 
1594     /* Start wait loop */
1595     do
1596     {
1597         /* Build the architecture common parts of the message */
1598         KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1599                           Context,
1600                           &WaitStateChange);
1601 
1602         /* Now finish creating the structure */
1603         KdpSetContextState(&WaitStateChange, Context);
1604 
1605         /* Fill out load data */
1606         WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1607         WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
1608         WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1609         WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1610         WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1611 
1612         /* Check if we have a path name */
1613         if (PathName)
1614         {
1615             /* Copy it to the path buffer */
1616             KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
1617                                 KdpPathBuffer,
1618                                 PathName->Length,
1619                                 0,
1620                                 MMDBG_COPY_UNSAFE,
1621                                 &PathNameLength);
1622 
1623             /* Null terminate */
1624             KdpPathBuffer[PathNameLength++] = ANSI_NULL;
1625 
1626             /* Set the path length */
1627             WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
1628 
1629             /* Set up the data */
1630             Data.Buffer = KdpPathBuffer;
1631             Data.Length = (USHORT)PathNameLength;
1632             ExtraData = &Data;
1633         }
1634         else
1635         {
1636             /* No name */
1637             WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1638             ExtraData = NULL;
1639         }
1640 
1641         /* Setup the header */
1642         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1643         Header.Buffer = (PCHAR)&WaitStateChange;
1644 
1645         /* Send the packet */
1646         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1647                                      &Header,
1648                                      ExtraData,
1649                                      Context);
1650     } while (Status == ContinueProcessorReselected);
1651 }
1652 
1653 VOID
1654 NTAPI
1655 KdpReportCommandStringStateChange(IN PSTRING NameString,
1656                                   IN PSTRING CommandString,
1657                                   IN OUT PCONTEXT Context)
1658 {
1659     STRING Header, Data;
1660     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1661     ULONG Length, ActualLength, TotalLength;
1662     KCONTINUE_STATUS Status;
1663 
1664     /* Start wait loop */
1665     do
1666     {
1667         /* Build the architecture common parts of the message */
1668         KdpSetCommonState(DbgKdCommandStringStateChange,
1669                           Context,
1670                           &WaitStateChange);
1671 
1672         /* Set the context */
1673         KdpSetContextState(&WaitStateChange, Context);
1674 
1675         /* Clear the command string structure */
1676         KdpZeroMemory(&WaitStateChange.u.CommandString,
1677                       sizeof(DBGKD_COMMAND_STRING));
1678 
1679         /* Normalize name string to max */
1680         Length = min(128 - 1, NameString->Length);
1681 
1682         /* Copy it to the message buffer */
1683         KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
1684                             KdpMessageBuffer,
1685                             Length,
1686                             0,
1687                             MMDBG_COPY_UNSAFE,
1688                             &ActualLength);
1689 
1690         /* Null terminate and calculate the total length */
1691         TotalLength = ActualLength;
1692         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1693 
1694         /* Check if the command string is too long */
1695         Length = CommandString->Length;
1696         if (Length > (PACKET_MAX_SIZE -
1697                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
1698         {
1699             /* Use maximum possible size */
1700             Length = (PACKET_MAX_SIZE -
1701                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
1702         }
1703 
1704         /* Copy it to the message buffer */
1705         KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
1706                             KdpMessageBuffer + TotalLength,
1707                             Length,
1708                             0,
1709                             MMDBG_COPY_UNSAFE,
1710                             &ActualLength);
1711 
1712         /* Null terminate and calculate the total length */
1713         TotalLength += ActualLength;
1714         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1715 
1716         /* Now set up the header and the data */
1717         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1718         Header.Buffer = (PCHAR)&WaitStateChange;
1719         Data.Length = (USHORT)TotalLength;
1720         Data.Buffer = KdpMessageBuffer;
1721 
1722         /* Send State Change packet and wait for a reply */
1723         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1724                                      &Header,
1725                                      &Data,
1726                                      Context);
1727     } while (Status == ContinueProcessorReselected);
1728 }
1729 
1730 BOOLEAN
1731 NTAPI
1732 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1733                               IN OUT PCONTEXT Context,
1734                               IN BOOLEAN SecondChanceException)
1735 {
1736     STRING Header, Data;
1737     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1738     KCONTINUE_STATUS Status;
1739 
1740     /* Start report loop */
1741     do
1742     {
1743         /* Build the architecture common parts of the message */
1744         KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1745 
1746 #if !defined(_WIN64)
1747 
1748         /* Convert it and copy it over */
1749         ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
1750                               &WaitStateChange.u.Exception.ExceptionRecord);
1751 
1752 #else
1753 
1754         /* Just copy it directly, no need to convert */
1755         KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord,
1756                       ExceptionRecord,
1757                       sizeof(EXCEPTION_RECORD));
1758 
1759 #endif
1760 
1761         /* Set the First Chance flag */
1762         WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1763 
1764         /* Now finish creating the structure */
1765         KdpSetContextState(&WaitStateChange, Context);
1766 
1767         /* Setup the actual header to send to KD */
1768         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1769         Header.Buffer = (PCHAR)&WaitStateChange;
1770 
1771         /* Setup the trace data */
1772         DumpTraceData(&Data);
1773 
1774         /* Send State Change packet and wait for a reply */
1775         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1776                                      &Header,
1777                                      &Data,
1778                                      Context);
1779     } while (Status == ContinueProcessorReselected);
1780 
1781     /* Return */
1782     return Status;
1783 }
1784 
1785 VOID
1786 NTAPI
1787 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1788                       IN PVOID DeferredContext,
1789                       IN PVOID SystemArgument1,
1790                       IN PVOID SystemArgument2)
1791 {
1792     LONG OldSlip, NewSlip, PendingSlip;
1793 
1794     /* Get the current pending slip */
1795     PendingSlip = KdpTimeSlipPending;
1796     do
1797     {
1798         /* Save the old value and either disable or enable it now. */
1799         OldSlip = PendingSlip;
1800         NewSlip = OldSlip > 1 ? 1 : 0;
1801 
1802         /* Try to change the value */
1803     } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1804                                         NewSlip,
1805                                         OldSlip) != OldSlip);
1806 
1807     /* If the New Slip value is 1, then do the Time Slipping */
1808     if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1809 }
1810 
1811 VOID
1812 NTAPI
1813 KdpTimeSlipWork(IN PVOID Context)
1814 {
1815     KIRQL OldIrql;
1816     LARGE_INTEGER DueTime;
1817 
1818     /* Update the System time from the CMOS */
1819     ExAcquireTimeRefreshLock(FALSE);
1820     ExUpdateSystemTimeFromCmos(FALSE, 0);
1821     ExReleaseTimeRefreshLock();
1822 
1823     /* Check if we have a registered Time Slip Event and signal it */
1824     KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1825     if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1826     KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1827 
1828     /* Delay the DPC until it runs next time */
1829     DueTime.QuadPart = -1800000000;
1830     KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1831 }
1832 
1833 BOOLEAN
1834 NTAPI
1835 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
1836                    IN OUT PCONTEXT ContextRecord,
1837                    IN BOOLEAN SecondChanceException)
1838 {
1839     BOOLEAN Status;
1840 
1841     /* Save the port data */
1842     KdSave(FALSE);
1843 
1844     /* Report a state change */
1845     Status = KdpReportExceptionStateChange(ExceptionRecord,
1846                                            ContextRecord,
1847                                            SecondChanceException);
1848 
1849     /* Restore the port data and return */
1850     KdRestore(FALSE);
1851     return Status;
1852 }
1853 
1854 LARGE_INTEGER
1855 NTAPI
1856 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1857 {
1858     LARGE_INTEGER Null = {{0}};
1859 
1860     /* Check if interrupts were disabled */
1861     if (!KeGetTrapFrameInterruptState(TrapFrame))
1862     {
1863         /* Nothing to return */
1864         return Null;
1865     }
1866 
1867     /* Otherwise, do the call */
1868     return KeQueryPerformanceCounter(NULL);
1869 }
1870 
1871 BOOLEAN
1872 NTAPI
1873 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1874                 IN PKEXCEPTION_FRAME ExceptionFrame)
1875 {
1876     BOOLEAN Enable;
1877 
1878     /* Check if we have a trap frame */
1879     if (TrapFrame)
1880     {
1881         /* Calculate the time difference for the enter */
1882         KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1883         KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1884                                      KdTimerStart.QuadPart;
1885     }
1886     else
1887     {
1888         /* No trap frame, so can't calculate */
1889         KdTimerStop.QuadPart = 0;
1890     }
1891 
1892     /* Save the current IRQL */
1893     KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1894 
1895     /* Freeze all CPUs */
1896     Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
1897 
1898     /* Lock the port, save the state and set debugger entered */
1899     KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1900     KdSave(FALSE);
1901     KdEnteredDebugger = TRUE;
1902 
1903     /* Check freeze flag */
1904     if (KiFreezeFlag & 1)
1905     {
1906         /* Print out errror */
1907         KdpDprintf("FreezeLock was jammed!  Backup SpinLock was used!\n");
1908     }
1909 
1910     /* Check processor state */
1911     if (KiFreezeFlag & 2)
1912     {
1913         /* Print out errror */
1914         KdpDprintf("Some processors not frozen in debugger!\n");
1915     }
1916 
1917     /* Make sure we acquired the port */
1918     if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
1919 
1920     /* Return if interrupts needs to be re-enabled */
1921     return Enable;
1922 }
1923 
1924 VOID
1925 NTAPI
1926 KdExitDebugger(IN BOOLEAN Enable)
1927 {
1928     ULONG TimeSlip;
1929 
1930     /* Restore the state and unlock the port */
1931     KdRestore(FALSE);
1932     if (KdpPortLocked) KdpPortUnlock();
1933 
1934     /* Unfreeze the CPUs */
1935     KeThawExecution(Enable);
1936 
1937     /* Compare time with the one from KdEnterDebugger */
1938     if (!KdTimerStop.QuadPart)
1939     {
1940         /* We didn't get a trap frame earlier in so never got the time */
1941         KdTimerStart = KdTimerStop;
1942     }
1943     else
1944     {
1945         /* Query the timer */
1946         KdTimerStart = KeQueryPerformanceCounter(NULL);
1947     }
1948 
1949     /* Check if a Time Slip was on queue */
1950     TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1951     if (TimeSlip == 1)
1952     {
1953         /* Queue a DPC for the time slip */
1954         InterlockedIncrement(&KdpTimeSlipPending);
1955         KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches!
1956     }
1957 }
1958 
1959 NTSTATUS
1960 NTAPI
1961 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
1962 {
1963     KIRQL OldIrql;
1964 
1965 #if defined(__GNUC__)
1966     /* Make gcc happy */
1967     OldIrql = PASSIVE_LEVEL;
1968 #endif
1969 
1970     /* Check if enabling the debugger is blocked */
1971     if (KdBlockEnable)
1972     {
1973         /* It is, fail the enable */
1974         return STATUS_ACCESS_DENIED;
1975     }
1976 
1977     /* Check if we need to acquire the lock */
1978     if (NeedLock)
1979     {
1980         /* Lock the port */
1981         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1982         KdpPortLock();
1983     }
1984 
1985     /* Check if we're not disabled */
1986     if (!KdDisableCount)
1987     {
1988         /* Check if we had locked the port before */
1989         if (NeedLock)
1990         {
1991             /* Do the unlock */
1992             KeLowerIrql(OldIrql);
1993             KdpPortUnlock();
1994 
1995             /* Fail: We're already enabled */
1996             return STATUS_INVALID_PARAMETER;
1997         }
1998         else
1999         {
2000             /*
2001              * This can only happen if we are called from a bugcheck
2002              * and were never initialized, so initialize the debugger now.
2003              */
2004             KdInitSystem(0, NULL);
2005 
2006             /* Return success since we initialized */
2007             return STATUS_SUCCESS;
2008         }
2009     }
2010 
2011     /* Decrease the disable count */
2012     if (!(--KdDisableCount))
2013     {
2014         /* We're now enabled again! Were we enabled before, too? */
2015         if (KdPreviouslyEnabled)
2016         {
2017             /* Reinitialize the Debugger */
2018             KdInitSystem(0, NULL);
2019             KdpRestoreAllBreakpoints();
2020         }
2021     }
2022 
2023     /* Check if we had locked the port before */
2024     if (NeedLock)
2025     {
2026         /* Yes, now unlock it */
2027         KeLowerIrql(OldIrql);
2028         KdpPortUnlock();
2029     }
2030 
2031     /* We're done */
2032     return STATUS_SUCCESS;
2033 }
2034 
2035 NTSTATUS
2036 NTAPI
2037 KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
2038 {
2039     KIRQL OldIrql;
2040     NTSTATUS Status;
2041 
2042 #if defined(__GNUC__)
2043     /* Make gcc happy */
2044     OldIrql = PASSIVE_LEVEL;
2045 #endif
2046 
2047     /*
2048      * If enabling the debugger is blocked
2049      * then there is nothing to disable (duh)
2050      */
2051     if (KdBlockEnable)
2052     {
2053         /* Fail */
2054         return STATUS_ACCESS_DENIED;
2055     }
2056 
2057     /* Check if we need to acquire the lock */
2058     if (NeedLock)
2059     {
2060         /* Lock the port */
2061         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2062         KdpPortLock();
2063     }
2064 
2065     /* Check if we're not disabled */
2066     if (!KdDisableCount)
2067     {
2068         /* Check if the debugger was never actually initialized */
2069         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
2070         {
2071             /* It wasn't, so don't re-enable it later */
2072             KdPreviouslyEnabled = FALSE;
2073         }
2074         else
2075         {
2076             /* It was, so we will re-enable it later */
2077             KdPreviouslyEnabled = TRUE;
2078         }
2079 
2080         /* Check if we were called from the exported API and are enabled */
2081         if ((NeedLock) && (KdPreviouslyEnabled))
2082         {
2083             /* Check if it is safe to disable the debugger */
2084             Status = KdpAllowDisable();
2085             if (!NT_SUCCESS(Status))
2086             {
2087                 /* Release the lock and fail */
2088                 KeLowerIrql(OldIrql);
2089                 KdpPortUnlock();
2090                 return Status;
2091             }
2092         }
2093 
2094         /* Only disable the debugger if it is enabled */
2095         if (KdDebuggerEnabled)
2096         {
2097             /*
2098              * Disable the debugger; suspend breakpoints
2099              * and reset the debug stub
2100              */
2101             KdpSuspendAllBreakPoints();
2102             KiDebugRoutine = KdpStub;
2103 
2104             /* We are disabled now */
2105             KdDebuggerEnabled = FALSE;
2106             SharedUserData->KdDebuggerEnabled = FALSE;
2107         }
2108      }
2109 
2110     /* Increment the disable count */
2111     KdDisableCount++;
2112 
2113     /* Check if we had locked the port before */
2114     if (NeedLock)
2115     {
2116         /* Yes, now unlock it */
2117         KeLowerIrql(OldIrql);
2118         KdpPortUnlock();
2119     }
2120 
2121     /* We're done */
2122     return STATUS_SUCCESS;
2123 }
2124 
2125 #endif // _WINKD_
2126 
2127 /* PUBLIC FUNCTIONS **********************************************************/
2128 
2129 #ifdef _WINKD_
2130 
2131 /*
2132  * @implemented
2133  */
2134 NTSTATUS
2135 NTAPI
2136 KdEnableDebugger(VOID)
2137 {
2138     /* Use the internal routine */
2139     return KdEnableDebuggerWithLock(TRUE);
2140 }
2141 
2142 /*
2143  * @implemented
2144  */
2145 NTSTATUS
2146 NTAPI
2147 KdDisableDebugger(VOID)
2148 {
2149     /* Use the internal routine */
2150     return KdDisableDebuggerWithLock(TRUE);
2151 }
2152 
2153 /*
2154  * @unimplemented
2155  */
2156 NTSTATUS
2157 NTAPI
2158 KdSystemDebugControl(
2159     _In_ SYSDBG_COMMAND Command,
2160     _In_ PVOID InputBuffer,
2161     _In_ ULONG InputBufferLength,
2162     _Out_ PVOID OutputBuffer,
2163     _In_ ULONG OutputBufferLength,
2164     _Inout_ PULONG ReturnLength,
2165     _In_ KPROCESSOR_MODE PreviousMode)
2166 {
2167     /* Handle some internal commands */
2168     switch ((ULONG)Command)
2169     {
2170 #if DBG
2171         case ' soR': /* ROS-INTERNAL */
2172         {
2173             switch ((ULONG_PTR)InputBuffer)
2174             {
2175                 case 0x21: // DumpAllThreads:
2176                     PspDumpThreads(TRUE);
2177                     break;
2178 
2179                 case 0x22: // DumpUserThreads:
2180                     PspDumpThreads(FALSE);
2181                     break;
2182 
2183                 case 0x24: // KdSpare3:
2184                     MmDumpArmPfnDatabase(FALSE);
2185                     break;
2186 
2187                 default:
2188                     break;
2189             }
2190             return STATUS_SUCCESS;
2191         }
2192 
2193         /* Special case for stack frame dumps */
2194         case 'DsoR':
2195         {
2196             KeRosDumpStackFrames((PULONG_PTR)InputBuffer, InputBufferLength);
2197             break;
2198         }
2199 #endif
2200         default:
2201             break;
2202     }
2203 
2204     /* Local kernel debugging is not yet supported */
2205     DbgPrint("KdSystemDebugControl is unimplemented!\n");
2206     return STATUS_NOT_IMPLEMENTED;
2207 }
2208 
2209 /*
2210  * @implemented
2211  */
2212 NTSTATUS
2213 NTAPI
2214 KdChangeOption(IN KD_OPTION Option,
2215                IN ULONG InBufferBytes OPTIONAL,
2216                IN PVOID InBuffer,
2217                IN ULONG OutBufferBytes OPTIONAL,
2218                OUT PVOID OutBuffer,
2219                OUT PULONG OutBufferNeeded OPTIONAL)
2220 {
2221     /* Fail if there is no debugger */
2222     if (KdPitchDebugger)
2223     {
2224         /* No debugger, no options */
2225         return STATUS_DEBUGGER_INACTIVE;
2226     }
2227 
2228     /* Do we recognize this option? */
2229     if (Option != KD_OPTION_SET_BLOCK_ENABLE)
2230     {
2231         /* We don't, clear the output length and fail */
2232         if (OutBufferNeeded) *OutBufferNeeded = 0;
2233         return STATUS_INVALID_INFO_CLASS;
2234     }
2235 
2236     /* Verify parameters */
2237     if ((InBufferBytes != sizeof(BOOLEAN)) ||
2238         (OutBufferBytes != 0) ||
2239         (OutBuffer != NULL))
2240     {
2241         /* Invalid parameters for this option, fail */
2242         return STATUS_INVALID_PARAMETER;
2243     }
2244 
2245     /*
2246      * Check if the high bit is set, meaning we don't
2247      * allow the debugger to be enabled
2248      */
2249     if (KdBlockEnable & 0x80)
2250     {
2251         /* Fail regardless of what state the caller tried to set */
2252         return STATUS_ACCESS_VIOLATION;
2253     }
2254 
2255     /* Set the new block enable state */
2256     KdBlockEnable = *(PBOOLEAN)InBuffer;
2257 
2258     /* No output buffer required for this option */
2259     if (OutBufferNeeded) *OutBufferNeeded = 0;
2260 
2261     /* We are done */
2262     return STATUS_SUCCESS;
2263 }
2264 
2265 /*
2266  * @implemented
2267  */
2268 NTSTATUS
2269 NTAPI
2270 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
2271 {
2272     /* Check what power state this is */
2273     if (NewState == PowerDeviceD0)
2274     {
2275         /* Wake up the debug port */
2276         KdD0Transition();
2277         return STATUS_SUCCESS;
2278     }
2279     else if ((NewState == PowerDeviceD1) ||
2280              (NewState == PowerDeviceD2) ||
2281              (NewState == PowerDeviceD3))
2282     {
2283         /* Power down the debug port */
2284         KdD3Transition();
2285         return STATUS_SUCCESS;
2286     }
2287     else
2288     {
2289         /* Invalid state! */
2290         return STATUS_INVALID_PARAMETER_1;
2291     }
2292 }
2293 
2294 /*
2295  * @implemented
2296  */
2297 BOOLEAN
2298 NTAPI
2299 KdRefreshDebuggerNotPresent(VOID)
2300 {
2301     BOOLEAN Enable, DebuggerNotPresent;
2302 
2303     /* Check if the debugger is completely disabled */
2304     if (KdPitchDebugger)
2305     {
2306         /* Don't try to refresh then, fail early */
2307         return TRUE;
2308     }
2309 
2310     /* Enter the debugger */
2311     Enable = KdEnterDebugger(NULL, NULL);
2312 
2313     /*
2314      * Attempt to send a string to the debugger
2315      * to refresh the connection state.
2316      */
2317     KdpDprintf("KDTARGET: Refreshing KD connection\n");
2318 
2319     /* Save the state while we are holding the lock */
2320     DebuggerNotPresent = KdDebuggerNotPresent;
2321 
2322     /* Exit the debugger and return the state */
2323     KdExitDebugger(Enable);
2324     return DebuggerNotPresent;
2325 }
2326 
2327 #endif // _WINKD_
2328 
2329 /*
2330  * @implemented
2331  */
2332 NTSTATUS
2333 NTAPI
2334 NtQueryDebugFilterState(
2335     _In_ ULONG ComponentId,
2336     _In_ ULONG Level)
2337 {
2338     PULONG Mask;
2339 
2340     /* Check if the ID fits in the component table */
2341     if (ComponentId < KdComponentTableSize)
2342     {
2343         /* It does, so get the mask from there */
2344         Mask = KdComponentTable[ComponentId];
2345     }
2346     else if (ComponentId == MAXULONG)
2347     {
2348         /*
2349          * This is the internal ID used for DbgPrint messages without ID
2350          * and Level. Use the system-wide mask for those.
2351          */
2352         Mask = &Kd_WIN2000_Mask;
2353     }
2354     else
2355     {
2356 #if (NTDDI_VERSION >= NTDDI_VISTA)
2357         /* Use the default component ID */
2358         Mask = &Kd_DEFAULT_Mask;
2359         // Level = DPFLTR_INFO_LEVEL; // Override the Level.
2360 #else
2361         /* Invalid ID, fail */
2362         return STATUS_INVALID_PARAMETER_1;
2363 #endif
2364     }
2365 
2366     /* Convert Level to bit field if required */
2367     if (Level < 32) Level = 1 << Level;
2368     Level &= ~DPFLTR_MASK;
2369 
2370     /* Determine if this Level is filtered out */
2371     if ((Kd_WIN2000_Mask & Level) || (*Mask & Level))
2372     {
2373         /* This mask will get through to the debugger */
2374         return (NTSTATUS)TRUE;
2375     }
2376     else
2377     {
2378         /* This mask is filtered out */
2379         return (NTSTATUS)FALSE;
2380     }
2381 }
2382 
2383 /*
2384  * @implemented
2385  */
2386 NTSTATUS
2387 NTAPI
2388 NtSetDebugFilterState(
2389     _In_ ULONG ComponentId,
2390     _In_ ULONG Level,
2391     _In_ BOOLEAN State)
2392 {
2393     PULONG Mask;
2394 
2395     /* Modifying debug filters requires the debug privilege */
2396     if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
2397     {
2398         /* Fail */
2399         return STATUS_ACCESS_DENIED;
2400     }
2401 
2402     /* Check if the ID fits in the component table */
2403     if (ComponentId < KdComponentTableSize)
2404     {
2405         /* It does, so get the mask from there */
2406         Mask = KdComponentTable[ComponentId];
2407     }
2408     else if (ComponentId == MAXULONG)
2409     {
2410         /*
2411          * This is the internal ID used for DbgPrint messages without ID
2412          * and Level. Use the system-wide mask for those.
2413          */
2414         Mask = &Kd_WIN2000_Mask;
2415     }
2416     else
2417     {
2418 #if (NTDDI_VERSION >= NTDDI_VISTA)
2419         /* Use the default component ID */
2420         Mask = &Kd_DEFAULT_Mask;
2421 #else
2422         /* Invalid ID, fail */
2423         return STATUS_INVALID_PARAMETER_1;
2424 #endif
2425     }
2426 
2427     /* Convert Level to bit field if required */
2428     if (Level < 32) Level = 1 << Level;
2429     Level &= ~DPFLTR_MASK;
2430 
2431     /* Set or remove the Level */
2432     if (State)
2433         *Mask |= Level;
2434     else
2435         *Mask &= ~Level;
2436 
2437     return STATUS_SUCCESS;
2438 }
2439