OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [bench/] [sysc/] [src/] [RspConnection.cpp] - Blame information for rev 298

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.