518 lines
11 KiB
C
518 lines
11 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
kdcpuapi.c
|
||
|
||
Abstract:
|
||
|
||
This module implements CPU specific remote debug APIs.
|
||
|
||
Author:
|
||
|
||
Mark Lucovsky (markl) 04-Sep-1990
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "kdp.h"
|
||
|
||
extern BOOLEAN KdpSendContext;
|
||
|
||
#define HEADER_FILE
|
||
#include "kxmips.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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOLEAN status;
|
||
|
||
//
|
||
// Set up description of event, including exception record
|
||
//
|
||
|
||
WaitStateChange->NewState = DbgKdExceptionStateChange;
|
||
WaitStateChange->ProcessorLevel = KeProcessorLevel;
|
||
WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
|
||
WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
|
||
WaitStateChange->Thread = (PVOID)KeGetCurrentThread();
|
||
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;
|
||
ULONG NumberOfEntries;
|
||
ULONG StartingEntry;
|
||
PULONG EntryBuffer;
|
||
PKPRCB Prcb;
|
||
PTB_ENTRY TbEntry;
|
||
|
||
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;
|
||
}
|
||
|
||
//
|
||
// Case on address to determine what part of Control space is being read.
|
||
//
|
||
|
||
ASSERT(sizeof(PVOID) == sizeof(ULONG));
|
||
if ( (ULONG)a->TargetBaseAddress >= 0 &&
|
||
(ULONG)a->TargetBaseAddress < KeNumberTbEntries &&
|
||
(m->Processor < (USHORT)KeNumberProcessors )) {
|
||
|
||
//
|
||
// Read TB entries.
|
||
//
|
||
|
||
NumberOfEntries = Length / sizeof(TB_ENTRY);
|
||
StartingEntry = (ULONG)a->TargetBaseAddress;
|
||
|
||
//
|
||
// Trim number of entries to tb range
|
||
//
|
||
|
||
if (StartingEntry + NumberOfEntries > KeNumberTbEntries) {
|
||
NumberOfEntries = KeNumberTbEntries - StartingEntry;
|
||
}
|
||
|
||
AdditionalData->Length = (USHORT)(NumberOfEntries * sizeof(TB_ENTRY));
|
||
EntryBuffer = (PULONG)AdditionalData->Buffer;
|
||
Prcb = KiProcessorBlock[m->Processor];
|
||
TbEntry = &Prcb->ProcessorState.TbEntry[0];
|
||
while (NumberOfEntries--) {
|
||
*(PENTRYLO)EntryBuffer++ = TbEntry[StartingEntry].Entrylo0;
|
||
*(PENTRYLO)EntryBuffer++ = TbEntry[StartingEntry].Entrylo1;
|
||
*(PENTRYHI)EntryBuffer++ = TbEntry[StartingEntry].Entryhi;
|
||
*(PPAGEMASK)EntryBuffer++ = TbEntry[StartingEntry].Pagemask;
|
||
StartingEntry += 1;
|
||
}
|
||
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
a->ActualBytesRead = AdditionalData->Length;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Uninterpreted Special Space
|
||
//
|
||
|
||
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;
|
||
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;
|
||
PUCHAR b;
|
||
PUSHORT s;
|
||
PULONG l;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
ASSERT(AdditionalData->Length == 0);
|
||
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Check Size and Alignment
|
||
//
|
||
|
||
switch ( a->DataSize ) {
|
||
case 1:
|
||
b = (PUCHAR)MmDbgReadCheck(a->IoAddress);
|
||
if ( b ) {
|
||
a->DataValue = (ULONG)*b;
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
break;
|
||
case 2:
|
||
if ((ULONG)a->IoAddress & 1 ) {
|
||
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
|
||
} else {
|
||
s = (PUSHORT)MmDbgReadCheck(a->IoAddress);
|
||
if ( s ) {
|
||
a->DataValue = (ULONG)*s;
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
}
|
||
break;
|
||
case 4:
|
||
if ((ULONG)a->IoAddress & 3 ) {
|
||
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
|
||
} else {
|
||
l = (PULONG)MmDbgReadCheck(a->IoAddress);
|
||
if ( l ) {
|
||
a->DataValue = (ULONG)*l;
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
m->ReturnStatus = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
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 write io space state
|
||
manipulation message. Its function is to write to 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;
|
||
PUCHAR b;
|
||
PUSHORT s;
|
||
PULONG l;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
ASSERT(AdditionalData->Length == 0);
|
||
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Check Size and Alignment
|
||
//
|
||
|
||
switch ( a->DataSize ) {
|
||
case 1:
|
||
b = (PUCHAR)MmDbgWriteCheck(a->IoAddress);
|
||
if ( b ) {
|
||
WRITE_REGISTER_UCHAR(b,(UCHAR)a->DataValue);
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
break;
|
||
case 2:
|
||
if ((ULONG)a->IoAddress & 1 ) {
|
||
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
|
||
} else {
|
||
s = (PUSHORT)MmDbgWriteCheck(a->IoAddress);
|
||
if ( s ) {
|
||
WRITE_REGISTER_USHORT(s,(USHORT)a->DataValue);
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
}
|
||
break;
|
||
case 4:
|
||
if ((ULONG)a->IoAddress & 3 ) {
|
||
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
|
||
} else {
|
||
l = (PULONG)MmDbgWriteCheck(a->IoAddress);
|
||
if ( l ) {
|
||
WRITE_REGISTER_ULONG(l,a->DataValue);
|
||
} else {
|
||
m->ReturnStatus = STATUS_ACCESS_VIOLATION;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
m->ReturnStatus = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
KdpSendPacket(
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
NULL
|
||
);
|
||
}
|