Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1029 lines
24 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Copyright (c) 1992 Digital Equipment Corporation
Module Name:
kdcpuapi.c
Abstract:
This module implements CPU specific remote debug APIs.
Author:
Mark Lucovsky (markl) 04-Sep-1990
Revision History:
Jeff McLeman (mcleman) 11-June-1992
Make this an alpha specific module
Joe Notarangelo 28-Sep-1992
Add Alpha-specific control space semantics.
Miche Baker-Harvey 22-Oct-1992
Added Kdp{Read,Write}IoSpace
--*/
#include "kdp.h"
extern BOOLEAN KdpSendContext;
#define HEADER_FILE
#include "kxalpha.h"
VOID
KdpSetLoadState (
IN PDBGKD_WAIT_STATE_CHANGE WaitStateChange,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
Fill in the Wait_State_Change message record for the load symbol case.
Arguments:
WaitStateChange - Supplies pointer to record to fill in
ContextRecord - Supplies a pointer to a context record.
Return Value:
None.
--*/
{
return;
}
VOID
KdpSetStateChange (
IN PDBGKD_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.
--*/
{
PKPRCB Prcb;
BOOLEAN status;
//
// Set up description of event, including exception record
//
WaitStateChange->NewState = DbgKdExceptionStateChange;
WaitStateChange->ProcessorLevel = KeProcessorLevel;
WaitStateChange->Processor = (USHORT)KdpGetCurrentPrcb()->Number;
WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
WaitStateChange->Thread = (PVOID)KdpGetCurrentThread();
WaitStateChange->ProgramCounter = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ContextRecord);
KdpQuickMoveMemory(
(PCHAR)&WaitStateChange->u.Exception.ExceptionRecord,
(PCHAR)ExceptionRecord,
sizeof(EXCEPTION_RECORD)
);
WaitStateChange->u.Exception.FirstChance = !SecondChance;
//
// Copy instruction stream immediately following location of event
//
WaitStateChange->ControlReport.InstructionCount =
KdpMoveMemory(
&(WaitStateChange->ControlReport.InstructionStream[0]),
WaitStateChange->ProgramCounter,
DBGKD_MAXSTREAM
);
//
// Copy context record immediately following instruction stream
//
if (KdpSendContext) {
KdpMoveMemory(
(PCHAR)&WaitStateChange->Context,
(PCHAR)ContextRecord,
sizeof(*ContextRecord)
);
}
//
// Clear breakpoints in copied area
//
status = KdpDeleteBreakpointRange(
WaitStateChange->ProgramCounter,
(PVOID)((PUCHAR)WaitStateChange->ProgramCounter +
WaitStateChange->ControlReport.InstructionCount - 1)
);
//
// If there were any breakpoints cleared, recopy the area without them
//
if (status == TRUE) {
KdpMoveMemory(
&(WaitStateChange->ControlReport.InstructionStream[0]),
WaitStateChange->ProgramCounter,
WaitStateChange->ControlReport.InstructionCount
);
}
}
VOID
KdpGetStateChange (
IN PDBGKD_MANIPULATE_STATE ManipulateState,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
Extract continuation control data from Manipulate_State message
N.B. This is a noop for MIPS.
Arguments:
ManipulateState - supplies pointer to Manipulate_State packet
ContextRecord - Supplies a pointer to a context record.
Return Value:
None.
--*/
{
}
VOID
KdpReadControlSpace (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read control space state
manipulation message. Its function is to read implementation
specific system data.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_MEMORY a = &m->u.ReadMemory;
ULONG Length;
STRING MessageHeader;
PVOID Buffer = AdditionalData->Buffer;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
if (a->TransferCount > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE))) {
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE);
} else {
Length = a->TransferCount;
}
ASSERT(sizeof(PVOID) == sizeof(ULONG));
//NOTENOTE
// This code will in fact only work on a uni-processor as the
// m->Processor field is ignored for now
//
// Case on address to determine what part of Control
// space is being read
//
switch( (ULONG)a->TargetBaseAddress ){
//
// Return the pcr address for the current processor.
//
case DEBUG_CONTROL_SPACE_PCR:
*(PKPCR *)Buffer = KdpGetPcr();
AdditionalData->Length = sizeof( PKPCR );
a->ActualBytesRead = AdditionalData->Length;
m->ReturnStatus = STATUS_SUCCESS;
break;
//
// Return the prcb address for the current processor.
//
case DEBUG_CONTROL_SPACE_PRCB:
*(PKPRCB *)Buffer = KdpGetCurrentPrcb();
AdditionalData->Length = sizeof( PKPRCB );
a->ActualBytesRead = AdditionalData->Length;
m->ReturnStatus = STATUS_SUCCESS;
break;
//
// Return the pointer to the current thread address for the
// current processor.
//
case DEBUG_CONTROL_SPACE_THREAD:
*(PKTHREAD *)Buffer = KdpGetCurrentThread();
AdditionalData->Length = sizeof( PKTHREAD );
a->ActualBytesRead = AdditionalData->Length;
m->ReturnStatus = STATUS_SUCCESS;
break;
//
// Return the current Thread Environment Block pointer for the
// current thread on the current processor.
//
case DEBUG_CONTROL_SPACE_TEB:
*(PVOID *)Buffer = (PVOID)NtCurrentTeb();
AdditionalData->Length = sizeof( struct _TEB * );
a->ActualBytesRead = AdditionalData->Length;
m->ReturnStatus = STATUS_SUCCESS;
break;
//
// Return the dpc active flag for the current processor.
//
case DEBUG_CONTROL_SPACE_DPCACTIVE:
*(BOOLEAN *)Buffer = KeIsExecutingDpc();
AdditionalData->Length = sizeof( ULONG );
a->ActualBytesRead = AdditionalData->Length;
m->ReturnStatus = STATUS_SUCCESS;
break;
//
// Return the internal processor register state.
//
// N.B. - the kernel debugger buffer is expected to be allocated
// in the 32-bit superpage
//
// N.B. - the size of the internal state cannot exceed the size of
// the buffer allocated to the kernel debugger via
// KDP_MESSAGE_BUFFER_SIZE
//
case DEBUG_CONTROL_SPACE_IPRSTATE:
//
// Guarantee that Buffer is quadword-aligned, and adjust the
// size of the available buffer accordingly.
//
Buffer = (PVOID)( ((ULONG)Buffer + 7) & ~7);
Length = (ULONG)&AdditionalData->Buffer[KDP_MESSAGE_BUFFER_SIZE] -
(ULONG)Buffer;
AdditionalData->Length = KdpReadInternalProcessorState(
Buffer,
Length );
//
// Check the returned size, if greater than the buffer size than
// we didn't have a sufficient buffer. If zero then the call
// failed otherwise.
//
if( (AdditionalData->Length > KDP_MESSAGE_BUFFER_SIZE) ||
(AdditionalData->Length == 0) ){
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesRead = 0;
} else {
m->ReturnStatus = STATUS_SUCCESS;
a->ActualBytesRead = AdditionalData->Length;
}
break;
//
// Return the internal processor counter values.
//
// N.B. - the kernel debugger buffer is expected to be allocated
// in the 32-bit superpage
//
// N.B. - the size of the counters structure cannot exceed the size of
// the buffer allocated to the kernel debugger via
// KDP_MESSAGE_BUFFER_SIZE
//
case DEBUG_CONTROL_SPACE_COUNTERS:
//
// Guarantee that Buffer is quadword-aligned, and adjust the
// size of the available buffer accordingly.
//
Buffer = (PVOID)( ((ULONG)Buffer + 7) & ~7);
Length = (ULONG)&AdditionalData->Buffer[KDP_MESSAGE_BUFFER_SIZE] -
(ULONG)Buffer;
AdditionalData->Length = KdpReadInternalProcessorCounters(
Buffer,
Length );
//
// Check the returned size, if greater than the buffer size than
// we didn't have a sufficient buffer. If zero then the call
// failed otherwise.
//
if( (AdditionalData->Length > KDP_MESSAGE_BUFFER_SIZE) ||
(AdditionalData->Length == 0) ){
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesRead = 0;
} else {
m->ReturnStatus = STATUS_SUCCESS;
a->ActualBytesRead = AdditionalData->Length;
}
break;
//
// Uninterpreted Special Space
//
default:
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesRead = 0;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData
);
}
VOID
KdpWriteControlSpace (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write control space state
manipulation message. Its function is to write implementation
specific system data.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_WRITE_MEMORY a = &m->u.WriteMemory;
ULONG Length;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesWritten = 0;
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData
);
}
VOID
KdpReadIoSpace (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read io space state
manipulation message. Its function is to read system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo;
STRING MessageHeader;
INTERFACE_TYPE InterfaceType;
ULONG BusNumber;
PHYSICAL_ADDRESS IoAddress;
PHYSICAL_ADDRESS TranslatedAddress;
ULONG AddressSpace;
ULONG DataSize;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
//
// Capture the input parameters and use the default values for those
// parameters not specified in the Api.
//
InterfaceType = Isa;
BusNumber = 0;
AddressSpace = 1;
IoAddress = RtlConvertUlongToLargeInteger( (ULONG)a->IoAddress );
DataSize = a->DataSize;
//
// Zero the return data value.
//
a->DataValue = 0;
//
// Translate the bus address to the physical system address
// or QVA.
//
if( !HalTranslateBusAddress( InterfaceType,
BusNumber,
IoAddress,
&AddressSpace,
&TranslatedAddress ) ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendReadIoSpaceResponse;
}
//
// N.B. - for the moment we will only support QVAs ie. when AddressSpace
// is one. It may be in later systems that we will have to
// check the address space, map it, perform the virtual read
// unmap, and then return the data - only we will have to be
// careful about what Irql we are to make sure the memory mgmt
// stuff will all work
//
if( !AddressSpace ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendReadIoSpaceResponse;
}
//
// Do the IO space read using the appropriate HAL routines based upon
// the default address space (io) and the data size requested.
//
switch( DataSize ){
case 1:
a->DataValue = READ_PORT_UCHAR( (PUCHAR)TranslatedAddress.LowPart );
break;
case 2:
a->DataValue = READ_PORT_USHORT( (PUSHORT)TranslatedAddress.LowPart );
break;
case 4:
a->DataValue = READ_PORT_ULONG((PULONG)TranslatedAddress.LowPart );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
SendReadIoSpaceResponse:
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
}
VOID
KdpReadIoSpaceExtended (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read io space extended state
manipulation message. Its function is to read system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO_EXTENDED a = &m->u.ReadWriteIoExtended;
ULONG Length;
STRING MessageHeader;
PUCHAR b;
PUSHORT s;
PULONG l;
ULONG BusNumber;
ULONG AddressSpace;
ULONG SavedAddressSpace;
PHYSICAL_ADDRESS IoAddress;
ULONG DataSize;
PHYSICAL_ADDRESS TranslatedAddress;
INTERFACE_TYPE InterfaceType;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
InterfaceType = a->InterfaceType;
BusNumber = a->BusNumber;
AddressSpace = SavedAddressSpace = a->AddressSpace;
IoAddress = RtlConvertUlongToLargeInteger( (ULONG)a->IoAddress );
DataSize = a->DataSize;
//
// Zero the return data value.
//
a->DataValue = 0;
//
// Translate the bus address to the physical system address
// or QVA.
//
if( !HalTranslateBusAddress( InterfaceType,
BusNumber,
IoAddress,
&AddressSpace,
&TranslatedAddress ) ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendReadIoSpaceExtendedResponse;
}
//
// N.B. - for the moment we will only support QVAs ie. when AddressSpace
// is one. It may be in later systems that we will have to
// check the address space, map it, perform the virtual read
// unmap, and then return the data - only we will have to be
// careful about what Irql we are to make sure the memory mgmt
// stuff will all work
//
if( !AddressSpace ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendReadIoSpaceExtendedResponse;
}
//
// Do the IO space read using the appropriate HAL routines based upon
// the original address space and the data size requested.
//
if( !SavedAddressSpace ){
//
// Memory (buffer) space on the bus
//
switch( DataSize ){
case 1:
a->DataValue = READ_REGISTER_UCHAR( (PUCHAR)TranslatedAddress.LowPart );
break;
case 2:
a->DataValue = READ_REGISTER_USHORT((PUSHORT)TranslatedAddress.LowPart );
break;
case 4:
a->DataValue = READ_REGISTER_ULONG((PULONG)TranslatedAddress.LowPart );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
} else {
//
// I/O space on the bus
//
switch( DataSize ){
case 1:
a->DataValue = READ_PORT_UCHAR( (PUCHAR)TranslatedAddress.LowPart );
break;
case 2:
a->DataValue = READ_PORT_USHORT( (PUSHORT)TranslatedAddress.LowPart );
break;
case 4:
a->DataValue = READ_PORT_ULONG( (PULONG)TranslatedAddress.LowPart );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
}
SendReadIoSpaceExtendedResponse:
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
}
VOID
KdpWriteIoSpace (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read io space state
manipulation message. Its function is to read system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo;
STRING MessageHeader;
INTERFACE_TYPE InterfaceType;
ULONG BusNumber;
PHYSICAL_ADDRESS IoAddress;
PHYSICAL_ADDRESS TranslatedAddress;
ULONG AddressSpace;
ULONG DataSize;
ULONG Value;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
//
// Capture the input parameters and use the default values for those
// parameters not specified in the Api.
//
InterfaceType = Isa;
BusNumber = 0;
AddressSpace = 1;
IoAddress = RtlConvertUlongToLargeInteger( (ULONG)a->IoAddress );
DataSize = a->DataSize;
Value = a->DataValue;
//
// Translate the bus address to the physical system address
// or QVA.
//
if( !HalTranslateBusAddress( InterfaceType,
BusNumber,
IoAddress,
&AddressSpace,
&TranslatedAddress ) ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendWriteIoSpaceResponse;
}
//
// N.B. - for the moment we will only support QVAs ie. when AddressSpace
// is one. It may be in later systems that we will have to
// check the address space, map it, perform the virtual read
// unmap, and then return the data - only we will have to be
// careful about what Irql we are to make sure the memory mgmt
// stuff will all work
//
if( !AddressSpace ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendWriteIoSpaceResponse;
}
//
// Do the IO space read using the appropriate HAL routines based upon
// the default address space (io) and the data size requested.
//
switch( DataSize ){
case 1:
WRITE_PORT_UCHAR( (PUCHAR)TranslatedAddress.LowPart, Value );
break;
case 2:
WRITE_PORT_USHORT( (PUSHORT)TranslatedAddress.LowPart, Value );
break;
case 4:
WRITE_PORT_ULONG( (PULONG)TranslatedAddress.LowPart, Value );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
SendWriteIoSpaceResponse:
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
}
VOID
KdpWriteIoSpaceExtended (
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read io space extended state
manipulation message. Its function is to read system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO_EXTENDED a = &m->u.ReadWriteIoExtended;
ULONG Length;
STRING MessageHeader;
PUCHAR b;
PUSHORT s;
PULONG l;
ULONG BusNumber;
ULONG AddressSpace;
ULONG SavedAddressSpace;
PHYSICAL_ADDRESS IoAddress;
ULONG DataSize;
PHYSICAL_ADDRESS TranslatedAddress;
INTERFACE_TYPE InterfaceType;
ULONG Value;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
InterfaceType = a->InterfaceType;
BusNumber = a->BusNumber;
AddressSpace = SavedAddressSpace = a->AddressSpace;
IoAddress = RtlConvertUlongToLargeInteger( (ULONG)a->IoAddress );
DataSize = a->DataSize;
Value = a->DataValue;
//
// Translate the bus address to the physical system address
// or QVA.
//
if( !HalTranslateBusAddress( InterfaceType,
BusNumber,
IoAddress,
&AddressSpace,
&TranslatedAddress ) ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendWriteIoSpaceExtendedResponse;
}
//
// N.B. - for the moment we will only support QVAs ie. when AddressSpace
// is one. It may be in later systems that we will have to
// check the address space, map it, perform the virtual read
// unmap, and then return the data - only we will have to be
// careful about what Irql we are to make sure the memory mgmt
// stuff will all work
//
if( !AddressSpace ){
m->ReturnStatus = STATUS_INVALID_PARAMETER;
goto SendWriteIoSpaceExtendedResponse;
}
//
// Do the IO space read using the appropriate HAL routines based upon
// the original address space and the data size requested.
//
if( !SavedAddressSpace ){
//
// Memory (buffer) space on the bus
//
switch( DataSize ){
case 1:
WRITE_REGISTER_UCHAR( (PUCHAR)TranslatedAddress.LowPart, Value );
break;
case 2:
WRITE_REGISTER_USHORT( (PUSHORT)TranslatedAddress.LowPart, Value );
break;
case 4:
WRITE_REGISTER_ULONG( (PULONG)TranslatedAddress.LowPart, Value );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
} else {
//
// I/O space on the bus
//
switch( DataSize ){
case 1:
WRITE_PORT_UCHAR( (PUCHAR)TranslatedAddress.LowPart, Value );
break;
case 2:
WRITE_PORT_USHORT( (PUSHORT)TranslatedAddress.LowPart, Value);
break;
case 4:
WRITE_PORT_ULONG( (PULONG)TranslatedAddress.LowPart, Value );
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
}
SendWriteIoSpaceExtendedResponse:
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
}