gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
terminal.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Authors: Nathan Binkert
29  * Ali Saidi
30  */
31 
32 /* @file
33  * Implements the user interface to a serial terminal
34  */
35 
36 #include <sys/ioctl.h>
37 
38 #if defined(__FreeBSD__)
39 #include <termios.h>
40 
41 #else
42 #include <sys/termios.h>
43 
44 #endif
45 #include "dev/terminal.hh"
46 
47 #include <poll.h>
48 #include <unistd.h>
49 
50 #include <cctype>
51 #include <cerrno>
52 #include <fstream>
53 #include <iostream>
54 #include <sstream>
55 #include <string>
56 
57 #include "base/atomicio.hh"
58 #include "base/misc.hh"
59 #include "base/output.hh"
60 #include "base/socket.hh"
61 #include "base/trace.hh"
62 #include "debug/Terminal.hh"
63 #include "debug/TerminalVerbose.hh"
64 #include "dev/platform.hh"
65 #include "dev/uart.hh"
66 
67 using namespace std;
68 
69 
70 /*
71  * Poll event for the listen socket
72  */
74  : PollEvent(fd, e), term(t)
75 {
76 }
77 
78 void
80 {
81  term->accept();
82 }
83 
84 /*
85  * Poll event for the data socket
86  */
88  : PollEvent(fd, e), term(t)
89 {
90 }
91 
92 void
94 {
95  // As a consequence of being called from the PollQueue, we might
96  // have been called from a different thread. Migrate to "our"
97  // thread.
98  EventQueue::ScopedMigration migrate(term->eventQueue());
99 
100  if (revent & POLLIN)
101  term->data();
102  else if (revent & POLLNVAL)
103  term->detach();
104 }
105 
106 /*
107  * Terminal code
108  */
110  : SimObject(p), termDataAvail(NULL), listenEvent(NULL), dataEvent(NULL),
111  number(p->number), data_fd(-1), txbuf(16384), rxbuf(16384),
112  outfile(p->output ? simout.findOrCreate(p->name) : NULL)
113 #if TRACING_ON == 1
114  , linebuf(16384)
115 #endif
116 {
117  if (outfile)
118  outfile->stream()->setf(ios::unitbuf);
119 
120  if (p->port)
121  listen(p->port);
122 }
123 
125 {
126  if (data_fd != -1)
127  ::close(data_fd);
128 
129  if (listenEvent)
130  delete listenEvent;
131 
132  if (dataEvent)
133  delete dataEvent;
134 }
135 
136 void
138 {
139  // This can happen if the user has connected multiple UARTs to the
140  // same terminal. In that case, each of them tries to register
141  // callbacks.
142  if (termDataAvail)
143  fatal("Terminal already has already been associated with a UART.\n");
144  termDataAvail = c;
145 }
146 
148 // socket creation and terminal attach
149 //
150 
151 void
153 {
155  warn_once("Sockets disabled, not accepting terminal connections");
156  return;
157  }
158 
159  while (!listener.listen(port, true)) {
161  ": can't bind address terminal port %d inuse PID %d\n",
162  port, getpid());
163  port++;
164  }
165 
166  int p1, p2;
167  p2 = name().rfind('.') - 1;
168  p1 = name().rfind('.', p2);
169  ccprintf(cerr, "Listening for %s connection on port %d\n",
170  name().substr(p1+1,p2-p1), port);
171 
172  listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
174 }
175 
176 void
178 {
179  if (!listener.islistening())
180  panic("%s: cannot accept a connection if not listening!", name());
181 
182  int fd = listener.accept(true);
183  if (data_fd != -1) {
184  char message[] = "terminal already attached!\n";
185  atomic_write(fd, message, sizeof(message));
186  ::close(fd);
187  return;
188  }
189 
190  data_fd = fd;
191  dataEvent = new DataEvent(this, data_fd, POLLIN);
193 
194  stringstream stream;
195  ccprintf(stream, "==== m5 slave terminal: Terminal %d ====", number);
196 
197  // we need an actual carriage return followed by a newline for the
198  // terminal
199  stream << "\r\n";
200 
201  write((const uint8_t *)stream.str().c_str(), stream.str().size());
202 
203  DPRINTFN("attach terminal %d\n", number);
204  char buf[1024];
205  for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) {
206  const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf)));
207  txbuf.peek(buf, i, chunk_len);
208  write((const uint8_t *)buf, chunk_len);
209  }
210 }
211 
212 void
214 {
215  if (data_fd != -1) {
216  ::close(data_fd);
217  data_fd = -1;
218  }
219 
221  delete dataEvent;
222  dataEvent = NULL;
223 
224  DPRINTFN("detach terminal %d\n", number);
225 }
226 
227 void
229 {
230  uint8_t buf[1024];
231  int len;
232 
233  len = read(buf, sizeof(buf));
234  if (len) {
235  rxbuf.write((char *)buf, len);
236  // Inform the UART there is data available
237  assert(termDataAvail);
239  }
240 }
241 
242 size_t
243 Terminal::read(uint8_t *buf, size_t len)
244 {
245  if (data_fd < 0)
246  panic("Terminal not properly attached.\n");
247 
248  ssize_t ret;
249  do {
250  ret = ::read(data_fd, buf, len);
251  } while (ret == -1 && errno == EINTR);
252 
253 
254  if (ret < 0)
255  DPRINTFN("Read failed.\n");
256 
257  if (ret <= 0) {
258  detach();
259  return 0;
260  }
261 
262  return ret;
263 }
264 
265 // Terminal output.
266 size_t
267 Terminal::write(const uint8_t *buf, size_t len)
268 {
269  if (data_fd < 0)
270  panic("Terminal not properly attached.\n");
271 
272  ssize_t ret = atomic_write(data_fd, buf, len);
273  if (ret < len)
274  detach();
275 
276  return ret;
277 }
278 
279 #define MORE_PENDING (ULL(1) << 61)
280 #define RECEIVE_SUCCESS (ULL(0) << 62)
281 #define RECEIVE_NONE (ULL(2) << 62)
282 #define RECEIVE_ERROR (ULL(3) << 62)
283 
284 uint8_t
286 {
287  uint8_t c;
288 
289  assert(!rxbuf.empty());
290  rxbuf.read((char *)&c, 1);
291 
292  DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n",
293  isprint(c) ? c : ' ', c, !rxbuf.empty());
294 
295  return c;
296 }
297 
298 uint64_t
300 {
301  uint64_t value;
302 
303  if (dataAvailable()) {
304  value = RECEIVE_SUCCESS | in();
305  if (!rxbuf.empty())
306  value |= MORE_PENDING;
307  } else {
308  value = RECEIVE_NONE;
309  }
310 
311  DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value);
312 
313  return value;
314 }
315 
316 void
318 {
319 #if TRACING_ON == 1
320  if (DTRACE(Terminal)) {
321  static char last = '\0';
322 
323  if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) {
324  if (c == '\n' || c == '\r') {
325  int size = linebuf.size();
326  char *buffer = new char[size + 1];
327  linebuf.read(buffer, size);
328  buffer[size] = '\0';
329  DPRINTF(Terminal, "%s\n", buffer);
330  delete [] buffer;
331  } else {
332  linebuf.write(&c, 1);
333  }
334  }
335 
336  last = c;
337  }
338 #endif
339 
340  txbuf.write(&c, 1);
341 
342  if (data_fd >= 0)
343  write(c);
344 
345  if (outfile)
346  outfile->stream()->write(&c, 1);
347 
348  DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
349  isprint(c) ? c : ' ', (int)c);
350 
351 }
352 
353 Terminal *
354 TerminalParams::create()
355 {
356  return new Terminal(this);
357 }
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
#define DPRINTF(x,...)
Definition: trace.hh:212
friend class ListenEvent
Definition: terminal.hh:81
OutputDirectory simout
Definition: output.cc:65
std::ostream * stream() const
Get the output underlying output stream.
Definition: output.hh:64
size_t size() const
Return the number of elements stored in the buffer.
Definition: circlebuf.hh:85
virtual void process()=0
virtual process function that is invoked when the callback queue is executed.
~Terminal()
Definition: terminal.cc:124
Generic callback class.
Definition: callback.hh:41
virtual bool listen(int port, bool reuse=true)
Definition: socket.cc:90
static void output(const char *filename)
Definition: debug.cc:63
int number
Definition: terminal.hh:98
void accept()
Definition: terminal.cc:177
PollQueue pollQueue
Definition: pollevent.cc:55
Bitfield< 7 > i
Definition: miscregs.hh:1378
#define panic(...)
Definition: misc.hh:153
void regDataAvailCallback(Callback *c)
Register a data available callback into the transport layer.
Definition: terminal.cc:137
void listen(int port)
Definition: terminal.cc:152
bool empty() const
Is the buffer empty?
Definition: circlebuf.hh:78
#define warn_once(...)
Definition: misc.hh:226
ListenSocket listener
Definition: terminal.hh:107
DataEvent * dataEvent
Definition: terminal.hh:95
#define DPRINTFN(...)
Definition: trace.hh:216
Base class for UART.
void process(int revent)
Definition: terminal.cc:93
void schedule(PollEvent *event)
Definition: pollevent.cc:159
int data_fd
Definition: terminal.hh:99
void read(uint8_t &c)
Definition: terminal.hh:126
void data()
Definition: terminal.cc:228
Temporarily migrate execution to a different event queue.
Definition: eventq.hh:546
#define RECEIVE_NONE
Definition: terminal.cc:281
void detach()
Definition: terminal.cc:213
#define DTRACE(x)
Definition: trace.hh:210
static bool allDisabled()
Definition: socket.cc:61
ssize_t atomic_write(int fd, const void *s, size_t n)
Definition: atomicio.cc:66
uint8_t in()
Definition: terminal.cc:285
Callback * termDataAvail
Currently registered transport layer callbacks.
Definition: terminal.hh:68
void out(char c)
Definition: terminal.cc:317
#define fatal(...)
Definition: misc.hh:163
void write(uint8_t c)
Definition: terminal.hh:128
friend class DataEvent
Definition: terminal.hh:94
bool dataAvailable()
Definition: terminal.hh:157
virtual int accept(bool nodelay=false)
Definition: socket.cc:136
void write(InputIterator in, size_t len)
Add elements to the end of the ring buffers and advance.
Definition: circlebuf.hh:157
void peek(OutputIterator out, size_t len) const
Copy buffer contents without advancing the read pointer.
Definition: circlebuf.hh:105
void read(OutputIterator out, size_t len)
Copy buffer contents and advance the read pointer.
Definition: circlebuf.hh:143
Bitfield< 9 > e
Definition: miscregs.hh:1376
#define MORE_PENDING
Definition: terminal.cc:279
ListenEvent * listenEvent
Definition: terminal.hh:82
Generic interface for platforms.
int size()
Definition: pagetable.hh:146
virtual const std::string name() const
Definition: sim_object.hh:117
Bitfield< 29 > c
Definition: miscregs.hh:1365
ListenEvent(Terminal *t, int fd, int e)
Definition: terminal.cc:73
void remove(PollEvent *event)
Definition: pollevent.cc:139
#define RECEIVE_SUCCESS
Definition: terminal.cc:280
OutputStream * outfile
Definition: terminal.hh:115
Bitfield< 18, 16 > len
Definition: miscregs.hh:1626
bool islistening() const
Definition: socket.hh:60
CircleBuf< char > txbuf
Definition: terminal.hh:113
CircleBuf< char > rxbuf
Definition: terminal.hh:114
TerminalParams Params
Definition: terminal.hh:102
Bitfield< 5 > t
Definition: miscregs.hh:1382
uint64_t console_in()
Definition: terminal.cc:299
Bitfield< 14, 12 > fd
Definition: types.hh:155
Bitfield< 0 > p
int getfd() const
Definition: socket.hh:59
Abstract superclass for simulation objects.
Definition: sim_object.hh:94
if(it_gpu==gpuTypeMap.end())
Definition: gpu_nomali.cc:75
Terminal(const Params *p)
Definition: terminal.cc:109
DataEvent(Terminal *t, int fd, int e)
Definition: terminal.cc:87
void process(int revent)
Definition: terminal.cc:79

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6