xref: /reactos/ntoskrnl/kd64/kdapi.c (revision b15dcb5c)
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                 /* 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
KdpReportLoadSymbolsStateChange(IN PSTRING PathName,IN PKD_SYMBOLS_INFO SymbolInfo,IN BOOLEAN Unload,IN OUT PCONTEXT Context)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
KdpReportCommandStringStateChange(IN PSTRING NameString,IN PSTRING CommandString,IN OUT PCONTEXT Context)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
KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,IN OUT PCONTEXT Context,IN BOOLEAN SecondChanceException)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
KdReportProcessorChange(VOID)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
KdpTimeSlipDpcRoutine(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)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
KdpTimeSlipWork(IN PVOID Context)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
KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)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
KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame)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
KdExitDebugger(IN BOOLEAN Enable)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
KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)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
KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)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
KdEnableDebugger(VOID)2162 KdEnableDebugger(VOID)
2163 {
2164     /* Use the internal routine */
2165     return KdEnableDebuggerWithLock(TRUE);
2166 }
2167 
2168 /*
2169  * @implemented
2170  */
2171 NTSTATUS
2172 NTAPI
KdDisableDebugger(VOID)2173 KdDisableDebugger(VOID)
2174 {
2175     /* Use the internal routine */
2176     return KdDisableDebuggerWithLock(TRUE);
2177 }
2178 
2179 /*
2180  * @unimplemented
2181  */
2182 NTSTATUS
2183 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)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
KdChangeOption(IN KD_OPTION Option,IN ULONG InBufferBytes OPTIONAL,IN PVOID InBuffer,IN ULONG OutBufferBytes OPTIONAL,OUT PVOID OutBuffer,OUT PULONG OutBufferNeeded OPTIONAL)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
KdPowerTransition(IN DEVICE_POWER_STATE NewState)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
KdRefreshDebuggerNotPresent(VOID)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
NtQueryDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level)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
NtSetDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level,_In_ BOOLEAN State)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