xref: /reactos/ntoskrnl/kd64/kdapi.c (revision 2d4c0b87)
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                 /* This API, introduced in NT4, has been obsoleted in NT5. It is
1501                  * replaced by ExpDebuggerPageIn support in ExpDebuggerWorker(). */
1502                 KdpDprintf("DbgKdPageInApi is obsolete!\n");
1503                 KdpNotSupported(&ManipulateState);
1504                 break;
1505 
1506             case DbgKdReadMachineSpecificRegister:
1507 
1508                 /* Read from the specified MSR */
1509                 KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
1510                 break;
1511 
1512             case DbgKdWriteMachineSpecificRegister:
1513 
1514                 /* Write to the specified MSR */
1515                 KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
1516                 break;
1517 
1518             case DbgKdSearchMemoryApi:
1519 
1520                 /* Search memory */
1521                 KdpSearchMemory(&ManipulateState, &Data, Context);
1522                 break;
1523 
1524             case DbgKdGetBusDataApi:
1525 
1526                 /* Read from the bus */
1527                 KdpGetBusData(&ManipulateState, &Data, Context);
1528                 break;
1529 
1530             case DbgKdSetBusDataApi:
1531 
1532                 /* Write to the bus */
1533                 KdpSetBusData(&ManipulateState, &Data, Context);
1534                 break;
1535 
1536             case DbgKdCheckLowMemoryApi:
1537 
1538                 /* Check for memory corruption in the lower 4 GB */
1539                 KdpCheckLowMemory(&ManipulateState);
1540                 break;
1541 
1542             case DbgKdClearAllInternalBreakpointsApi:
1543 
1544                 /* Just clear the counter */
1545                 KdpNumInternalBreakpoints = 0;
1546                 break;
1547 
1548             case DbgKdFillMemoryApi:
1549 
1550                 /* Fill memory */
1551                 KdpFillMemory(&ManipulateState, &Data, Context);
1552                 break;
1553 
1554             case DbgKdQueryMemoryApi:
1555 
1556                 /* Query memory */
1557                 KdpQueryMemory(&ManipulateState, Context);
1558                 break;
1559 
1560             case DbgKdSwitchPartition:
1561 
1562                 /* TODO */
1563                 KdpDprintf("Partition Switch support is unimplemented!\n");
1564                 KdpNotSupported(&ManipulateState);
1565                 break;
1566 
1567             case DbgKdWriteCustomBreakpointApi:
1568 
1569                 /* Write the customized breakpoint */
1570                 KdpWriteCustomBreakpoint(&ManipulateState, &Data, Context);
1571                 break;
1572 
1573             case DbgKdGetContextExApi:
1574 
1575                 /* Extended Context Get */
1576                 KdpGetContextEx(&ManipulateState, &Data, Context);
1577                 break;
1578 
1579             case DbgKdSetContextExApi:
1580 
1581                 /* Extended Context Set */
1582                 KdpSetContextEx(&ManipulateState, &Data, Context);
1583                 break;
1584 
1585             /* Unsupported Messages */
1586             default:
1587 
1588                 /* Send warning */
1589                 KdpDprintf("Received Unrecognized API 0x%lx\n", ManipulateState.ApiNumber);
1590 
1591                 /* Setup an empty message, with failure */
1592                 Data.Length = 0;
1593                 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1594 
1595                 /* Send it */
1596                 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1597                              &Header,
1598                              &Data,
1599                              &KdpContext);
1600                 break;
1601         }
1602     }
1603 }
1604 
1605 VOID
1606 NTAPI
1607 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
1608                                 IN PKD_SYMBOLS_INFO SymbolInfo,
1609                                 IN BOOLEAN Unload,
1610                                 IN OUT PCONTEXT Context)
1611 {
1612     PSTRING ExtraData;
1613     STRING Data, Header;
1614     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1615     ULONG PathNameLength;
1616     KCONTINUE_STATUS Status;
1617 
1618     /* Start wait loop */
1619     do
1620     {
1621         /* Build the architecture common parts of the message */
1622         KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1623                           Context,
1624                           &WaitStateChange);
1625 
1626         /* Now finish creating the structure */
1627         KdpSetContextState(&WaitStateChange, Context);
1628 
1629         /* Fill out load data */
1630         WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1631         WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
1632         WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1633         WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1634         WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1635 
1636         /* Check if we have a path name */
1637         if (PathName)
1638         {
1639             /* Copy it to the path buffer */
1640             KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
1641                                 KdpPathBuffer,
1642                                 PathName->Length,
1643                                 0,
1644                                 MMDBG_COPY_UNSAFE,
1645                                 &PathNameLength);
1646 
1647             /* Null terminate */
1648             KdpPathBuffer[PathNameLength++] = ANSI_NULL;
1649 
1650             /* Set the path length */
1651             WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
1652 
1653             /* Set up the data */
1654             Data.Buffer = KdpPathBuffer;
1655             Data.Length = (USHORT)PathNameLength;
1656             ExtraData = &Data;
1657         }
1658         else
1659         {
1660             /* No name */
1661             WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1662             ExtraData = NULL;
1663         }
1664 
1665         /* Setup the header */
1666         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1667         Header.Buffer = (PCHAR)&WaitStateChange;
1668 
1669         /* Send the packet */
1670         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1671                                      &Header,
1672                                      ExtraData,
1673                                      Context);
1674     } while (Status == ContinueProcessorReselected);
1675 }
1676 
1677 VOID
1678 NTAPI
1679 KdpReportCommandStringStateChange(IN PSTRING NameString,
1680                                   IN PSTRING CommandString,
1681                                   IN OUT PCONTEXT Context)
1682 {
1683     STRING Header, Data;
1684     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1685     ULONG Length, ActualLength, TotalLength;
1686     KCONTINUE_STATUS Status;
1687 
1688     /* Start wait loop */
1689     do
1690     {
1691         /* Build the architecture common parts of the message */
1692         KdpSetCommonState(DbgKdCommandStringStateChange,
1693                           Context,
1694                           &WaitStateChange);
1695 
1696         /* Set the context */
1697         KdpSetContextState(&WaitStateChange, Context);
1698 
1699         /* Clear the command string structure */
1700         KdpZeroMemory(&WaitStateChange.u.CommandString,
1701                       sizeof(DBGKD_COMMAND_STRING));
1702 
1703         /* Normalize name string to max */
1704         Length = min(128 - 1, NameString->Length);
1705 
1706         /* Copy it to the message buffer */
1707         KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
1708                             KdpMessageBuffer,
1709                             Length,
1710                             0,
1711                             MMDBG_COPY_UNSAFE,
1712                             &ActualLength);
1713 
1714         /* Null terminate and calculate the total length */
1715         TotalLength = ActualLength;
1716         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1717 
1718         /* Check if the command string is too long */
1719         Length = CommandString->Length;
1720         if (Length > (PACKET_MAX_SIZE -
1721                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
1722         {
1723             /* Use maximum possible size */
1724             Length = (PACKET_MAX_SIZE -
1725                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
1726         }
1727 
1728         /* Copy it to the message buffer */
1729         KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
1730                             KdpMessageBuffer + TotalLength,
1731                             Length,
1732                             0,
1733                             MMDBG_COPY_UNSAFE,
1734                             &ActualLength);
1735 
1736         /* Null terminate and calculate the total length */
1737         TotalLength += ActualLength;
1738         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1739 
1740         /* Now set up the header and the data */
1741         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1742         Header.Buffer = (PCHAR)&WaitStateChange;
1743         Data.Length = (USHORT)TotalLength;
1744         Data.Buffer = KdpMessageBuffer;
1745 
1746         /* Send State Change packet and wait for a reply */
1747         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1748                                      &Header,
1749                                      &Data,
1750                                      Context);
1751     } while (Status == ContinueProcessorReselected);
1752 }
1753 
1754 BOOLEAN
1755 NTAPI
1756 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1757                               IN OUT PCONTEXT Context,
1758                               IN BOOLEAN SecondChanceException)
1759 {
1760     STRING Header, Data;
1761     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1762     KCONTINUE_STATUS Status;
1763 
1764     /* Start report loop */
1765     do
1766     {
1767         /* Build the architecture common parts of the message */
1768         KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1769 
1770 #if !defined(_WIN64)
1771 
1772         /* Convert it and copy it over */
1773         ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
1774                               &WaitStateChange.u.Exception.ExceptionRecord);
1775 
1776 #else
1777 
1778         /* Just copy it directly, no need to convert */
1779         KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord,
1780                       ExceptionRecord,
1781                       sizeof(EXCEPTION_RECORD));
1782 
1783 #endif
1784 
1785         /* Set the First Chance flag */
1786         WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1787 
1788         /* Now finish creating the structure */
1789         KdpSetContextState(&WaitStateChange, Context);
1790 
1791         /* Setup the actual header to send to KD */
1792         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1793         Header.Buffer = (PCHAR)&WaitStateChange;
1794 
1795         /* Setup the trace data */
1796         DumpTraceData(&Data);
1797 
1798         /* Send State Change packet and wait for a reply */
1799         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1800                                      &Header,
1801                                      &Data,
1802                                      Context);
1803     } while (Status == ContinueProcessorReselected);
1804 
1805     /* Return */
1806     return Status;
1807 }
1808 
1809 KCONTINUE_STATUS
1810 NTAPI
1811 KdReportProcessorChange(
1812     VOID)
1813 {
1814     PKPRCB CurrentPrcb = KeGetCurrentPrcb();
1815     PCONTEXT ContextRecord = &CurrentPrcb->ProcessorState.ContextFrame;
1816     EXCEPTION_RECORD ExceptionRecord = {0};
1817     KCONTINUE_STATUS Status;
1818 
1819     /* Save the port data */
1820     KdSave(FALSE);
1821 
1822     ExceptionRecord.ExceptionAddress = (PVOID)KeGetContextPc(ContextRecord);
1823     ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
1824 
1825     /* Report the new state */
1826     Status = KdpReportExceptionStateChange(&ExceptionRecord,
1827                                            ContextRecord,
1828                                            FALSE);
1829 
1830     /* Restore the port data */
1831     KdRestore(FALSE);
1832 
1833     return Status;
1834 }
1835 
1836 VOID
1837 NTAPI
1838 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1839                       IN PVOID DeferredContext,
1840                       IN PVOID SystemArgument1,
1841                       IN PVOID SystemArgument2)
1842 {
1843     LONG OldSlip, NewSlip, PendingSlip;
1844 
1845     /* Get the current pending slip */
1846     PendingSlip = KdpTimeSlipPending;
1847     do
1848     {
1849         /* Save the old value and either disable or enable it now. */
1850         OldSlip = PendingSlip;
1851         NewSlip = OldSlip > 1 ? 1 : 0;
1852 
1853         /* Try to change the value */
1854     } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1855                                         NewSlip,
1856                                         OldSlip) != OldSlip);
1857 
1858     /* If the New Slip value is 1, then do the Time Slipping */
1859     if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1860 }
1861 
1862 VOID
1863 NTAPI
1864 KdpTimeSlipWork(IN PVOID Context)
1865 {
1866     KIRQL OldIrql;
1867     LARGE_INTEGER DueTime;
1868 
1869     /* Update the System time from the CMOS */
1870     ExAcquireTimeRefreshLock(FALSE);
1871     ExUpdateSystemTimeFromCmos(FALSE, 0);
1872     ExReleaseTimeRefreshLock();
1873 
1874     /* Check if we have a registered Time Slip Event and signal it */
1875     KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1876     if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1877     KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1878 
1879     /* Delay the DPC until it runs next time */
1880     DueTime.QuadPart = -1800000000;
1881     KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1882 }
1883 
1884 LARGE_INTEGER
1885 NTAPI
1886 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1887 {
1888     LARGE_INTEGER Null = {{0}};
1889 
1890     /* Check if interrupts were disabled */
1891     if (!KeGetTrapFrameInterruptState(TrapFrame))
1892     {
1893         /* Nothing to return */
1894         return Null;
1895     }
1896 
1897     /* Otherwise, do the call */
1898     return KeQueryPerformanceCounter(NULL);
1899 }
1900 
1901 BOOLEAN
1902 NTAPI
1903 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1904                 IN PKEXCEPTION_FRAME ExceptionFrame)
1905 {
1906     BOOLEAN Enable;
1907 
1908     /* Check if we have a trap frame */
1909     if (TrapFrame)
1910     {
1911         /* Calculate the time difference for the enter */
1912         KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1913         KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1914                                      KdTimerStart.QuadPart;
1915     }
1916     else
1917     {
1918         /* No trap frame, so can't calculate */
1919         KdTimerStop.QuadPart = 0;
1920     }
1921 
1922     /* Save the current IRQL */
1923     KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1924 
1925     /* Freeze all CPUs, raising also the IRQL to HIGH_LEVEL */
1926     Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
1927 
1928     /* Lock the port, save the state and set debugger entered */
1929     KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1930     KdSave(FALSE);
1931     KdEnteredDebugger = TRUE;
1932 
1933     /* Check freeze flag */
1934     if (KiFreezeFlag & 1)
1935     {
1936         /* Print out errror */
1937         KdpDprintf("FreezeLock was jammed!  Backup SpinLock was used!\n");
1938     }
1939 
1940     /* Check processor state */
1941     if (KiFreezeFlag & 2)
1942     {
1943         /* Print out errror */
1944         KdpDprintf("Some processors not frozen in debugger!\n");
1945     }
1946 
1947     /* Make sure we acquired the port */
1948     if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
1949 
1950     /* Return if interrupts needs to be re-enabled */
1951     return Enable;
1952 }
1953 
1954 VOID
1955 NTAPI
1956 KdExitDebugger(IN BOOLEAN Enable)
1957 {
1958     ULONG TimeSlip;
1959 
1960     /* Restore the state and unlock the port */
1961     KdRestore(FALSE);
1962     if (KdpPortLocked) KdpPortUnlock();
1963 
1964     /* Unfreeze the CPUs, restoring also the IRQL */
1965     KeThawExecution(Enable);
1966 
1967     /* Compare time with the one from KdEnterDebugger */
1968     if (!KdTimerStop.QuadPart)
1969     {
1970         /* We didn't get a trap frame earlier in so never got the time */
1971         KdTimerStart = KdTimerStop;
1972     }
1973     else
1974     {
1975         /* Query the timer */
1976         KdTimerStart = KeQueryPerformanceCounter(NULL);
1977     }
1978 
1979     /* Check if a Time Slip was on queue */
1980     TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1981     if (TimeSlip == 1)
1982     {
1983         /* Queue a DPC for the time slip */
1984         InterlockedIncrement(&KdpTimeSlipPending);
1985         KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches!
1986     }
1987 }
1988 
1989 NTSTATUS
1990 NTAPI
1991 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
1992 {
1993     KIRQL OldIrql;
1994 
1995 #if defined(__GNUC__)
1996     /* Make gcc happy */
1997     OldIrql = PASSIVE_LEVEL;
1998 #endif
1999 
2000     /* Check if enabling the debugger is blocked */
2001     if (KdBlockEnable)
2002     {
2003         /* It is, fail the enable */
2004         return STATUS_ACCESS_DENIED;
2005     }
2006 
2007     /* Check if we need to acquire the lock */
2008     if (NeedLock)
2009     {
2010         /* Lock the port */
2011         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2012         KdpPortLock();
2013     }
2014 
2015     /* Check if we're not disabled */
2016     if (!KdDisableCount)
2017     {
2018         /* Check if we had locked the port before */
2019         if (NeedLock)
2020         {
2021             /* Do the unlock */
2022             KdpPortUnlock();
2023             KeLowerIrql(OldIrql);
2024 
2025             /* Fail: We're already enabled */
2026             return STATUS_INVALID_PARAMETER;
2027         }
2028         else
2029         {
2030             /*
2031              * This can only happen if we are called from a bugcheck
2032              * and were never initialized, so initialize the debugger now.
2033              */
2034             KdInitSystem(0, NULL);
2035 
2036             /* Return success since we initialized */
2037             return STATUS_SUCCESS;
2038         }
2039     }
2040 
2041     /* Decrease the disable count */
2042     if (!(--KdDisableCount))
2043     {
2044         /* We're now enabled again! Were we enabled before, too? */
2045         if (KdPreviouslyEnabled)
2046         {
2047             /* Reinitialize the Debugger */
2048             KdInitSystem(0, NULL);
2049             KdpRestoreAllBreakpoints();
2050         }
2051     }
2052 
2053     /* Check if we had locked the port before */
2054     if (NeedLock)
2055     {
2056         /* Yes, now unlock it */
2057         KdpPortUnlock();
2058         KeLowerIrql(OldIrql);
2059     }
2060 
2061     /* We're done */
2062     return STATUS_SUCCESS;
2063 }
2064 
2065 NTSTATUS
2066 NTAPI
2067 KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
2068 {
2069     KIRQL OldIrql;
2070     NTSTATUS Status;
2071 
2072 #if defined(__GNUC__)
2073     /* Make gcc happy */
2074     OldIrql = PASSIVE_LEVEL;
2075 #endif
2076 
2077     /*
2078      * If enabling the debugger is blocked
2079      * then there is nothing to disable (duh)
2080      */
2081     if (KdBlockEnable)
2082     {
2083         /* Fail */
2084         return STATUS_ACCESS_DENIED;
2085     }
2086 
2087     /* Check if we need to acquire the lock */
2088     if (NeedLock)
2089     {
2090         /* Lock the port */
2091         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2092         KdpPortLock();
2093     }
2094 
2095     /* Check if we're not disabled */
2096     if (!KdDisableCount)
2097     {
2098         /* Check if the debugger was never actually initialized */
2099         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
2100         {
2101             /* It wasn't, so don't re-enable it later */
2102             KdPreviouslyEnabled = FALSE;
2103         }
2104         else
2105         {
2106             /* It was, so we will re-enable it later */
2107             KdPreviouslyEnabled = TRUE;
2108         }
2109 
2110         /* Check if we were called from the exported API and are enabled */
2111         if ((NeedLock) && (KdPreviouslyEnabled))
2112         {
2113             /* Check if it is safe to disable the debugger */
2114             Status = KdpAllowDisable();
2115             if (!NT_SUCCESS(Status))
2116             {
2117                 /* Release the lock and fail */
2118                 KdpPortUnlock();
2119                 KeLowerIrql(OldIrql);
2120                 return Status;
2121             }
2122         }
2123 
2124         /* Only disable the debugger if it is enabled */
2125         if (KdDebuggerEnabled)
2126         {
2127             /*
2128              * Disable the debugger; suspend breakpoints
2129              * and reset the debug stub
2130              */
2131             KdpSuspendAllBreakPoints();
2132             KiDebugRoutine = KdpStub;
2133 
2134             /* We are disabled now */
2135             KdDebuggerEnabled = FALSE;
2136             SharedUserData->KdDebuggerEnabled = FALSE;
2137         }
2138      }
2139 
2140     /* Increment the disable count */
2141     KdDisableCount++;
2142 
2143     /* Check if we had locked the port before */
2144     if (NeedLock)
2145     {
2146         /* Yes, now unlock it */
2147         KdpPortUnlock();
2148         KeLowerIrql(OldIrql);
2149     }
2150 
2151     /* We're done */
2152     return STATUS_SUCCESS;
2153 }
2154 
2155 /* PUBLIC FUNCTIONS **********************************************************/
2156 
2157 /*
2158  * @implemented
2159  */
2160 NTSTATUS
2161 NTAPI
2162 KdEnableDebugger(VOID)
2163 {
2164     /* Use the internal routine */
2165     return KdEnableDebuggerWithLock(TRUE);
2166 }
2167 
2168 /*
2169  * @implemented
2170  */
2171 NTSTATUS
2172 NTAPI
2173 KdDisableDebugger(VOID)
2174 {
2175     /* Use the internal routine */
2176     return KdDisableDebuggerWithLock(TRUE);
2177 }
2178 
2179 /*
2180  * @unimplemented
2181  */
2182 NTSTATUS
2183 NTAPI
2184 KdSystemDebugControl(
2185     _In_ SYSDBG_COMMAND Command,
2186     _In_ PVOID InputBuffer,
2187     _In_ ULONG InputBufferLength,
2188     _Out_ PVOID OutputBuffer,
2189     _In_ ULONG OutputBufferLength,
2190     _Inout_ PULONG ReturnLength,
2191     _In_ KPROCESSOR_MODE PreviousMode)
2192 {
2193     /* Handle some internal commands */
2194     switch ((ULONG)Command)
2195     {
2196 #if DBG
2197         case ' soR': /* ROS-INTERNAL */
2198         {
2199             switch ((ULONG_PTR)InputBuffer)
2200             {
2201                 case 0x21: // DumpAllThreads:
2202                     PspDumpThreads(TRUE);
2203                     break;
2204 
2205                 case 0x22: // DumpUserThreads:
2206                     PspDumpThreads(FALSE);
2207                     break;
2208 
2209                 case 0x24: // KdSpare3:
2210                     MmDumpArmPfnDatabase(FALSE);
2211                     break;
2212 
2213                 default:
2214                     break;
2215             }
2216             return STATUS_SUCCESS;
2217         }
2218 
2219 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
2220         /* Register a debug callback */
2221         case 'CsoR':
2222         {
2223             switch (InputBufferLength)
2224             {
2225                 case ID_Win32PreServiceHook:
2226                     KeWin32PreServiceHook = InputBuffer;
2227                     break;
2228 
2229                 case ID_Win32PostServiceHook:
2230                     KeWin32PostServiceHook = InputBuffer;
2231                     break;
2232 
2233             }
2234             break;
2235         }
2236 #endif
2237 
2238         /* Special case for stack frame dumps */
2239         case 'DsoR':
2240         {
2241             KeRosDumpStackFrames((PULONG_PTR)InputBuffer, InputBufferLength);
2242             break;
2243         }
2244 #ifdef KDBG
2245         /* Register KDBG CLI callback */
2246         case 'RbdK':
2247         {
2248             return KdbRegisterCliCallback(InputBuffer, InputBufferLength);
2249         }
2250 #endif // KDBG
2251 #endif
2252         default:
2253             break;
2254     }
2255 
2256     /* Local kernel debugging is not yet supported */
2257     DbgPrint("KdSystemDebugControl is unimplemented!\n");
2258     return STATUS_NOT_IMPLEMENTED;
2259 }
2260 
2261 /*
2262  * @implemented
2263  */
2264 NTSTATUS
2265 NTAPI
2266 KdChangeOption(IN KD_OPTION Option,
2267                IN ULONG InBufferBytes OPTIONAL,
2268                IN PVOID InBuffer,
2269                IN ULONG OutBufferBytes OPTIONAL,
2270                OUT PVOID OutBuffer,
2271                OUT PULONG OutBufferNeeded OPTIONAL)
2272 {
2273     /* Fail if there is no debugger */
2274     if (KdPitchDebugger)
2275     {
2276         /* No debugger, no options */
2277         return STATUS_DEBUGGER_INACTIVE;
2278     }
2279 
2280     /* Do we recognize this option? */
2281     if (Option != KD_OPTION_SET_BLOCK_ENABLE)
2282     {
2283         /* We don't, clear the output length and fail */
2284         if (OutBufferNeeded) *OutBufferNeeded = 0;
2285         return STATUS_INVALID_INFO_CLASS;
2286     }
2287 
2288     /* Verify parameters */
2289     if ((InBufferBytes != sizeof(BOOLEAN)) ||
2290         (OutBufferBytes != 0) ||
2291         (OutBuffer != NULL))
2292     {
2293         /* Invalid parameters for this option, fail */
2294         return STATUS_INVALID_PARAMETER;
2295     }
2296 
2297     /*
2298      * Check if the high bit is set, meaning we don't
2299      * allow the debugger to be enabled
2300      */
2301     if (KdBlockEnable & 0x80)
2302     {
2303         /* Fail regardless of what state the caller tried to set */
2304         return STATUS_ACCESS_VIOLATION;
2305     }
2306 
2307     /* Set the new block enable state */
2308     KdBlockEnable = *(PBOOLEAN)InBuffer;
2309 
2310     /* No output buffer required for this option */
2311     if (OutBufferNeeded) *OutBufferNeeded = 0;
2312 
2313     /* We are done */
2314     return STATUS_SUCCESS;
2315 }
2316 
2317 /*
2318  * @implemented
2319  */
2320 NTSTATUS
2321 NTAPI
2322 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
2323 {
2324     /* Check what power state this is */
2325     if (NewState == PowerDeviceD0)
2326     {
2327         /* Wake up the debug port */
2328         KdD0Transition();
2329         return STATUS_SUCCESS;
2330     }
2331     else if ((NewState == PowerDeviceD1) ||
2332              (NewState == PowerDeviceD2) ||
2333              (NewState == PowerDeviceD3))
2334     {
2335         /* Power down the debug port */
2336         KdD3Transition();
2337         return STATUS_SUCCESS;
2338     }
2339     else
2340     {
2341         /* Invalid state! */
2342         return STATUS_INVALID_PARAMETER_1;
2343     }
2344 }
2345 
2346 /*
2347  * @implemented
2348  */
2349 BOOLEAN
2350 NTAPI
2351 KdRefreshDebuggerNotPresent(VOID)
2352 {
2353     BOOLEAN Enable, DebuggerNotPresent;
2354 
2355     /* Check if the debugger is completely disabled */
2356     if (KdPitchDebugger)
2357     {
2358         /* Don't try to refresh then, fail early */
2359         return TRUE;
2360     }
2361 
2362     /* Enter the debugger */
2363     Enable = KdEnterDebugger(NULL, NULL);
2364 
2365     /*
2366      * Attempt to send a string to the debugger
2367      * to refresh the connection state.
2368      */
2369     KdpDprintf("KDTARGET: Refreshing KD connection\n");
2370 
2371     /* Save the state while we are holding the lock */
2372     DebuggerNotPresent = KdDebuggerNotPresent;
2373 
2374     /* Exit the debugger and return the state */
2375     KdExitDebugger(Enable);
2376     return DebuggerNotPresent;
2377 }
2378 
2379 /*
2380  * @implemented
2381  */
2382 NTSTATUS
2383 NTAPI
2384 NtQueryDebugFilterState(
2385     _In_ ULONG ComponentId,
2386     _In_ ULONG Level)
2387 {
2388     PULONG Mask;
2389 
2390     /* Check if the ID fits in the component table */
2391     if (ComponentId < KdComponentTableSize)
2392     {
2393         /* It does, so get the mask from there */
2394         Mask = KdComponentTable[ComponentId];
2395     }
2396     else if (ComponentId == MAXULONG)
2397     {
2398         /*
2399          * This is the internal ID used for DbgPrint messages without ID
2400          * and Level. Use the system-wide mask for those.
2401          */
2402         Mask = &Kd_WIN2000_Mask;
2403     }
2404     else
2405     {
2406 #if (NTDDI_VERSION >= NTDDI_VISTA)
2407         /* Use the default component ID */
2408         Mask = &Kd_DEFAULT_Mask;
2409         // Level = DPFLTR_INFO_LEVEL; // Override the Level.
2410 #else
2411         /* Invalid ID, fail */
2412         return STATUS_INVALID_PARAMETER_1;
2413 #endif
2414     }
2415 
2416     /* Convert Level to bit field if required */
2417     if (Level < 32) Level = 1 << Level;
2418     Level &= ~DPFLTR_MASK;
2419 
2420     /* Determine if this Level is filtered out */
2421     if ((Kd_WIN2000_Mask & Level) || (*Mask & Level))
2422     {
2423         /* This mask will get through to the debugger */
2424         return (NTSTATUS)TRUE;
2425     }
2426     else
2427     {
2428         /* This mask is filtered out */
2429         return (NTSTATUS)FALSE;
2430     }
2431 }
2432 
2433 /*
2434  * @implemented
2435  */
2436 NTSTATUS
2437 NTAPI
2438 NtSetDebugFilterState(
2439     _In_ ULONG ComponentId,
2440     _In_ ULONG Level,
2441     _In_ BOOLEAN State)
2442 {
2443     PULONG Mask;
2444 
2445     /* Modifying debug filters requires the debug privilege */
2446     if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
2447     {
2448         /* Fail */
2449         return STATUS_ACCESS_DENIED;
2450     }
2451 
2452     /* Check if the ID fits in the component table */
2453     if (ComponentId < KdComponentTableSize)
2454     {
2455         /* It does, so get the mask from there */
2456         Mask = KdComponentTable[ComponentId];
2457     }
2458     else if (ComponentId == MAXULONG)
2459     {
2460         /*
2461          * This is the internal ID used for DbgPrint messages without ID
2462          * and Level. Use the system-wide mask for those.
2463          */
2464         Mask = &Kd_WIN2000_Mask;
2465     }
2466     else
2467     {
2468 #if (NTDDI_VERSION >= NTDDI_VISTA)
2469         /* Use the default component ID */
2470         Mask = &Kd_DEFAULT_Mask;
2471 #else
2472         /* Invalid ID, fail */
2473         return STATUS_INVALID_PARAMETER_1;
2474 #endif
2475     }
2476 
2477     /* Convert Level to bit field if required */
2478     if (Level < 32) Level = 1 << Level;
2479     Level &= ~DPFLTR_MASK;
2480 
2481     /* Set or remove the Level */
2482     if (State)
2483         *Mask |= Level;
2484     else
2485         *Mask &= ~Level;
2486 
2487     return STATUS_SUCCESS;
2488 }
2489