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