Sync with trunk r63831.
[reactos.git] / 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 case 0x315f: // This one is unknown, but used by WinDbg, keep silent!
1358
1359 /* Setup an empty message, with failure */
1360 Data.Length = 0;
1361 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1362
1363 /* Send it */
1364 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1365 &Header,
1366 &Data,
1367 &KdpContext);
1368 break;
1369
1370 /* Unsupported Message */
1371 default:
1372
1373 /* Setup an empty message, with failure */
1374 KdpDprintf("Received Unhandled API %lx\n", ManipulateState.ApiNumber);
1375 Data.Length = 0;
1376 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1377
1378 /* Send it */
1379 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1380 &Header,
1381 &Data,
1382 &KdpContext);
1383 break;
1384 }
1385 }
1386 }
1387
1388 VOID
1389 NTAPI
1390 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
1391 IN PKD_SYMBOLS_INFO SymbolInfo,
1392 IN BOOLEAN Unload,
1393 IN OUT PCONTEXT Context)
1394 {
1395 PSTRING ExtraData;
1396 STRING Data, Header;
1397 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1398 ULONG PathNameLength;
1399 KCONTINUE_STATUS Status;
1400
1401 /* Start wait loop */
1402 do
1403 {
1404 /* Build the architecture common parts of the message */
1405 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1406 Context,
1407 &WaitStateChange);
1408
1409 /* Now finish creating the structure */
1410 KdpSetContextState(&WaitStateChange, Context);
1411
1412 /* Fill out load data */
1413 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1414 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
1415 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1416 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1417 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1418
1419 /* Check if we have a path name */
1420 if (PathName)
1421 {
1422 /* Copy it to the path buffer */
1423 KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
1424 KdpPathBuffer,
1425 PathName->Length,
1426 0,
1427 MMDBG_COPY_UNSAFE,
1428 &PathNameLength);
1429
1430 /* Null terminate */
1431 KdpPathBuffer[PathNameLength++] = ANSI_NULL;
1432
1433 /* Set the path length */
1434 WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
1435
1436 /* Set up the data */
1437 Data.Buffer = KdpPathBuffer;
1438 Data.Length = (USHORT)PathNameLength;
1439 ExtraData = &Data;
1440 }
1441 else
1442 {
1443 /* No name */
1444 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1445 ExtraData = NULL;
1446 }
1447
1448 /* Setup the header */
1449 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1450 Header.Buffer = (PCHAR)&WaitStateChange;
1451
1452 /* Send the packet */
1453 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1454 &Header,
1455 ExtraData,
1456 Context);
1457 } while (Status == ContinueProcessorReselected);
1458 }
1459
1460 VOID
1461 NTAPI
1462 KdpReportCommandStringStateChange(IN PSTRING NameString,
1463 IN PSTRING CommandString,
1464 IN OUT PCONTEXT Context)
1465 {
1466 STRING Header, Data;
1467 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1468 ULONG Length, ActualLength, TotalLength;
1469 KCONTINUE_STATUS Status;
1470
1471 /* Start wait loop */
1472 do
1473 {
1474 /* Build the architecture common parts of the message */
1475 KdpSetCommonState(DbgKdCommandStringStateChange,
1476 Context,
1477 &WaitStateChange);
1478
1479 /* Set the context */
1480 KdpSetContextState(&WaitStateChange, Context);
1481
1482 /* Clear the command string structure */
1483 RtlZeroMemory(&WaitStateChange.u.CommandString,
1484 sizeof(DBGKD_COMMAND_STRING));
1485
1486 /* Normalize name string to max */
1487 Length = min(128 - 1, NameString->Length);
1488
1489 /* Copy it to the message buffer */
1490 KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
1491 KdpMessageBuffer,
1492 Length,
1493 0,
1494 MMDBG_COPY_UNSAFE,
1495 &ActualLength);
1496
1497 /* Null terminate and calculate the total length */
1498 TotalLength = ActualLength;
1499 KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1500
1501 /* Check if the command string is too long */
1502 Length = CommandString->Length;
1503 if (Length > (PACKET_MAX_SIZE -
1504 sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
1505 {
1506 /* Use maximum possible size */
1507 Length = (PACKET_MAX_SIZE -
1508 sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
1509 }
1510
1511 /* Copy it to the message buffer */
1512 KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
1513 KdpMessageBuffer + TotalLength,
1514 Length,
1515 0,
1516 MMDBG_COPY_UNSAFE,
1517 &ActualLength);
1518
1519 /* Null terminate and calculate the total length */
1520 TotalLength += ActualLength;
1521 KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1522
1523 /* Now set up the header and the data */
1524 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1525 Header.Buffer = (PCHAR)&WaitStateChange;
1526 Data.Length = (USHORT)TotalLength;
1527 Data.Buffer = KdpMessageBuffer;
1528
1529 /* Send State Change packet and wait for a reply */
1530 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1531 &Header,
1532 &Data,
1533 Context);
1534 } while (Status == ContinueProcessorReselected);
1535 }
1536
1537 BOOLEAN
1538 NTAPI
1539 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1540 IN OUT PCONTEXT Context,
1541 IN BOOLEAN SecondChanceException)
1542 {
1543 STRING Header, Data;
1544 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1545 KCONTINUE_STATUS Status;
1546
1547 /* Start report loop */
1548 do
1549 {
1550 /* Build the architecture common parts of the message */
1551 KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1552
1553 /* Copy the Exception Record and set First Chance flag */
1554 #if !defined(_WIN64)
1555 ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
1556 &WaitStateChange.u.Exception.ExceptionRecord);
1557 #else
1558 RtlCopyMemory(&WaitStateChange.u.Exception.ExceptionRecord,
1559 ExceptionRecord,
1560 sizeof(EXCEPTION_RECORD));
1561 #endif
1562 WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1563
1564 /* Now finish creating the structure */
1565 KdpSetContextState(&WaitStateChange, Context);
1566
1567 /* Setup the actual header to send to KD */
1568 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1569 Header.Buffer = (PCHAR)&WaitStateChange;
1570
1571 /* Setup the trace data */
1572 DumpTraceData(&Data);
1573
1574 /* Send State Change packet and wait for a reply */
1575 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1576 &Header,
1577 &Data,
1578 Context);
1579 } while (Status == ContinueProcessorReselected);
1580
1581 /* Return */
1582 return Status;
1583 }
1584
1585 VOID
1586 NTAPI
1587 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1588 IN PVOID DeferredContext,
1589 IN PVOID SystemArgument1,
1590 IN PVOID SystemArgument2)
1591 {
1592 LONG OldSlip, NewSlip, PendingSlip;
1593
1594 /* Get the current pending slip */
1595 PendingSlip = KdpTimeSlipPending;
1596 do
1597 {
1598 /* Save the old value and either disable or enable it now. */
1599 OldSlip = PendingSlip;
1600 NewSlip = OldSlip > 1 ? 1 : 0;
1601
1602 /* Try to change the value */
1603 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1604 NewSlip,
1605 OldSlip) != OldSlip);
1606
1607 /* If the New Slip value is 1, then do the Time Slipping */
1608 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1609 }
1610
1611 VOID
1612 NTAPI
1613 KdpTimeSlipWork(IN PVOID Context)
1614 {
1615 KIRQL OldIrql;
1616 LARGE_INTEGER DueTime;
1617
1618 /* Update the System time from the CMOS */
1619 ExAcquireTimeRefreshLock(FALSE);
1620 ExUpdateSystemTimeFromCmos(FALSE, 0);
1621 ExReleaseTimeRefreshLock();
1622
1623 /* Check if we have a registered Time Slip Event and signal it */
1624 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1625 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1626 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1627
1628 /* Delay the DPC until it runs next time */
1629 DueTime.QuadPart = -1800000000;
1630 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1631 }
1632
1633 BOOLEAN
1634 NTAPI
1635 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
1636 IN OUT PCONTEXT ContextRecord,
1637 IN BOOLEAN SecondChanceException)
1638 {
1639 BOOLEAN Status;
1640
1641 /* Save the port data */
1642 KdSave(FALSE);
1643
1644 /* Report a state change */
1645 Status = KdpReportExceptionStateChange(ExceptionRecord,
1646 ContextRecord,
1647 SecondChanceException);
1648
1649 /* Restore the port data and return */
1650 KdRestore(FALSE);
1651 return Status;
1652 }
1653
1654 LARGE_INTEGER
1655 NTAPI
1656 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1657 {
1658 LARGE_INTEGER Null = {{0}};
1659
1660 /* Check if interrupts were disabled */
1661 if (!KeGetTrapFrameInterruptState(TrapFrame))
1662 {
1663 /* Nothing to return */
1664 return Null;
1665 }
1666
1667 /* Otherwise, do the call */
1668 return KeQueryPerformanceCounter(NULL);
1669 }
1670
1671 BOOLEAN
1672 NTAPI
1673 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1674 IN PKEXCEPTION_FRAME ExceptionFrame)
1675 {
1676 BOOLEAN Enable;
1677
1678 /* Check if we have a trap frame */
1679 if (TrapFrame)
1680 {
1681 /* Calculate the time difference for the enter */
1682 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1683 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1684 KdTimerStart.QuadPart;
1685 }
1686 else
1687 {
1688 /* No trap frame, so can't calculate */
1689 KdTimerStop.QuadPart = 0;
1690 }
1691
1692 /* Save the current IRQL */
1693 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1694
1695 /* Freeze all CPUs */
1696 Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
1697
1698 /* Lock the port, save the state and set debugger entered */
1699 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1700 KdSave(FALSE);
1701 KdEnteredDebugger = TRUE;
1702
1703 /* Check freeze flag */
1704 if (KiFreezeFlag & 1)
1705 {
1706 /* Print out errror */
1707 KdpDprintf("FreezeLock was jammed! Backup SpinLock was used!\n");
1708 }
1709
1710 /* Check processor state */
1711 if (KiFreezeFlag & 2)
1712 {
1713 /* Print out errror */
1714 KdpDprintf("Some processors not frozen in debugger!\n");
1715 }
1716
1717 /* Make sure we acquired the port */
1718 if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
1719
1720 /* Return if interrupts needs to be re-enabled */
1721 return Enable;
1722 }
1723
1724 VOID
1725 NTAPI
1726 KdExitDebugger(IN BOOLEAN Enable)
1727 {
1728 ULONG TimeSlip;
1729
1730 /* Restore the state and unlock the port */
1731 KdRestore(FALSE);
1732 if (KdpPortLocked) KdpPortUnlock();
1733
1734 /* Unfreeze the CPUs */
1735 KeThawExecution(Enable);
1736
1737 /* Compare time with the one from KdEnterDebugger */
1738 if (!KdTimerStop.QuadPart)
1739 {
1740 /* We didn't get a trap frame earlier in so never got the time */
1741 KdTimerStart = KdTimerStop;
1742 }
1743 else
1744 {
1745 /* Query the timer */
1746 KdTimerStart = KeQueryPerformanceCounter(NULL);
1747 }
1748
1749 /* Check if a Time Slip was on queue */
1750 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1751 if (TimeSlip == 1)
1752 {
1753 /* Queue a DPC for the time slip */
1754 InterlockedIncrement(&KdpTimeSlipPending);
1755 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches!
1756 }
1757 }
1758
1759 NTSTATUS
1760 NTAPI
1761 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
1762 {
1763 KIRQL OldIrql;
1764
1765 #if defined(__GNUC__)
1766 /* Make gcc happy */
1767 OldIrql = PASSIVE_LEVEL;
1768 #endif
1769
1770 /* Check if enabling the debugger is blocked */
1771 if (KdBlockEnable)
1772 {
1773 /* It is, fail the enable */
1774 return STATUS_ACCESS_DENIED;
1775 }
1776
1777 /* Check if we need to acquire the lock */
1778 if (NeedLock)
1779 {
1780 /* Lock the port */
1781 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1782 KdpPortLock();
1783 }
1784
1785 /* Check if we're not disabled */
1786 if (!KdDisableCount)
1787 {
1788 /* Check if we had locked the port before */
1789 if (NeedLock)
1790 {
1791 /* Do the unlock */
1792 KeLowerIrql(OldIrql);
1793 KdpPortUnlock();
1794
1795 /* Fail: We're already enabled */
1796 return STATUS_INVALID_PARAMETER;
1797 }
1798 else
1799 {
1800 /*
1801 * This can only happen if we are called from a bugcheck
1802 * and were never initialized, so initialize the debugger now.
1803 */
1804 KdInitSystem(0, NULL);
1805
1806 /* Return success since we initialized */
1807 return STATUS_SUCCESS;
1808 }
1809 }
1810
1811 /* Decrease the disable count */
1812 if (!(--KdDisableCount))
1813 {
1814 /* We're now enabled again! Were we enabled before, too? */
1815 if (KdPreviouslyEnabled)
1816 {
1817 /* Reinitialize the Debugger */
1818 KdInitSystem(0, NULL) ;
1819 KdpRestoreAllBreakpoints();
1820 }
1821 }
1822
1823 /* Check if we had locked the port before */
1824 if (NeedLock)
1825 {
1826 /* Yes, now unlock it */
1827 KeLowerIrql(OldIrql);
1828 KdpPortUnlock();
1829 }
1830
1831 /* We're done */
1832 return STATUS_SUCCESS;
1833 }
1834
1835 NTSTATUS
1836 NTAPI
1837 KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
1838 {
1839 KIRQL OldIrql;
1840 NTSTATUS Status;
1841
1842 #if defined(__GNUC__)
1843 /* Make gcc happy */
1844 OldIrql = PASSIVE_LEVEL;
1845 #endif
1846
1847 /*
1848 * If enabling the debugger is blocked
1849 * then there is nothing to disable (duh)
1850 */
1851 if (KdBlockEnable)
1852 {
1853 /* Fail */
1854 return STATUS_ACCESS_DENIED;
1855 }
1856
1857 /* Check if we need to acquire the lock */
1858 if (NeedLock)
1859 {
1860 /* Lock the port */
1861 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1862 KdpPortLock();
1863 }
1864
1865 /* Check if we're not disabled */
1866 if (!KdDisableCount)
1867 {
1868 /* Check if the debugger was never actually initialized */
1869 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1870 {
1871 /* It wasn't, so don't re-enable it later */
1872 KdPreviouslyEnabled = FALSE;
1873 }
1874 else
1875 {
1876 /* It was, so we will re-enable it later */
1877 KdPreviouslyEnabled = TRUE;
1878 }
1879
1880 /* Check if we were called from the exported API and are enabled */
1881 if ((NeedLock) && (KdPreviouslyEnabled))
1882 {
1883 /* Check if it is safe to disable the debugger */
1884 Status = KdpAllowDisable();
1885 if (!NT_SUCCESS(Status))
1886 {
1887 /* Release the lock and fail */
1888 KeLowerIrql(OldIrql);
1889 KdpPortUnlock();
1890 return Status;
1891 }
1892 }
1893
1894 /* Only disable the debugger if it is enabled */
1895 if (KdDebuggerEnabled)
1896 {
1897 /*
1898 * Disable the debugger; suspend breakpoints
1899 * and reset the debug stub
1900 */
1901 KdpSuspendAllBreakPoints();
1902 KiDebugRoutine = KdpStub;
1903
1904 /* We are disabled now */
1905 KdDebuggerEnabled = FALSE;
1906 SharedUserData->KdDebuggerEnabled = FALSE;
1907 }
1908 }
1909
1910 /* Increment the disable count */
1911 KdDisableCount++;
1912
1913 /* Check if we had locked the port before */
1914 if (NeedLock)
1915 {
1916 /* Yes, now unlock it */
1917 KeLowerIrql(OldIrql);
1918 KdpPortUnlock();
1919 }
1920
1921 /* We're done */
1922 return STATUS_SUCCESS;
1923 }
1924
1925 /* PUBLIC FUNCTIONS **********************************************************/
1926
1927 /*
1928 * @implemented
1929 */
1930 NTSTATUS
1931 NTAPI
1932 KdEnableDebugger(VOID)
1933 {
1934 /* Use the internal routine */
1935 return KdEnableDebuggerWithLock(TRUE);
1936 }
1937
1938 /*
1939 * @implemented
1940 */
1941 NTSTATUS
1942 NTAPI
1943 KdDisableDebugger(VOID)
1944 {
1945 /* Use the internal routine */
1946 return KdDisableDebuggerWithLock(TRUE);
1947 }
1948
1949 /*
1950 * @unimplemented
1951 */
1952 NTSTATUS
1953 NTAPI
1954 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
1955 IN PVOID InputBuffer,
1956 IN ULONG InputBufferLength,
1957 OUT PVOID OutputBuffer,
1958 IN ULONG OutputBufferLength,
1959 IN OUT PULONG ReturnLength,
1960 IN KPROCESSOR_MODE PreviousMode)
1961 {
1962 /* handle sime internal commands */
1963 if (Command == ' soR')
1964 {
1965 switch ((ULONG_PTR)InputBuffer)
1966 {
1967 case 0x24:
1968 MmDumpArmPfnDatabase(FALSE);
1969 break;
1970 }
1971 return STATUS_SUCCESS;
1972 }
1973
1974 /* Local kernel debugging is not yet supported */
1975 DbgPrint("KdSystemDebugControl is unimplemented!\n");
1976 return STATUS_NOT_IMPLEMENTED;
1977 }
1978
1979 /*
1980 * @implemented
1981 */
1982 NTSTATUS
1983 NTAPI
1984 KdChangeOption(IN KD_OPTION Option,
1985 IN ULONG InBufferBytes OPTIONAL,
1986 IN PVOID InBuffer,
1987 IN ULONG OutBufferBytes OPTIONAL,
1988 OUT PVOID OutBuffer,
1989 OUT PULONG OutBufferNeeded OPTIONAL)
1990 {
1991 /* Fail if there is no debugger */
1992 if (KdPitchDebugger)
1993 {
1994 /* No debugger, no options */
1995 return STATUS_DEBUGGER_INACTIVE;
1996 }
1997
1998 /* Do we recognize this option? */
1999 if (Option != KD_OPTION_SET_BLOCK_ENABLE)
2000 {
2001 /* We don't, clear the output length and fail */
2002 if (OutBufferNeeded) *OutBufferNeeded = 0;
2003 return STATUS_INVALID_INFO_CLASS;
2004 }
2005
2006 /* Verify parameters */
2007 if ((InBufferBytes != sizeof(BOOLEAN)) ||
2008 (OutBufferBytes != 0) ||
2009 (OutBuffer != NULL))
2010 {
2011 /* Invalid parameters for this option, fail */
2012 return STATUS_INVALID_PARAMETER;
2013 }
2014
2015 /*
2016 * Check if the high bit is set, meaning we don't
2017 * allow the debugger to be enabled
2018 */
2019 if (KdBlockEnable & 0x80)
2020 {
2021 /* Fail regardless of what state the caller tried to set */
2022 return STATUS_ACCESS_VIOLATION;
2023 }
2024
2025 /* Set the new block enable state */
2026 KdBlockEnable = *(PBOOLEAN)InBuffer;
2027
2028 /* No output buffer required for this option */
2029 if (OutBufferNeeded) *OutBufferNeeded = 0;
2030
2031 /* We are done */
2032 return STATUS_SUCCESS;
2033 }
2034
2035 /*
2036 * @implemented
2037 */
2038 NTSTATUS
2039 NTAPI
2040 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
2041 {
2042 /* Check what power state this is */
2043 if (NewState == PowerDeviceD0)
2044 {
2045 /* Wake up the debug port */
2046 KdD0Transition();
2047 return STATUS_SUCCESS;
2048 }
2049 else if ((NewState == PowerDeviceD1) ||
2050 (NewState == PowerDeviceD2) ||
2051 (NewState == PowerDeviceD3))
2052 {
2053 /* Power down the debug port */
2054 KdD3Transition();
2055 return STATUS_SUCCESS;
2056 }
2057 else
2058 {
2059 /* Invalid state! */
2060 return STATUS_INVALID_PARAMETER_1;
2061 }
2062 }
2063
2064 /*
2065 * @implemented
2066 */
2067 BOOLEAN
2068 NTAPI
2069 KdRefreshDebuggerNotPresent(VOID)
2070 {
2071 BOOLEAN Enable, DebuggerNotPresent;
2072
2073 /* Check if the debugger is completely disabled */
2074 if (KdPitchDebugger)
2075 {
2076 /* Don't try to refresh then -- fail early */
2077 return TRUE;
2078 }
2079
2080 /* Enter the debugger */
2081 Enable = KdEnterDebugger(NULL, NULL);
2082
2083 /*
2084 * Attempt to send a string to the debugger to refresh the
2085 * connection state
2086 */
2087 KdpDprintf("KDTARGET: Refreshing KD connection\n");
2088
2089 /* Save the state while we are holding the lock */
2090 DebuggerNotPresent = KdDebuggerNotPresent;
2091
2092 /* Exit the debugger and return the state */
2093 KdExitDebugger(Enable);
2094 return DebuggerNotPresent;
2095 }
2096
2097 /*
2098 * @implemented
2099 */
2100 NTSTATUS
2101 NTAPI
2102 NtQueryDebugFilterState(IN ULONG ComponentId,
2103 IN ULONG Level)
2104 {
2105 PULONG Mask;
2106
2107 /* Check if the ID fits in the component table */
2108 if (ComponentId < KdComponentTableSize)
2109 {
2110 /* It does, so get the mask from there */
2111 Mask = KdComponentTable[ComponentId];
2112 }
2113 else if (ComponentId == MAXULONG)
2114 {
2115 /*
2116 * This is the internal ID used for DbgPrint messages without ID and
2117 * Level. Use the system-wide mask for those.
2118 */
2119 Mask = &Kd_WIN2000_Mask;
2120 }
2121 else
2122 {
2123 /* Invalid ID, fail */
2124 return STATUS_INVALID_PARAMETER_1;
2125 }
2126
2127 /* Convert Level to bit field if necessary */
2128 if (Level < 32) Level = 1 << Level;
2129
2130 /* Determine if this Level is filtered out */
2131 if ((Kd_WIN2000_Mask & Level) ||
2132 (*Mask & Level))
2133 {
2134 /* This mask will get through to the debugger */
2135 return (NTSTATUS)TRUE;
2136 }
2137 else
2138 {
2139 /* This mask is filtered out */
2140 return (NTSTATUS)FALSE;
2141 }
2142 }
2143
2144 /*
2145 * @implemented
2146 */
2147 NTSTATUS
2148 NTAPI
2149 NtSetDebugFilterState(IN ULONG ComponentId,
2150 IN ULONG Level,
2151 IN BOOLEAN State)
2152 {
2153 PULONG Mask;
2154
2155 /* Modifying debug filters requires the debug privilege */
2156 if (!SeSinglePrivilegeCheck(SeDebugPrivilege,
2157 ExGetPreviousMode()))
2158 {
2159 /* Fail */
2160 return STATUS_ACCESS_DENIED;
2161 }
2162
2163 /* Check if the ID fits in the component table */
2164 if (ComponentId < KdComponentTableSize)
2165 {
2166 /* It does, so get the mask from there */
2167 Mask = KdComponentTable[ComponentId];
2168 }
2169 else if (ComponentId == MAXULONG)
2170 {
2171 /*
2172 * This is the internal ID used for DbgPrint messages without ID and
2173 * Level. Use the system-wide mask for those.
2174 */
2175 Mask = &Kd_WIN2000_Mask;
2176 }
2177 else
2178 {
2179 /* Invalid ID, fail */
2180 return STATUS_INVALID_PARAMETER_1;
2181 }
2182
2183 /* Convert Level to bit field if required */
2184 if (Level < 32) Level = 1 << Level;
2185
2186 /* Check what kind of operation this is */
2187 if (State)
2188 {
2189 /* Set the Level */
2190 *Mask |= Level;
2191 }
2192 else
2193 {
2194 /* Remove the Level */
2195 *Mask &= ~Level;
2196 }
2197
2198 /* Success */
2199 return STATUS_SUCCESS;
2200 }