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