/*++ Copyright (c) 1990-2001 Microsoft Corporation Module Name: kdcpuapi.c Abstract: This module implements CPU specific remote debug APIs. Author: Chuck Bauman 14-Aug-1993 Revision History: Based on Mark Lucovsky (markl) MIPS version 04-Sep-1990 --*/ #include "kdp.h" #define END_OF_CONTROL_SPACE (sizeof(KPROCESSOR_STATE)) ULONG64 KiReadMsr( IN ULONG Msr ); VOID KiWriteMsr( IN ULONG Msr, IN ULONG64 Value ); NTSTATUS KdpAllowDisable( VOID ) /*++ Routine Description: Determines whether the current state of the debugger allows disabling or not. Arguments: None. Return Value: NTSTATUS. --*/ { ULONG Processor; // // If any kernel data breakpoints are active on any processor we can't // disable the debugger. // for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) { PKPCR Pcr = (PKPCR)(KSEG3_BASE + (KiProcessorBlock[Processor]->PcrPage << PAGE_SHIFT)); if (Pcr->KernelDebugActive) { return STATUS_ACCESS_DENIED; } } return STATUS_SUCCESS; } VOID KdpSetContextState ( IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange, IN PCONTEXT ContextRecord ) /*++ Routine Description: Fill in the Wait_State_Change message record with context information. Arguments: WaitStateChange - Supplies pointer to record to fill in ContextRecord - Supplies a pointer to a context record. Return Value: None. --*/ { // No CPU specific work necessary. UNREFERENCED_PARAMETER (WaitStateChange); UNREFERENCED_PARAMETER (ContextRecord); } 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. --*/ { // No CPU specific work necessary. UNREFERENCED_PARAMETER (WaitStateChange); UNREFERENCED_PARAMETER (ExceptionRecord); UNREFERENCED_PARAMETER (ContextRecord); UNREFERENCED_PARAMETER (SecondChance); } VOID KdpGetStateChange ( IN PDBGKD_MANIPULATE_STATE64 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. --*/ { if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) == TRUE) { // // If NT_SUCCESS returns TRUE, then the debugger is doing a // continue, and it makes sense to apply control changes. // Otherwise the debugger is saying that it doesn't know what // to do with this exception, so control values are ignored. // // // Clear .ss (bit 40 - single step) and .tb (bit 26 - taken branch) flags here // { PPSR ContextIPSR = (PPSR)&ContextRecord->StIPSR; ContextIPSR->sb.psr_ss = ((ManipulateState->u.Continue2.ControlSet.Continue & IA64_DBGKD_CONTROL_SET_CONTINUE_TRACE_INSTRUCTION) != 0); ContextIPSR->sb.psr_tb = ((ManipulateState->u.Continue2.ControlSet.Continue & IA64_DBGKD_CONTROL_SET_CONTINUE_TRACE_TAKEN_BRANCH) != 0); } // // Set KernelDebugActive if hardware debug registers are in use // The kernel settings for debug registers are kept in // the special registers, whereas the user settings are // in the context. Make sure to check the kernel settings. // { PKSPECIAL_REGISTERS Special = &KiProcessorBlock[KeGetCurrentProcessorNumber()]-> ProcessorState.SpecialRegisters; UCHAR KernelDebugActive = (UCHAR)( Special->KernelDbI1 || Special->KernelDbI3 || Special->KernelDbI5 || Special->KernelDbI7 || Special->KernelDbD1 || Special->KernelDbD3 || Special->KernelDbD5 || Special->KernelDbD7); USHORT Proc; for (Proc = 0; Proc < KeNumberProcessors; ++Proc) { PKPCR Pcr = (PKPCR)(KSEG3_BASE + (KiProcessorBlock[Proc]->PcrPage << PAGE_SHIFT)); Pcr->KernelDebugActive = KernelDebugActive; } } } } NTSTATUS KdpSysReadControlSpace( ULONG Processor, ULONG64 Address, PVOID Buffer, ULONG Request, PULONG Actual ) /*++ Routine Description: Reads implementation specific system data. Arguments: Processor - Processor's information to access. Address - Offset in control space. Buffer - Data buffer. Request - Amount of data to move. Actual - Amount of data actually moved. Return Value: NTSTATUS. --*/ { ULONG Length; PVOID Pointer; PVOID Data; if (Processor >= (ULONG)KeNumberProcessors) { *Actual = 0; return STATUS_UNSUCCESSFUL; } // // Case on address to determine what part of Control space is being read. // switch ( Address ) { // // Return the pcr address for the current processor. // case DEBUG_CONTROL_SPACE_PCR: Pointer = (PKPCR)(KSEG3_BASE + (KiProcessorBlock[Processor]->PcrPage << PAGE_SHIFT)); Data = &Pointer; Length = sizeof(Pointer); break; // // Return the prcb address for the current processor. // case DEBUG_CONTROL_SPACE_PRCB: Pointer = KiProcessorBlock[Processor]; Data = &Pointer; Length = sizeof(Pointer); break; // // Return the pointer to the current thread address for the // current processor. // case DEBUG_CONTROL_SPACE_THREAD: Pointer = KiProcessorBlock[Processor]->CurrentThread; Data = &Pointer; Length = sizeof(Pointer); break; case DEBUG_CONTROL_SPACE_KSPECIAL: Data = &(KiProcessorBlock[Processor]->ProcessorState.SpecialRegisters); Length = sizeof( KSPECIAL_REGISTERS ); break; default: *Actual = 0; return STATUS_UNSUCCESSFUL; } if (Length > Request) { Length = Request; } return KdpCopyToPtr(Buffer, Data, Length, Actual); } NTSTATUS KdpSysWriteControlSpace( ULONG Processor, ULONG64 Address, PVOID Buffer, ULONG Request, PULONG Actual ) /*++ Routine Description: Writes implementation specific system data. Arguments: Processor - Processor's information to access. Address - Offset in control space. Buffer - Data buffer. Request - Amount of data to move. Actual - Amount of data actually moved. Return Value: NTSTATUS. --*/ { ULONG Length; if (Processor >= (ULONG)KeNumberProcessors) { *Actual = 0; return STATUS_UNSUCCESSFUL; } switch ( Address ) { case DEBUG_CONTROL_SPACE_KSPECIAL: if (Request > sizeof(KSPECIAL_REGISTERS)) { Length = sizeof(KSPECIAL_REGISTERS); } else { Length = Request; } return KdpCopyFromPtr(&KiProcessorBlock[Processor]->ProcessorState.SpecialRegisters, Buffer, Length, Actual); default: *Actual = 0; 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; *Actual = 0; if (InterfaceType != Isa || BusNumber != 0 || AddressSpace != 1) { return STATUS_UNSUCCESSFUL; } Status = STATUS_SUCCESS; // // Check Size and Alignment // switch ( Request ) { case 1: *(PUCHAR)Buffer = READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address); *Actual = 1; break; case 2: if ( Address & 1 ) { Status = STATUS_DATATYPE_MISALIGNMENT; } else { *(PUSHORT)Buffer = READ_PORT_USHORT((PUSHORT)(ULONG_PTR)Address); *Actual = 2; } break; case 4: if ( Address & 3 ) { Status = STATUS_DATATYPE_MISALIGNMENT; } else { *(PULONG)Buffer = READ_PORT_ULONG((PULONG)(ULONG_PTR)Address); *Actual = 4; } break; default: Status = STATUS_INVALID_PARAMETER; 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; *Actual = 0; if (InterfaceType != Isa || BusNumber != 0 || AddressSpace != 1) { return STATUS_UNSUCCESSFUL; } Status = STATUS_SUCCESS; // // Check Size and Alignment // switch ( Request ) { case 1: WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address, *(PUCHAR)Buffer); *Actual = 1; break; case 2: if ( Address & 1 ) { Status = STATUS_DATATYPE_MISALIGNMENT; } else { WRITE_PORT_USHORT((PUSHORT)(ULONG_PTR)Address, *(PUSHORT)Buffer); *Actual = 2; } break; case 4: if ( Address & 3 ) { Status = STATUS_DATATYPE_MISALIGNMENT; } else { WRITE_PORT_ULONG((PULONG)(ULONG_PTR)Address, *(PULONG)Buffer); *Actual = 4; } break; default: Status = STATUS_INVALID_PARAMETER; 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 = KiReadMsr(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 { KiWriteMsr(Msr, *Data); } except (EXCEPTION_EXECUTE_HANDLER) { Status = STATUS_NO_SUCH_DEVICE; } return Status; }