windows-nt/Source/XPSP1/NT/base/boot/kdcom/xxkdsup.c

552 lines
14 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}