/*++ 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 #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; }