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;
|
||
}
|
||
|