xref: /reactos/ntoskrnl/kd64/kdapi.c (revision 72fd54a7)
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
KdpMoveMemory(_In_ PVOID Destination,_In_ PVOID Source,_In_ SIZE_T Length)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
KdpZeroMemory(_In_ PVOID Destination,_In_ SIZE_T Length)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
KdpCopyMemoryChunks(_In_ ULONG64 Address,_In_ PVOID Buffer,_In_ ULONG TotalSize,_In_ ULONG ChunkSize,_In_ ULONG Flags,_Out_opt_ PULONG ActualSize)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
KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PCONTEXT Context)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
KdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteCustomBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
DumpTraceData(IN PSTRING TraceData)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
KdpSetCommonState(IN ULONG NewState,IN PCONTEXT Context,IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)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
KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)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
KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)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
KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)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
KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)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
KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)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
KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)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
KdpSwitchProcessor(_In_ USHORT ProcessorIndex)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
KdpSendWaitContinue(IN ULONG PacketType,IN PSTRING SendHeader,IN PSTRING SendData OPTIONAL,IN OUT PCONTEXT Context)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
KdpReportLoadSymbolsStateChange(IN PSTRING PathName,IN PKD_SYMBOLS_INFO SymbolInfo,IN BOOLEAN Unload,IN OUT PCONTEXT Context)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
KdpReportCommandStringStateChange(IN PSTRING NameString,IN PSTRING CommandString,IN OUT PCONTEXT Context)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
KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,IN OUT PCONTEXT Context,IN BOOLEAN SecondChanceException)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
KdReportProcessorChange(VOID)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
KdpTimeSlipDpcRoutine(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)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
KdpTimeSlipWork(IN PVOID Context)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
KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)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
KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame)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
KdExitDebugger(IN BOOLEAN Enable)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
KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)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
KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)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
KdEnableDebugger(VOID)2161 KdEnableDebugger(VOID)
2162 {
2163     /* Use the internal routine */
2164     return KdEnableDebuggerWithLock(TRUE);
2165 }
2166 
2167 /*
2168  * @implemented
2169  */
2170 NTSTATUS
2171 NTAPI
KdDisableDebugger(VOID)2172 KdDisableDebugger(VOID)
2173 {
2174     /* Use the internal routine */
2175     return KdDisableDebuggerWithLock(TRUE);
2176 }
2177 
2178 /*
2179  * @unimplemented
2180  */
2181 NTSTATUS
2182 NTAPI
KdSystemDebugControl(_In_ SYSDBG_COMMAND Command,_In_ PVOID InputBuffer,_In_ ULONG InputBufferLength,_Out_ PVOID OutputBuffer,_In_ ULONG OutputBufferLength,_Inout_ PULONG ReturnLength,_In_ KPROCESSOR_MODE PreviousMode)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
KdChangeOption(IN KD_OPTION Option,IN ULONG InBufferBytes OPTIONAL,IN PVOID InBuffer,IN ULONG OutBufferBytes OPTIONAL,OUT PVOID OutBuffer,OUT PULONG OutBufferNeeded OPTIONAL)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
KdPowerTransition(IN DEVICE_POWER_STATE NewState)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
KdRefreshDebuggerNotPresent(VOID)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
NtQueryDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level)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
NtSetDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level,_In_ BOOLEAN State)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