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