windows-nt/Source/XPSP1/NT/base/ntos/kd64/amd64/kdcpuapi.c
2020-09-26 16:20:57 +08:00

640 lines
13 KiB
C

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
kdcpuapi.c
Abstract:
This module implements CPU specific remote debug APIs.
Author:
David N. Cutler (davec) 14-May-2000
Revision History:
--*/
#include "kdp.h"
#include <stdio.h>
#pragma alloc_text(PAGEKD, KdpSetContextState)
#pragma alloc_text(PAGEKD, KdpSetStateChange)
#pragma alloc_text(PAGEKD, KdpGetStateChange)
#pragma alloc_text(PAGEKD, KdpSysReadControlSpace)
#pragma alloc_text(PAGEKD, KdpSysWriteControlSpace)
#pragma alloc_text(PAGEKD, KdpReadIoSpace)
#pragma alloc_text(PAGEKD, KdpWriteIoSpace)
#pragma alloc_text(PAGEKD, KdpReadMachineSpecificRegister)
#pragma alloc_text(PAGEKD, KdpWriteMachineSpecificRegister)
VOID
KdpSetContextState (
IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
IN PCONTEXT ContextRecord
)
{
PKPRCB Prcb;
//
// Copy special registers for the AMD64.
//
Prcb = KeGetCurrentPrcb();
WaitStateChange->ControlReport.Dr6 =
Prcb->ProcessorState.SpecialRegisters.KernelDr6;
WaitStateChange->ControlReport.Dr7 =
Prcb->ProcessorState.SpecialRegisters.KernelDr7;
WaitStateChange->ControlReport.SegCs = ContextRecord->SegCs;
WaitStateChange->ControlReport.SegDs = ContextRecord->SegDs;
WaitStateChange->ControlReport.SegEs = ContextRecord->SegEs;
WaitStateChange->ControlReport.SegFs = ContextRecord->SegFs;
WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags;
WaitStateChange->ControlReport.ReportFlags = AMD64_REPORT_INCLUDES_SEGS;
// If the current code segment is a known flat code
// segment let the debugger know so that it doesn't
// have to retrieve the descriptor.
if (ContextRecord->SegCs == KGDT64_R0_CODE ||
ContextRecord->SegCs == KGDT64_R3_CODE + 3) {
WaitStateChange->ControlReport.ReportFlags |= AMD64_REPORT_STANDARD_CS;
}
}
VOID
KdpSetStateChange (
IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT ContextRecord,
IN BOOLEAN SecondChance
)
/*++
Routine Description:
Fill in the Wait_State_Change message record.
Arguments:
WaitStateChange - Supplies pointer to record to fill in
ExceptionRecord - Supplies a pointer to an exception record.
ContextRecord - Supplies a pointer to a context record.
SecondChance - Supplies a boolean value that determines whether this is
the first or second chance for the exception.
Return Value:
None.
--*/
{
KdpSetContextState(WaitStateChange, ContextRecord);
}
VOID
KdpGetStateChange (
IN PDBGKD_MANIPULATE_STATE64 ManipulateState,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
Extract continuation control data from manipulate state message.
Arguments:
ManipulateState - Supplies pointer to manipulate state packet.
ContextRecord - Supplies a pointer to a context record.
Return Value:
None.
--*/
{
ULONG Number;
PKPRCB Prcb;
//
// If the status of the manipulate state message was successful, then
// extract the continuation control information.
//
if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) != FALSE) {
//
// Set or clear the TF flag in the EFLAGS field of the context record.
//
if (ManipulateState->u.Continue2.ControlSet.TraceFlag != FALSE) {
ContextRecord->EFlags |= EFLAGS_TF_MASK;
} else {
ContextRecord->EFlags &= ~EFLAGS_TF_MASK;
}
//
// Clear DR6 and set the specified DR7 value for each of the processors.
//
for (Number = 0; Number < (ULONG)KeNumberProcessors; Number += 1) {
Prcb = KiProcessorBlock[Number];
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0;
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
ManipulateState->u.Continue2.ControlSet.Dr7;
}
}
return;
}
NTSTATUS
KdpSysReadControlSpace (
ULONG Processor,
ULONG64 Address,
PVOID Buffer,
ULONG Request,
PULONG Actual
)
/*++
Routine Description:
This function reads implementation specific system data for the specified
processor.
Arguments:
Processor - Supplies the source processor number.
Address - Supplies the type of data to read.
Buffer - Supplies the address of the output buffer.
Request - Supplies the requested number of bytes of data.
Actual - Supplies a point to a variable that receives the actual number
of bytes of data returned.
Return Value:
NTSTATUS.
--*/
{
PVOID Data;
ULONG Length;
PKPRCB Prcb;
PVOID Source;
//
// If the specified processor number is greater than the number of
// processors in the system or the specified processor is not in the
// host configuration, then return an unsuccessful status.
//
*Actual = 0;
if ((Processor >= (ULONG)KeNumberProcessors) ||
(KiProcessorBlock[Processor] == NULL)) {
return STATUS_UNSUCCESSFUL;
}
//
// Case on address to determine what part of Control space is being read.
//
Prcb = KiProcessorBlock[Processor];
switch (Address) {
//
// Read the address of the PCR for the specified processor.
//
case DEBUG_CONTROL_SPACE_PCR:
Data = CONTAINING_RECORD(Prcb, KPCR, Prcb);
Source = &Data;
Length = sizeof(PVOID);
break;
//
// Read the address of the PRCB for the specified processor.
//
case DEBUG_CONTROL_SPACE_PRCB:
Source = &Prcb;
Length = sizeof(PVOID);
break;
//
// Read the address of the current thread for the specified
// processor.
//
case DEBUG_CONTROL_SPACE_THREAD:
Source = &Prcb->CurrentThread;
Length = sizeof(PVOID);
break;
//
// Read the special processor registers structure for the specified
// processor.
//
case DEBUG_CONTROL_SPACE_KSPECIAL:
Source = &Prcb->ProcessorState.SpecialRegisters;
Length = sizeof(KSPECIAL_REGISTERS);
break;
//
// Invalid information type.
//
default:
return STATUS_UNSUCCESSFUL;
}
//
// If the length of the data is greater than the request length, then
// reduce the length to the requested length.
//
if (Length > Request) {
Length = Request;
}
//
// Move the data to the supplied buffer and return status dependent on
// whether the entire data item can be moved.
//
return KdpCopyToPtr(Buffer, Source, Length, Actual);
}
NTSTATUS
KdpSysWriteControlSpace (
ULONG Processor,
ULONG64 Address,
PVOID Buffer,
ULONG Request,
PULONG Actual
)
/*++
Routine Description:
This function write implementation specific system data for the specified
processor.
Arguments:
Processor - Supplies the source processor number.
Address - Supplies the type of data to write.
Buffer - Supplies the address of the input buffer.
Request - Supplies the requested number of bytes of data.
Actual - Supplies a point to a variable that receives the actual number
of bytes of data written.
Return Value:
NTSTATUS.
--*/
{
PKPRCB Prcb;
//
// If the specified processor number is greater than the number of
// processors in the system or the specified processor is not in the
// host configuration, then return an unsuccessful status.
//
*Actual = 0;
if ((Processor >= (ULONG)KeNumberProcessors) ||
(KiProcessorBlock[Processor] == NULL)) {
return STATUS_UNSUCCESSFUL;
}
//
// Case on address to determine what part of control space is being writen.
//
Prcb = KiProcessorBlock[Processor];
switch (Address) {
//
// Write the special processor registers structure for the specified
// processor.
//
case DEBUG_CONTROL_SPACE_KSPECIAL:
//
// If the length of the data is greater than the request length, then
// reduce the requested length to the length of the data.
//
if (Request > sizeof(KSPECIAL_REGISTERS)) {
Request = sizeof(KSPECIAL_REGISTERS);
}
//
// Move the data to the supplied buffer and return status dependent on
// whether the entire data item can be moved.
//
return KdpCopyFromPtr(&Prcb->ProcessorState.SpecialRegisters,
Buffer,
Request,
Actual);
//
// Invalid information type.
//
default:
return STATUS_UNSUCCESSFUL;
}
}
NTSTATUS
KdpSysReadIoSpace(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG AddressSpace,
ULONG64 Address,
PVOID Buffer,
ULONG Request,
PULONG Actual
)
/*++
Routine Description:
Reads system I/O locations.
Arguments:
InterfaceType - I/O interface type.
BusNumber - Bus number.
AddressSpace - Address space.
Address - I/O address.
Buffer - Data buffer.
Request - Amount of data to move.
Actual - Amount of data actually moved.
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
if ((InterfaceType != Isa) || (BusNumber != 0) || (AddressSpace != 1)) {
*Actual = 0;
return STATUS_UNSUCCESSFUL;
}
//
// Check Size and Alignment
//
switch (Request) {
case 1:
*(PUCHAR)Buffer = READ_PORT_UCHAR((PUCHAR)Address);
*Actual = 1;
break;
case 2:
if (Address & 1) {
Status = STATUS_DATATYPE_MISALIGNMENT;
} else {
*(PUSHORT)Buffer = READ_PORT_USHORT((PUSHORT)Address);
*Actual = 2;
}
break;
case 4:
if (Address & 3) {
Status = STATUS_DATATYPE_MISALIGNMENT;
} else {
*(PULONG)Buffer = READ_PORT_ULONG((PULONG)Address);
*Actual = 4;
}
break;
default:
Status = STATUS_INVALID_PARAMETER;
*Actual = 0;
break;
}
return Status;
}
NTSTATUS
KdpSysWriteIoSpace(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG AddressSpace,
ULONG64 Address,
PVOID Buffer,
ULONG Request,
PULONG Actual
)
/*++
Routine Description:
Writes system I/O locations.
Arguments:
InterfaceType - I/O interface type.
BusNumber - Bus number.
AddressSpace - Address space.
Address - I/O address.
Buffer - Data buffer.
Request - Amount of data to move.
Actual - Amount of data actually moved.
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
if ((InterfaceType != Isa) || (BusNumber != 0) || (AddressSpace != 1)) {
*Actual = 0;
return STATUS_UNSUCCESSFUL;
}
//
// Check Size and Alignment
//
switch (Request) {
case 1:
WRITE_PORT_UCHAR((PUCHAR)Address, *(PUCHAR)Buffer);
*Actual = 1;
break;
case 2:
if (Address & 1) {
Status = STATUS_DATATYPE_MISALIGNMENT;
} else {
WRITE_PORT_USHORT((PUSHORT)Address, *(PUSHORT)Buffer);
*Actual = 2;
}
break;
case 4:
if (Address & 3) {
Status = STATUS_DATATYPE_MISALIGNMENT;
} else {
WRITE_PORT_ULONG((PULONG)Address, *(PULONG)Buffer);
*Actual = 4;
}
break;
default:
Status = STATUS_INVALID_PARAMETER;
*Actual = 0;
break;
}
return Status;
}
NTSTATUS
KdpSysReadMsr(
ULONG Msr,
PULONG64 Data
)
/*++
Routine Description:
Reads an MSR.
Arguments:
Msr - MSR index.
Data - Data buffer.
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
try {
*Data = ReadMSR(Msr);
} except (EXCEPTION_EXECUTE_HANDLER) {
*Data = 0;
Status = STATUS_NO_SUCH_DEVICE;
}
return Status;
}
NTSTATUS
KdpSysWriteMsr(
ULONG Msr,
PULONG64 Data
)
/*++
Routine Description:
Writes an MSR.
Arguments:
Msr - MSR index.
Data - Data buffer.
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
try {
WriteMSR(Msr, *Data);
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_NO_SUCH_DEVICE;
}
return Status;
}