gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
41/* @file
42 * Implements the user interface to a serial terminal
43 */
44
45#include <sys/ioctl.h>
46
47#if defined(__FreeBSD__)
48#include <termios.h>
49
50#else
51#include <sys/termios.h>
52
53#endif
55
56#include <poll.h>
57#include <unistd.h>
58
59#include <cctype>
60#include <cerrno>
61#include <fstream>
62#include <iostream>
63#include <sstream>
64#include <string>
65
66#include "base/atomicio.hh"
67#include "base/logging.hh"
68#include "base/output.hh"
69#include "base/socket.hh"
70#include "base/trace.hh"
71#include "debug/Terminal.hh"
72#include "debug/TerminalVerbose.hh"
73#include "dev/platform.hh"
74#include "dev/serial/uart.hh"
75
76namespace gem5
77{
78
79/*
80 * Poll event for the listen socket
81 */
83 : PollEvent(fd, e), term(t)
84{
85}
86
87void
89{
90 // As a consequence of being called from the PollQueue, we might
91 // have been called from a different thread. Migrate to "our"
92 // thread.
93 EventQueue::ScopedMigration migrate(term->eventQueue());
94 term->accept();
95}
96
97/*
98 * Poll event for the data socket
99 */
101 : PollEvent(fd, e), term(t)
102{
103}
104
105void
107{
108 // As a consequence of being called from the PollQueue, we might
109 // have been called from a different thread. Migrate to "our"
110 // thread.
111 EventQueue::ScopedMigration migrate(term->eventQueue());
112
113 if (revent & POLLIN)
114 term->data();
115 else if (revent & POLLNVAL)
116 term->detach();
117}
118
119/*
120 * Terminal code
121 */
123 : SerialDevice(p), listenEvent(NULL), dataEvent(NULL),
124 number(p.number), data_fd(-1), listener(p.port.build(p.name)),
125 txbuf(16384), rxbuf(16384), outfile(terminalDump(p))
126#if TRACING_ON == 1
127 , linebuf(16384)
128#endif
129{
130 if (outfile)
131 outfile->stream()->setf(std::ios::unitbuf);
132
133 if (p.port)
134 listen();
135}
136
138{
139 if (data_fd != -1)
140 ::close(data_fd);
141
142 if (listenEvent)
143 delete listenEvent;
144
145 if (dataEvent)
146 delete dataEvent;
147}
148
150Terminal::terminalDump(const TerminalParams &p)
151{
152 switch (p.outfile) {
153 case TerminalDump::none:
154 return nullptr;
155 case TerminalDump::stdoutput:
156 return simout.findOrCreate("stdout");
157 case TerminalDump::stderror:
158 return simout.findOrCreate("stderr");
159 case TerminalDump::file:
160 return simout.findOrCreate(p.name);
161 default:
162 panic("Invalid option\n");
163 }
164}
165
167// socket creation and terminal attach
168//
169
170void
172{
174 warn_once("Sockets disabled, not accepting terminal connections");
175 return;
176 }
177
178 listener->listen();
179
180 listenEvent = new ListenEvent(this, listener->getfd(), POLLIN);
182}
183
184void
186{
187 if (!listener->islistening())
188 panic("%s: cannot accept a connection if not listening!", name());
189
190 int fd = listener->accept();
191 if (data_fd != -1) {
192 char message[] = "terminal already attached!\n";
193 atomic_write(fd, message, sizeof(message));
194 ::close(fd);
195 return;
196 }
197
198 data_fd = fd;
199 dataEvent = new DataEvent(this, data_fd, POLLIN);
201
202 std::stringstream stream;
203 ccprintf(stream, "==== m5 terminal: Terminal %d ====", number);
204
205 // we need an actual carriage return followed by a newline for the
206 // terminal
207 stream << "\r\n";
208
209 write((const uint8_t *)stream.str().c_str(), stream.str().size());
210
211 DPRINTFN("attach terminal %d\n", number);
212 char buf[1024];
213 for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) {
214 const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf)));
215 txbuf.peek(buf, i, chunk_len);
216 write((const uint8_t *)buf, chunk_len);
217 }
218}
219
220void
222{
223 if (data_fd != -1) {
224 ::close(data_fd);
225 data_fd = -1;
226 }
227
229 delete dataEvent;
230 dataEvent = NULL;
231
232 DPRINTFN("detach terminal %d\n", number);
233}
234
235void
237{
238 uint8_t buf[1024];
239 int len;
240
241 len = read(buf, sizeof(buf));
242 if (len) {
243 rxbuf.write((char *)buf, len);
245 }
246}
247
248size_t
249Terminal::read(uint8_t *buf, size_t len)
250{
251 if (data_fd < 0)
252 panic("Terminal not properly attached.\n");
253
254 ssize_t ret;
255 do {
256 ret = ::read(data_fd, buf, len);
257 } while (ret == -1 && errno == EINTR);
258
259
260 if (ret < 0)
261 DPRINTFN("Read failed.\n");
262
263 if (ret <= 0) {
264 detach();
265 return 0;
266 }
267
268 return ret;
269}
270
271// Terminal output.
272size_t
273Terminal::write(const uint8_t *buf, size_t len)
274{
275 if (data_fd < 0)
276 panic("Terminal not properly attached.\n");
277
278 ssize_t ret = atomic_write(data_fd, buf, len);
279 if (ret < len)
280 detach();
281
282 return ret;
283}
284
285#define MORE_PENDING (1ULL << 61)
286#define RECEIVE_SUCCESS (0ULL << 62)
287#define RECEIVE_NONE (2ULL << 62)
288#define RECEIVE_ERROR (3ULL << 62)
289
290uint8_t
292{
293 uint8_t c;
294
295 assert(!rxbuf.empty());
296 rxbuf.read((char *)&c, 1);
297
298 DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n",
299 isprint(c) ? c : ' ', c, !rxbuf.empty());
300
301 return c;
302}
303
304uint64_t
306{
307 uint64_t value;
308
309 if (dataAvailable()) {
310 value = RECEIVE_SUCCESS | readData();
311 if (!rxbuf.empty())
312 value |= MORE_PENDING;
313 } else {
314 value = RECEIVE_NONE;
315 }
316
317 DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value);
318
319 return value;
320}
321
322void
324{
325#if TRACING_ON == 1
326 if (debug::Terminal) {
327 static char last = '\0';
328
329 if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) {
330 if (c == '\n' || c == '\r') {
331 int size = linebuf.size();
332 char *buffer = new char[size + 1];
333 linebuf.read(buffer, size);
334 buffer[size] = '\0';
335 DPRINTF(Terminal, "%s\n", buffer);
336 delete [] buffer;
337 } else {
338 linebuf.write(&c, 1);
339 }
340 }
341
342 last = c;
343 }
344#endif
345
346 txbuf.write(&c, 1);
347
348 if (data_fd >= 0)
349 write(c);
350
351 if (outfile)
352 outfile->stream()->put((char)c);
353
354 DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
355 isprint(c) ? c : ' ', (int)c);
356
357}
358
359} // namespace gem5
#define DPRINTFN(...)
Definition trace.hh:238
#define DPRINTF(x,...)
Definition trace.hh:210
size_t size() const
Definition circlebuf.hh:72
void read(OutputIterator out, size_t len)
Copy buffer contents and advance the read pointer.
Definition circlebuf.hh:140
void write(InputIterator in, size_t len)
Add elements to the end of the ring buffers and advance.
Definition circlebuf.hh:158
bool empty() const
Definition circlebuf.hh:71
void peek(OutputIterator out, size_t len) const
Copy buffer contents without advancing the read pointer.
Definition circlebuf.hh:93
static bool allDisabled()
Definition socket.cc:90
virtual std::string name() const
Definition named.hh:47
OutputStream * findOrCreate(const std::string &name, bool binary=false)
Definition output.cc:262
std::ostream * stream() const
Get the output underlying output stream.
Definition output.hh:62
Base class for serial devices such as terminals.
Definition serial.hh:95
void notifyInterface()
Notify the host interface of pending data.
Definition serial.cc:67
DataEvent(Terminal *t, int fd, int e)
Definition terminal.cc:100
void process(int revent)
Definition terminal.cc:106
void process(int revent)
Definition terminal.cc:88
ListenEvent(Terminal *t, int fd, int e)
Definition terminal.cc:82
void read(uint8_t &c)
Definition terminal.hh:123
CircleBuf< char > rxbuf
Definition terminal.hh:111
OutputStream * terminalDump(const TerminalParams &p)
Definition terminal.cc:150
CircleBuf< char > txbuf
Definition terminal.hh:110
ListenSocketPtr listener
Definition terminal.hh:104
uint8_t readData() override
Read a character from the device.
Definition terminal.cc:291
Terminal(const Params &p)
Definition terminal.cc:122
OutputStream * outfile
Definition terminal.hh:112
TerminalParams Params
Definition terminal.hh:98
void writeData(uint8_t c) override
Transmit a character from the host interface to the device.
Definition terminal.cc:323
void write(uint8_t c)
Definition terminal.hh:125
friend class DataEvent
Definition terminal.hh:90
ListenEvent * listenEvent
Definition terminal.hh:78
friend class ListenEvent
Definition terminal.hh:77
uint64_t console_in()
Definition terminal.cc:305
bool dataAvailable() const override
Check if there is pending data from the serial device.
Definition terminal.hh:132
DataEvent * dataEvent
Definition terminal.hh:91
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
void remove(PollEvent *event)
Definition pollevent.cc:139
PollQueue pollQueue
Definition pollevent.cc:55
void schedule(PollEvent *event)
Definition pollevent.cc:159
#define warn_once(...)
Definition logging.hh:260
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 18, 16 > len
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 29 > c
Definition misc_types.hh:53
Bitfield< 0 > p
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
OutputDirectory simout
Definition output.cc:62
ssize_t atomic_write(int fd, const void *s, size_t n)
Definition atomicio.cc:67
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
Generic interface for platforms.
#define RECEIVE_NONE
Definition terminal.cc:287
#define RECEIVE_SUCCESS
Definition terminal.cc:286
#define MORE_PENDING
Definition terminal.cc:285
Base class for UART.

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0