640 lines
13 KiB
C
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;
|
||
|
}
|