552 lines
14 KiB
C
552 lines
14 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
xxkdsup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Com support. Code to init a com port, store port state, map
|
|||
|
portable procedures to x86 procedures.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bryan M. Willman (bryanwi) 24-Sep-90
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Shielin Tzong (shielint) 10-Apr-91
|
|||
|
Add packet control protocol.
|
|||
|
|
|||
|
John Vert (jvert) 11-Jul-1991
|
|||
|
Moved from KD/i386 to HAL
|
|||
|
|
|||
|
Eric Nelson (enelson) 1-Jan-00
|
|||
|
Move from HAL into DLL
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "kdcomp.h"
|
|||
|
#include "kdcom.h"
|
|||
|
#include "stdio.h"
|
|||
|
#include "acpitabl.h"
|
|||
|
|
|||
|
#if DBG && IA64
|
|||
|
CHAR KdProtocolTraceIn[4096];
|
|||
|
ULONG KdProtocolIndexIn;
|
|||
|
CHAR KdProtocolTraceOut[4096];
|
|||
|
ULONG KdProtocolIndexOut;
|
|||
|
#endif
|
|||
|
|
|||
|
PDEBUG_PORT_TABLE HalpDebugPortTable;
|
|||
|
|
|||
|
//
|
|||
|
// This MUST be initialized to zero so we know not to do anything when
|
|||
|
// CpGetByte is called when the kernel debugger is disabled.
|
|||
|
//
|
|||
|
|
|||
|
CPPORT Port = {NULL, 0, PORT_DEFAULTRATE };
|
|||
|
|
|||
|
//
|
|||
|
// Remember the debugger port information
|
|||
|
//
|
|||
|
|
|||
|
CPPORT PortInformation = {NULL, 0, PORT_DEFAULTRATE};
|
|||
|
ULONG ComPort = 0;
|
|||
|
PHYSICAL_ADDRESS DbgpKdComPhysicalAddress; // ACPI DBGP KdCom physical address.
|
|||
|
|
|||
|
//
|
|||
|
// Default debugger port in IO space.
|
|||
|
//
|
|||
|
|
|||
|
UCHAR KdComAddressID = 1; // port debugger ident. : MMIO or IO space. Def:IO.
|
|||
|
pKWriteUchar KdWriteUchar = CpWritePortUchar; // stub to real function: MMIO or IO space. Def:IO.
|
|||
|
pKReadUchar KdReadUchar = CpReadPortUchar; // stub to real function: MMIO or IO space. Def:IO.
|
|||
|
|
|||
|
//
|
|||
|
// We need this so the serial driver knows that the kernel debugger
|
|||
|
// is using a particular port. The serial driver then knows not to
|
|||
|
// touch this port. KdInitCom fills this in with the number of the
|
|||
|
// COM port it is using (1 or 2)
|
|||
|
//
|
|||
|
// This will go in the registry as soon as the registry is working.
|
|||
|
//
|
|||
|
|
|||
|
extern PUCHAR *KdComPortInUse;
|
|||
|
|
|||
|
BOOLEAN HalpGetInfoFromACPI = FALSE;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KdCompInitialize(
|
|||
|
PDEBUG_PARAMETERS DebugParameters,
|
|||
|
PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure checks for which COM port should be used by kernel
|
|||
|
debugger. If DebugParameter specifies a COM port, we will use it
|
|||
|
even if we can not find it (we trust user). Otherwise, if COM2
|
|||
|
is present and there is no mouse attaching to it, we use COM2.
|
|||
|
If COM2 is not availabe, we check COM1. If both COM1 and COM2 are
|
|||
|
not present, we give up and return false.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DebugParameters - Supplies a pointer a structure which optionally
|
|||
|
sepcified the debugging port information.
|
|||
|
|
|||
|
LoaderBlock - supplies a pointer to the loader parameter block.
|
|||
|
|
|||
|
Returned Value:
|
|||
|
|
|||
|
TRUE - If a debug port is found.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PCONFIGURATION_COMPONENT_DATA ConfigurationEntry, ChildEntry;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|||
|
PCM_PARTIAL_RESOURCE_LIST List;
|
|||
|
ULONG MatchKey, i;
|
|||
|
ULONG BaudRate = BD_19200;
|
|||
|
PUCHAR PortAddress = NULL;
|
|||
|
UCHAR Irq = 0;
|
|||
|
ULONG Com = 0;
|
|||
|
|
|||
|
if (LoaderBlock && KdGetAcpiTablePhase0) {
|
|||
|
HalpDebugPortTable =
|
|||
|
KdGetAcpiTablePhase0(LoaderBlock, DBGP_SIGNATURE);
|
|||
|
}
|
|||
|
|
|||
|
if (HalpDebugPortTable) {
|
|||
|
|
|||
|
KdComAddressID = HalpDebugPortTable->BaseAddress.AddressSpaceID;
|
|||
|
|
|||
|
//
|
|||
|
// Debug ports are supported in memory and IO space only.
|
|||
|
//
|
|||
|
|
|||
|
if ((KdComAddressID == 0) ||
|
|||
|
(KdComAddressID == 1)) {
|
|||
|
|
|||
|
DbgpKdComPhysicalAddress = HalpDebugPortTable->BaseAddress.Address;
|
|||
|
|
|||
|
if(KdComAddressID == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// The address is memory, map it.
|
|||
|
//
|
|||
|
|
|||
|
if (KdMapPhysicalMemory64) {
|
|||
|
PortInformation.Address =
|
|||
|
KdMapPhysicalMemory64(DbgpKdComPhysicalAddress, 1);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The address is in IO space.
|
|||
|
//
|
|||
|
|
|||
|
PortInformation.Address = (PUCHAR)UlongToPtr(DbgpKdComPhysicalAddress.LowPart);
|
|||
|
}
|
|||
|
|
|||
|
Port.Flags &= ~(PORT_MODEMCONTROL | PORT_DEFAULTRATE);
|
|||
|
HalpGetInfoFromACPI = TRUE;
|
|||
|
|
|||
|
if (HalpDebugPortTable->InterfaceType == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// This is actually a 16550. So pay attention
|
|||
|
// to the baud rate requested by the user.
|
|||
|
//
|
|||
|
|
|||
|
if(DebugParameters->BaudRate != 0){
|
|||
|
// Baud rate set by user so use it
|
|||
|
PortInformation.Baud = DebugParameters->BaudRate;
|
|||
|
} else if(HalpDebugPortTable->BaudRate != 0){
|
|||
|
// not specified by user so get it out of the debug table
|
|||
|
PortInformation.Baud = KdCompGetDebugTblBaudRate(HalpDebugPortTable->BaudRate);
|
|||
|
} else {
|
|||
|
// No debug table information available so use default
|
|||
|
PortInformation.Baud = BD_57600;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is not a 16550. So we must use
|
|||
|
// the fixed baud rate of 57600.
|
|||
|
//
|
|||
|
|
|||
|
PortInformation.Baud = BD_57600;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if Port and baudrate have been determined.
|
|||
|
//
|
|||
|
|
|||
|
if ((PortInformation.Address == NULL) && !HalpGetInfoFromACPI) {
|
|||
|
|
|||
|
//
|
|||
|
// First see if the DebugParameters contains debugging port info.
|
|||
|
//
|
|||
|
|
|||
|
if (DebugParameters->BaudRate != 0) {
|
|||
|
BaudRate = DebugParameters->BaudRate;
|
|||
|
Port.Flags &= ~PORT_DEFAULTRATE;
|
|||
|
}
|
|||
|
|
|||
|
if (DebugParameters->CommunicationPort != 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Find the configuration information of the specified serial port.
|
|||
|
//
|
|||
|
|
|||
|
Com = DebugParameters->CommunicationPort;
|
|||
|
MatchKey = Com - 1;
|
|||
|
if (LoaderBlock != NULL) {
|
|||
|
ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
|
|||
|
ControllerClass,
|
|||
|
SerialController,
|
|||
|
&MatchKey);
|
|||
|
|
|||
|
} else {
|
|||
|
ConfigurationEntry = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Check if COM2 is present and make sure no mouse attaches to it.
|
|||
|
//
|
|||
|
|
|||
|
MatchKey = 1;
|
|||
|
if (LoaderBlock != NULL) {
|
|||
|
ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
|
|||
|
ControllerClass,
|
|||
|
SerialController,
|
|||
|
&MatchKey);
|
|||
|
|
|||
|
} else {
|
|||
|
ConfigurationEntry = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (ConfigurationEntry != NULL) {
|
|||
|
ChildEntry = ConfigurationEntry->Child;
|
|||
|
if ((ChildEntry != NULL) &&
|
|||
|
(ChildEntry->ComponentEntry.Type == PointerPeripheral)) {
|
|||
|
ConfigurationEntry = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If COM2 does not exist or a serial mouse attaches to it, try
|
|||
|
// COM1. If COM1 exists, we will use it no matter what is on
|
|||
|
// it.
|
|||
|
//
|
|||
|
|
|||
|
if (ConfigurationEntry == NULL) {
|
|||
|
MatchKey = 0;
|
|||
|
if (LoaderBlock != NULL) {
|
|||
|
ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
|
|||
|
ControllerClass,
|
|||
|
SerialController,
|
|||
|
&MatchKey);
|
|||
|
|
|||
|
} else {
|
|||
|
ConfigurationEntry = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (ConfigurationEntry != NULL) {
|
|||
|
Com = 1;
|
|||
|
} else if (CpDoesPortExist((PUCHAR)COM2_PORT)) {
|
|||
|
PortAddress = (PUCHAR)COM2_PORT;
|
|||
|
Com = 2;
|
|||
|
} else if (CpDoesPortExist((PUCHAR)COM1_PORT)) {
|
|||
|
PortAddress = (PUCHAR)COM1_PORT;
|
|||
|
Com = 1;
|
|||
|
} else {
|
|||
|
return STATUS_NOT_FOUND;
|
|||
|
}
|
|||
|
} else {
|
|||
|
Com = 2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get Comport address from the component configuration data.
|
|||
|
// (If we find the ComponentEntry associated with the com port)
|
|||
|
//
|
|||
|
|
|||
|
if (ConfigurationEntry) {
|
|||
|
List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
|
|||
|
for (i = 0; i < List->Count ; i++ ) {
|
|||
|
Descriptor = &List->PartialDescriptors[i];
|
|||
|
if (Descriptor->Type == CmResourceTypePort) {
|
|||
|
PortAddress = (PUCHAR)UlongToPtr(Descriptor->u.Port.Start.LowPart);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we can not find the port address for the comport, simply use
|
|||
|
// default value.
|
|||
|
//
|
|||
|
|
|||
|
if (PortAddress == NULL) {
|
|||
|
switch (Com) {
|
|||
|
case 1:
|
|||
|
PortAddress = (PUCHAR)COM1_PORT;
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
PortAddress = (PUCHAR)COM2_PORT;
|
|||
|
break;
|
|||
|
case 3:
|
|||
|
PortAddress = (PUCHAR)COM3_PORT;
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
PortAddress = (PUCHAR)COM4_PORT;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the port structure.
|
|||
|
//
|
|||
|
|
|||
|
ComPort = Com;
|
|||
|
PortInformation.Address = PortAddress;
|
|||
|
PortInformation.Baud = BaudRate;
|
|||
|
}
|
|||
|
|
|||
|
if (KdComAddressID == 0) { // MMIO
|
|||
|
KdWriteUchar = CpWriteRegisterUchar;
|
|||
|
KdReadUchar = CpReadRegisterUchar;
|
|||
|
}
|
|||
|
|
|||
|
CpInitialize(&Port,
|
|||
|
PortInformation.Address,
|
|||
|
PortInformation.Baud
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The following should be reworked in conjunction with the serial
|
|||
|
// driver. The serial driver doesn't understand the concept of
|
|||
|
// ports being memory so we need to have it believe we are using
|
|||
|
// the IO port even though we are using a memory mapped equivalent.
|
|||
|
//
|
|||
|
|
|||
|
if (HalpDebugPortTable && (KdComAddressID == 0)) {
|
|||
|
*KdComPortInUse = (UCHAR *)((ULONG_PTR)(*KdComPortInUse) & (PAGE_SIZE-1));
|
|||
|
}
|
|||
|
else {
|
|||
|
*KdComPortInUse = PortInformation.Address;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
KdCompGetByte(
|
|||
|
OUT PUCHAR Input
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Fetch a byte from the debug port and return it.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level, and
|
|||
|
necessary multiprocessor synchronization has been performed before this
|
|||
|
routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Input - Returns the data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
CP_GET_SUCCESS is returned if a byte is successfully read from the
|
|||
|
kernel debugger line.
|
|||
|
CP_GET_ERROR is returned if error encountered during reading.
|
|||
|
CP_GET_NODATA is returned if timeout.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG status = CpGetByte(&Port, Input, TRUE);
|
|||
|
#if DBG && IA64
|
|||
|
KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
|
|||
|
#endif
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
KdCompPollByte(
|
|||
|
OUT PUCHAR Input
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Fetch a byte from the debug port and return it if one is available.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level, and
|
|||
|
necessary multiprocessor synchronization has been performed before this
|
|||
|
routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Input - Returns the data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
CP_GET_SUCCESS is returned if a byte is successfully read from the
|
|||
|
kernel debugger line.
|
|||
|
CP_GET_ERROR is returned if error encountered during reading.
|
|||
|
CP_GET_NODATA is returned if timeout.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG status = CpGetByte(&Port, Input, FALSE);
|
|||
|
#if DBG && IA64
|
|||
|
KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
|
|||
|
#endif
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KdCompPutByte(
|
|||
|
IN UCHAR Output
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Write a byte to the debug port.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level, and
|
|||
|
necessary multiprocessor synchronization has been performed before this
|
|||
|
routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Output - Supplies the output data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#if DBG && IA64
|
|||
|
KdProtocolTraceOut[KdProtocolIndexOut++%4096]=Output;
|
|||
|
#endif
|
|||
|
CpPutByte(&Port, Output);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KdCompRestore(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does NOTHING on the x86.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level, and
|
|||
|
necessary multiprocessor synchronization has been performed before this
|
|||
|
routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Port.Flags &= ~PORT_SAVED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KdCompSave(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does NOTHING on the x86.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level, and
|
|||
|
necessary multiprocessor synchronization has been performed before this
|
|||
|
routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Port.Flags |= PORT_SAVED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KdCompInitialize1(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
if(KdComAddressID == 0) { // MMIO
|
|||
|
Port.Address = (PUCHAR)MmMapIoSpace(DbgpKdComPhysicalAddress,8,MmNonCached);
|
|||
|
*KdComPortInUse = Port.Address;
|
|||
|
}
|
|||
|
} // KdCompInitialize1()
|
|||
|
|
|||
|
ULONG
|
|||
|
KdCompGetDebugTblBaudRate(
|
|||
|
UCHAR BaudRateFlag
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG Rate = BD_57600; // default.
|
|||
|
|
|||
|
switch(BaudRateFlag) {
|
|||
|
case 3:
|
|||
|
Rate = BD_9600;
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
Rate = BD_19200;
|
|||
|
break;
|
|||
|
case 7:
|
|||
|
Rate = BD_115200;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return Rate;
|
|||
|
}
|
|||
|
|