📄 edbgprot.c
字号:
// establish connection with desktop
if (!(pClient->State & KITL_CLIENT_REGISTERED) && !ExchangeConfig (pClient))
return FALSE;
if (dwUserDataLen > KITL_MAX_DATA_SIZE) {
KITL_DEBUGMSG(ZONE_WARNING,("!KITLSend: Buffer too large\n"));
return FALSE;
}
// check if the data overlapped with buffer pool, reject if it does
if ((pUserData < pClient->pTxBufferPool + pClient->WindowSize * KITL_MTU)
&& (pUserData + dwUserDataLen > pClient->pTxBufferPool)) {
KITLOutputDebugString ("!KITLSend: Data to be send overlapped with buffer pools\r\n");
return FALSE;
}
// Check for re-entrancy -- e.g. if kernel debug zones are turned on
if (pClient->ServiceId == KITL_SVC_DBGMSG ) {
if (((hCurThread == hDbgMsgThread) || (hCurThread == hIntrThread) || (hCurThread == hTimerThread))
&& (KITLGlobalState & KITL_ST_MULTITHREADED)) {
if (!(KITLDebugZone & KITL_ZONE_NOSERIAL)) {
KITL_DBGMSG_INFO *pDbgMsg = (KITL_DBGMSG_INFO *)pUserData;
KITLOutputDebugString("!KITLSend(DBGMSG): Reentrant call, hTh:%X\n",hCurThread);
KITLOutputDebugString("%s\n",pUserData + pDbgMsg->dwLen);
}
return TRUE;
}
else
hDbgMsgThread = hCurThread;
}
// Determine whether we can make system calls or not. There are three cases where we cannot:
// o During system init, until KITLInitializeInterrupt is called
// o When we are called from within a system call
// o When we are called from the debugger
if (KITLGlobalState & KITL_ST_MULTITHREADED) {
// If we're in a sys call, can't block on anything (but won't be preempted)
if (InSysCall() || IsInPwrHdlr ()) {
KITL_DEBUGMSG(ZONE_WARNING,("KITLSend(%u): InSysCall or InPowerHandler, use polling\n",Id));
fUseSysCalls = FALSE;
fRestoreClientState = TRUE;
PrevSyscallState = pClient->State & KITL_USE_SYSCALLS;
pClient->State &= ~KITL_USE_SYSCALLS;
KITLGlobalState &= ~KITL_ST_MULTITHREADED;
fRestoreGlobalState = TRUE;
// The protocol state machine can't handle us stepping in at some arbitrary point
// and mucking with state, so if someone owns the CS, just bail and print to the
// debug serial port.
if (pClient->ClientCS.OwnerThread || KITLKCallcs.OwnerThread) {
KITL_DEBUGMSG(ZONE_WARNING,("!KITLSend(%u): In syscall with ClientCS owned (KCallcs = 0x%x)",Id, KITLKCallcs.OwnerThread));
if ((pClient->ServiceId == KITL_SVC_DBGMSG) && !(KITLDebugZone & KITL_ZONE_NOSERIAL)) {
KITL_DBGMSG_INFO *pDbgMsg = (KITL_DBGMSG_INFO *)pUserData;
KITLOutputDebugString("%s",pUserData + pDbgMsg->dwLen);
}
fRet = FALSE;
goto KITLSend_exit;
}
}
else if (pClient->State & KITL_USE_SYSCALLS) {
// Normal case
fUseSysCalls = TRUE;
}
else {
// This client cannot use system calls, and guarantees that scheduling is disabled while
// it is called into the KITL functions. Currently, this only applies to KDBG client.
if (Id != KITL_SVC_KDBG) {
KITL_DEBUGMSG(ZONE_WARNING,("!KITLSend(%u): KITL_USE_SYSCALLS for client turned off\n",Id));
}
fUseSysCalls = FALSE;
KITLGlobalState &= ~KITL_ST_MULTITHREADED;
fRestoreGlobalState = TRUE;
}
}
else {
// Single threaded and non preemptible
fUseSysCalls = FALSE;
}
if (fUseSysCalls)
EnterCriticalSection(&pClient->ClientCS);
KITL_DEBUGMSG(ZONE_SEND,("+KITLSend(%u), Len: %u, Seq: %u, AckExpected: %u, SC:%u\n",
Id, dwUserDataLen,pClient->TxSeqNum, pClient->AckExpected,fUseSysCalls));
// If Tx window full, block
#ifdef DEBUG
if (SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize) {
KITL_DEBUGMSG(ZONE_WARNING,("KITLSend(%u): Tx window full (AckExpected: %u, Seq: %u) SC:%u\n",
Id,pClient->AckExpected,pClient->TxSeqNum,fUseSysCalls));
}
#endif
while ( SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize) {
if (fUseSysCalls) {
SC_EventModify(pClient->evTxFull, EVENT_RESET);
LeaveCriticalSection(&pClient->ClientCS);
// Some platforms don't have interrupts
if (KITLGlobalState & KITL_ST_INT_ENABLED) {
WaitAgain:
if (SC_WaitForMultiple (1,&pClient->evTxFull,0,KITL_TIMEOUT_INTERVAL_MS) != WAIT_OBJECT_0) {
KITLOutputDebugString("0x%x: KITLSend(%u): Timed out waiting for ack (AckExpected: %u, TxSeq: %u)\n", hCurThread, Id,
pClient->AckExpected,pClient->TxSeqNum);
// For default services, don't give up
if (IS_DFLT_SVC(Id))
goto WaitAgain;
fRet = FALSE;
goto KITLSend_exit;
}
if (!(pClient->State & KITL_CLIENT_REGISTERED)) {
// client de-registered, return FALSE
KITL_DEBUGMSG(ZONE_WARNING,("KITLSend(%u): Client de-registered while sending\n", Id));
fRet = FALSE;
goto KITLSend_exit;
}
}
else {
if (!KITLPollData(TRUE, NULL, NULL)) {
fRet = FALSE;
goto KITLSend_exit;
}
// Give retransmit thread chance to run
if (SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize)
SC_Sleep(1);
}
EnterCriticalSection(&pClient->ClientCS);
} else {
// we're InSysCall or in KD, Poll until window closes
KITLPollResponse (FALSE, ChkAck, TranAck, pClient);
}
}
// Format frame into Tx buffer (leave space for transport headers)
dwPacketIndex = pClient->TxSeqNum % pClient->WindowSize;
pFrame = pClient->pTxBufferPool + (dwPacketIndex * KITL_MTU);
pHdr = (PKITL_HDR) (pFrame + Kitl.FrmHdrSize);
pHdr->Id = KITL_ID;
pHdr->Service = pClient->ServiceId;
pHdr->Flags = KITL_FL_FROM_DEV;
pHdr->Cmd = KITL_CMD_SVC_DATA;
pHdr->SeqNum = pClient->TxSeqNum;
SEQ_INC(pClient->TxSeqNum);
pData = (UCHAR *)KITLDATA(pHdr);
// Copy user data into buffer
memcpy(pData, pUserData, dwUserDataLen);
pClient->TxFrameLen[dwPacketIndex] = (USHORT)(dwUserDataLen + sizeof(KITL_HDR));
if (KITLDebugZone & ZONE_FRAMEDUMP)
KITLDecodeFrame(">>KITLSend", pHdr, pClient->TxFrameLen[dwPacketIndex]);
if (!(fRet = KitlSendFrame (pFrame, pClient->TxFrameLen[dwPacketIndex])))
KITLOutputDebugString("!KITLSend: Error in KitlSendFrame\n");
else {
if (!fUseSysCalls)
fRet = KITLPollResponse (FALSE, ChkAck, TranAck, pClient);
else {
// Start retransmit timer
TimerStart(pClient, dwPacketIndex, KITL_RETRANSMIT_INTERVAL_MS, TRUE);
// If we're in stop and wait mode, wait for ack here. Also need to do this
// if our interrupt isn't enabled.
if ((pClient->CfgFlags & KITL_CFGFL_STOP_AND_WAIT) ||
!(KITLGlobalState & KITL_ST_INT_ENABLED)) {
SC_EventModify(pClient->evTxFull, EVENT_RESET);
LeaveCriticalSection(&pClient->ClientCS);
if (KITLGlobalState & KITL_ST_INT_ENABLED) {
while (SC_WaitForMultiple (1,&pClient->evTxFull, 0, KITL_TIMEOUT_INTERVAL_MS) == WAIT_TIMEOUT) {
KITL_DEBUGMSG(ZONE_WARNING,("KITLSend: Id: %u Timed out waiting for ack (AckExpected: %u, TxSeq: %u)\n",Id,
pClient->AckExpected,pClient->TxSeqNum));
}
if (!(pClient->State & KITL_CLIENT_REGISTERED)) {
// client de-registered, return FALSE
KITL_DEBUGMSG(ZONE_WARNING,("KITLSend(%u): Client de-registered while sending\n", Id));
fRet = FALSE;
goto KITLSend_exit;
}
}
else {
fRet = KITLPollResponse (TRUE, ChkAck, TranAck, pClient);
}
EnterCriticalSection(&pClient->ClientCS);
}
if (!fRet)
TimerStop(pClient, dwPacketIndex, TRUE);
}
}
if (!fRet) {
// Restore state
pClient->TxSeqNum = SEQ_SUB1(pClient->TxSeqNum);
pClient->TxFrameLen[dwPacketIndex] = 0;
}
if (fUseSysCalls)
LeaveCriticalSection(&pClient->ClientCS);
KITLSend_exit:
if (pClient->ServiceId == KITL_SVC_DBGMSG)
hDbgMsgThread = 0;
if (fRestoreClientState)
pClient->State |= PrevSyscallState;
if (fRestoreGlobalState)
KITLGlobalState |= KITL_ST_MULTITHREADED;
KITL_DEBUGMSG(ZONE_SEND,("-Send (%u): Ret %u\n", Id, fRet));
return fRet;
}
/* RetransmitFrame
*
* Retransmit specified frame in Tx buffer, either due to a timeout waiting
* for an ack, or a NACK received from the peer.
*
* Return Value:
* Return TRUE if the timer should be rescheduled, FALSE if not. We only return
* FALSE if the retransmitted frame does not fall in the Tx window. This can
* happen if we get called in a sys call, and so cannot touch the timer structs
* (since can't get the CS).
*/
BOOL
RetransmitFrame(KITL_CLIENT *pClient, UCHAR Index, BOOL fUseSysCalls)
{
UCHAR *pData = pClient->pTxBufferPool + (Index * KITL_MTU);
DWORD OldProcPerms;
BOOL fRet = TRUE;
KITL_HDR *pHdr;
pHdr = (KITL_HDR *)(pData + Kitl.FrmHdrSize);
if (fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS))
EnterCriticalSection(&pClient->ClientCS);
// Set permissions for accessing client buffer, if necessary
if (pClient->ProcPerms) {
SWITCHKEY (OldProcPerms, pClient->ProcPerms);
}
if (!SEQ_BETWEEN(pClient->AckExpected, pHdr->SeqNum, pClient->TxSeqNum)) {
KITL_DEBUGMSG(ZONE_WARNING,("!RetransmitFrame: Frame seq %u not in Tx window (%u,%u)\n",
pHdr->SeqNum, pClient->AckExpected, pClient->TxSeqNum));
fRet = FALSE; // Don't reschedule timer
} else {
if (KITLDebugZone & ZONE_FRAMEDUMP)
KITLDecodeFrame(">>Retransmit", pHdr, pClient->TxFrameLen[Index]);
KITL_DEBUGMSG(ZONE_RETRANSMIT,("RetransmitFrame(Id:%u), Seq: %u, Len: %u, Window (%u,%u)\n",pClient->ServiceId,
pHdr->SeqNum, pClient->TxFrameLen[Index], pClient->AckExpected, pClient->TxSeqNum));
if (!KitlSendRawData (pData, (USHORT) (pClient->TxFrameLen[Index] + Kitl.FrmHdrSize + Kitl.FrmTlrSize))) {
KITLOutputDebugString("!RetransmitFrame: Error in KitlSendRawData\n");
// Go ahead and return TRUE so frame will be tried again.
}
}
if (pClient->ProcPerms) {
SETCURKEY (OldProcPerms);
}
if (fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS))
LeaveCriticalSection(&pClient->ClientCS);
return fRet;
}
/* SendAckNack
*
* Send an ACK or NACK frame to peer:
* ACK: Acknowledge receipt of all frames up to SeqNum
* NACK: Request retransmission of frame specified by SeqNum
*/
static void
SendAckNack(BOOL IsAck, KITL_CLIENT *pClient, UCHAR SeqNum)
{
UCHAR *AckNackBuf;
KITL_HDR *pHdr;
AckNackBuf = _alloca (Kitl.FrmHdrSize // for transport header
+ sizeof(KITL_HDR) // for protocol header
+ Kitl.FrmTlrSize); // for transport tailer
if (!AckNackBuf) {
KITLOutputDebugString ("!SendAckNack: Stack overflow\r\n");
return;
}
pHdr = (KITL_HDR *)(AckNackBuf + Kitl.FrmHdrSize);
pHdr->Id = KITL_ID;
pHdr->Service = pClient->ServiceId; // must use id of the other side
pHdr->Flags = (IsAck? KITL_FL_ACK:KITL_FL_NACK)|KITL_FL_FROM_DEV;
pHdr->Cmd = KITL_CMD_SVC_DATA;
pHdr->SeqNum = SeqNum;
if (KITLDebugZone & ZONE_FRAMEDUMP)
KITLDecodeFrame(">>SendAckNack ", pHdr, sizeof(KITL_HDR));
if (!KitlSendFrame (AckNackBuf, sizeof(KITL_HDR)))
KITLOutputDebugString("!KITL: Error in KitlSendFrame for ACK\n");
}
/*
* @func BOOL | KITLRecv | Receive message over debug Ethernet interface.
* @rdesc Return TRUE if successful, FALSE if error occurrs.
* @comm Receive message from peer KITL client. If no received data
* is available for the specified service, block until data is ready, or
* timeout occurs.
* Note: If the caller does not provide a big enough buffer to hold the data,
* the buffer is filled, and remaining data is tossed. Don't have to worry
* about this by providing a buffer of KITL_MAX_DATA_SIZE bytes.
* @xref <f KITLRegisterClient> <f KITLSend>
*/
BOOL
KITLRecv(
UCHAR Id, // @parm [IN] - KITL client id (returned from <f KITLRegisterClient>)
UCHAR *pRecvBuf, // @parm [OUT]- Buffer to receive data
DWORD *pdwLen, // @parm [IN] - Buffer size. [OUT] - Bytes of data received.
DWORD Timeout) // @parm [IN] - Timeout value (0 == don't block, INFINITE == wait forever)
{
KITL_CLIENT *pClient = KITLClients[Id];
DWORD dwStartTime;
DWORD dwBytesToCopy;
UCHAR PrevSyscallState;
BOOL fRestoreClientState = FALSE, fRestoreGlobalState = FALSE;
BOOL fUseSysCalls;
BOOL fRet = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -