PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/bench/sysc/src/RspConnection.cpp

https://github.com/fjullien/orpsocv2
C++ | 597 lines | 302 code | 112 blank | 183 comment | 78 complexity | 28ccf843d6adb31b584e2b786dd7594b MD5 | raw file
  1. // ----------------------------------------------------------------------------
  2. // Remote Serial Protocol connection: implementation
  3. // Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
  4. // Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
  5. // This file is part of the cycle accurate model of the OpenRISC 1000 based
  6. // system-on-chip, ORPSoC, built using Verilator.
  7. // This program is free software: you can redistribute it and/or modify it
  8. // under the terms of the GNU Lesser General Public License as published by
  9. // the Free Software Foundation, either version 3 of the License, or (at your
  10. // option) any later version.
  11. // This program is distributed in the hope that it will be useful, but WITHOUT
  12. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  14. // License for more details.
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. // ----------------------------------------------------------------------------
  18. // $Id: RspConnection.cpp 327 2009-03-07 19:10:56Z jeremy $
  19. #include <iostream>
  20. #include <iomanip>
  21. #include <cerrno>
  22. #include <csignal>
  23. #include <cstring>
  24. #include <netdb.h>
  25. #include <arpa/inet.h>
  26. #include <netinet/in.h>
  27. #include <netinet/tcp.h>
  28. #include <sys/socket.h>
  29. #include <sys/ioctl.h>
  30. #include <fcntl.h>
  31. #include <poll.h>
  32. #include "RspConnection.h"
  33. #include "Utils.h"
  34. using std::cerr;
  35. using std::cout;
  36. using std::dec;
  37. using std::endl;
  38. using std::flush;
  39. using std::hex;
  40. using std::setfill;
  41. using std::setw;
  42. // Define RSP_TRACE to turn on tracing of packets sent and received
  43. // #define RSP_TRACE
  44. //-----------------------------------------------------------------------------
  45. //! Constructor when using a port number
  46. //! Calls the generic initializer.
  47. //! @param[in] _portNum The port number to connect to
  48. //-----------------------------------------------------------------------------
  49. RspConnection::RspConnection(int _portNum)
  50. {
  51. rspInit(_portNum, DEFAULT_RSP_SERVICE);
  52. } // RspConnection ()
  53. //-----------------------------------------------------------------------------
  54. //! Constructor when using a service
  55. //! Calls the generic initializer.
  56. //! @param[in] _serviceName The service name to use. Defaults to
  57. //! DEFAULT_RSP_SERVER
  58. //-----------------------------------------------------------------------------
  59. RspConnection::RspConnection(const char *_serviceName)
  60. {
  61. rspInit(0, _serviceName);
  62. } // RspConnection ()
  63. //-----------------------------------------------------------------------------
  64. //! Destructor
  65. //! Close the connection if it is still open
  66. //-----------------------------------------------------------------------------
  67. RspConnection::~RspConnection()
  68. {
  69. this->rspClose(); // Don't confuse with any other close ()
  70. } // ~RspConnection ()
  71. //-----------------------------------------------------------------------------
  72. //! Generic initialization routine specifying both port number and service
  73. //! name.
  74. //! Private, since this is not intended to be called by users. The service
  75. //! name is only used if port number is zero.
  76. //! Allocate the two fifos from packets from the client and to the client.
  77. //! We only use a single packet in transit at any one time, so allocate that
  78. //! packet here (rather than getting a new one each time.
  79. //! @param[in] _portNum The port number to connect to
  80. //! @param[in] _serviceName The service name to use (if PortNum == 0).
  81. //-----------------------------------------------------------------------------
  82. void
  83. RspConnection::rspInit(int _portNum, const char *_serviceName)
  84. {
  85. portNum = _portNum;
  86. serviceName = _serviceName;
  87. clientFd = -1;
  88. } // init ()
  89. //-----------------------------------------------------------------------------
  90. //! Get a new client connection.
  91. //! Blocks until the client connection is available.
  92. //! A lot of this code is copied from remote_open in gdbserver remote-utils.c.
  93. //! This involves setting up a socket to listen on a socket for attempted
  94. //! connections from a single GDB instance (we couldn't be talking to multiple
  95. //! GDBs at once!).
  96. //! The service is specified either as a port number in the Or1ksim
  97. //! configuration (parameter rsp_port in section debug, default 51000) or as a
  98. //! service name in the constant OR1KSIM_RSP_SERVICE.
  99. //! If there is a catastrophic communication failure, service will be
  100. //! terminated using sc_stop.
  101. //! The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL.
  102. //! @return TRUE if the connection was established or can be retried. FALSE
  103. //! if the error was so serious the program must be aborted.
  104. //-----------------------------------------------------------------------------
  105. bool RspConnection::rspConnect()
  106. {
  107. // 0 is used as the RSP port number to indicate that we should use the
  108. // service name instead.
  109. if (0 == portNum) {
  110. struct servent *service = getservbyname(serviceName, "tcp");
  111. if (NULL == service) {
  112. cerr << "ERROR: RSP unable to find service \"" <<
  113. serviceName << "\": " << strerror(errno) << endl;
  114. return false;
  115. }
  116. portNum = ntohs(service->s_port);
  117. }
  118. // Open a socket on which we'll listen for clients
  119. int tmpFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  120. if (tmpFd < 0) {
  121. cerr << "ERROR: Cannot open RSP socket" << endl;
  122. return false;
  123. }
  124. // Allow rapid reuse of the port on this socket
  125. int optval = 1;
  126. setsockopt(tmpFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
  127. sizeof(optval));
  128. // Bind the port to the socket
  129. struct sockaddr_in sockAddr;
  130. sockAddr.sin_family = PF_INET;
  131. sockAddr.sin_port = htons(portNum);
  132. sockAddr.sin_addr.s_addr = INADDR_ANY;
  133. if (bind(tmpFd, (struct sockaddr *)&sockAddr, sizeof(sockAddr))) {
  134. cerr << "ERROR: Cannot bind to RSP socket" << endl;
  135. return false;
  136. }
  137. // Listen for (at most one) client
  138. if (listen(tmpFd, 1)) {
  139. cerr << "ERROR: Cannot listen on RSP socket" << endl;
  140. return false;
  141. }
  142. cout << "Listening for RSP on port " << portNum << endl << flush;
  143. // Accept a client which connects
  144. socklen_t len; // Size of the socket address
  145. clientFd = accept(tmpFd, (struct sockaddr *)&sockAddr, &len);
  146. if (-1 == clientFd) {
  147. cerr << "Warning: Failed to accept RSP client" << endl;
  148. return true; // OK to retry
  149. }
  150. // Enable TCP keep alive process
  151. optval = 1;
  152. setsockopt(clientFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval,
  153. sizeof(optval));
  154. int flags;
  155. /* If they have O_NONBLOCK, use the Posix way to do it */
  156. #if defined(O_NONBLOCK)
  157. /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
  158. if (-1 == (flags = fcntl(clientFd, F_GETFL, 0)))
  159. flags = 0;
  160. fcntl(clientFd, F_SETFL, flags | O_NONBLOCK);
  161. #else
  162. /* Otherwise, use the old way of doing it */
  163. flags = 1;
  164. ioctl(clientFd, FIOBIO, &flags);
  165. #endif
  166. /* Set socket to be non-blocking */
  167. /* We do this because when we're given a continue, or step
  168. instruction,command we set the processor stall off, then instantly check
  169. if it's stopped. If it hasn't then we drop through and wait for input
  170. from GDB. Obviously this will cause problems when it will stop after we
  171. do the check. So now, rspSocketPeek() been implemented to simply check if
  172. there's an incoming command from GDB (although, mainly interested in
  173. int. commands), otherwise it returns back to poll the processor's
  174. stall bit. It can only do this if the socket is non-blocking.
  175. At first test, simply adding this line appeared to give no problems with
  176. the existing code. No "simulation" of blocking behaviour on the
  177. non-blocking socket was required (in the event that a read/write throws
  178. back a EWOULDBLOCK error, as was looked to be the case in the previous
  179. GDB handling code) -- Julius
  180. */
  181. if (ioctl(clientFd, FIONBIO, (char *)&optval) > 0) {
  182. cerr << "RspConnect: ioctl failed, line " << __LINE__ << endl;
  183. close(clientFd);
  184. close(tmpFd);
  185. return false;
  186. }
  187. // Don't delay small packets, for better interactive response (disable
  188. // Nagel's algorithm)
  189. optval = 1;
  190. setsockopt(clientFd, IPPROTO_TCP, TCP_NODELAY, (char *)&optval,
  191. sizeof(optval));
  192. // Socket is no longer needed
  193. close(tmpFd); // No longer need this
  194. signal(SIGPIPE, SIG_IGN); // So we don't exit if client dies
  195. cout << "Remote debugging from host " << inet_ntoa(sockAddr.sin_addr)
  196. << endl;
  197. return true;
  198. } // rspConnect ()
  199. //-----------------------------------------------------------------------------
  200. //! Close a client connection if it is open
  201. //-----------------------------------------------------------------------------
  202. void RspConnection::rspClose()
  203. {
  204. if (isConnected()) {
  205. cout << "Closing connection" << endl;
  206. close(clientFd);
  207. clientFd = -1;
  208. }
  209. } // rspClose ()
  210. //-----------------------------------------------------------------------------
  211. //! Report if we are connected to a client.
  212. //! @return TRUE if we are connected, FALSE otherwise
  213. //-----------------------------------------------------------------------------
  214. bool RspConnection::isConnected()
  215. {
  216. return -1 != clientFd;
  217. } // isConnected ()
  218. //-----------------------------------------------------------------------------
  219. //! Peek at data coming into server from GDB
  220. //! Useful for polling for ETX (0x3) chars being sent when GDB wants to
  221. //! interrupt
  222. //! @return the char we peeked, 0 otherwise
  223. //-----------------------------------------------------------------------------
  224. char RspConnection::rspSocketPeek()
  225. {
  226. char c;
  227. int n;
  228. // Using recv here instead of read becuase we can pass the MSG_PEEK
  229. // flag, which lets us look at what's on the socket, without actually
  230. // taking it off
  231. //if (DEBUG_GDB)
  232. // printf("peeking at GDB socket...\n");
  233. n = recv(clientFd, &c, sizeof(c), MSG_PEEK);
  234. //if (DEBUG_GDB)
  235. // printf("peeked, got n=%d, c=0x%x\n",n, c);
  236. if (n > 0)
  237. return c;
  238. else
  239. return -1;
  240. /*
  241. if (n > 0)
  242. return c;
  243. else
  244. return '\0';
  245. */
  246. }
  247. //-----------------------------------------------------------------------------
  248. //! Get the next packet from the RSP connection
  249. //! Modeled on the stub version supplied with GDB. This allows the user to
  250. //! replace the character read function, which is why we get stuff a character
  251. //! at at time.
  252. //! Unlike the reference implementation, we don't deal with sequence
  253. //! numbers. GDB has never used them, and this implementation is only intended
  254. //! for use with GDB 6.8 or later. Sequence numbers were removed from the RSP
  255. //! standard at GDB 5.0.
  256. //! Since this is SystemC, if we hit something that is not a packet and
  257. //! requires a restart/retransmission, we wait so another thread gets a lookin.
  258. //! @param[in] pkt The packet for storing the result.
  259. //! @return TRUE to indicate success, FALSE otherwise (means a communications
  260. //! failure)
  261. //-----------------------------------------------------------------------------
  262. bool RspConnection::getPkt(RspPacket * pkt)
  263. {
  264. // Keep getting packets, until one is found with a valid checksum
  265. while (true) {
  266. int bufSize = pkt->getBufSize();
  267. unsigned char checksum; // The checksum we have computed
  268. int count; // Index into the buffer
  269. int ch; // Current character
  270. // Wait around for the start character ('$'). Ignore all other
  271. // characters
  272. ch = getRspChar();
  273. while (ch != '$') {
  274. if (-1 == ch) {
  275. return false; // Connection failed
  276. } else {
  277. ch = getRspChar();
  278. }
  279. }
  280. // Read until a '#' or end of buffer is found
  281. checksum = 0;
  282. count = 0;
  283. while (count < bufSize - 1) {
  284. ch = getRspChar();
  285. if (-1 == ch) {
  286. return false; // Connection failed
  287. }
  288. // If we hit a start of line char begin all over again
  289. if ('$' == ch) {
  290. checksum = 0;
  291. count = 0;
  292. continue;
  293. }
  294. // Break out if we get the end of line char
  295. if ('#' == ch) {
  296. break;
  297. }
  298. // Update the checksum and add the char to the buffer
  299. checksum = checksum + (unsigned char)ch;
  300. pkt->data[count] = (char)ch;
  301. count++;
  302. }
  303. // Mark the end of the buffer with EOS - it's convenient for non-binary
  304. // data to be valid strings.
  305. pkt->data[count] = 0;
  306. pkt->setLen(count);
  307. // If we have a valid end of packet char, validate the checksum. If we
  308. // don't it's because we ran out of buffer in the previous loop.
  309. if ('#' == ch) {
  310. unsigned char xmitcsum; // The checksum in the packet
  311. ch = getRspChar();
  312. if (-1 == ch) {
  313. return false; // Connection failed
  314. }
  315. xmitcsum = Utils::char2Hex(ch) << 4;
  316. ch = getRspChar();
  317. if (-1 == ch) {
  318. return false; // Connection failed
  319. }
  320. xmitcsum += Utils::char2Hex(ch);
  321. // If the checksums don't match print a warning, and put the
  322. // negative ack back to the client. Otherwise put a positive ack.
  323. if (checksum != xmitcsum) {
  324. cerr << "Warning: Bad RSP checksum: Computed 0x"
  325. << setw(2) << setfill('0') << hex
  326. << checksum << ", received 0x" << xmitcsum
  327. << setfill(' ') << dec << endl;
  328. if (!putRspChar('-')) // Failed checksum
  329. {
  330. return false; // Comms failure
  331. }
  332. } else {
  333. if (!putRspChar('+')) // successful transfer
  334. {
  335. return false; // Comms failure
  336. } else {
  337. #ifdef RSP_TRACE
  338. cout << "getPkt: " << *pkt << endl;
  339. #endif
  340. return true; // Success
  341. }
  342. }
  343. } else {
  344. cerr << "Warning: RSP packet overran buffer" << endl;
  345. }
  346. }
  347. } // getPkt ()
  348. //-----------------------------------------------------------------------------
  349. //! Put the packet out on the RSP connection
  350. //! Modeled on the stub version supplied with GDB. Put out the data preceded
  351. //! by a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}'
  352. //! are escaped by preceding them with '}' and then XORing the character with
  353. //! 0x20.
  354. //! Since this is SystemC, if we hit something that requires a
  355. //! restart/retransmission, we wait so another thread gets a lookin.
  356. //! @param[in] pkt The Packet to transmit
  357. //! @return TRUE to indicate success, FALSE otherwise (means a communications
  358. //! failure).
  359. //-----------------------------------------------------------------------------
  360. bool RspConnection::putPkt(RspPacket * pkt)
  361. {
  362. int len = pkt->getLen();
  363. int ch; // Ack char
  364. // Construct $<packet info>#<checksum>. Repeat until the GDB client
  365. // acknowledges satisfactory receipt.
  366. do {
  367. unsigned char checksum = 0; // Computed checksum
  368. int count = 0; // Index into the buffer
  369. if (!putRspChar('$')) // Start char
  370. {
  371. return false; // Comms failure
  372. }
  373. // Body of the packet
  374. for (count = 0; count < len; count++) {
  375. unsigned char ch = pkt->data[count];
  376. // Check for escaped chars
  377. if (('$' == ch) || ('#' == ch) || ('*' == ch)
  378. || ('}' == ch)) {
  379. ch ^= 0x20;
  380. checksum += (unsigned char)'}';
  381. if (!putRspChar('}')) {
  382. return false; // Comms failure
  383. }
  384. }
  385. checksum += ch;
  386. if (!putRspChar(ch)) {
  387. return false; // Comms failure
  388. }
  389. }
  390. if (!putRspChar('#')) // End char
  391. {
  392. return false; // Comms failure
  393. }
  394. // Computed checksum
  395. if (!putRspChar(Utils::hex2Char(checksum >> 4))) {
  396. return false; // Comms failure
  397. }
  398. if (!putRspChar(Utils::hex2Char(checksum % 16))) {
  399. return false; // Comms failure
  400. }
  401. // Check for ack of connection failure
  402. ch = getRspChar();
  403. if (-1 == ch) {
  404. return false; // Comms failure
  405. }
  406. }
  407. while ('+' != ch);
  408. #ifdef RSP_TRACE
  409. cout << "putPkt: " << *pkt << endl;
  410. #endif
  411. return true;
  412. } // putPkt ()
  413. //-----------------------------------------------------------------------------
  414. //! Put a single character out on the RSP connection
  415. //! Utility routine. This should only be called if the client is open, but we
  416. //! check for safety.
  417. //! @param[in] c The character to put out
  418. //! @return TRUE if char sent OK, FALSE if not (communications failure)
  419. //-----------------------------------------------------------------------------
  420. bool RspConnection::putRspChar(char c)
  421. {
  422. if (-1 == clientFd) {
  423. cerr << "Warning: Attempt to write '" << c
  424. << "' to unopened RSP client: Ignored" << endl;
  425. return false;
  426. }
  427. // Write until successful (we retry after interrupts) or catastrophic
  428. // failure.
  429. while (true) {
  430. switch (write(clientFd, &c, sizeof(c))) {
  431. case -1:
  432. // Error: only allow interrupts or would block
  433. if ((EAGAIN != errno) && (EINTR != errno)) {
  434. cerr <<
  435. "Warning: Failed to write to RSP client: "
  436. << "Closing client connection: " <<
  437. strerror(errno) << endl;
  438. return false;
  439. }
  440. break;
  441. case 0:
  442. break; // Nothing written! Try again
  443. default:
  444. return true; // Success, we can return
  445. }
  446. }
  447. } // putRspChar ()
  448. //-----------------------------------------------------------------------------
  449. //! Get a single character from the RSP connection
  450. //! Utility routine. This should only be called if the client is open, but we
  451. //! check for safety.
  452. //! @return The character received or -1 on failure
  453. //-----------------------------------------------------------------------------
  454. int RspConnection::getRspChar()
  455. {
  456. if (-1 == clientFd) {
  457. cerr << "Warning: Attempt to read from "
  458. << "unopened RSP client: Ignored" << endl;
  459. return -1;
  460. }
  461. // Blocking read until successful (we retry after interrupts) or
  462. // catastrophic failure.
  463. while (true) {
  464. unsigned char c;
  465. switch (read(clientFd, &c, sizeof(c))) {
  466. case -1:
  467. if (errno == EAGAIN || errno == EWOULDBLOCK)
  468. continue;
  469. // Error: only allow interrupts
  470. if (EINTR != errno) {
  471. cerr <<
  472. "Warning: Failed to read from RSP client: "
  473. << "Closing client connection: " <<
  474. strerror(errno) << endl;
  475. return -1;
  476. }
  477. break;
  478. case 0:
  479. return -1;
  480. default:
  481. return c & 0xff; // Success, we can return (no sign extend!)
  482. }
  483. }
  484. } // getRspChar ()