reactos/reactos/ntoskrnl/kd64/i386/kdsup.c

430 lines
12 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/kd64/i386/kdsup.c
* PURPOSE: KD support routines for x86
- Replace RtlpGetExceptionAddress by the _ReturnAddress intrinsic and add it to ARM intrin.h as it was missing. - Simplify RtlpCheckForActiveDebugger: Remove the BOOLEAN parameter as we would always pass it FALSE. Always return FALSE false from kernel mode for simplicity. - Fix a critical flaw in our exception support: RtlRaiseException and RtlRaiseStatus were implemented in C on x86. This lead to unpredictable register corruption because the compiler could not know that it had to preserve non-volatile registers before calling RtlCaptureContext as the saved context is later used to restore the caller in case the exception is handled and execution is continued. This made the functions unsafe to return from as any non-volatile register could be corrupted. Implement them in assembly for x86 to safely capture the context using only EBP and ESP. The C versions of those routines are still used and shared for the other architectures we support -- needs to be determined if this is safe and correct for those architectures. - The ntdll exception Wine exposed this issue, and all tests now pass. The remaining failures on the build server are caused by missing or incomplete debug register support in KVM/QEMU. Run the test in another VM or on real hardware and all the tests will pass. - Implement Debug Prompt (DbgPrompt) support for KD and KDBG. The KDBG implementation reads the prompt from keyboard or serial depending on the mode so that sysreg and rosdbg can support it too. - Properly implement RtlAssert using DbgPrompt to prompt for the action to take instead of always doing a breakpoint. The new implementation is disabled until sysreg can support this. Also move RtlAssert to its own file as it has nothing to do with the error routines (nor does it belong in exception.c). - Note that DbgPrompt was already used in PspCatchCriticalBreak, and this would have resulted in a silent hang as BREAKPOINT_PROMPT wasn't handled at all by KDBG. - Implement KiRaiseAssertion (10 lines of code with the trap macros) and thus support NT_ASSERT. Add partial support for it to KDBG to print out a warning and the address of the failure, but don't do anything else. Also add NT_ASSERT to the DDK headers so that we can use it, but don't use it yet as the ARM method of performing this has not been decided nor implemented. - KiTrap3 doesn't set STATUS_SUCCESS but BREAKPOINT_BREAK. They have the same numerical value but very different meaning -- BREAKPOINT_BREAK means that the exception is a software breakpoint and not a debug service call. Fix some comments to document that this is what is checked for. - Fix inverted and broken logic in KdpReport. It would never pass second chance exceptions to the debugger, didn't respect the stop-on-exception flag properly and would always fail to handle some special exceptions in both first and second chance instead of just failing to handle it in first chance. Clean up, reformat and document what is going on. - The DebugPrint and DebugPrompt support routines only perform a 2D interrupt on x86; use more portable comments. - Add Alex to the programmer section of x86's kdsup.c -- he wrote KdpGetStateChange, KdpSetContextState and the code that was previously in KdpRead/WriteControlSpace. - Add my name to the parts of KD where I have made significant work on getting KD/WinDbg support up and running. - KD debugging is now quite functional and stable. Some bugs and stubs remain to be flushed out, but overall KD is now much better and easier to use than KDBG. svn path=/trunk/; revision=43705
2009-10-23 22:51:39 +00:00
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Stefan Ginsberg (stefan.ginsberg@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
VOID
NTAPI
KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
{
/* Copy the version block */
RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));
}
VOID
NTAPI
KdpGetStateChange(IN PDBGKD_MANIPULATE_STATE64 State,
IN PCONTEXT Context)
{
PKPRCB Prcb;
ULONG i;
/* Check for success */
if (NT_SUCCESS(State->u.Continue2.ContinueStatus))
{
/* Check if we're tracing */
if (State->u.Continue2.ControlSet.TraceFlag)
{
/* Enable TF */
Context->EFlags |= EFLAGS_TF;
}
else
{
/* Remove it */
Context->EFlags &= ~EFLAGS_TF;
}
/* Loop all processors */
for (i = 0; i < KeNumberProcessors; i++)
{
/* Get the PRCB and update DR7 and DR6 */
Prcb = KiProcessorBlock[i];
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
State->u.Continue2.ControlSet.Dr7;
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0;
}
/* Check if we have new symbol information */
if (State->u.Continue2.ControlSet.CurrentSymbolStart != 1)
{
/* Update it */
KdpCurrentSymbolStart =
State->u.Continue2.ControlSet.CurrentSymbolStart;
KdpCurrentSymbolEnd= State->u.Continue2.ControlSet.CurrentSymbolEnd;
}
}
}
VOID
NTAPI
- DBGKD_WAIT_STATE_CHANGE64 is used in KD protocol 5, not number 6 that we use. Protocol 6 uses the DBGKD_ANY_WAIT_STATE_CHANGE structure which is sized according to the largest control-report structure (AMD64_DBGKD_CONTROL_REPORT currently), and is larger than DBGKD_WAIT_STATE_CHANGE64 on x86. This worked because our DBGKD_WAIT_STATE_CHANGE32/64 structures contained incorrect DBGKD_CONTROL_REPORT (used) and CONTEXT (unused) members that sized up the wait-state structure to pass WinDbg's length verification! It actually becomes larger than DBGKD_ANY_WAIT_STATE_CHANGE, but WinDbg only seems bail out only if the structure is too small. Remove the incorrect members from the protocol 5 structures and change to DBGKD_ANY_WAIT_STATE_CHANGE everywhere. - Correct the value of SIZE_OF_FX_REGISTERS -- it was 4 times too low which resulted in KeContextToTrapFrame not properly clearing out the XMM register area. Correct the define and move it out from ke.h to x86's ketypes.h and use it in the FXSAVE format structure. Also remove the IOPM definitions from ke.h as they have been in the NDK for a while. - KD uses STRINGs, not ANSI_STRINGs -- they are the same thing, but let's be consistent. - ExceptionRecord32To64 should be available for both 32 and 64 bit builds (and it shouldn't be a forceinline). Get rid of CopyExceptionRecord and determine if we need to convert or can just copy it directly instead. - Use _WIN64 instead of _M_AMD64 when determining if we need to set the DBGKD_VERS_FLAG_PTR64 flag. - Don't check Nt/DbgQueryDebugFilterState for zero or nonzero -- it actually returns TRUE, FALSE or STATUS_INVALID_PARAMETER_1! Check for != TRUE in preparation for proper implementation of NtSet/QueryDebugFilterState. - Fix Format parameter of DbgPrintReturnControlC -- it is const like the other DbgPrint* routines. - Be consistent with the types used in debug.c and don't set local variables to zero if we are going to return to caller -- this doesn't seem to be required anymore. - Fix DebugService and DebugService2: DebugService should take a ULONG followed by 4 pointers and DebugService2 doesn't return anything. - Use ZwCurrentProcess() instead of -1 or 0xFFFFFFFF (which is incorrect for 64-bit) for the ProcessId parameter of DbgLoad/UnloadImageSymbols to clarify what is being passed. Don't use ZwCurrentProcess() in KeBugCheckWithTf for the pointer parameter of DbgUnLoadImageSymbols either. Use MAXULONG_PTR casted to PVOID instead. - Use better named and sized variables in KdpTrap for setting the "return register" in the caller's CONTEXT. - Correct and clarify the comment documenting under what conditions we pass user mode exceptions to the kernel debugger. svn path=/trunk/; revision=43741
2009-10-25 15:56:38 +00:00
KdpSetContextState(IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
IN PCONTEXT Context)
{
PKPRCB Prcb = KeGetCurrentPrcb();
/* Copy i386 specific debug registers */
WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.
KernelDr6;
WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.
KernelDr7;
/* Copy i386 specific segments */
WaitStateChange->ControlReport.SegCs = (USHORT)Context->SegCs;
WaitStateChange->ControlReport.SegDs = (USHORT)Context->SegDs;
WaitStateChange->ControlReport.SegEs = (USHORT)Context->SegEs;
WaitStateChange->ControlReport.SegFs = (USHORT)Context->SegFs;
/* Copy EFlags */
WaitStateChange->ControlReport.EFlags = Context->EFlags;
/* Set Report Flags */
WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS;
if (WaitStateChange->ControlReport.SegCs == KGDT_R0_CODE)
{
WaitStateChange->ControlReport.ReportFlags |= REPORT_STANDARD_CS;
}
}
NTSTATUS
NTAPI
KdpSysReadMsr(IN ULONG Msr,
OUT PLARGE_INTEGER MsrValue)
{
/* Wrap this in SEH in case the MSR doesn't exist */
//_SEH2_TRY
{
/* Read from the MSR */
MsrValue->QuadPart = RDMSR(Msr);
}
//_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Invalid MSR */
//_SEH2_YIELD(return STATUS_NO_SUCH_DEVICE);
}
//_SEH2_END;
/* Success */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdpSysWriteMsr(IN ULONG Msr,
IN PLARGE_INTEGER MsrValue)
{
/* Wrap this in SEH in case the MSR doesn't exist */
//_SEH2_TRY
{
/* Write to the MSR */
WRMSR(Msr, MsrValue->QuadPart);
}
//_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Invalid MSR */
//_SEH2_YIELD(return STATUS_NO_SUCH_DEVICE);
}
//_SEH2_END;
/* Success */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdpSysReadBusData(IN ULONG BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN ULONG Offset,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG ActualLength)
{
/* Just forward to HAL */
*ActualLength = HalGetBusDataByOffset(BusDataType,
BusNumber,
SlotNumber,
Buffer,
Offset,
Length);
/* Return status */
return (*ActualLength != 0) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS
NTAPI
KdpSysWriteBusData(IN ULONG BusDataType,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN ULONG Offset,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG ActualLength)
{
/* Just forward to HAL */
*ActualLength = HalSetBusDataByOffset(BusDataType,
BusNumber,
SlotNumber,
Buffer,
Offset,
Length);
/* Return status */
return (*ActualLength != 0) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS
NTAPI
KdpSysReadControlSpace(IN ULONG Processor,
IN ULONG64 BaseAddress,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG ActualLength)
{
PVOID ControlStart;
ULONG RealLength;
/* Make sure that this is a valid request */
if ((BaseAddress < sizeof(KPROCESSOR_STATE)) &&
(Processor < KeNumberProcessors))
{
/* Get the actual length */
RealLength = sizeof(KPROCESSOR_STATE) - (ULONG_PTR)BaseAddress;
if (RealLength < Length) Length = RealLength;
/* Set the proper address */
ControlStart = (PVOID)((ULONG_PTR)BaseAddress +
(ULONG_PTR)&KiProcessorBlock[Processor]->
ProcessorState);
/* Copy the memory */
RtlCopyMemory(Buffer, ControlStart, Length);
/* Finish up */
*ActualLength = Length;
return STATUS_SUCCESS;
}
else
{
/* Invalid request */
*ActualLength = 0;
return STATUS_UNSUCCESSFUL;
}
}
NTSTATUS
NTAPI
KdpSysWriteControlSpace(IN ULONG Processor,
IN ULONG64 BaseAddress,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG ActualLength)
{
PVOID ControlStart;
/* Make sure that this is a valid request */
if (((BaseAddress + Length) <= sizeof(KPROCESSOR_STATE)) &&
(Processor < KeNumberProcessors))
{
/* Set the proper address */
ControlStart = (PVOID)((ULONG_PTR)BaseAddress +
(ULONG_PTR)&KiProcessorBlock[Processor]->
ProcessorState);
/* Copy the memory */
RtlCopyMemory(ControlStart, Buffer, Length);
/* Finish up */
*ActualLength = Length;
return STATUS_SUCCESS;
}
else
{
/* Invalid request */
*ActualLength = 0;
return STATUS_UNSUCCESSFUL;
}
}
NTSTATUS
NTAPI
KdpSysReadIoSpace(IN ULONG InterfaceType,
IN ULONG BusNumber,
IN ULONG AddressSpace,
IN ULONG64 IoAddress,
IN PVOID DataValue,
IN ULONG DataSize,
OUT PULONG ActualDataSize)
{
NTSTATUS Status;
/* Verify parameters */
if ((InterfaceType != Isa) ||
(BusNumber != 0) ||
(AddressSpace != 1))
{
/* Fail, we don't support this */
*ActualDataSize = 0;
return STATUS_UNSUCCESSFUL;
}
/* Check the size */
switch (DataSize)
{
case sizeof(UCHAR):
/* Read 1 byte */
*(PUCHAR)DataValue =
READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)IoAddress);
*ActualDataSize = sizeof(UCHAR);
Status = STATUS_SUCCESS;
break;
case sizeof(USHORT):
/* Make sure the address is aligned */
if ((IoAddress & (sizeof(USHORT) - 1)) != 0)
{
/* It isn't, bail out */
*ActualDataSize = 0;
Status = STATUS_DATATYPE_MISALIGNMENT;
break;
}
/* Read 2 bytes */
*(PUSHORT)DataValue =
READ_PORT_USHORT((PUSHORT)(ULONG_PTR)IoAddress);
*ActualDataSize = sizeof(USHORT);
Status = STATUS_SUCCESS;
break;
case sizeof(ULONG):
/* Make sure the address is aligned */
if ((IoAddress & (sizeof(ULONG) - 1)) != 0)
{
/* It isn't, bail out */
*ActualDataSize = 0;
Status = STATUS_DATATYPE_MISALIGNMENT;
break;
}
/* Read 4 bytes */
*(PULONG)DataValue =
READ_PORT_ULONG((PULONG)(ULONG_PTR)IoAddress);
*ActualDataSize = sizeof(ULONG);
Status = STATUS_SUCCESS;
break;
default:
/* Invalid size, fail */
*ActualDataSize = 0;
Status = STATUS_INVALID_PARAMETER;
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
KdpSysWriteIoSpace(IN ULONG InterfaceType,
IN ULONG BusNumber,
IN ULONG AddressSpace,
IN ULONG64 IoAddress,
IN PVOID DataValue,
IN ULONG DataSize,
OUT PULONG ActualDataSize)
{
NTSTATUS Status;
/* Verify parameters */
if ((InterfaceType != Isa) ||
(BusNumber != 0) ||
(AddressSpace != 1))
{
/* Fail, we don't support this */
*ActualDataSize = 0;
return STATUS_UNSUCCESSFUL;
}
/* Check the size */
switch (DataSize)
{
case sizeof(UCHAR):
/* Write 1 byte */
WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)IoAddress,
*(PUCHAR)DataValue);
*ActualDataSize = sizeof(UCHAR);
Status = STATUS_SUCCESS;
break;
case sizeof(USHORT):
/* Make sure the address is aligned */
if ((IoAddress & (sizeof(USHORT) - 1)) != 0)
{
/* It isn't, bail out */
*ActualDataSize = 0;
Status = STATUS_DATATYPE_MISALIGNMENT;
break;
}
/* Write 2 bytes */
WRITE_PORT_USHORT((PUSHORT)(ULONG_PTR)IoAddress,
*(PUSHORT)DataValue);
*ActualDataSize = sizeof(USHORT);
Status = STATUS_SUCCESS;
break;
case sizeof(ULONG):
/* Make sure the address is aligned */
if ((IoAddress & (sizeof(ULONG) - 1)) != 0)
{
/* It isn't, bail out */
*ActualDataSize = 0;
Status = STATUS_DATATYPE_MISALIGNMENT;
break;
}
/* Write 4 bytes */
WRITE_PORT_ULONG((PULONG)(ULONG_PTR)IoAddress,
*(PULONG)DataValue);
*ActualDataSize = sizeof(ULONG);
Status = STATUS_SUCCESS;
break;
default:
/* Invalid size, fail */
*ActualDataSize = 0;
Status = STATUS_INVALID_PARAMETER;
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
KdpSysCheckLowMemory(IN ULONG Flags)
{
/* Stubbed as we don't support PAE */
return STATUS_UNSUCCESSFUL;
}