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)
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
19 KdpSetCommonState(IN ULONG NewState
,
21 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange
)
23 USHORT InstructionCount
;
24 BOOLEAN HadBreakpoints
;
26 /* Setup common stuff available for all CPU architectures */
27 WaitStateChange
->NewState
= NewState
;
28 WaitStateChange
->ProcessorLevel
= KeProcessorLevel
;
29 WaitStateChange
->Processor
= (USHORT
)KeGetCurrentPrcb()->Number
;
30 WaitStateChange
->NumberProcessors
= (ULONG
)KeNumberProcessors
;
31 WaitStateChange
->Thread
= (ULONG
)KeGetCurrentThread();
32 WaitStateChange
->ProgramCounter
= (ULONG64
)Context
->Eip
;
34 /* Zero out the Control Report */
35 RtlZeroMemory(&WaitStateChange
->ControlReport
,
36 sizeof(DBGKD_CONTROL_REPORT
));
38 /* Now copy the instruction stream and set the count */
39 RtlCopyMemory(&WaitStateChange
->ControlReport
.InstructionStream
[0],
40 (PVOID
)(ULONG_PTR
)WaitStateChange
->ProgramCounter
,
42 InstructionCount
= DBGKD_MAXSTREAM
;
43 WaitStateChange
->ControlReport
.InstructionCount
= InstructionCount
;
45 /* Clear all the breakpoints in this region */
46 HadBreakpoints
= FALSE
;
48 KdpDeleteBreakpointRange((PVOID
)WaitStateChange
->ProgramCounter
,
49 (PVOID
)(WaitStateChange
->ProgramCounter
+
50 WaitStateChange
->ControlReport
.
51 InstructionCount
- 1));
55 /* Copy the instruction stream again, this time without breakpoints */
56 RtlCopyMemory(&WaitStateChange
->ControlReport
.InstructionStream
[0],
57 (PVOID
)(ULONG_PTR
)WaitStateChange
->ProgramCounter
,
58 WaitStateChange
->ControlReport
.InstructionCount
);
64 KdpSetContextState(IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange
,
67 PKPRCB Prcb
= KeGetCurrentPrcb();
69 /* Copy i386 specific debug registers */
70 WaitStateChange
->ControlReport
.Dr6
= Prcb
->ProcessorState
.SpecialRegisters
.
72 WaitStateChange
->ControlReport
.Dr7
= Prcb
->ProcessorState
.SpecialRegisters
.
75 /* Copy i386 specific segments */
76 WaitStateChange
->ControlReport
.SegCs
= (USHORT
)Context
->SegCs
;
77 WaitStateChange
->ControlReport
.SegDs
= (USHORT
)Context
->SegDs
;
78 WaitStateChange
->ControlReport
.SegEs
= (USHORT
)Context
->SegEs
;
79 WaitStateChange
->ControlReport
.SegFs
= (USHORT
)Context
->SegFs
;
82 WaitStateChange
->ControlReport
.EFlags
= Context
->EFlags
;
84 /* Set Report Flags */
85 WaitStateChange
->ControlReport
.ReportFlags
= REPORT_INCLUDES_SEGS
;
86 if (WaitStateChange
->ControlReport
.SegCs
== KGDT_R0_CODE
)
88 WaitStateChange
->ControlReport
.ReportFlags
= REPORT_INCLUDES_CS
;
94 KdpSendWaitContinue(IN ULONG PacketType
,
95 IN PSTRING SendHeader
,
96 IN PSTRING SendData OPTIONAL
,
97 IN OUT PCONTEXT ContextRecord
)
100 DBGKD_MANIPULATE_STATE64 ManipulateState
;
104 /* Setup the Manipulate State structure */
105 Header
.MaximumLength
= sizeof(DBGKD_MANIPULATE_STATE64
);
106 Header
.Buffer
= (PCHAR
)&ManipulateState
;
107 Data
.MaximumLength
= sizeof(KdpMessageBuffer
);
108 Data
.Buffer
= KdpMessageBuffer
;
109 //KdpContextSent = FALSE;
112 /* Send the Packet */
113 KdSendPacket(PacketType
, SendHeader
, SendData
, &KdpContext
);
115 /* If the debugger isn't present anymore, just return success */
116 if (KdDebuggerNotPresent
) return TRUE
;
118 /* Main processing Loop */
124 /* Wait to get a reply to our packet */
125 ManipulateState
.ApiNumber
= 0xFFFFFFFF;
126 RecvCode
= KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE
,
132 /* If we got a resend request, do it */
133 if (RecvCode
== KdPacketNeedsResend
) goto SendPacket
;
134 } while (RecvCode
== KdPacketTimedOut
);
136 /* Now check what API we got */
137 switch (ManipulateState
.ApiNumber
)
139 case DbgKdReadVirtualMemoryApi
:
142 Ke386SetCr2(DbgKdReadVirtualMemoryApi
);
146 case DbgKdWriteVirtualMemoryApi
:
149 Ke386SetCr2(DbgKdWriteVirtualMemoryApi
);
153 case DbgKdGetContextApi
:
156 Ke386SetCr2(DbgKdGetContextApi
);
160 case DbgKdSetContextApi
:
163 Ke386SetCr2(DbgKdSetContextApi
);
167 case DbgKdWriteBreakPointApi
:
170 Ke386SetCr2(DbgKdWriteBreakPointApi
);
174 case DbgKdRestoreBreakPointApi
:
177 Ke386SetCr2(DbgKdRestoreBreakPointApi
);
181 case DbgKdContinueApi
:
184 Ke386SetCr2(DbgKdContinueApi
);
188 case DbgKdReadControlSpaceApi
:
191 Ke386SetCr2(DbgKdReadControlSpaceApi
);
195 case DbgKdWriteControlSpaceApi
:
198 Ke386SetCr2(DbgKdWriteControlSpaceApi
);
202 case DbgKdReadIoSpaceApi
:
205 Ke386SetCr2(DbgKdReadIoSpaceApi
);
209 case DbgKdWriteIoSpaceApi
:
212 Ke386SetCr2(DbgKdWriteIoSpaceApi
);
219 Ke386SetCr2(DbgKdRebootApi
);
223 case DbgKdContinueApi2
:
226 Ke386SetCr2(DbgKdContinueApi2
);
230 case DbgKdReadPhysicalMemoryApi
:
233 Ke386SetCr2(DbgKdReadPhysicalMemoryApi
);
237 case DbgKdWritePhysicalMemoryApi
:
240 Ke386SetCr2(DbgKdWritePhysicalMemoryApi
);
244 case DbgKdQuerySpecialCallsApi
:
247 Ke386SetCr2(DbgKdQuerySpecialCallsApi
);
251 case DbgKdSetSpecialCallApi
:
254 Ke386SetCr2(DbgKdSetSpecialCallApi
);
258 case DbgKdClearSpecialCallsApi
:
261 Ke386SetCr2(DbgKdClearSpecialCallsApi
);
265 case DbgKdSetInternalBreakPointApi
:
268 Ke386SetCr2(DbgKdSetInternalBreakPointApi
);
272 case DbgKdGetInternalBreakPointApi
:
275 Ke386SetCr2(DbgKdGetInternalBreakPointApi
);
279 case DbgKdReadIoSpaceExtendedApi
:
282 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi
);
286 case DbgKdWriteIoSpaceExtendedApi
:
289 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi
);
293 case DbgKdGetVersionApi
:
296 Ke386SetCr2(DbgKdGetVersionApi
);
300 case DbgKdWriteBreakPointExApi
:
303 Ke386SetCr2(DbgKdWriteBreakPointExApi
);
307 case DbgKdRestoreBreakPointExApi
:
310 Ke386SetCr2(DbgKdRestoreBreakPointExApi
);
314 case DbgKdCauseBugCheckApi
:
317 Ke386SetCr2(DbgKdCauseBugCheckApi
);
321 case DbgKdSwitchProcessor
:
324 Ke386SetCr2(DbgKdSwitchProcessor
);
331 Ke386SetCr2(DbgKdPageInApi
);
335 case DbgKdReadMachineSpecificRegister
:
338 Ke386SetCr2(DbgKdReadMachineSpecificRegister
);
342 case DbgKdWriteMachineSpecificRegister
:
345 Ke386SetCr2(DbgKdWriteMachineSpecificRegister
);
352 Ke386SetCr2(OldVlm1
);
359 Ke386SetCr2(OldVlm2
);
363 case DbgKdSearchMemoryApi
:
366 Ke386SetCr2(DbgKdSearchMemoryApi
);
370 case DbgKdGetBusDataApi
:
373 Ke386SetCr2(DbgKdGetBusDataApi
);
377 case DbgKdSetBusDataApi
:
380 Ke386SetCr2(DbgKdSetBusDataApi
);
384 case DbgKdCheckLowMemoryApi
:
387 Ke386SetCr2(DbgKdCheckLowMemoryApi
);
391 case DbgKdClearAllInternalBreakpointsApi
:
394 Ke386SetCr2(DbgKdClearAllInternalBreakpointsApi
);
398 case DbgKdFillMemoryApi
:
401 Ke386SetCr2(DbgKdFillMemoryApi
);
405 case DbgKdQueryMemoryApi
:
408 Ke386SetCr2(DbgKdQueryMemoryApi
);
412 case DbgKdSwitchPartition
:
415 Ke386SetCr2(DbgKdSwitchPartition
);
419 /* Unsupported Message */
422 /* Setup an empty message, with failure */
425 ManipulateState
.ReturnStatus
= STATUS_UNSUCCESSFUL
;
428 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE
,
439 KdpReportLoadSymbolsStateChange(IN PSTRING PathName
,
440 IN PKD_SYMBOLS_INFO SymbolInfo
,
442 IN OUT PCONTEXT Context
)
446 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange
;
447 KCONTINUE_STATUS Status
;
449 /* Start wait loop */
452 /* Build the architecture common parts of the message */
453 KdpSetCommonState(DbgKdLoadSymbolsStateChange
,
457 /* Now finish creating the structure */
458 KdpSetContextState(&WaitStateChange
, Context
);
460 /* Fill out load data */
461 WaitStateChange
.u
.LoadSymbols
.UnloadSymbols
= Unload
;
462 WaitStateChange
.u
.LoadSymbols
.BaseOfDll
= (ULONG
)SymbolInfo
->BaseOfDll
;
463 WaitStateChange
.u
.LoadSymbols
.ProcessId
= SymbolInfo
->ProcessId
;
464 WaitStateChange
.u
.LoadSymbols
.CheckSum
= SymbolInfo
->CheckSum
;
465 WaitStateChange
.u
.LoadSymbols
.SizeOfImage
= SymbolInfo
->SizeOfImage
;
467 /* Check if we have a symbol name */
470 /* Setup the information */
471 WaitStateChange
.u
.LoadSymbols
.PathNameLength
= PathName
->Length
;
472 Data
.Buffer
= KdpPathBuffer
;
473 Data
.Length
= WaitStateChange
.u
.LoadSymbols
.PathNameLength
;
479 WaitStateChange
.u
.LoadSymbols
.PathNameLength
= 0;
483 /* Setup the header */
484 Header
.Length
= sizeof(DBGKD_WAIT_STATE_CHANGE64
);
485 Header
.Buffer
= (PCHAR
)&WaitStateChange
;
487 /* Send the packet */
488 Status
= KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64
,
492 } while(Status
== ContinueProcessorReselected
);
501 KdpTimeSlipDpcRoutine(IN PKDPC Dpc
,
502 IN PVOID DeferredContext
,
503 IN PVOID SystemArgument1
,
504 IN PVOID SystemArgument2
)
506 LONG OldSlip
, NewSlip
, PendingSlip
;
508 /* Get the current pending slip */
509 PendingSlip
= KdpTimeSlipPending
;
512 /* Save the old value and either disable or enable it now. */
513 OldSlip
= PendingSlip
;
514 NewSlip
= OldSlip
> 1 ? 1 : 0;
516 /* Try to change the value */
517 } while (InterlockedCompareExchange(&KdpTimeSlipPending
,
519 OldSlip
) != OldSlip
);
521 /* If the New Slip value is 1, then do the Time Slipping */
522 if (NewSlip
) ExQueueWorkItem(&KdpTimeSlipWorkItem
, DelayedWorkQueue
);
527 KdpTimeSlipWork(IN PVOID Context
)
530 LARGE_INTEGER DueTime
;
532 /* Update the System time from the CMOS */
533 ExAcquireTimeRefreshLock(FALSE
);
534 ExUpdateSystemTimeFromCmos(FALSE
, 0);
535 ExReleaseTimeRefreshLock();
537 /* Check if we have a registered Time Slip Event and signal it */
538 KeAcquireSpinLock(&KdpTimeSlipEventLock
, &OldIrql
);
539 if (KdpTimeSlipEvent
) KeSetEvent(KdpTimeSlipEvent
, 0, FALSE
);
540 KeReleaseSpinLock(&KdpTimeSlipEventLock
, OldIrql
);
542 /* Delay the DPC until it runs next time */
543 DueTime
.QuadPart
= -1800000000;
544 KeSetTimer(&KdpTimeSlipTimer
, DueTime
, &KdpTimeSlipDpc
);
549 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord
,
550 IN OUT PCONTEXT ContextRecord
,
551 IN BOOLEAN SecondChanceException
)
555 /* Save the port data */
558 /* Report a state change */
560 Status
= KdpReportExceptionStateChange(ExceptionRecord
,
562 SecondChanceException
);
567 /* Restore the port data and return */
574 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame
)
576 LARGE_INTEGER Null
= {{0}};
578 /* Check if interrupts were disabled */
579 if (!(TrapFrame
->EFlags
& EFLAGS_INTERRUPT_MASK
))
581 /* Nothing to return */
585 /* Otherwise, do the call */
586 return KeQueryPerformanceCounter(NULL
);
591 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame
,
592 IN PKEXCEPTION_FRAME ExceptionFrame
)
596 /* Check if we have a trap frame */
599 /* Calculate the time difference for the enter */
600 KdTimerStop
= KdpQueryPerformanceCounter(TrapFrame
);
601 KdTimerDifference
.QuadPart
= KdTimerStop
.QuadPart
-
602 KdTimerStart
.QuadPart
;
606 /* No trap frame, so can't calculate */
607 KdTimerStop
.QuadPart
= 0;
610 /* Save the current IRQL */
611 KeGetCurrentPrcb()->DebuggerSavedIRQL
= KeGetCurrentIrql();
613 /* Freeze all CPUs */
614 Entered
= KeFreezeExecution(TrapFrame
, ExceptionFrame
);
616 /* Lock the port, save the state and set debugger entered */
617 KdpPortLocked
= KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock
);
619 KdEnteredDebugger
= TRUE
;
621 /* Check freeze flag */
622 if (KiFreezeFlag
& 1)
624 /* Print out errror */
625 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
628 /* Check processor state */
629 if (KiFreezeFlag
& 2)
631 /* Print out errror */
632 DbgPrint("Some processors not frozen in debugger!\n");
635 /* Make sure we acquired the port */
636 if (!KdpPortLocked
) DbgPrint("Port lock was not acquired!\n");
638 /* Return enter state */
644 KdExitDebugger(IN BOOLEAN Entered
)
648 /* Restore the state and unlock the port */
650 if (KdpPortLocked
) KdpPortUnlock();
652 /* Unfreeze the CPUs */
653 KeThawExecution(Entered
);
655 /* Compare time with the one from KdEnterDebugger */
656 if (!KdTimerStop
.QuadPart
)
658 /* We didn't get a trap frame earlier in so never got the time */
659 KdTimerStart
= KdTimerStop
;
663 /* Query the timer */
664 KdTimerStart
= KeQueryPerformanceCounter(NULL
);
667 /* Check if a Time Slip was on queue */
668 TimeSlip
= InterlockedIncrement(&KdpTimeSlipPending
);
671 /* Queue a DPC for the time slip */
672 InterlockedIncrement(&KdpTimeSlipPending
);
673 KeInsertQueueDpc(&KdpTimeSlipDpc
, NULL
, NULL
);
679 KdEnableDebuggerWithLock(BOOLEAN NeedLock
)
683 /* Check if we need to acquire the lock */
687 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
691 /* Check if we're not disabled */
694 /* Check if we had locked the port before */
698 KeLowerIrql(OldIrql
);
702 /* Fail: We're already enabled */
703 return STATUS_INVALID_PARAMETER
;
706 /* Decrease the disable count */
707 if (!(--KdDisableCount
))
709 /* We're now enabled again! Were we enabled before, too? */
710 if (KdPreviouslyEnabled
)
712 /* Reinitialize the Debugger */
713 KdInitSystem(0, NULL
) ;
714 //KdpRestoreAllBreakpoints();
718 /* Check if we had locked the port before */
721 /* Yes, now unlock it */
722 KeLowerIrql(OldIrql
);
727 return STATUS_SUCCESS
;
730 /* PUBLIC FUNCTIONS **********************************************************/
737 KdEnableDebugger(VOID
)
739 /* Use the internal routine */
741 return KdEnableDebuggerWithLock(TRUE
);