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

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13