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