112239Sandreas.sandberg@arm.com/* 214249Sgiacomo.travaglini@arm.com * Copyright (c) 2019 ARM Limited 314249Sgiacomo.travaglini@arm.com * All rights reserved 414249Sgiacomo.travaglini@arm.com * 514249Sgiacomo.travaglini@arm.com * The license below extends only to copyright in the software and shall 614249Sgiacomo.travaglini@arm.com * not be construed as granting a license to any other intellectual 714249Sgiacomo.travaglini@arm.com * property including but not limited to intellectual property relating 814249Sgiacomo.travaglini@arm.com * to a hardware implementation of the functionality of the software 914249Sgiacomo.travaglini@arm.com * licensed hereunder. You may use the software subject to the license 1014249Sgiacomo.travaglini@arm.com * terms below provided that you ensure that this notice is replicated 1114249Sgiacomo.travaglini@arm.com * unmodified and in its entirety in all distributions of the software, 1214249Sgiacomo.travaglini@arm.com * modified or unmodified, in source code or in binary form. 1314249Sgiacomo.travaglini@arm.com * 1412239Sandreas.sandberg@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan 1512239Sandreas.sandberg@arm.com * All rights reserved. 1612239Sandreas.sandberg@arm.com * 1712239Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without 1812239Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are 1912239Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright 2012239Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer; 2112239Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright 2212239Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 2312239Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution; 2412239Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its 2512239Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from 2612239Sandreas.sandberg@arm.com * this software without specific prior written permission. 2712239Sandreas.sandberg@arm.com * 2812239Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912239Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012239Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112239Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212239Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312239Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412239Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512239Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612239Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712239Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812239Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912239Sandreas.sandberg@arm.com * 4012239Sandreas.sandberg@arm.com * Authors: Nathan Binkert 4112239Sandreas.sandberg@arm.com * Ali Saidi 4212239Sandreas.sandberg@arm.com */ 4312239Sandreas.sandberg@arm.com 4412239Sandreas.sandberg@arm.com/* @file 4512239Sandreas.sandberg@arm.com * Implements the user interface to a serial terminal 4612239Sandreas.sandberg@arm.com */ 4712239Sandreas.sandberg@arm.com 4812239Sandreas.sandberg@arm.com#include <sys/ioctl.h> 4912239Sandreas.sandberg@arm.com 5012239Sandreas.sandberg@arm.com#if defined(__FreeBSD__) 5112239Sandreas.sandberg@arm.com#include <termios.h> 5212239Sandreas.sandberg@arm.com 5312239Sandreas.sandberg@arm.com#else 5412239Sandreas.sandberg@arm.com#include <sys/termios.h> 5512239Sandreas.sandberg@arm.com 5612239Sandreas.sandberg@arm.com#endif 5712239Sandreas.sandberg@arm.com#include "dev/serial/terminal.hh" 5812239Sandreas.sandberg@arm.com 5912239Sandreas.sandberg@arm.com#include <poll.h> 6012239Sandreas.sandberg@arm.com#include <unistd.h> 6112239Sandreas.sandberg@arm.com 6212239Sandreas.sandberg@arm.com#include <cctype> 6312239Sandreas.sandberg@arm.com#include <cerrno> 6412239Sandreas.sandberg@arm.com#include <fstream> 6512239Sandreas.sandberg@arm.com#include <iostream> 6612239Sandreas.sandberg@arm.com#include <sstream> 6712239Sandreas.sandberg@arm.com#include <string> 6812239Sandreas.sandberg@arm.com 6912239Sandreas.sandberg@arm.com#include "base/atomicio.hh" 7012334Sgabeblack@google.com#include "base/logging.hh" 7112239Sandreas.sandberg@arm.com#include "base/output.hh" 7212239Sandreas.sandberg@arm.com#include "base/socket.hh" 7312239Sandreas.sandberg@arm.com#include "base/trace.hh" 7412239Sandreas.sandberg@arm.com#include "debug/Terminal.hh" 7512239Sandreas.sandberg@arm.com#include "debug/TerminalVerbose.hh" 7612239Sandreas.sandberg@arm.com#include "dev/platform.hh" 7712239Sandreas.sandberg@arm.com#include "dev/serial/uart.hh" 7812239Sandreas.sandberg@arm.com 7912239Sandreas.sandberg@arm.comusing namespace std; 8012239Sandreas.sandberg@arm.com 8112239Sandreas.sandberg@arm.com 8212239Sandreas.sandberg@arm.com/* 8312239Sandreas.sandberg@arm.com * Poll event for the listen socket 8412239Sandreas.sandberg@arm.com */ 8512239Sandreas.sandberg@arm.comTerminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e) 8612239Sandreas.sandberg@arm.com : PollEvent(fd, e), term(t) 8712239Sandreas.sandberg@arm.com{ 8812239Sandreas.sandberg@arm.com} 8912239Sandreas.sandberg@arm.com 9012239Sandreas.sandberg@arm.comvoid 9112239Sandreas.sandberg@arm.comTerminal::ListenEvent::process(int revent) 9212239Sandreas.sandberg@arm.com{ 9312239Sandreas.sandberg@arm.com term->accept(); 9412239Sandreas.sandberg@arm.com} 9512239Sandreas.sandberg@arm.com 9612239Sandreas.sandberg@arm.com/* 9712239Sandreas.sandberg@arm.com * Poll event for the data socket 9812239Sandreas.sandberg@arm.com */ 9912239Sandreas.sandberg@arm.comTerminal::DataEvent::DataEvent(Terminal *t, int fd, int e) 10012239Sandreas.sandberg@arm.com : PollEvent(fd, e), term(t) 10112239Sandreas.sandberg@arm.com{ 10212239Sandreas.sandberg@arm.com} 10312239Sandreas.sandberg@arm.com 10412239Sandreas.sandberg@arm.comvoid 10512239Sandreas.sandberg@arm.comTerminal::DataEvent::process(int revent) 10612239Sandreas.sandberg@arm.com{ 10712239Sandreas.sandberg@arm.com // As a consequence of being called from the PollQueue, we might 10812239Sandreas.sandberg@arm.com // have been called from a different thread. Migrate to "our" 10912239Sandreas.sandberg@arm.com // thread. 11012239Sandreas.sandberg@arm.com EventQueue::ScopedMigration migrate(term->eventQueue()); 11112239Sandreas.sandberg@arm.com 11212239Sandreas.sandberg@arm.com if (revent & POLLIN) 11312239Sandreas.sandberg@arm.com term->data(); 11412239Sandreas.sandberg@arm.com else if (revent & POLLNVAL) 11512239Sandreas.sandberg@arm.com term->detach(); 11612239Sandreas.sandberg@arm.com} 11712239Sandreas.sandberg@arm.com 11812239Sandreas.sandberg@arm.com/* 11912239Sandreas.sandberg@arm.com * Terminal code 12012239Sandreas.sandberg@arm.com */ 12112239Sandreas.sandberg@arm.comTerminal::Terminal(const Params *p) 12212239Sandreas.sandberg@arm.com : SerialDevice(p), listenEvent(NULL), dataEvent(NULL), 12312239Sandreas.sandberg@arm.com number(p->number), data_fd(-1), txbuf(16384), rxbuf(16384), 12414249Sgiacomo.travaglini@arm.com outfile(terminalDump(p)) 12512239Sandreas.sandberg@arm.com#if TRACING_ON == 1 12612239Sandreas.sandberg@arm.com , linebuf(16384) 12712239Sandreas.sandberg@arm.com#endif 12812239Sandreas.sandberg@arm.com{ 12912239Sandreas.sandberg@arm.com if (outfile) 13012239Sandreas.sandberg@arm.com outfile->stream()->setf(ios::unitbuf); 13112239Sandreas.sandberg@arm.com 13212239Sandreas.sandberg@arm.com if (p->port) 13312239Sandreas.sandberg@arm.com listen(p->port); 13412239Sandreas.sandberg@arm.com} 13512239Sandreas.sandberg@arm.com 13612239Sandreas.sandberg@arm.comTerminal::~Terminal() 13712239Sandreas.sandberg@arm.com{ 13812239Sandreas.sandberg@arm.com if (data_fd != -1) 13912239Sandreas.sandberg@arm.com ::close(data_fd); 14012239Sandreas.sandberg@arm.com 14112239Sandreas.sandberg@arm.com if (listenEvent) 14212239Sandreas.sandberg@arm.com delete listenEvent; 14312239Sandreas.sandberg@arm.com 14412239Sandreas.sandberg@arm.com if (dataEvent) 14512239Sandreas.sandberg@arm.com delete dataEvent; 14612239Sandreas.sandberg@arm.com} 14712239Sandreas.sandberg@arm.com 14814249Sgiacomo.travaglini@arm.comOutputStream * 14914249Sgiacomo.travaglini@arm.comTerminal::terminalDump(const TerminalParams* p) 15014249Sgiacomo.travaglini@arm.com{ 15114249Sgiacomo.travaglini@arm.com switch (p->outfile) { 15214249Sgiacomo.travaglini@arm.com case Enums::TerminalDump::none: 15314249Sgiacomo.travaglini@arm.com return nullptr; 15414288SAndrea.Mondelli@ucf.edu case Enums::TerminalDump::stdoutput: 15514249Sgiacomo.travaglini@arm.com return simout.findOrCreate("stdout"); 15614288SAndrea.Mondelli@ucf.edu case Enums::TerminalDump::stderror: 15714249Sgiacomo.travaglini@arm.com return simout.findOrCreate("stderr"); 15814249Sgiacomo.travaglini@arm.com case Enums::TerminalDump::file: 15914249Sgiacomo.travaglini@arm.com return simout.findOrCreate(p->name); 16014249Sgiacomo.travaglini@arm.com default: 16114249Sgiacomo.travaglini@arm.com panic("Invalid option\n"); 16214249Sgiacomo.travaglini@arm.com } 16314249Sgiacomo.travaglini@arm.com} 16412239Sandreas.sandberg@arm.com 16512239Sandreas.sandberg@arm.com/////////////////////////////////////////////////////////////////////// 16612239Sandreas.sandberg@arm.com// socket creation and terminal attach 16712239Sandreas.sandberg@arm.com// 16812239Sandreas.sandberg@arm.com 16912239Sandreas.sandberg@arm.comvoid 17012239Sandreas.sandberg@arm.comTerminal::listen(int port) 17112239Sandreas.sandberg@arm.com{ 17212239Sandreas.sandberg@arm.com if (ListenSocket::allDisabled()) { 17312239Sandreas.sandberg@arm.com warn_once("Sockets disabled, not accepting terminal connections"); 17412239Sandreas.sandberg@arm.com return; 17512239Sandreas.sandberg@arm.com } 17612239Sandreas.sandberg@arm.com 17712239Sandreas.sandberg@arm.com while (!listener.listen(port, true)) { 17812239Sandreas.sandberg@arm.com DPRINTF(Terminal, 17912239Sandreas.sandberg@arm.com ": can't bind address terminal port %d inuse PID %d\n", 18012239Sandreas.sandberg@arm.com port, getpid()); 18112239Sandreas.sandberg@arm.com port++; 18212239Sandreas.sandberg@arm.com } 18312239Sandreas.sandberg@arm.com 18412693Sandreas.sandberg@arm.com ccprintf(cerr, "%s: Listening for connections on port %d\n", 18512693Sandreas.sandberg@arm.com name(), port); 18612239Sandreas.sandberg@arm.com 18712239Sandreas.sandberg@arm.com listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); 18812239Sandreas.sandberg@arm.com pollQueue.schedule(listenEvent); 18912239Sandreas.sandberg@arm.com} 19012239Sandreas.sandberg@arm.com 19112239Sandreas.sandberg@arm.comvoid 19212239Sandreas.sandberg@arm.comTerminal::accept() 19312239Sandreas.sandberg@arm.com{ 19412239Sandreas.sandberg@arm.com if (!listener.islistening()) 19512239Sandreas.sandberg@arm.com panic("%s: cannot accept a connection if not listening!", name()); 19612239Sandreas.sandberg@arm.com 19712239Sandreas.sandberg@arm.com int fd = listener.accept(true); 19812239Sandreas.sandberg@arm.com if (data_fd != -1) { 19912239Sandreas.sandberg@arm.com char message[] = "terminal already attached!\n"; 20012239Sandreas.sandberg@arm.com atomic_write(fd, message, sizeof(message)); 20112239Sandreas.sandberg@arm.com ::close(fd); 20212239Sandreas.sandberg@arm.com return; 20312239Sandreas.sandberg@arm.com } 20412239Sandreas.sandberg@arm.com 20512239Sandreas.sandberg@arm.com data_fd = fd; 20612239Sandreas.sandberg@arm.com dataEvent = new DataEvent(this, data_fd, POLLIN); 20712239Sandreas.sandberg@arm.com pollQueue.schedule(dataEvent); 20812239Sandreas.sandberg@arm.com 20912239Sandreas.sandberg@arm.com stringstream stream; 21012239Sandreas.sandberg@arm.com ccprintf(stream, "==== m5 slave terminal: Terminal %d ====", number); 21112239Sandreas.sandberg@arm.com 21212239Sandreas.sandberg@arm.com // we need an actual carriage return followed by a newline for the 21312239Sandreas.sandberg@arm.com // terminal 21412239Sandreas.sandberg@arm.com stream << "\r\n"; 21512239Sandreas.sandberg@arm.com 21612239Sandreas.sandberg@arm.com write((const uint8_t *)stream.str().c_str(), stream.str().size()); 21712239Sandreas.sandberg@arm.com 21812239Sandreas.sandberg@arm.com DPRINTFN("attach terminal %d\n", number); 21912239Sandreas.sandberg@arm.com char buf[1024]; 22012239Sandreas.sandberg@arm.com for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) { 22112239Sandreas.sandberg@arm.com const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf))); 22212239Sandreas.sandberg@arm.com txbuf.peek(buf, i, chunk_len); 22312239Sandreas.sandberg@arm.com write((const uint8_t *)buf, chunk_len); 22412239Sandreas.sandberg@arm.com } 22512239Sandreas.sandberg@arm.com} 22612239Sandreas.sandberg@arm.com 22712239Sandreas.sandberg@arm.comvoid 22812239Sandreas.sandberg@arm.comTerminal::detach() 22912239Sandreas.sandberg@arm.com{ 23012239Sandreas.sandberg@arm.com if (data_fd != -1) { 23112239Sandreas.sandberg@arm.com ::close(data_fd); 23212239Sandreas.sandberg@arm.com data_fd = -1; 23312239Sandreas.sandberg@arm.com } 23412239Sandreas.sandberg@arm.com 23512239Sandreas.sandberg@arm.com pollQueue.remove(dataEvent); 23612239Sandreas.sandberg@arm.com delete dataEvent; 23712239Sandreas.sandberg@arm.com dataEvent = NULL; 23812239Sandreas.sandberg@arm.com 23912239Sandreas.sandberg@arm.com DPRINTFN("detach terminal %d\n", number); 24012239Sandreas.sandberg@arm.com} 24112239Sandreas.sandberg@arm.com 24212239Sandreas.sandberg@arm.comvoid 24312239Sandreas.sandberg@arm.comTerminal::data() 24412239Sandreas.sandberg@arm.com{ 24512239Sandreas.sandberg@arm.com uint8_t buf[1024]; 24612239Sandreas.sandberg@arm.com int len; 24712239Sandreas.sandberg@arm.com 24812239Sandreas.sandberg@arm.com len = read(buf, sizeof(buf)); 24912239Sandreas.sandberg@arm.com if (len) { 25012239Sandreas.sandberg@arm.com rxbuf.write((char *)buf, len); 25112239Sandreas.sandberg@arm.com notifyInterface(); 25212239Sandreas.sandberg@arm.com } 25312239Sandreas.sandberg@arm.com} 25412239Sandreas.sandberg@arm.com 25512239Sandreas.sandberg@arm.comsize_t 25612239Sandreas.sandberg@arm.comTerminal::read(uint8_t *buf, size_t len) 25712239Sandreas.sandberg@arm.com{ 25812239Sandreas.sandberg@arm.com if (data_fd < 0) 25912239Sandreas.sandberg@arm.com panic("Terminal not properly attached.\n"); 26012239Sandreas.sandberg@arm.com 26112239Sandreas.sandberg@arm.com ssize_t ret; 26212239Sandreas.sandberg@arm.com do { 26312239Sandreas.sandberg@arm.com ret = ::read(data_fd, buf, len); 26412239Sandreas.sandberg@arm.com } while (ret == -1 && errno == EINTR); 26512239Sandreas.sandberg@arm.com 26612239Sandreas.sandberg@arm.com 26712239Sandreas.sandberg@arm.com if (ret < 0) 26812239Sandreas.sandberg@arm.com DPRINTFN("Read failed.\n"); 26912239Sandreas.sandberg@arm.com 27012239Sandreas.sandberg@arm.com if (ret <= 0) { 27112239Sandreas.sandberg@arm.com detach(); 27212239Sandreas.sandberg@arm.com return 0; 27312239Sandreas.sandberg@arm.com } 27412239Sandreas.sandberg@arm.com 27512239Sandreas.sandberg@arm.com return ret; 27612239Sandreas.sandberg@arm.com} 27712239Sandreas.sandberg@arm.com 27812239Sandreas.sandberg@arm.com// Terminal output. 27912239Sandreas.sandberg@arm.comsize_t 28012239Sandreas.sandberg@arm.comTerminal::write(const uint8_t *buf, size_t len) 28112239Sandreas.sandberg@arm.com{ 28212239Sandreas.sandberg@arm.com if (data_fd < 0) 28312239Sandreas.sandberg@arm.com panic("Terminal not properly attached.\n"); 28412239Sandreas.sandberg@arm.com 28512239Sandreas.sandberg@arm.com ssize_t ret = atomic_write(data_fd, buf, len); 28612239Sandreas.sandberg@arm.com if (ret < len) 28712239Sandreas.sandberg@arm.com detach(); 28812239Sandreas.sandberg@arm.com 28912239Sandreas.sandberg@arm.com return ret; 29012239Sandreas.sandberg@arm.com} 29112239Sandreas.sandberg@arm.com 29212239Sandreas.sandberg@arm.com#define MORE_PENDING (ULL(1) << 61) 29312239Sandreas.sandberg@arm.com#define RECEIVE_SUCCESS (ULL(0) << 62) 29412239Sandreas.sandberg@arm.com#define RECEIVE_NONE (ULL(2) << 62) 29512239Sandreas.sandberg@arm.com#define RECEIVE_ERROR (ULL(3) << 62) 29612239Sandreas.sandberg@arm.com 29712239Sandreas.sandberg@arm.comuint8_t 29812239Sandreas.sandberg@arm.comTerminal::readData() 29912239Sandreas.sandberg@arm.com{ 30012239Sandreas.sandberg@arm.com uint8_t c; 30112239Sandreas.sandberg@arm.com 30212239Sandreas.sandberg@arm.com assert(!rxbuf.empty()); 30312239Sandreas.sandberg@arm.com rxbuf.read((char *)&c, 1); 30412239Sandreas.sandberg@arm.com 30512239Sandreas.sandberg@arm.com DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n", 30612239Sandreas.sandberg@arm.com isprint(c) ? c : ' ', c, !rxbuf.empty()); 30712239Sandreas.sandberg@arm.com 30812239Sandreas.sandberg@arm.com return c; 30912239Sandreas.sandberg@arm.com} 31012239Sandreas.sandberg@arm.com 31112239Sandreas.sandberg@arm.comuint64_t 31212239Sandreas.sandberg@arm.comTerminal::console_in() 31312239Sandreas.sandberg@arm.com{ 31412239Sandreas.sandberg@arm.com uint64_t value; 31512239Sandreas.sandberg@arm.com 31612239Sandreas.sandberg@arm.com if (dataAvailable()) { 31712239Sandreas.sandberg@arm.com value = RECEIVE_SUCCESS | readData(); 31812239Sandreas.sandberg@arm.com if (!rxbuf.empty()) 31912239Sandreas.sandberg@arm.com value |= MORE_PENDING; 32012239Sandreas.sandberg@arm.com } else { 32112239Sandreas.sandberg@arm.com value = RECEIVE_NONE; 32212239Sandreas.sandberg@arm.com } 32312239Sandreas.sandberg@arm.com 32412239Sandreas.sandberg@arm.com DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value); 32512239Sandreas.sandberg@arm.com 32612239Sandreas.sandberg@arm.com return value; 32712239Sandreas.sandberg@arm.com} 32812239Sandreas.sandberg@arm.com 32912239Sandreas.sandberg@arm.comvoid 33012239Sandreas.sandberg@arm.comTerminal::writeData(uint8_t c) 33112239Sandreas.sandberg@arm.com{ 33212239Sandreas.sandberg@arm.com#if TRACING_ON == 1 33312239Sandreas.sandberg@arm.com if (DTRACE(Terminal)) { 33412239Sandreas.sandberg@arm.com static char last = '\0'; 33512239Sandreas.sandberg@arm.com 33612239Sandreas.sandberg@arm.com if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) { 33712239Sandreas.sandberg@arm.com if (c == '\n' || c == '\r') { 33812239Sandreas.sandberg@arm.com int size = linebuf.size(); 33912239Sandreas.sandberg@arm.com char *buffer = new char[size + 1]; 34012239Sandreas.sandberg@arm.com linebuf.read(buffer, size); 34112239Sandreas.sandberg@arm.com buffer[size] = '\0'; 34212239Sandreas.sandberg@arm.com DPRINTF(Terminal, "%s\n", buffer); 34312239Sandreas.sandberg@arm.com delete [] buffer; 34412239Sandreas.sandberg@arm.com } else { 34512239Sandreas.sandberg@arm.com linebuf.write(&c, 1); 34612239Sandreas.sandberg@arm.com } 34712239Sandreas.sandberg@arm.com } 34812239Sandreas.sandberg@arm.com 34912239Sandreas.sandberg@arm.com last = c; 35012239Sandreas.sandberg@arm.com } 35112239Sandreas.sandberg@arm.com#endif 35212239Sandreas.sandberg@arm.com 35312239Sandreas.sandberg@arm.com txbuf.write(&c, 1); 35412239Sandreas.sandberg@arm.com 35512239Sandreas.sandberg@arm.com if (data_fd >= 0) 35612239Sandreas.sandberg@arm.com write(c); 35712239Sandreas.sandberg@arm.com 35812239Sandreas.sandberg@arm.com if (outfile) 35912239Sandreas.sandberg@arm.com outfile->stream()->put((char)c); 36012239Sandreas.sandberg@arm.com 36112239Sandreas.sandberg@arm.com DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n", 36212239Sandreas.sandberg@arm.com isprint(c) ? c : ' ', (int)c); 36312239Sandreas.sandberg@arm.com 36412239Sandreas.sandberg@arm.com} 36512239Sandreas.sandberg@arm.com 36612239Sandreas.sandberg@arm.comTerminal * 36712239Sandreas.sandberg@arm.comTerminalParams::create() 36812239Sandreas.sandberg@arm.com{ 36912239Sandreas.sandberg@arm.com return new Terminal(this); 37012239Sandreas.sandberg@arm.com} 371