xref: /reactos/ntoskrnl/kd64/kdapi.c (revision 7068a790)
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(_Out_ PDBGKD_GET_VERSION64 Version)433 KdpSysGetVersion(
434     _Out_ PDBGKD_GET_VERSION64 Version)
435 {
436     /* Copy the version block */
437     KdpMoveMemory(Version,
438                   &KdVersionBlock,
439                   sizeof(DBGKD_GET_VERSION64));
440 }
441 
442 VOID
443 NTAPI
KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)444 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
445 {
446     STRING Header;
447 
448     /* Fill out the header */
449     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
450     Header.Buffer = (PCHAR)State;
451 
452     /* Get the version block */
453     KdpSysGetVersion(&State->u.GetVersion64);
454 
455     /* Fill out the state */
456     State->ApiNumber = DbgKdGetVersionApi;
457     State->ReturnStatus = STATUS_SUCCESS;
458 
459     /* Send the packet */
460     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
461                  &Header,
462                  NULL,
463                  &KdpContext);
464 }
465 
466 VOID
467 NTAPI
KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)468 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
469                      IN PSTRING Data,
470                      IN PCONTEXT Context)
471 {
472     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
473     STRING Header;
474     ULONG Length = ReadMemory->TransferCount;
475 
476     /* Setup the header */
477     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
478     Header.Buffer = (PCHAR)State;
479     ASSERT(Data->Length == 0);
480 
481     /* Validate length */
482     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
483     {
484         /* Overflow, set it to maximum possible */
485         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
486     }
487 
488     /* Do the read */
489     State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
490                                               Data->Buffer,
491                                               Length,
492                                               0,
493                                               MMDBG_COPY_UNSAFE,
494                                               &Length);
495 
496     /* Return the actual length read */
497     ReadMemory->ActualBytesRead = Length;
498     Data->Length = (USHORT)Length;
499 
500     /* Send the packet */
501     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
502                  &Header,
503                  Data,
504                  &KdpContext);
505 }
506 
507 VOID
508 NTAPI
KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)509 KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
510                       IN PSTRING Data,
511                       IN PCONTEXT Context)
512 {
513     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
514     STRING Header;
515 
516     /* Setup the header */
517     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
518     Header.Buffer = (PCHAR)State;
519 
520     /* Do the write */
521     State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
522                                               Data->Buffer,
523                                               Data->Length,
524                                               0,
525                                               MMDBG_COPY_UNSAFE |
526                                               MMDBG_COPY_WRITE,
527                                               &WriteMemory->ActualBytesWritten);
528 
529     /* Send the packet */
530     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
531                  &Header,
532                  NULL,
533                  &KdpContext);
534 }
535 
536 VOID
537 NTAPI
KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)538 KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
539                       IN PSTRING Data,
540                       IN PCONTEXT Context)
541 {
542     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
543     STRING Header;
544     ULONG Length = ReadMemory->TransferCount;
545     ULONG Flags, CacheFlags;
546 
547     /* Setup the header */
548     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
549     Header.Buffer = (PCHAR)State;
550     ASSERT(Data->Length == 0);
551 
552     /* Validate length */
553     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
554     {
555         /* Overflow, set it to maximum possible */
556         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
557     }
558 
559     /* Start with the default flags */
560     Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL;
561 
562     /* Get the caching flags and check if a type is specified */
563     CacheFlags = ReadMemory->ActualBytesRead;
564     if (CacheFlags == DBGKD_CACHING_CACHED)
565     {
566         /* Cached */
567         Flags |= MMDBG_COPY_CACHED;
568     }
569     else if (CacheFlags == DBGKD_CACHING_UNCACHED)
570     {
571         /* Uncached */
572         Flags |= MMDBG_COPY_UNCACHED;
573     }
574     else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
575     {
576         /* Write Combined */
577         Flags |= MMDBG_COPY_WRITE_COMBINED;
578     }
579 
580     /* Do the read */
581     State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
582                                               Data->Buffer,
583                                               Length,
584                                               0,
585                                               Flags,
586                                               &Length);
587 
588     /* Return the actual length read */
589     ReadMemory->ActualBytesRead = Length;
590     Data->Length = (USHORT)Length;
591 
592     /* Send the packet */
593     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
594                  &Header,
595                  Data,
596                  &KdpContext);
597 }
598 
599 VOID
600 NTAPI
KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)601 KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
602                        IN PSTRING Data,
603                        IN PCONTEXT Context)
604 {
605     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
606     STRING Header;
607     ULONG Flags, CacheFlags;
608 
609     /* Setup the header */
610     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
611     Header.Buffer = (PCHAR)State;
612 
613     /* Start with the default flags */
614     Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL;
615 
616     /* Get the caching flags and check if a type is specified */
617     CacheFlags = WriteMemory->ActualBytesWritten;
618     if (CacheFlags == DBGKD_CACHING_CACHED)
619     {
620         /* Cached */
621         Flags |= MMDBG_COPY_CACHED;
622     }
623     else if (CacheFlags == DBGKD_CACHING_UNCACHED)
624     {
625         /* Uncached */
626         Flags |= MMDBG_COPY_UNCACHED;
627     }
628     else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
629     {
630         /* Write Combined */
631         Flags |= MMDBG_COPY_WRITE_COMBINED;
632     }
633 
634     /* Do the write */
635     State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
636                                               Data->Buffer,
637                                               Data->Length,
638                                               0,
639                                               Flags,
640                                               &WriteMemory->ActualBytesWritten);
641 
642     /* Send the packet */
643     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
644                  &Header,
645                  NULL,
646                  &KdpContext);
647 }
648 
649 VOID
650 NTAPI
KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)651 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
652                     IN PSTRING Data,
653                     IN PCONTEXT Context)
654 {
655     PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
656     STRING Header;
657     ULONG Length;
658 
659     /* Setup the header */
660     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
661     Header.Buffer = (PCHAR)State;
662     ASSERT(Data->Length == 0);
663 
664     /* Check the length requested */
665     Length = ReadMemory->TransferCount;
666     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
667     {
668         /* Use maximum allowed */
669         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
670     }
671 
672     /* Call the internal routine */
673     State->ReturnStatus = KdpSysReadControlSpace(State->Processor,
674                                                  ReadMemory->TargetBaseAddress,
675                                                  Data->Buffer,
676                                                  Length,
677                                                  &Length);
678 
679     /* Return the actual length read */
680     ReadMemory->ActualBytesRead = Length;
681     Data->Length = (USHORT)Length;
682 
683     /* Send the reply */
684     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
685                  &Header,
686                  Data,
687                  &KdpContext);
688 }
689 
690 VOID
691 NTAPI
KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)692 KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
693                      IN PSTRING Data,
694                      IN PCONTEXT Context)
695 {
696     PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
697     STRING Header;
698 
699     /* Setup the header */
700     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
701     Header.Buffer = (PCHAR)State;
702 
703     /* Call the internal routine */
704     State->ReturnStatus = KdpSysWriteControlSpace(State->Processor,
705                                                   WriteMemory->TargetBaseAddress,
706                                                   Data->Buffer,
707                                                   Data->Length,
708                                                   &WriteMemory->ActualBytesWritten);
709 
710     /* Send the reply */
711     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
712                  &Header,
713                  Data,
714                  &KdpContext);
715 }
716 
717 VOID
718 NTAPI
KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)719 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
720               IN PSTRING Data,
721               IN PCONTEXT Context)
722 {
723     STRING Header;
724     PCONTEXT TargetContext;
725 
726     /* Setup the header */
727     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
728     Header.Buffer = (PCHAR)State;
729     ASSERT(Data->Length == 0);
730 
731     /* Make sure that this is a valid request */
732     if (State->Processor < KeNumberProcessors)
733     {
734         /* Check if the request is for this CPU */
735         if (State->Processor == KeGetCurrentPrcb()->Number)
736         {
737             /* We're just copying our own context */
738             TargetContext = Context;
739         }
740         else
741         {
742             /* Get the context from the PRCB array */
743             TargetContext = &KiProcessorBlock[State->Processor]->
744                             ProcessorState.ContextFrame;
745         }
746 
747         /* Copy it over to the debugger */
748         KdpMoveMemory(Data->Buffer,
749                       TargetContext,
750                       sizeof(CONTEXT));
751         Data->Length = sizeof(CONTEXT);
752 
753         /* Let the debugger set the context now */
754         KdpContextSent = TRUE;
755 
756         /* Finish up */
757         State->ReturnStatus = STATUS_SUCCESS;
758     }
759     else
760     {
761         /* Invalid request */
762         State->ReturnStatus = STATUS_UNSUCCESSFUL;
763     }
764 
765     /* Send the reply */
766     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
767                  &Header,
768                  Data,
769                  &KdpContext);
770 }
771 
772 VOID
773 NTAPI
KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)774 KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
775               IN PSTRING Data,
776               IN PCONTEXT Context)
777 {
778     STRING Header;
779     PCONTEXT TargetContext;
780 
781     /* Setup the header */
782     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
783     Header.Buffer = (PCHAR)State;
784     ASSERT(Data->Length == sizeof(CONTEXT));
785 
786     /* Make sure that this is a valid request */
787     if ((State->Processor < KeNumberProcessors) &&
788         (KdpContextSent))
789     {
790         /* Check if the request is for this CPU */
791         if (State->Processor == KeGetCurrentPrcb()->Number)
792         {
793             /* We're just copying our own context */
794             TargetContext = Context;
795         }
796         else
797         {
798             /* Get the context from the PRCB array */
799             TargetContext = &KiProcessorBlock[State->Processor]->
800                             ProcessorState.ContextFrame;
801         }
802 
803         /* Copy the new context to it */
804         KdpMoveMemory(TargetContext,
805                       Data->Buffer,
806                       sizeof(CONTEXT));
807 
808         /* Finish up */
809         State->ReturnStatus = STATUS_SUCCESS;
810     }
811     else
812     {
813         /* Invalid request */
814         State->ReturnStatus = STATUS_UNSUCCESSFUL;
815     }
816 
817     /* Send the reply */
818     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
819                  &Header,
820                  NULL,
821                  &KdpContext);
822 }
823 
824 VOID
825 NTAPI
KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)826 KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
827                 IN PSTRING Data,
828                 IN PCONTEXT Context)
829 {
830     STRING Header;
831     PDBGKD_CONTEXT_EX ContextEx;
832     PCONTEXT TargetContext;
833     ASSERT(Data->Length == 0);
834 
835     /* Get our struct */
836     ContextEx = &State->u.ContextEx;
837 
838     /* Set up the header */
839     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
840     Header.Buffer = (PCHAR)State;
841 
842     /* Make sure that this is a valid request */
843     if ((State->Processor < KeNumberProcessors) &&
844         (ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT))
845     {
846         /* Check if the request is for this CPU */
847         if (State->Processor == KeGetCurrentPrcb()->Number)
848         {
849             /* We're just copying our own context */
850             TargetContext = Context;
851         }
852         else
853         {
854             /* Get the context from the PRCB array */
855             TargetContext = &KiProcessorBlock[State->Processor]->
856                             ProcessorState.ContextFrame;
857         }
858 
859         /* Copy what is requested */
860         KdpMoveMemory(Data->Buffer,
861                       (PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
862                       ContextEx->ByteCount);
863 
864         /* KD copies all */
865         Data->Length = ContextEx->BytesCopied = ContextEx->ByteCount;
866 
867         /* Let the debugger set the context now */
868         KdpContextSent = TRUE;
869 
870         /* Finish up */
871         State->ReturnStatus = STATUS_SUCCESS;
872     }
873     else
874     {
875         /* Invalid request */
876         ContextEx->BytesCopied = 0;
877         State->ReturnStatus = STATUS_UNSUCCESSFUL;
878     }
879 
880     /* Send the reply */
881     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
882                  &Header,
883                  Data,
884                  &KdpContext);
885 }
886 
887 VOID
888 NTAPI
KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)889 KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
890                 IN PSTRING Data,
891                 IN PCONTEXT Context)
892 {
893     STRING Header;
894     PDBGKD_CONTEXT_EX ContextEx;
895     PCONTEXT TargetContext;
896 
897     /* Get our struct */
898     ContextEx = &State->u.ContextEx;
899     ASSERT(Data->Length == ContextEx->ByteCount);
900 
901     /* Set up the header */
902     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
903     Header.Buffer = (PCHAR)State;
904 
905     /* Make sure that this is a valid request */
906     if ((State->Processor < KeNumberProcessors) &&
907         ((ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT)) &&
908         (KdpContextSent))
909     {
910         /* Check if the request is for this CPU */
911         if (State->Processor == KeGetCurrentPrcb()->Number)
912         {
913             /* We're just copying our own context */
914             TargetContext = Context;
915         }
916         else
917         {
918             /* Get the context from the PRCB array */
919             TargetContext = &KiProcessorBlock[State->Processor]->
920                             ProcessorState.ContextFrame;
921         }
922 
923         /* Copy what is requested */
924         KdpMoveMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
925                       Data->Buffer,
926                       ContextEx->ByteCount);
927 
928         /* KD copies all */
929         ContextEx->BytesCopied = ContextEx->ByteCount;
930 
931         /* Finish up */
932         State->ReturnStatus = STATUS_SUCCESS;
933     }
934     else
935     {
936         /* Invalid request */
937         ContextEx->BytesCopied = 0;
938         State->ReturnStatus = STATUS_UNSUCCESSFUL;
939     }
940 
941     /* Send the reply */
942     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
943                  &Header,
944                  NULL,
945                  &KdpContext);
946 }
947 
948 VOID
949 NTAPI
KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)950 KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)
951 {
952     /* Crash with the special code */
953     KeBugCheck(MANUALLY_INITIATED_CRASH);
954 }
955 
956 VOID
957 NTAPI
KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)958 KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
959                                IN PSTRING Data,
960                                IN PCONTEXT Context)
961 {
962     STRING Header;
963     PDBGKD_READ_WRITE_MSR ReadMsr = &State->u.ReadWriteMsr;
964     ULARGE_INTEGER MsrValue;
965 
966     /* Setup the header */
967     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
968     Header.Buffer = (PCHAR)State;
969     ASSERT(Data->Length == 0);
970 
971     /* Call the internal routine */
972     State->ReturnStatus = KdpSysReadMsr(ReadMsr->Msr, &MsrValue.QuadPart);
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     ULARGE_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, &MsrValue.QuadPart);
1004 
1005     /* Send the reply */
1006     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1007                  &Header,
1008                  NULL,
1009                  &KdpContext);
1010 }
1011 
1012 VOID
1013 NTAPI
KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1014 KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1015               IN PSTRING Data,
1016               IN PCONTEXT Context)
1017 {
1018     STRING Header;
1019     PDBGKD_GET_SET_BUS_DATA GetBusData = &State->u.GetSetBusData;
1020     ULONG Length;
1021 
1022     /* Setup the header */
1023     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1024     Header.Buffer = (PCHAR)State;
1025     ASSERT(Data->Length == 0);
1026 
1027     /* Check the length requested */
1028     Length = GetBusData->Length;
1029     if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
1030     {
1031         /* Use maximum allowed */
1032         Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
1033     }
1034 
1035     /* Call the internal routine */
1036     State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType,
1037                                             GetBusData->BusNumber,
1038                                             GetBusData->SlotNumber,
1039                                             GetBusData->Offset,
1040                                             Data->Buffer,
1041                                             Length,
1042                                             &Length);
1043 
1044     /* Return the actual length read */
1045     GetBusData->Length = Length;
1046     Data->Length = (USHORT)Length;
1047 
1048     /* Send the reply */
1049     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1050                  &Header,
1051                  Data,
1052                  &KdpContext);
1053 }
1054 
1055 VOID
1056 NTAPI
KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1057 KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1058               IN PSTRING Data,
1059               IN PCONTEXT Context)
1060 {
1061     STRING Header;
1062     PDBGKD_GET_SET_BUS_DATA SetBusData = &State->u.GetSetBusData;
1063 
1064     /* Setup the header */
1065     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1066     Header.Buffer = (PCHAR)State;
1067 
1068     /* Call the internal routine */
1069     State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType,
1070                                              SetBusData->BusNumber,
1071                                              SetBusData->SlotNumber,
1072                                              SetBusData->Offset,
1073                                              Data->Buffer,
1074                                              SetBusData->Length,
1075                                              &SetBusData->Length);
1076 
1077     /* Send the reply */
1078     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1079                  &Header,
1080                  NULL,
1081                  &KdpContext);
1082 }
1083 
1084 VOID
1085 NTAPI
KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1086 KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1087                IN PSTRING Data,
1088                IN PCONTEXT Context)
1089 {
1090     STRING Header;
1091     PDBGKD_READ_WRITE_IO64 ReadIo = &State->u.ReadWriteIo;
1092 
1093     /* Setup the header */
1094     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1095     Header.Buffer = (PCHAR)State;
1096     ASSERT(Data->Length == 0);
1097 
1098     /*
1099      * Clear the value so 1 or 2 byte reads
1100      * don't leave the higher bits unmodified
1101      */
1102     ReadIo->DataValue = 0;
1103 
1104     /* Call the internal routine */
1105     State->ReturnStatus = KdpSysReadIoSpace(Isa,
1106                                             0,
1107                                             1,
1108                                             ReadIo->IoAddress,
1109                                             &ReadIo->DataValue,
1110                                             ReadIo->DataSize,
1111                                             &ReadIo->DataSize);
1112 
1113     /* Send the reply */
1114     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1115                  &Header,
1116                  NULL,
1117                  &KdpContext);
1118 }
1119 
1120 VOID
1121 NTAPI
KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1122 KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1123                 IN PSTRING Data,
1124                 IN PCONTEXT Context)
1125 {
1126     STRING Header;
1127     PDBGKD_READ_WRITE_IO64 WriteIo = &State->u.ReadWriteIo;
1128 
1129     /* Setup the header */
1130     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1131     Header.Buffer = (PCHAR)State;
1132     ASSERT(Data->Length == 0);
1133 
1134     /* Call the internal routine */
1135     State->ReturnStatus = KdpSysWriteIoSpace(Isa,
1136                                              0,
1137                                              1,
1138                                              WriteIo->IoAddress,
1139                                              &WriteIo->DataValue,
1140                                              WriteIo->DataSize,
1141                                              &WriteIo->DataSize);
1142 
1143     /* Send the reply */
1144     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1145                  &Header,
1146                  NULL,
1147                  &KdpContext);
1148 }
1149 
1150 VOID
1151 NTAPI
KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1152 KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1153                        IN PSTRING Data,
1154                        IN PCONTEXT Context)
1155 {
1156     STRING Header;
1157     PDBGKD_READ_WRITE_IO_EXTENDED64 ReadIoExtended = &State->u.
1158                                                       ReadWriteIoExtended;
1159 
1160     /* Setup the header */
1161     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1162     Header.Buffer = (PCHAR)State;
1163     ASSERT(Data->Length == 0);
1164 
1165     /*
1166      * Clear the value so 1 or 2 byte reads
1167      * don't leave the higher bits unmodified
1168      */
1169     ReadIoExtended->DataValue = 0;
1170 
1171     /* Call the internal routine */
1172     State->ReturnStatus = KdpSysReadIoSpace(ReadIoExtended->InterfaceType,
1173                                             ReadIoExtended->BusNumber,
1174                                             ReadIoExtended->AddressSpace,
1175                                             ReadIoExtended->IoAddress,
1176                                             &ReadIoExtended->DataValue,
1177                                             ReadIoExtended->DataSize,
1178                                             &ReadIoExtended->DataSize);
1179 
1180     /* Send the reply */
1181     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1182                  &Header,
1183                  NULL,
1184                  &KdpContext);
1185 }
1186 
1187 VOID
1188 NTAPI
KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1189 KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1190                         IN PSTRING Data,
1191                         IN PCONTEXT Context)
1192 {
1193     STRING Header;
1194     PDBGKD_READ_WRITE_IO_EXTENDED64 WriteIoExtended = &State->u.
1195                                                        ReadWriteIoExtended;
1196 
1197     /* Setup the header */
1198     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1199     Header.Buffer = (PCHAR)State;
1200     ASSERT(Data->Length == 0);
1201 
1202     /* Call the internal routine */
1203     State->ReturnStatus = KdpSysWriteIoSpace(WriteIoExtended->InterfaceType,
1204                                              WriteIoExtended->BusNumber,
1205                                              WriteIoExtended->AddressSpace,
1206                                              WriteIoExtended->IoAddress,
1207                                              &WriteIoExtended->DataValue,
1208                                              WriteIoExtended->DataSize,
1209                                              &WriteIoExtended->DataSize);
1210 
1211     /* Send the reply */
1212     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1213                  &Header,
1214                  NULL,
1215                  &KdpContext);
1216 }
1217 
1218 VOID
1219 NTAPI
KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)1220 KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)
1221 {
1222     STRING Header;
1223 
1224     /* Setup the header */
1225     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1226     Header.Buffer = (PCHAR)State;
1227 
1228     /* Call the internal routine */
1229     State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
1230 
1231     /* Send the reply */
1232     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1233                  &Header,
1234                  NULL,
1235                  &KdpContext);
1236 }
1237 
1238 VOID
1239 NTAPI
KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)1240 KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)
1241 {
1242     STRING Header;
1243 
1244     /* Set failure */
1245     State->ReturnStatus = STATUS_UNSUCCESSFUL;
1246 
1247     /* Setup the packet */
1248     Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1249     Header.Buffer = (PCHAR)State;
1250 
1251     /* Send it */
1252     KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1253                  &Header,
1254                  NULL,
1255                  &KdpContext);
1256 }
1257 
1258 static
1259 KCONTINUE_STATUS
KdpSwitchProcessor(_In_ USHORT ProcessorIndex)1260 KdpSwitchProcessor(
1261     _In_ USHORT ProcessorIndex)
1262 {
1263     /* Make sure that the processor index is valid */
1264     if (ProcessorIndex >= KeNumberProcessors)
1265     {
1266         KdpDprintf("%u is not a valid processor number\n", ProcessorIndex);
1267         return ContinueProcessorReselected;
1268     }
1269 
1270     /* If the new processor is the current one, there is nothing to do */
1271     if (ProcessorIndex == KeGetCurrentProcessorNumber())
1272     {
1273         return ContinueProcessorReselected;
1274     }
1275 
1276     /* Call the architecture specific Ke routine */
1277     return KxSwitchKdProcessor(ProcessorIndex);
1278 }
1279 
1280 KCONTINUE_STATUS
1281 NTAPI
KdpSendWaitContinue(IN ULONG PacketType,IN PSTRING SendHeader,IN PSTRING SendData OPTIONAL,IN OUT PCONTEXT Context)1282 KdpSendWaitContinue(IN ULONG PacketType,
1283                     IN PSTRING SendHeader,
1284                     IN PSTRING SendData OPTIONAL,
1285                     IN OUT PCONTEXT Context)
1286 {
1287     STRING Data, Header;
1288     DBGKD_MANIPULATE_STATE64 ManipulateState;
1289     ULONG Length;
1290     KDSTATUS RecvCode;
1291 
1292     /* Setup the Manipulate State structure */
1293     Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
1294     Header.Buffer = (PCHAR)&ManipulateState;
1295     Data.MaximumLength = sizeof(KdpMessageBuffer);
1296     Data.Buffer = KdpMessageBuffer;
1297 
1298     /*
1299      * Reset the context state to ensure the debugger has received
1300      * the current context before it sets it.
1301      */
1302     KdpContextSent = FALSE;
1303 
1304 SendPacket:
1305     /* Send the Packet */
1306     KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
1307 
1308     /* If the debugger isn't present anymore, just return success */
1309     if (KdDebuggerNotPresent) return ContinueSuccess;
1310 
1311     /* Main processing Loop */
1312     for (;;)
1313     {
1314         /* Receive Loop */
1315         do
1316         {
1317             /* Wait to get a reply to our packet */
1318             RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1319                                        &Header,
1320                                        &Data,
1321                                        &Length,
1322                                        &KdpContext);
1323 
1324             /* If we got a resend request, do it */
1325             if (RecvCode == KdPacketNeedsResend) goto SendPacket;
1326         } while (RecvCode == KdPacketTimedOut);
1327 
1328         /* Now check what API we got */
1329         switch (ManipulateState.ApiNumber)
1330         {
1331             case DbgKdReadVirtualMemoryApi:
1332 
1333                 /* Read virtual memory */
1334                 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
1335                 break;
1336 
1337             case DbgKdWriteVirtualMemoryApi:
1338 
1339                 /* Write virtual memory */
1340                 KdpWriteVirtualMemory(&ManipulateState, &Data, Context);
1341                 break;
1342 
1343             case DbgKdGetContextApi:
1344 
1345                 /* Get the current context */
1346                 KdpGetContext(&ManipulateState, &Data, Context);
1347                 break;
1348 
1349             case DbgKdSetContextApi:
1350 
1351                 /* Set a new context */
1352                 KdpSetContext(&ManipulateState, &Data, Context);
1353                 break;
1354 
1355             case DbgKdWriteBreakPointApi:
1356 
1357                 /* Write the breakpoint */
1358                 KdpWriteBreakpoint(&ManipulateState, &Data, Context);
1359                 break;
1360 
1361             case DbgKdRestoreBreakPointApi:
1362 
1363                 /* Restore the breakpoint */
1364                 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
1365                 break;
1366 
1367             case DbgKdContinueApi:
1368 
1369                 /* Simply continue */
1370                 return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
1371 
1372             case DbgKdReadControlSpaceApi:
1373 
1374                 /* Read control space */
1375                 KdpReadControlSpace(&ManipulateState, &Data, Context);
1376                 break;
1377 
1378             case DbgKdWriteControlSpaceApi:
1379 
1380                 /* Write control space */
1381                 KdpWriteControlSpace(&ManipulateState, &Data, Context);
1382                 break;
1383 
1384             case DbgKdReadIoSpaceApi:
1385 
1386                 /* Read I/O Space */
1387                 KdpReadIoSpace(&ManipulateState, &Data, Context);
1388                 break;
1389 
1390             case DbgKdWriteIoSpaceApi:
1391 
1392                 /* Write I/O Space */
1393                 KdpWriteIoSpace(&ManipulateState, &Data, Context);
1394                 break;
1395 
1396             case DbgKdRebootApi:
1397 
1398                 /* Reboot the system */
1399                 HalReturnToFirmware(HalRebootRoutine);
1400                 break;
1401 
1402             case DbgKdContinueApi2:
1403 
1404                 /* Check if caller reports success */
1405                 if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
1406                 {
1407                     /* Update the state */
1408                     KdpGetStateChange(&ManipulateState, Context);
1409                     return ContinueSuccess;
1410                 }
1411                 else
1412                 {
1413                     /* Return an error */
1414                     return ContinueError;
1415                 }
1416 
1417             case DbgKdReadPhysicalMemoryApi:
1418 
1419                 /* Read  physical memory */
1420                 KdpReadPhysicalMemory(&ManipulateState, &Data, Context);
1421                 break;
1422 
1423             case DbgKdWritePhysicalMemoryApi:
1424 
1425                 /* Write  physical memory */
1426                 KdpWritePhysicalMemory(&ManipulateState, &Data, Context);
1427                 break;
1428 
1429             case DbgKdQuerySpecialCallsApi:
1430             case DbgKdSetSpecialCallApi:
1431             case DbgKdClearSpecialCallsApi:
1432 
1433                 /* TODO */
1434                 KdpDprintf("Special Call support is unimplemented!\n");
1435                 KdpNotSupported(&ManipulateState);
1436                 break;
1437 
1438             case DbgKdSetInternalBreakPointApi:
1439             case DbgKdGetInternalBreakPointApi:
1440 
1441                 /* TODO */
1442                 KdpDprintf("Internal Breakpoint support is unimplemented!\n");
1443                 KdpNotSupported(&ManipulateState);
1444                 break;
1445 
1446             case DbgKdReadIoSpaceExtendedApi:
1447 
1448                 /* Read I/O Space */
1449                 KdpReadIoSpaceExtended(&ManipulateState, &Data, Context);
1450                 break;
1451 
1452             case DbgKdWriteIoSpaceExtendedApi:
1453 
1454                 /* Write I/O Space */
1455                 KdpWriteIoSpaceExtended(&ManipulateState, &Data, Context);
1456                 break;
1457 
1458             case DbgKdGetVersionApi:
1459 
1460                 /* Get version data */
1461                 KdpGetVersion(&ManipulateState);
1462                 break;
1463 
1464             case DbgKdWriteBreakPointExApi:
1465 
1466                 /* Write the breakpoint and check if it failed */
1467                 if (!NT_SUCCESS(KdpWriteBreakPointEx(&ManipulateState,
1468                                                      &Data,
1469                                                      Context)))
1470                 {
1471                     /* Return an error */
1472                     return ContinueError;
1473                 }
1474                 break;
1475 
1476             case DbgKdRestoreBreakPointExApi:
1477 
1478                 /* Restore the breakpoint */
1479                 KdpRestoreBreakPointEx(&ManipulateState, &Data, Context);
1480                 break;
1481 
1482             case DbgKdCauseBugCheckApi:
1483 
1484                 /* Crash the system */
1485                 KdpCauseBugCheck(&ManipulateState);
1486                 break;
1487 
1488             case DbgKdSwitchProcessor:
1489 
1490                 /* Switch the processor and return */
1491                 return KdpSwitchProcessor(ManipulateState.Processor);
1492 
1493             case DbgKdPageInApi:
1494 
1495                 /* This API, introduced in NT4, has been obsoleted in NT5. It is
1496                  * replaced by ExpDebuggerPageIn support in ExpDebuggerWorker(). */
1497                 KdpDprintf("DbgKdPageInApi is obsolete!\n");
1498                 KdpNotSupported(&ManipulateState);
1499                 break;
1500 
1501             case DbgKdReadMachineSpecificRegister:
1502 
1503                 /* Read from the specified MSR */
1504                 KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
1505                 break;
1506 
1507             case DbgKdWriteMachineSpecificRegister:
1508 
1509                 /* Write to the specified MSR */
1510                 KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
1511                 break;
1512 
1513             case DbgKdSearchMemoryApi:
1514 
1515                 /* Search memory */
1516                 KdpSearchMemory(&ManipulateState, &Data, Context);
1517                 break;
1518 
1519             case DbgKdGetBusDataApi:
1520 
1521                 /* Read from the bus */
1522                 KdpGetBusData(&ManipulateState, &Data, Context);
1523                 break;
1524 
1525             case DbgKdSetBusDataApi:
1526 
1527                 /* Write to the bus */
1528                 KdpSetBusData(&ManipulateState, &Data, Context);
1529                 break;
1530 
1531             case DbgKdCheckLowMemoryApi:
1532 
1533                 /* Check for memory corruption in the lower 4 GB */
1534                 KdpCheckLowMemory(&ManipulateState);
1535                 break;
1536 
1537             case DbgKdClearAllInternalBreakpointsApi:
1538 
1539                 /* Just clear the counter */
1540                 KdpNumInternalBreakpoints = 0;
1541                 break;
1542 
1543             case DbgKdFillMemoryApi:
1544 
1545                 /* Fill memory */
1546                 KdpFillMemory(&ManipulateState, &Data, Context);
1547                 break;
1548 
1549             case DbgKdQueryMemoryApi:
1550 
1551                 /* Query memory */
1552                 KdpQueryMemory(&ManipulateState, Context);
1553                 break;
1554 
1555             case DbgKdSwitchPartition:
1556 
1557                 /* TODO */
1558                 KdpDprintf("Partition Switch support is unimplemented!\n");
1559                 KdpNotSupported(&ManipulateState);
1560                 break;
1561 
1562             case DbgKdWriteCustomBreakpointApi:
1563 
1564                 /* Write the customized breakpoint */
1565                 KdpWriteCustomBreakpoint(&ManipulateState, &Data, Context);
1566                 break;
1567 
1568             case DbgKdGetContextExApi:
1569 
1570                 /* Extended Context Get */
1571                 KdpGetContextEx(&ManipulateState, &Data, Context);
1572                 break;
1573 
1574             case DbgKdSetContextExApi:
1575 
1576                 /* Extended Context Set */
1577                 KdpSetContextEx(&ManipulateState, &Data, Context);
1578                 break;
1579 
1580             /* Unsupported Messages */
1581             default:
1582 
1583                 /* Send warning */
1584                 KdpDprintf("Received Unrecognized API 0x%lx\n", ManipulateState.ApiNumber);
1585 
1586                 /* Setup an empty message, with failure */
1587                 Data.Length = 0;
1588                 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1589 
1590                 /* Send it */
1591                 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1592                              &Header,
1593                              &Data,
1594                              &KdpContext);
1595                 break;
1596         }
1597     }
1598 }
1599 
1600 VOID
1601 NTAPI
KdpReportLoadSymbolsStateChange(IN PSTRING PathName,IN PKD_SYMBOLS_INFO SymbolInfo,IN BOOLEAN Unload,IN OUT PCONTEXT Context)1602 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
1603                                 IN PKD_SYMBOLS_INFO SymbolInfo,
1604                                 IN BOOLEAN Unload,
1605                                 IN OUT PCONTEXT Context)
1606 {
1607     PSTRING ExtraData;
1608     STRING Data, Header;
1609     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1610     ULONG PathNameLength;
1611     KCONTINUE_STATUS Status;
1612 
1613     /* Start wait loop */
1614     do
1615     {
1616         /* Build the architecture common parts of the message */
1617         KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1618                           Context,
1619                           &WaitStateChange);
1620 
1621         /* Now finish creating the structure */
1622         KdpSetContextState(&WaitStateChange, Context);
1623 
1624         /* Fill out load data */
1625         WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1626         WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
1627         WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1628         WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1629         WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1630 
1631         /* Check if we have a path name */
1632         if (PathName)
1633         {
1634             /* Copy it to the path buffer */
1635             KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
1636                                 KdpPathBuffer,
1637                                 PathName->Length,
1638                                 0,
1639                                 MMDBG_COPY_UNSAFE,
1640                                 &PathNameLength);
1641 
1642             /* Null terminate */
1643             KdpPathBuffer[PathNameLength++] = ANSI_NULL;
1644 
1645             /* Set the path length */
1646             WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
1647 
1648             /* Set up the data */
1649             Data.Buffer = KdpPathBuffer;
1650             Data.Length = (USHORT)PathNameLength;
1651             ExtraData = &Data;
1652         }
1653         else
1654         {
1655             /* No name */
1656             WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1657             ExtraData = NULL;
1658         }
1659 
1660         /* Setup the header */
1661         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1662         Header.Buffer = (PCHAR)&WaitStateChange;
1663 
1664         /* Send the packet */
1665         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1666                                      &Header,
1667                                      ExtraData,
1668                                      Context);
1669     } while (Status == ContinueProcessorReselected);
1670 }
1671 
1672 VOID
1673 NTAPI
KdpReportCommandStringStateChange(IN PSTRING NameString,IN PSTRING CommandString,IN OUT PCONTEXT Context)1674 KdpReportCommandStringStateChange(IN PSTRING NameString,
1675                                   IN PSTRING CommandString,
1676                                   IN OUT PCONTEXT Context)
1677 {
1678     STRING Header, Data;
1679     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1680     ULONG Length, ActualLength, TotalLength;
1681     KCONTINUE_STATUS Status;
1682 
1683     /* Start wait loop */
1684     do
1685     {
1686         /* Build the architecture common parts of the message */
1687         KdpSetCommonState(DbgKdCommandStringStateChange,
1688                           Context,
1689                           &WaitStateChange);
1690 
1691         /* Set the context */
1692         KdpSetContextState(&WaitStateChange, Context);
1693 
1694         /* Clear the command string structure */
1695         KdpZeroMemory(&WaitStateChange.u.CommandString,
1696                       sizeof(DBGKD_COMMAND_STRING));
1697 
1698         /* Normalize name string to max */
1699         Length = min(128 - 1, NameString->Length);
1700 
1701         /* Copy it to the message buffer */
1702         KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
1703                             KdpMessageBuffer,
1704                             Length,
1705                             0,
1706                             MMDBG_COPY_UNSAFE,
1707                             &ActualLength);
1708 
1709         /* Null terminate and calculate the total length */
1710         TotalLength = ActualLength;
1711         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1712 
1713         /* Check if the command string is too long */
1714         Length = CommandString->Length;
1715         if (Length > (PACKET_MAX_SIZE -
1716                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
1717         {
1718             /* Use maximum possible size */
1719             Length = (PACKET_MAX_SIZE -
1720                       sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
1721         }
1722 
1723         /* Copy it to the message buffer */
1724         KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
1725                             KdpMessageBuffer + TotalLength,
1726                             Length,
1727                             0,
1728                             MMDBG_COPY_UNSAFE,
1729                             &ActualLength);
1730 
1731         /* Null terminate and calculate the total length */
1732         TotalLength += ActualLength;
1733         KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1734 
1735         /* Now set up the header and the data */
1736         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1737         Header.Buffer = (PCHAR)&WaitStateChange;
1738         Data.Length = (USHORT)TotalLength;
1739         Data.Buffer = KdpMessageBuffer;
1740 
1741         /* Send State Change packet and wait for a reply */
1742         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1743                                      &Header,
1744                                      &Data,
1745                                      Context);
1746     } while (Status == ContinueProcessorReselected);
1747 }
1748 
1749 BOOLEAN
1750 NTAPI
KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,IN OUT PCONTEXT Context,IN BOOLEAN SecondChanceException)1751 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1752                               IN OUT PCONTEXT Context,
1753                               IN BOOLEAN SecondChanceException)
1754 {
1755     STRING Header, Data;
1756     DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1757     KCONTINUE_STATUS Status;
1758 
1759     /* Start report loop */
1760     do
1761     {
1762         /* Build the architecture common parts of the message */
1763         KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1764 
1765 #if !defined(_WIN64)
1766 
1767         /* Convert it and copy it over */
1768         ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
1769                               &WaitStateChange.u.Exception.ExceptionRecord);
1770 
1771 #else
1772 
1773         /* Just copy it directly, no need to convert */
1774         KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord,
1775                       ExceptionRecord,
1776                       sizeof(EXCEPTION_RECORD));
1777 
1778 #endif
1779 
1780         /* Set the First Chance flag */
1781         WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1782 
1783         /* Now finish creating the structure */
1784         KdpSetContextState(&WaitStateChange, Context);
1785 
1786         /* Setup the actual header to send to KD */
1787         Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1788         Header.Buffer = (PCHAR)&WaitStateChange;
1789 
1790         /* Setup the trace data */
1791         DumpTraceData(&Data);
1792 
1793         /* Send State Change packet and wait for a reply */
1794         Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1795                                      &Header,
1796                                      &Data,
1797                                      Context);
1798     } while (Status == ContinueProcessorReselected);
1799 
1800     /* Return */
1801     return Status;
1802 }
1803 
1804 KCONTINUE_STATUS
1805 NTAPI
KdReportProcessorChange(VOID)1806 KdReportProcessorChange(
1807     VOID)
1808 {
1809     PKPRCB CurrentPrcb = KeGetCurrentPrcb();
1810     PCONTEXT ContextRecord = &CurrentPrcb->ProcessorState.ContextFrame;
1811     EXCEPTION_RECORD ExceptionRecord = {0};
1812     KCONTINUE_STATUS Status;
1813 
1814     /* Save the port data */
1815     KdSave(FALSE);
1816 
1817     ExceptionRecord.ExceptionAddress = (PVOID)KeGetContextPc(ContextRecord);
1818     ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
1819 
1820     /* Report the new state */
1821     Status = KdpReportExceptionStateChange(&ExceptionRecord,
1822                                            ContextRecord,
1823                                            FALSE);
1824 
1825     /* Restore the port data */
1826     KdRestore(FALSE);
1827 
1828     return Status;
1829 }
1830 
1831 VOID
1832 NTAPI
KdpTimeSlipDpcRoutine(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)1833 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1834                       IN PVOID DeferredContext,
1835                       IN PVOID SystemArgument1,
1836                       IN PVOID SystemArgument2)
1837 {
1838     LONG OldSlip, NewSlip, PendingSlip;
1839 
1840     /* Get the current pending slip */
1841     PendingSlip = KdpTimeSlipPending;
1842     do
1843     {
1844         /* Save the old value and either disable or enable it now. */
1845         OldSlip = PendingSlip;
1846         NewSlip = OldSlip > 1 ? 1 : 0;
1847 
1848         /* Try to change the value */
1849     } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1850                                         NewSlip,
1851                                         OldSlip) != OldSlip);
1852 
1853     /* If the New Slip value is 1, then do the Time Slipping */
1854     if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1855 }
1856 
1857 VOID
1858 NTAPI
KdpTimeSlipWork(IN PVOID Context)1859 KdpTimeSlipWork(IN PVOID Context)
1860 {
1861     KIRQL OldIrql;
1862     LARGE_INTEGER DueTime;
1863 
1864     /* Update the System time from the CMOS */
1865     ExAcquireTimeRefreshLock(FALSE);
1866     ExUpdateSystemTimeFromCmos(FALSE, 0);
1867     ExReleaseTimeRefreshLock();
1868 
1869     /* Check if we have a registered Time Slip Event and signal it */
1870     KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1871     if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1872     KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1873 
1874     /* Delay the DPC until it runs next time */
1875     DueTime.QuadPart = -1800000000;
1876     KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1877 }
1878 
1879 LARGE_INTEGER
1880 NTAPI
KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)1881 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1882 {
1883     LARGE_INTEGER Null = {{0}};
1884 
1885     /* Check if interrupts were disabled */
1886     if (!KeGetTrapFrameInterruptState(TrapFrame))
1887     {
1888         /* Nothing to return */
1889         return Null;
1890     }
1891 
1892     /* Otherwise, do the call */
1893     return KeQueryPerformanceCounter(NULL);
1894 }
1895 
1896 BOOLEAN
1897 NTAPI
KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame)1898 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1899                 IN PKEXCEPTION_FRAME ExceptionFrame)
1900 {
1901     BOOLEAN Enable;
1902 
1903     /* Check if we have a trap frame */
1904     if (TrapFrame)
1905     {
1906         /* Calculate the time difference for the enter */
1907         KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1908         KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1909                                      KdTimerStart.QuadPart;
1910     }
1911     else
1912     {
1913         /* No trap frame, so can't calculate */
1914         KdTimerStop.QuadPart = 0;
1915     }
1916 
1917     /* Save the current IRQL */
1918     KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1919 
1920     /* Freeze all CPUs, raising also the IRQL to HIGH_LEVEL */
1921     Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
1922 
1923     /* Lock the port, save its state and set the debugger entered flag */
1924     KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1925     KdSave(FALSE);
1926     KdEnteredDebugger = TRUE;
1927 
1928     /* Check freeze flag */
1929     if (KiFreezeFlag & 1)
1930     {
1931         /* Print out errror */
1932         KdpDprintf("FreezeLock was jammed!  Backup SpinLock was used!\n");
1933     }
1934 
1935     /* Check processor state */
1936     if (KiFreezeFlag & 2)
1937     {
1938         /* Print out errror */
1939         KdpDprintf("Some processors not frozen in debugger!\n");
1940     }
1941 
1942     /* Make sure we acquired the port */
1943     if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
1944 
1945     /* Return if interrupts needs to be re-enabled */
1946     return Enable;
1947 }
1948 
1949 VOID
1950 NTAPI
KdExitDebugger(IN BOOLEAN Enable)1951 KdExitDebugger(IN BOOLEAN Enable)
1952 {
1953     ULONG TimeSlip;
1954 
1955     /* Reset the debugger entered flag, restore the port state and unlock it */
1956     KdEnteredDebugger = FALSE;
1957     KdRestore(FALSE);
1958     if (KdpPortLocked) KdpPortUnlock();
1959 
1960     /* Unfreeze the CPUs, restoring also the IRQL */
1961     KeThawExecution(Enable);
1962 
1963     /* Compare time with the one from KdEnterDebugger */
1964     if (!KdTimerStop.QuadPart)
1965     {
1966         /* We didn't get a trap frame earlier in so never got the time */
1967         KdTimerStart = KdTimerStop;
1968     }
1969     else
1970     {
1971         /* Query the timer */
1972         KdTimerStart = KeQueryPerformanceCounter(NULL);
1973     }
1974 
1975     /* Check if a Time Slip was on queue */
1976     TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1977     if (TimeSlip == 1)
1978     {
1979         /* Queue a DPC for the time slip */
1980         InterlockedIncrement(&KdpTimeSlipPending);
1981         KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches!
1982     }
1983 }
1984 
1985 NTSTATUS
1986 NTAPI
KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)1987 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
1988 {
1989     KIRQL OldIrql;
1990 
1991 #if defined(__GNUC__)
1992     /* Make gcc happy */
1993     OldIrql = PASSIVE_LEVEL;
1994 #endif
1995 
1996     /* Check if enabling the debugger is blocked */
1997     if (KdBlockEnable)
1998     {
1999         /* It is, fail the enable */
2000         return STATUS_ACCESS_DENIED;
2001     }
2002 
2003     /* Check if we need to acquire the lock */
2004     if (NeedLock)
2005     {
2006         /* Lock the port */
2007         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2008         KdpPortLock();
2009     }
2010 
2011     /* Check if we're not disabled */
2012     if (!KdDisableCount)
2013     {
2014         /* Check if we had locked the port before */
2015         if (NeedLock)
2016         {
2017             /* Do the unlock */
2018             KdpPortUnlock();
2019             KeLowerIrql(OldIrql);
2020 
2021             /* Fail: We're already enabled */
2022             return STATUS_INVALID_PARAMETER;
2023         }
2024         else
2025         {
2026             /*
2027              * This can only happen if we are called from a bugcheck
2028              * and were never initialized, so initialize the debugger now.
2029              */
2030             KdInitSystem(0, NULL);
2031 
2032             /* Return success since we initialized */
2033             return STATUS_SUCCESS;
2034         }
2035     }
2036 
2037     /* Decrease the disable count */
2038     if (!(--KdDisableCount))
2039     {
2040         /* We're now enabled again! Were we enabled before, too? */
2041         if (KdPreviouslyEnabled)
2042         {
2043             /* Reinitialize the Debugger */
2044             KdInitSystem(0, NULL);
2045             KdpRestoreAllBreakpoints();
2046         }
2047     }
2048 
2049     /* Check if we had locked the port before */
2050     if (NeedLock)
2051     {
2052         /* Yes, now unlock it */
2053         KdpPortUnlock();
2054         KeLowerIrql(OldIrql);
2055     }
2056 
2057     /* We're done */
2058     return STATUS_SUCCESS;
2059 }
2060 
2061 NTSTATUS
2062 NTAPI
KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)2063 KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
2064 {
2065     KIRQL OldIrql;
2066     NTSTATUS Status;
2067 
2068 #if defined(__GNUC__)
2069     /* Make gcc happy */
2070     OldIrql = PASSIVE_LEVEL;
2071 #endif
2072 
2073     /*
2074      * If enabling the debugger is blocked
2075      * then there is nothing to disable (duh)
2076      */
2077     if (KdBlockEnable)
2078     {
2079         /* Fail */
2080         return STATUS_ACCESS_DENIED;
2081     }
2082 
2083     /* Check if we need to acquire the lock */
2084     if (NeedLock)
2085     {
2086         /* Lock the port */
2087         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2088         KdpPortLock();
2089     }
2090 
2091     /* Check if we're not disabled */
2092     if (!KdDisableCount)
2093     {
2094         /* Check if the debugger was never actually initialized */
2095         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
2096         {
2097             /* It wasn't, so don't re-enable it later */
2098             KdPreviouslyEnabled = FALSE;
2099         }
2100         else
2101         {
2102             /* It was, so we will re-enable it later */
2103             KdPreviouslyEnabled = TRUE;
2104         }
2105 
2106         /* Check if we were called from the exported API and are enabled */
2107         if ((NeedLock) && (KdPreviouslyEnabled))
2108         {
2109             /* Check if it is safe to disable the debugger */
2110             Status = KdpAllowDisable();
2111             if (!NT_SUCCESS(Status))
2112             {
2113                 /* Release the lock and fail */
2114                 KdpPortUnlock();
2115                 KeLowerIrql(OldIrql);
2116                 return Status;
2117             }
2118         }
2119 
2120         /* Only disable the debugger if it is enabled */
2121         if (KdDebuggerEnabled)
2122         {
2123             /*
2124              * Disable the debugger; suspend breakpoints
2125              * and reset the debug stub
2126              */
2127             KdpSuspendAllBreakPoints();
2128             KiDebugRoutine = KdpStub;
2129 
2130             /* We are disabled now */
2131             KdDebuggerEnabled = FALSE;
2132             SharedUserData->KdDebuggerEnabled = FALSE;
2133         }
2134      }
2135 
2136     /* Increment the disable count */
2137     KdDisableCount++;
2138 
2139     /* Check if we had locked the port before */
2140     if (NeedLock)
2141     {
2142         /* Yes, now unlock it */
2143         KdpPortUnlock();
2144         KeLowerIrql(OldIrql);
2145     }
2146 
2147     /* We're done */
2148     return STATUS_SUCCESS;
2149 }
2150 
2151 /* PUBLIC FUNCTIONS **********************************************************/
2152 
2153 /*
2154  * @implemented
2155  */
2156 NTSTATUS
2157 NTAPI
KdEnableDebugger(VOID)2158 KdEnableDebugger(VOID)
2159 {
2160     /* Use the internal routine */
2161     return KdEnableDebuggerWithLock(TRUE);
2162 }
2163 
2164 /*
2165  * @implemented
2166  */
2167 NTSTATUS
2168 NTAPI
KdDisableDebugger(VOID)2169 KdDisableDebugger(VOID)
2170 {
2171     /* Use the internal routine */
2172     return KdDisableDebuggerWithLock(TRUE);
2173 }
2174 
2175 /**
2176  * @brief
2177  * Perform various queries to the kernel debugger.
2178  *
2179  * @param[in]   Command
2180  * A SYSDBG_COMMAND value describing the kernel debugger command to perform.
2181  *
2182  * @param[in]   InputBuffer
2183  * Pointer to a user-provided input command-specific buffer, whose length
2184  * is given by InputBufferLength.
2185  *
2186  * @param[in]   InputBufferLength
2187  * The size (in bytes) of the buffer pointed by InputBuffer.
2188  *
2189  * @param[out]  OutputBuffer
2190  * Pointer to a user-provided command-specific output buffer, whose length
2191  * is given by OutputBufferLength.
2192  *
2193  * @param[in]   OutputBufferLength
2194  * The size (in bytes) of the buffer pointed by OutputBuffer.
2195  *
2196  * @param[out]  ReturnLength
2197  * Optional pointer to a ULONG variable that receives the actual length of
2198  * data written written in the output buffer. It is always zero, except for
2199  * the live dump commands where an actual non-zero length is returned.
2200  *
2201  * @param[in]   PreviousMode
2202  * The processor mode (KernelMode or UserMode) in which the command is being executed.
2203  *
2204  * @return
2205  * STATUS_SUCCESS in case of success, or a proper error code otherwise.
2206  *
2207  * @remarks
2208  * - This is a kernel-mode function, accessible only by kernel-mode drivers.
2209  *
2210  * @note
2211  * See: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-2339
2212  *
2213  * @see NtSystemDebugControl()
2214  **/
2215 NTSTATUS
2216 NTAPI
KdSystemDebugControl(_In_ SYSDBG_COMMAND Command,_In_reads_bytes_ (InputBufferLength)PVOID InputBuffer,_In_ ULONG InputBufferLength,_Out_writes_bytes_ (OutputBufferLength)PVOID OutputBuffer,_In_ ULONG OutputBufferLength,_Out_opt_ PULONG ReturnLength,_In_ KPROCESSOR_MODE PreviousMode)2217 KdSystemDebugControl(
2218     _In_ SYSDBG_COMMAND Command,
2219     _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
2220     _In_ ULONG InputBufferLength,
2221     _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer,
2222     _In_ ULONG OutputBufferLength,
2223     _Out_opt_ PULONG ReturnLength,
2224     _In_ KPROCESSOR_MODE PreviousMode)
2225 {
2226     NTSTATUS Status;
2227     ULONG Length = 0;
2228 
2229     /* Handle some internal commands */
2230     switch ((ULONG)Command)
2231     {
2232 #if DBG
2233         case ' soR': /* ROS-INTERNAL */
2234         {
2235             switch ((ULONG_PTR)InputBuffer)
2236             {
2237                 case 0x21: // DumpAllThreads:
2238                     PspDumpThreads(TRUE);
2239                     break;
2240 
2241                 case 0x22: // DumpUserThreads:
2242                     PspDumpThreads(FALSE);
2243                     break;
2244 
2245                 case 0x24: // KdSpare3:
2246                     MmDumpArmPfnDatabase(FALSE);
2247                     break;
2248 
2249                 default:
2250                     break;
2251             }
2252             return STATUS_SUCCESS;
2253         }
2254 
2255 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
2256         /* Register a debug callback */
2257         case 'CsoR':
2258         {
2259             switch (InputBufferLength)
2260             {
2261                 case ID_Win32PreServiceHook:
2262                     KeWin32PreServiceHook = InputBuffer;
2263                     break;
2264 
2265                 case ID_Win32PostServiceHook:
2266                     KeWin32PostServiceHook = InputBuffer;
2267                     break;
2268 
2269             }
2270             break;
2271         }
2272 #endif
2273 
2274         /* Special case for stack frame dumps */
2275         case 'DsoR':
2276         {
2277             KeRosDumpStackFrames((PULONG_PTR)InputBuffer, InputBufferLength);
2278             break;
2279         }
2280 #ifdef KDBG
2281         /* Register KDBG CLI callback */
2282         case 'RbdK':
2283         {
2284             return KdbRegisterCliCallback(InputBuffer, InputBufferLength);
2285         }
2286 #endif // KDBG
2287 #endif
2288         default:
2289             break;
2290     }
2291 
2292     switch (Command)
2293     {
2294         case SysDbgQueryVersion:
2295             if (OutputBufferLength != sizeof(DBGKD_GET_VERSION64))
2296             {
2297                 Status = STATUS_INFO_LENGTH_MISMATCH;
2298             }
2299             else
2300             {
2301                 KdpSysGetVersion((PDBGKD_GET_VERSION64)OutputBuffer);
2302                 Status = STATUS_SUCCESS;
2303             }
2304             break;
2305 
2306         case SysDbgReadVirtual:
2307         case SysDbgWriteVirtual:
2308             if (InputBufferLength != sizeof(SYSDBG_VIRTUAL))
2309             {
2310                 Status = STATUS_INFO_LENGTH_MISMATCH;
2311             }
2312             else
2313             {
2314                 SYSDBG_VIRTUAL Request = *(PSYSDBG_VIRTUAL)InputBuffer;
2315                 PVOID LockedBuffer;
2316                 PMDL LockVariable;
2317 
2318                 Status = ExLockUserBuffer(Request.Buffer,
2319                                           Request.Request,
2320                                           PreviousMode,
2321                                           Command == SysDbgReadVirtual ? IoWriteAccess : IoReadAccess,
2322                                           &LockedBuffer,
2323                                           &LockVariable);
2324                 if (NT_SUCCESS(Status))
2325                 {
2326                     Status = KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Request.Address,
2327                                                  Request.Buffer,
2328                                                  Request.Request,
2329                                                  0,
2330                                                  Command == SysDbgReadVirtual ? 0 : MMDBG_COPY_WRITE,
2331                                                  &Length);
2332                     ExUnlockUserBuffer(LockVariable);
2333                 }
2334             }
2335             break;
2336 
2337         case SysDbgReadPhysical:
2338         case SysDbgWritePhysical:
2339             if (InputBufferLength != sizeof(SYSDBG_PHYSICAL))
2340             {
2341                 Status = STATUS_INFO_LENGTH_MISMATCH;
2342             }
2343             else
2344             {
2345                 SYSDBG_PHYSICAL Request = *(PSYSDBG_PHYSICAL)InputBuffer;
2346                 PVOID LockedBuffer;
2347                 PMDL LockVariable;
2348 
2349                 Status = ExLockUserBuffer(Request.Buffer,
2350                                           Request.Request,
2351                                           PreviousMode,
2352                                           Command == SysDbgReadVirtual ? IoWriteAccess : IoReadAccess,
2353                                           &LockedBuffer,
2354                                           &LockVariable);
2355                 if (NT_SUCCESS(Status))
2356                 {
2357                     Status = KdpCopyMemoryChunks(Request.Address.QuadPart,
2358                                                  Request.Buffer,
2359                                                  Request.Request,
2360                                                  0,
2361                                                  MMDBG_COPY_PHYSICAL | (Command == SysDbgReadVirtual ? 0 : MMDBG_COPY_WRITE),
2362                                                  &Length);
2363                     ExUnlockUserBuffer(LockVariable);
2364                 }
2365             }
2366             break;
2367 
2368         case SysDbgReadControlSpace:
2369             if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE))
2370             {
2371                 Status = STATUS_INFO_LENGTH_MISMATCH;
2372             }
2373             else
2374             {
2375                 SYSDBG_CONTROL_SPACE Request = *(PSYSDBG_CONTROL_SPACE)InputBuffer;
2376                 PVOID LockedBuffer;
2377                 PMDL LockVariable;
2378 
2379                 Status = ExLockUserBuffer(Request.Buffer,
2380                                           Request.Request,
2381                                           PreviousMode,
2382                                           IoWriteAccess,
2383                                           &LockedBuffer,
2384                                           &LockVariable);
2385                 if (NT_SUCCESS(Status))
2386                 {
2387                     Status = KdpSysReadControlSpace(Request.Processor,
2388                                                     Request.Address,
2389                                                     LockedBuffer,
2390                                                     Request.Request,
2391                                                     &Length);
2392                     ExUnlockUserBuffer(LockVariable);
2393                 }
2394             }
2395             break;
2396 
2397         case SysDbgWriteControlSpace:
2398             if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE))
2399             {
2400                 Status = STATUS_INFO_LENGTH_MISMATCH;
2401             }
2402             else
2403             {
2404                 SYSDBG_CONTROL_SPACE Request = *(PSYSDBG_CONTROL_SPACE)InputBuffer;
2405                 PVOID LockedBuffer;
2406                 PMDL LockVariable;
2407 
2408                 Status = ExLockUserBuffer(Request.Buffer,
2409                                           Request.Request,
2410                                           PreviousMode,
2411                                           IoReadAccess,
2412                                           &LockedBuffer,
2413                                           &LockVariable);
2414                 if (NT_SUCCESS(Status))
2415                 {
2416                     Status = KdpSysWriteControlSpace(Request.Processor,
2417                                                      Request.Address,
2418                                                      LockedBuffer,
2419                                                      Request.Request,
2420                                                      &Length);
2421                     ExUnlockUserBuffer(LockVariable);
2422                 }
2423             }
2424             break;
2425 
2426         case SysDbgReadIoSpace:
2427             if (InputBufferLength != sizeof(SYSDBG_IO_SPACE))
2428             {
2429                 Status = STATUS_INFO_LENGTH_MISMATCH;
2430             }
2431             else
2432             {
2433                 SYSDBG_IO_SPACE Request = *(PSYSDBG_IO_SPACE)InputBuffer;
2434                 PVOID LockedBuffer;
2435                 PMDL LockVariable;
2436 
2437                 Status = ExLockUserBuffer(Request.Buffer,
2438                                           Request.Request,
2439                                           PreviousMode,
2440                                           IoWriteAccess,
2441                                           &LockedBuffer,
2442                                           &LockVariable);
2443                 if (NT_SUCCESS(Status))
2444                 {
2445                     Status = KdpSysReadIoSpace(Request.InterfaceType,
2446                                                Request.BusNumber,
2447                                                Request.AddressSpace,
2448                                                Request.Address,
2449                                                LockedBuffer,
2450                                                Request.Request,
2451                                                &Length);
2452                     ExUnlockUserBuffer(LockVariable);
2453                 }
2454             }
2455             break;
2456 
2457         case SysDbgWriteIoSpace:
2458             if (InputBufferLength != sizeof(SYSDBG_IO_SPACE))
2459             {
2460                 Status = STATUS_INFO_LENGTH_MISMATCH;
2461             }
2462             else
2463             {
2464                 SYSDBG_IO_SPACE Request = *(PSYSDBG_IO_SPACE)InputBuffer;
2465                 PVOID LockedBuffer;
2466                 PMDL LockVariable;
2467 
2468                 Status = ExLockUserBuffer(Request.Buffer,
2469                                           Request.Request,
2470                                           PreviousMode,
2471                                           IoReadAccess,
2472                                           &LockedBuffer,
2473                                           &LockVariable);
2474                 if (NT_SUCCESS(Status))
2475                 {
2476                     Status = KdpSysWriteIoSpace(Request.InterfaceType,
2477                                                 Request.BusNumber,
2478                                                 Request.AddressSpace,
2479                                                 Request.Address,
2480                                                 LockedBuffer,
2481                                                 Request.Request,
2482                                                 &Length);
2483                     ExUnlockUserBuffer(LockVariable);
2484                 }
2485             }
2486             break;
2487 
2488         case SysDbgReadMsr:
2489             if (InputBufferLength != sizeof(SYSDBG_MSR))
2490             {
2491                 Status = STATUS_INFO_LENGTH_MISMATCH;
2492             }
2493             else
2494             {
2495                 PSYSDBG_MSR Request = (PSYSDBG_MSR)InputBuffer;
2496                 Status = KdpSysReadMsr(Request->Address, &Request->Data);
2497             }
2498             break;
2499 
2500         case SysDbgWriteMsr:
2501             if (InputBufferLength != sizeof(SYSDBG_MSR))
2502             {
2503                 Status = STATUS_INFO_LENGTH_MISMATCH;
2504             }
2505             else
2506             {
2507                 PSYSDBG_MSR Request = (PSYSDBG_MSR)InputBuffer;
2508                 Status = KdpSysWriteMsr(Request->Address, &Request->Data);
2509             }
2510             break;
2511 
2512         case SysDbgReadBusData:
2513             if (InputBufferLength != sizeof(SYSDBG_BUS_DATA))
2514             {
2515                 Status = STATUS_INFO_LENGTH_MISMATCH;
2516             }
2517             else
2518             {
2519                 SYSDBG_BUS_DATA Request = *(PSYSDBG_BUS_DATA)InputBuffer;
2520                 PVOID LockedBuffer;
2521                 PMDL LockVariable;
2522 
2523                 Status = ExLockUserBuffer(Request.Buffer,
2524                                           Request.Request,
2525                                           PreviousMode,
2526                                           IoWriteAccess,
2527                                           &LockedBuffer,
2528                                           &LockVariable);
2529                 if (NT_SUCCESS(Status))
2530                 {
2531                     Status = KdpSysReadBusData(Request.BusDataType,
2532                                                Request.BusNumber,
2533                                                Request.SlotNumber,
2534                                                Request.Address,
2535                                                LockedBuffer,
2536                                                Request.Request,
2537                                                &Length);
2538                     ExUnlockUserBuffer(LockVariable);
2539                 }
2540             }
2541             break;
2542 
2543         case SysDbgWriteBusData:
2544             if (InputBufferLength != sizeof(SYSDBG_BUS_DATA))
2545             {
2546                 Status = STATUS_INFO_LENGTH_MISMATCH;
2547             }
2548             else
2549             {
2550                 SYSDBG_BUS_DATA Request = *(PSYSDBG_BUS_DATA)InputBuffer;
2551                 PVOID LockedBuffer;
2552                 PMDL LockVariable;
2553 
2554                 Status = ExLockUserBuffer(Request.Buffer,
2555                                           Request.Request,
2556                                           PreviousMode,
2557                                           IoReadAccess,
2558                                           &LockedBuffer,
2559                                           &LockVariable);
2560                 if (NT_SUCCESS(Status))
2561                 {
2562                     Status = KdpSysWriteBusData(Request.BusDataType,
2563                                                 Request.BusNumber,
2564                                                 Request.SlotNumber,
2565                                                 Request.Address,
2566                                                 LockedBuffer,
2567                                                 Request.Request,
2568                                                 &Length);
2569                     ExUnlockUserBuffer(LockVariable);
2570                 }
2571             }
2572             break;
2573 
2574         case SysDbgCheckLowMemory:
2575             Status = KdpSysCheckLowMemory(0);
2576             break;
2577 
2578         default:
2579             Status = STATUS_INVALID_INFO_CLASS;
2580             break;
2581     }
2582 
2583     if (ReturnLength)
2584         *ReturnLength = Length;
2585 
2586     return Status;
2587 }
2588 
2589 /*
2590  * @implemented
2591  */
2592 NTSTATUS
2593 NTAPI
KdChangeOption(IN KD_OPTION Option,IN ULONG InBufferBytes OPTIONAL,IN PVOID InBuffer,IN ULONG OutBufferBytes OPTIONAL,OUT PVOID OutBuffer,OUT PULONG OutBufferNeeded OPTIONAL)2594 KdChangeOption(IN KD_OPTION Option,
2595                IN ULONG InBufferBytes OPTIONAL,
2596                IN PVOID InBuffer,
2597                IN ULONG OutBufferBytes OPTIONAL,
2598                OUT PVOID OutBuffer,
2599                OUT PULONG OutBufferNeeded OPTIONAL)
2600 {
2601     /* Fail if there is no debugger */
2602     if (KdPitchDebugger)
2603     {
2604         /* No debugger, no options */
2605         return STATUS_DEBUGGER_INACTIVE;
2606     }
2607 
2608     /* Do we recognize this option? */
2609     if (Option != KD_OPTION_SET_BLOCK_ENABLE)
2610     {
2611         /* We don't, clear the output length and fail */
2612         if (OutBufferNeeded) *OutBufferNeeded = 0;
2613         return STATUS_INVALID_INFO_CLASS;
2614     }
2615 
2616     /* Verify parameters */
2617     if ((InBufferBytes != sizeof(BOOLEAN)) ||
2618         (OutBufferBytes != 0) ||
2619         (OutBuffer != NULL))
2620     {
2621         /* Invalid parameters for this option, fail */
2622         return STATUS_INVALID_PARAMETER;
2623     }
2624 
2625     /*
2626      * Check if the high bit is set, meaning we don't
2627      * allow the debugger to be enabled
2628      */
2629     if (KdBlockEnable & 0x80)
2630     {
2631         /* Fail regardless of what state the caller tried to set */
2632         return STATUS_ACCESS_VIOLATION;
2633     }
2634 
2635     /* Set the new block enable state */
2636     KdBlockEnable = *(PBOOLEAN)InBuffer;
2637 
2638     /* No output buffer required for this option */
2639     if (OutBufferNeeded) *OutBufferNeeded = 0;
2640 
2641     /* We are done */
2642     return STATUS_SUCCESS;
2643 }
2644 
2645 /*
2646  * @implemented
2647  */
2648 NTSTATUS
2649 NTAPI
KdPowerTransition(IN DEVICE_POWER_STATE NewState)2650 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
2651 {
2652     /* Check what power state this is */
2653     if (NewState == PowerDeviceD0)
2654     {
2655         /* Wake up the debug port */
2656         KdD0Transition();
2657         return STATUS_SUCCESS;
2658     }
2659     else if ((NewState == PowerDeviceD1) ||
2660              (NewState == PowerDeviceD2) ||
2661              (NewState == PowerDeviceD3))
2662     {
2663         /* Power down the debug port */
2664         KdD3Transition();
2665         return STATUS_SUCCESS;
2666     }
2667     else
2668     {
2669         /* Invalid state! */
2670         return STATUS_INVALID_PARAMETER_1;
2671     }
2672 }
2673 
2674 /*
2675  * @implemented
2676  */
2677 BOOLEAN
2678 NTAPI
KdRefreshDebuggerNotPresent(VOID)2679 KdRefreshDebuggerNotPresent(VOID)
2680 {
2681     BOOLEAN Enable, DebuggerNotPresent;
2682 
2683     /* Check if the debugger is completely disabled */
2684     if (KdPitchDebugger)
2685     {
2686         /* Don't try to refresh then, fail early */
2687         return TRUE;
2688     }
2689 
2690     /* Enter the debugger */
2691     Enable = KdEnterDebugger(NULL, NULL);
2692 
2693     /*
2694      * Attempt to send a string to the debugger
2695      * to refresh the connection state.
2696      */
2697     KdpDprintf("KDTARGET: Refreshing KD connection\n");
2698 
2699     /* Save the state while we are holding the lock */
2700     DebuggerNotPresent = KdDebuggerNotPresent;
2701 
2702     /* Exit the debugger and return the state */
2703     KdExitDebugger(Enable);
2704     return DebuggerNotPresent;
2705 }
2706 
2707 /*
2708  * @implemented
2709  */
2710 NTSTATUS
2711 NTAPI
NtQueryDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level)2712 NtQueryDebugFilterState(
2713     _In_ ULONG ComponentId,
2714     _In_ ULONG Level)
2715 {
2716     PULONG Mask;
2717 
2718     /* Check if the ID fits in the component table */
2719     if (ComponentId < KdComponentTableSize)
2720     {
2721         /* It does, so get the mask from there */
2722         Mask = KdComponentTable[ComponentId];
2723     }
2724     else if (ComponentId == MAXULONG)
2725     {
2726         /*
2727          * This is the internal ID used for DbgPrint messages without ID
2728          * and Level. Use the system-wide mask for those.
2729          */
2730         Mask = &Kd_WIN2000_Mask;
2731     }
2732     else
2733     {
2734 #if (NTDDI_VERSION >= NTDDI_VISTA)
2735         /* Use the default component ID */
2736         Mask = &Kd_DEFAULT_Mask;
2737         // Level = DPFLTR_INFO_LEVEL; // Override the Level.
2738 #else
2739         /* Invalid ID, fail */
2740         return STATUS_INVALID_PARAMETER_1;
2741 #endif
2742     }
2743 
2744     /* Convert Level to bit field if required */
2745     if (Level < 32) Level = 1 << Level;
2746     Level &= ~DPFLTR_MASK;
2747 
2748     /* Determine if this Level is filtered out */
2749     if ((Kd_WIN2000_Mask & Level) || (*Mask & Level))
2750     {
2751         /* This mask will get through to the debugger */
2752         return (NTSTATUS)TRUE;
2753     }
2754     else
2755     {
2756         /* This mask is filtered out */
2757         return (NTSTATUS)FALSE;
2758     }
2759 }
2760 
2761 /*
2762  * @implemented
2763  */
2764 NTSTATUS
2765 NTAPI
NtSetDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level,_In_ BOOLEAN State)2766 NtSetDebugFilterState(
2767     _In_ ULONG ComponentId,
2768     _In_ ULONG Level,
2769     _In_ BOOLEAN State)
2770 {
2771     PULONG Mask;
2772 
2773     /* Modifying debug filters requires the debug privilege */
2774     if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
2775     {
2776         /* Fail */
2777         return STATUS_ACCESS_DENIED;
2778     }
2779 
2780     /* Check if the ID fits in the component table */
2781     if (ComponentId < KdComponentTableSize)
2782     {
2783         /* It does, so get the mask from there */
2784         Mask = KdComponentTable[ComponentId];
2785     }
2786     else if (ComponentId == MAXULONG)
2787     {
2788         /*
2789          * This is the internal ID used for DbgPrint messages without ID
2790          * and Level. Use the system-wide mask for those.
2791          */
2792         Mask = &Kd_WIN2000_Mask;
2793     }
2794     else
2795     {
2796 #if (NTDDI_VERSION >= NTDDI_VISTA)
2797         /* Use the default component ID */
2798         Mask = &Kd_DEFAULT_Mask;
2799 #else
2800         /* Invalid ID, fail */
2801         return STATUS_INVALID_PARAMETER_1;
2802 #endif
2803     }
2804 
2805     /* Convert Level to bit field if required */
2806     if (Level < 32) Level = 1 << Level;
2807     Level &= ~DPFLTR_MASK;
2808 
2809     /* Set or remove the Level */
2810     if (State)
2811         *Mask |= Level;
2812     else
2813         *Mask &= ~Level;
2814 
2815     return STATUS_SUCCESS;
2816 }
2817