Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

817 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. comio.c
  5. Abstract:
  6. This module implements the I/O comunications for the portable kernel
  7. debugger.
  8. Author:
  9. David N. Cutler 27-July-1990
  10. Revision History:
  11. --*/
  12. #include "bd.h"
  13. ULONG
  14. BdComputeChecksum (
  15. IN PUCHAR Buffer,
  16. IN ULONG Length
  17. )
  18. /*++
  19. Routine Description:
  20. This routine computes the checksum of the specified buffer.
  21. Arguments:
  22. Buffer - Supplies a pointer to the buffer.
  23. Length - Supplies the length of the buffer.
  24. Return Value:
  25. A ULONG is return as the checksum for the input string.
  26. --*/
  27. {
  28. ULONG Checksum = 0;
  29. while (Length > 0) {
  30. Checksum = Checksum + (ULONG)*Buffer++;
  31. Length--;
  32. }
  33. return Checksum;
  34. }
  35. USHORT
  36. BdReceivePacketLeader (
  37. IN ULONG PacketType,
  38. OUT PULONG PacketLeader
  39. )
  40. /*++
  41. Routine Description:
  42. This routine waits for a packet header leader.
  43. Arguments:
  44. PacketType - supplies the type of packet we are expecting.
  45. PacketLeader - supplies a pointer to a ulong variable to receive
  46. packet leader bytes.
  47. Return Value:
  48. BD_PACKET_RESEND - if resend is required.
  49. BD_PAKCET_TIMEOUT - if timeout.
  50. BD_PACKET_RECEIVED - if packet received.
  51. --*/
  52. {
  53. UCHAR Input, PreviousByte = 0;
  54. ULONG PacketId = 0;
  55. ULONG Index;
  56. ULONG ReturnCode;
  57. BOOLEAN BreakinDetected = FALSE;
  58. //
  59. // NOTE - With all the interrupts being off, it is very hard
  60. // to implement the actual timeout code. (Maybe, by reading the CMOS.)
  61. // Here we use a loop count to wait about 3 seconds. The CpGetByte
  62. // will return with error code = CP_GET_NODATA if it cannot find data
  63. // byte within 1 second. Kernel debugger's timeout period is 5 seconds.
  64. //
  65. Index = 0;
  66. do {
  67. ReturnCode = BlPortGetByte(BdFileId, &Input);
  68. if (ReturnCode == CP_GET_NODATA) {
  69. if (BreakinDetected) {
  70. BdControlCPending = TRUE;
  71. return BD_PACKET_RESEND;
  72. } else {
  73. return BD_PACKET_TIMEOUT;
  74. }
  75. } else if (ReturnCode == CP_GET_ERROR) {
  76. Index = 0;
  77. continue;
  78. } else { // if (ReturnCode == CP_GET_SUCCESS)
  79. if ( Input == PACKET_LEADER_BYTE ||
  80. Input == CONTROL_PACKET_LEADER_BYTE ) {
  81. if ( Index == 0 ) {
  82. PreviousByte = Input;
  83. Index++;
  84. } else if (Input == PreviousByte ) {
  85. Index++;
  86. } else {
  87. PreviousByte = Input;
  88. Index = 1;
  89. }
  90. } else {
  91. //
  92. // If we detect breakin character, we need to verify it
  93. // validity. (It is possible that we missed a packet leader
  94. // and the breakin character is simply a data byte in the
  95. // packet.)
  96. // Since kernel debugger send out breakin character ONLY
  97. // when it is waiting for State Change packet. The breakin
  98. // character should not be followed by any other character
  99. // except packet leader byte.
  100. //
  101. if ( Input == BREAKIN_PACKET_BYTE ) {
  102. BreakinDetected = TRUE;
  103. } else {
  104. //
  105. // The following statement is ABSOLUTELY necessary.
  106. //
  107. BreakinDetected = FALSE;
  108. }
  109. Index = 0;
  110. }
  111. }
  112. } while ( Index < 4 );
  113. if (BreakinDetected) {
  114. BdControlCPending = TRUE;
  115. }
  116. //
  117. // return the packet leader and FALSE to indicate no resend is needed.
  118. //
  119. if ( Input == PACKET_LEADER_BYTE ) {
  120. *PacketLeader = PACKET_LEADER;
  121. } else {
  122. *PacketLeader = CONTROL_PACKET_LEADER;
  123. }
  124. BdDebuggerNotPresent = FALSE;
  125. return BD_PACKET_RECEIVED;
  126. }
  127. VOID
  128. BdSendControlPacket (
  129. IN USHORT PacketType,
  130. IN ULONG PacketId OPTIONAL
  131. )
  132. /*++
  133. Routine Description:
  134. This routine sends a control packet to the host machine that is running the
  135. kernel debugger and waits for an ACK.
  136. Arguments:
  137. PacketType - Supplies the type of packet to send.
  138. PacketId - Supplies packet id, optionally.
  139. Return Value:
  140. None.
  141. --*/
  142. {
  143. KD_PACKET PacketHeader;
  144. //
  145. // Initialize and send the packet header.
  146. //
  147. PacketHeader.PacketLeader = CONTROL_PACKET_LEADER;
  148. if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR) PacketId )) {
  149. PacketHeader.PacketId = PacketId;
  150. }
  151. PacketHeader.ByteCount = 0;
  152. PacketHeader.Checksum = 0;
  153. PacketHeader.PacketType = PacketType;
  154. BdSendString((PCHAR)&PacketHeader, sizeof(KD_PACKET));
  155. return;
  156. }
  157. ULONG
  158. BdReceivePacket (
  159. IN ULONG PacketType,
  160. OUT PSTRING MessageHeader,
  161. OUT PSTRING MessageData,
  162. OUT PULONG DataLength
  163. )
  164. /*++
  165. Routine Description:
  166. This routine receives a packet from the host machine that is running
  167. the kernel debugger UI. This routine is ALWAYS called after packet being
  168. sent by caller. It first waits for ACK packet for the packet sent and
  169. then waits for the packet desired.
  170. N.B. If caller is BdrintString, the parameter PacketType is
  171. PACKET_TYPE_KD_ACKNOWLEDGE. In this case, this routine will return
  172. right after the ack packet is received.
  173. Arguments:
  174. PacketType - Supplies the type of packet that is excepted.
  175. MessageHeader - Supplies a pointer to a string descriptor for the input
  176. message.
  177. MessageData - Supplies a pointer to a string descriptor for the input data.
  178. DataLength - Supplies pointer to ULONG to receive length of recv. data.
  179. Return Value:
  180. BD_PACKET_RESEND - if resend is required.
  181. BD_PAKCET_TIMEOUT - if timeout.
  182. BD_PACKET_RECEIVED - if packet received.
  183. --*/
  184. {
  185. UCHAR Input;
  186. ULONG MessageLength;
  187. KD_PACKET PacketHeader;
  188. ULONG ReturnCode;
  189. ULONG Checksum;
  190. WaitForPacketLeader:
  191. //
  192. // Read Packet Leader
  193. //
  194. ReturnCode = BdReceivePacketLeader(PacketType, &PacketHeader.PacketLeader);
  195. //
  196. // If we can successfully read packet leader, it has high possibility that
  197. // kernel debugger is alive. So reset count.
  198. //
  199. if (ReturnCode != BD_PACKET_TIMEOUT) {
  200. BdNumberRetries = BdRetryCount;
  201. }
  202. if (ReturnCode != BD_PACKET_RECEIVED) {
  203. return ReturnCode;
  204. }
  205. //
  206. // Read packet type.
  207. //
  208. ReturnCode = BdReceiveString((PCHAR)&PacketHeader.PacketType,
  209. sizeof(PacketHeader.PacketType));
  210. if (ReturnCode == CP_GET_NODATA) {
  211. return BD_PACKET_TIMEOUT;
  212. } else if (ReturnCode == CP_GET_ERROR) {
  213. if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
  214. //
  215. // If read error and it is for a control packet, simply
  216. // preptend that we have not seen this packet. Hopefully
  217. // we will receive the packet we desire which automatically acks
  218. // the packet we just sent.
  219. //
  220. goto WaitForPacketLeader;
  221. } else {
  222. //
  223. // if read error while reading data packet, we have to ask
  224. // kernel debugger to resend us the packet.
  225. //
  226. goto SendResendPacket;
  227. }
  228. }
  229. //
  230. // if the packet we received is a resend request, we return true and
  231. // let caller resend the packet.
  232. //
  233. if ( PacketHeader.PacketLeader == CONTROL_PACKET_LEADER &&
  234. PacketHeader.PacketType == PACKET_TYPE_KD_RESEND ) {
  235. return BD_PACKET_RESEND;
  236. }
  237. //
  238. // Read data length.
  239. //
  240. ReturnCode = BdReceiveString((PCHAR)&PacketHeader.ByteCount,
  241. sizeof(PacketHeader.ByteCount));
  242. if (ReturnCode == CP_GET_NODATA) {
  243. return BD_PACKET_TIMEOUT;
  244. } else if (ReturnCode == CP_GET_ERROR) {
  245. if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
  246. goto WaitForPacketLeader;
  247. } else {
  248. goto SendResendPacket;
  249. }
  250. }
  251. //
  252. // Read Packet Id.
  253. //
  254. ReturnCode = BdReceiveString((PCHAR)&PacketHeader.PacketId,
  255. sizeof(PacketHeader.PacketId));
  256. if (ReturnCode == CP_GET_NODATA) {
  257. return BD_PACKET_TIMEOUT;
  258. } else if (ReturnCode == CP_GET_ERROR) {
  259. if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
  260. goto WaitForPacketLeader;
  261. } else {
  262. goto SendResendPacket;
  263. }
  264. }
  265. //
  266. // Read packet checksum.
  267. //
  268. ReturnCode = BdReceiveString((PCHAR)&PacketHeader.Checksum,
  269. sizeof(PacketHeader.Checksum));
  270. if (ReturnCode == CP_GET_NODATA) {
  271. return BD_PACKET_TIMEOUT;
  272. } else if (ReturnCode == CP_GET_ERROR) {
  273. if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
  274. goto WaitForPacketLeader;
  275. } else {
  276. goto SendResendPacket;
  277. }
  278. }
  279. //
  280. // A complete packet header is received. Check its validity and
  281. // perform appropriate action depending on packet type.
  282. //
  283. if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER ) {
  284. if (PacketHeader.PacketType == PACKET_TYPE_KD_ACKNOWLEDGE ) {
  285. //
  286. // If we received an expected ACK packet and we are not
  287. // waiting for any new packet, update outgoing packet id
  288. // and return. If we are NOT waiting for ACK packet
  289. // we will keep on waiting. If the ACK packet
  290. // is not for the packet we send, ignore it and keep on waiting.
  291. //
  292. if (PacketHeader.PacketId !=
  293. (BdNextPacketIdToSend & ~SYNC_PACKET_ID)) {
  294. goto WaitForPacketLeader;
  295. } else if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE) {
  296. BdNextPacketIdToSend ^= 1;
  297. return BD_PACKET_RECEIVED;
  298. } else {
  299. goto WaitForPacketLeader;
  300. }
  301. } else if (PacketHeader.PacketType == PACKET_TYPE_KD_RESET) {
  302. //
  303. // if we received Reset packet, reset the packet control variables
  304. // and resend earlier packet.
  305. //
  306. BdNextPacketIdToSend = INITIAL_PACKET_ID;
  307. BdPacketIdExpected = INITIAL_PACKET_ID;
  308. BdSendControlPacket(PACKET_TYPE_KD_RESET, 0L);
  309. return BD_PACKET_RESEND;
  310. } else if (PacketHeader.PacketType == PACKET_TYPE_KD_RESEND) {
  311. return BD_PACKET_RESEND;
  312. } else {
  313. //
  314. // Invalid packet header, ignore it.
  315. //
  316. goto WaitForPacketLeader;
  317. }
  318. //
  319. // The packet header is for data packet (not control packet).
  320. //
  321. } else if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE) {
  322. //
  323. // if we are waiting for ACK packet ONLY
  324. // and we receive a data packet header, check if the packet id
  325. // is what we expected. If yes, assume the acknowledge is lost (but
  326. // sent), ask sender to resend and return with PACKET_RECEIVED.
  327. //
  328. if (PacketHeader.PacketId == BdPacketIdExpected) {
  329. BdSendControlPacket(PACKET_TYPE_KD_RESEND, 0L);
  330. BdNextPacketIdToSend ^= 1;
  331. return BD_PACKET_RECEIVED;
  332. } else {
  333. BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
  334. PacketHeader.PacketId);
  335. goto WaitForPacketLeader;
  336. }
  337. }
  338. //
  339. // we are waiting for data packet and we received the packet header
  340. // for data packet. Perform the following checkings to make sure
  341. // it is the packet we are waiting for.
  342. //
  343. // Check ByteCount received is valid
  344. //
  345. MessageLength = MessageHeader->MaximumLength;
  346. if ((PacketHeader.ByteCount > (USHORT)PACKET_MAX_SIZE) ||
  347. (PacketHeader.ByteCount < (USHORT)MessageLength)) {
  348. goto SendResendPacket;
  349. }
  350. *DataLength = PacketHeader.ByteCount - MessageLength;
  351. //
  352. // Read the message header.
  353. //
  354. ReturnCode = BdReceiveString(MessageHeader->Buffer, MessageLength);
  355. if (ReturnCode != CP_GET_SUCCESS) {
  356. goto SendResendPacket;
  357. }
  358. MessageHeader->Length = (USHORT)MessageLength;
  359. //
  360. // Read the message data.
  361. //
  362. ReturnCode = BdReceiveString(MessageData->Buffer, *DataLength);
  363. if (ReturnCode != CP_GET_SUCCESS) {
  364. goto SendResendPacket;
  365. }
  366. MessageData->Length = (USHORT)*DataLength;
  367. //
  368. // Read packet trailing byte
  369. //
  370. ReturnCode = BlPortGetByte(BdFileId, &Input);
  371. if (ReturnCode != CP_GET_SUCCESS || Input != PACKET_TRAILING_BYTE) {
  372. goto SendResendPacket;
  373. }
  374. //
  375. // Check PacketType is what we are waiting for.
  376. //
  377. if (PacketType != PacketHeader.PacketType) {
  378. BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
  379. PacketHeader.PacketId
  380. );
  381. goto WaitForPacketLeader;
  382. }
  383. //
  384. // Check PacketId is valid.
  385. //
  386. if (PacketHeader.PacketId == INITIAL_PACKET_ID ||
  387. PacketHeader.PacketId == (INITIAL_PACKET_ID ^ 1)) {
  388. if (PacketHeader.PacketId != BdPacketIdExpected) {
  389. BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
  390. PacketHeader.PacketId
  391. );
  392. goto WaitForPacketLeader;
  393. }
  394. } else {
  395. goto SendResendPacket;
  396. }
  397. //
  398. // Check checksum is valid.
  399. //
  400. Checksum = BdComputeChecksum(MessageHeader->Buffer,
  401. MessageHeader->Length);
  402. Checksum += BdComputeChecksum(MessageData->Buffer,
  403. MessageData->Length);
  404. if (Checksum != PacketHeader.Checksum) {
  405. goto SendResendPacket;
  406. }
  407. //
  408. // Send Acknowledge byte and the Id of the packet received.
  409. // Then, update the ExpectId for next incoming packet.
  410. //
  411. BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
  412. PacketHeader.PacketId);
  413. //
  414. // We have successfully received the packet so update the
  415. // packet control variables and return sucess.
  416. //
  417. BdPacketIdExpected ^= 1;
  418. return BD_PACKET_RECEIVED;
  419. SendResendPacket:
  420. BdSendControlPacket(PACKET_TYPE_KD_RESEND, 0L);
  421. goto WaitForPacketLeader;
  422. }
  423. VOID
  424. BdSendPacket (
  425. IN ULONG PacketType,
  426. IN PSTRING MessageHeader,
  427. IN PSTRING MessageData OPTIONAL
  428. )
  429. /*++
  430. Routine Description:
  431. This routine sends a packet to the host machine that is running the
  432. kernel debugger and waits for an ACK.
  433. Arguments:
  434. PacketType - Supplies the type of packet to send.
  435. MessageHeader - Supplies a pointer to a string descriptor that describes
  436. the message information.
  437. MessageData - Supplies a pointer to a string descriptor that describes
  438. the optional message data.
  439. Return Value:
  440. None.
  441. --*/
  442. {
  443. KD_PACKET PacketHeader;
  444. ULONG MessageDataLength;
  445. ULONG ReturnCode;
  446. PDBGKD_DEBUG_IO DebugIo;
  447. PDBGKD_WAIT_STATE_CHANGE64 StateChange;
  448. if (ARGUMENT_PRESENT(MessageData)) {
  449. MessageDataLength = MessageData->Length;
  450. PacketHeader.Checksum = BdComputeChecksum(MessageData->Buffer,
  451. MessageData->Length);
  452. } else {
  453. MessageDataLength = 0;
  454. PacketHeader.Checksum = 0;
  455. }
  456. PacketHeader.Checksum += BdComputeChecksum(MessageHeader->Buffer,
  457. MessageHeader->Length);
  458. //
  459. // Initialize and send the packet header.
  460. //
  461. PacketHeader.PacketLeader = PACKET_LEADER;
  462. PacketHeader.ByteCount = (USHORT)(MessageHeader->Length + MessageDataLength);
  463. PacketHeader.PacketType = (USHORT)PacketType;
  464. BdNumberRetries = BdRetryCount;
  465. do {
  466. if (BdNumberRetries == 0) {
  467. //
  468. // If the packet is not for reporting exception, we give up
  469. // and declare debugger not present.
  470. //
  471. if (PacketType == PACKET_TYPE_KD_DEBUG_IO) {
  472. DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
  473. if (DebugIo->ApiNumber == DbgKdPrintStringApi) {
  474. BdDebuggerNotPresent = TRUE;
  475. BdNextPacketIdToSend = INITIAL_PACKET_ID | SYNC_PACKET_ID;
  476. BdPacketIdExpected = INITIAL_PACKET_ID;
  477. return;
  478. }
  479. } else if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64) {
  480. StateChange = (PDBGKD_WAIT_STATE_CHANGE64)MessageHeader->Buffer;
  481. if (StateChange->NewState == DbgKdLoadSymbolsStateChange) {
  482. BdDebuggerNotPresent = TRUE;
  483. BdNextPacketIdToSend = INITIAL_PACKET_ID | SYNC_PACKET_ID;
  484. BdPacketIdExpected = INITIAL_PACKET_ID;
  485. return;
  486. }
  487. } else if (PacketType == PACKET_TYPE_KD_FILE_IO) {
  488. PDBGKD_FILE_IO FileIo;
  489. FileIo = (PDBGKD_FILE_IO)MessageHeader->Buffer;
  490. if (FileIo->ApiNumber == DbgKdCreateFileApi) {
  491. BdDebuggerNotPresent = TRUE;
  492. BdNextPacketIdToSend = INITIAL_PACKET_ID | SYNC_PACKET_ID;
  493. BdPacketIdExpected = INITIAL_PACKET_ID;
  494. return;
  495. }
  496. }
  497. }
  498. //
  499. // Setting PacketId has to be in the do loop in case Packet Id was
  500. // reset.
  501. //
  502. PacketHeader.PacketId = BdNextPacketIdToSend;
  503. BdSendString((PCHAR)&PacketHeader, sizeof(KD_PACKET));
  504. //
  505. // Output message header.
  506. //
  507. BdSendString(MessageHeader->Buffer, MessageHeader->Length);
  508. //
  509. // Output message data.
  510. //
  511. if ( MessageDataLength ) {
  512. BdSendString(MessageData->Buffer, MessageData->Length);
  513. }
  514. //
  515. // Output a packet trailing byte
  516. //
  517. BlPortPutByte(BdFileId, PACKET_TRAILING_BYTE);
  518. //
  519. // Wait for the Ack Packet
  520. //
  521. ReturnCode = BdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
  522. NULL,
  523. NULL,
  524. NULL);
  525. if (ReturnCode == BD_PACKET_TIMEOUT) {
  526. BdNumberRetries--;
  527. }
  528. } while (ReturnCode != BD_PACKET_RECEIVED);
  529. //
  530. // Reset Sync bit in packet id. The packet we sent may have Sync bit set
  531. //
  532. BdNextPacketIdToSend &= ~SYNC_PACKET_ID;
  533. //
  534. // Since we are able to talk to debugger, the retrycount is set to
  535. // maximum value.
  536. //
  537. BdRetryCount = MAXIMUM_RETRIES;
  538. }
  539. ULONG
  540. BdReceiveString (
  541. OUT PCHAR Destination,
  542. IN ULONG Length
  543. )
  544. /*++
  545. Routine Description:
  546. This routine reads a string from the kernel debugger port.
  547. Arguments:
  548. Destination - Supplies a pointer to the input string.
  549. Length - Supplies the length of the string to be read.
  550. Return Value:
  551. CP_GET_SUCCESS is returned if string is successfully read from the
  552. kernel debugger line.
  553. CP_GET_ERROR is returned if error encountered during reading.
  554. CP_GET_NODATA is returned if timeout.
  555. --*/
  556. {
  557. UCHAR Input;
  558. ULONG ReturnCode;
  559. //
  560. // Read bytes until either a error is encountered or the entire string
  561. // has been read.
  562. //
  563. while (Length > 0) {
  564. ReturnCode = BlPortGetByte(BdFileId, &Input);
  565. if (ReturnCode != CP_GET_SUCCESS) {
  566. return ReturnCode;
  567. } else {
  568. *Destination++ = Input;
  569. Length -= 1;
  570. }
  571. }
  572. return CP_GET_SUCCESS;
  573. }
  574. VOID
  575. BdSendString (
  576. IN PCHAR Source,
  577. IN ULONG Length
  578. )
  579. /*++
  580. Routine Description:
  581. This routine writes a string to the kernel debugger port.
  582. Arguments:
  583. Source - Supplies a pointer to the output string.
  584. Length - Supplies the length of the string to be written.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. UCHAR Output;
  590. //
  591. // Write bytes to the kernel debugger port.
  592. //
  593. while (Length > 0) {
  594. Output = *Source++;
  595. BlPortPutByte(BdFileId, Output);
  596. Length -= 1;
  597. }
  598. return;
  599. }