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