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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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