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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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