gem5/dev/console.cc
Steve Reinhardt 25693e9e69 Make include paths explicit and update makefile accordingly.
arch/alpha/alpha_memory.cc:
arch/alpha/alpha_memory.hh:
arch/alpha/arguments.cc:
arch/alpha/arguments.hh:
arch/alpha/ev5.cc:
arch/alpha/ev5.hh:
arch/alpha/fake_syscall.cc:
arch/alpha/faults.cc:
arch/alpha/isa_desc:
arch/alpha/isa_traits.hh:
arch/alpha/osfpal.cc:
arch/alpha/vtophys.cc:
arch/alpha/vtophys.hh:
base/circlebuf.cc:
base/compression/lzss_compression.cc:
base/compression/lzss_compression.hh:
base/cprintf.cc:
base/cprintf.hh:
base/fast_alloc.cc:
base/fifo_buffer.cc:
base/fifo_buffer.hh:
base/hashmap.hh:
base/hostinfo.cc:
base/hostinfo.hh:
base/hybrid_pred.cc:
base/hybrid_pred.hh:
base/inet.cc:
base/inet.hh:
base/inifile.cc:
base/inifile.hh:
base/intmath.cc:
base/loader/aout_object.cc:
base/loader/aout_object.hh:
base/loader/ecoff_object.cc:
base/loader/ecoff_object.hh:
base/loader/elf_object.cc:
base/loader/elf_object.hh:
base/loader/exec_aout.h:
base/loader/exec_ecoff.h:
base/loader/object_file.cc:
base/loader/object_file.hh:
base/loader/symtab.cc:
base/loader/symtab.hh:
base/misc.cc:
base/misc.hh:
base/pollevent.cc:
base/pollevent.hh:
base/random.cc:
base/random.hh:
base/range.hh:
base/remote_gdb.cc:
base/remote_gdb.hh:
base/res_list.hh:
base/sat_counter.cc:
base/sat_counter.hh:
base/sched_list.hh:
base/socket.cc:
base/statistics.cc:
base/statistics.hh:
base/str.cc:
base/trace.cc:
base/trace.hh:
cpu/base_cpu.cc:
cpu/base_cpu.hh:
cpu/exec_context.cc:
cpu/exec_context.hh:
cpu/exetrace.cc:
cpu/exetrace.hh:
cpu/intr_control.cc:
cpu/intr_control.hh:
cpu/memtest/memtest.cc:
cpu/memtest/memtest.hh:
cpu/pc_event.cc:
cpu/pc_event.hh:
cpu/simple_cpu/simple_cpu.cc:
cpu/simple_cpu/simple_cpu.hh:
cpu/static_inst.cc:
cpu/static_inst.hh:
dev/alpha_console.cc:
dev/alpha_console.hh:
dev/console.cc:
dev/console.hh:
dev/disk_image.cc:
dev/disk_image.hh:
dev/etherbus.cc:
dev/etherbus.hh:
dev/etherdump.cc:
dev/etherdump.hh:
dev/etherint.cc:
dev/etherint.hh:
dev/etherlink.cc:
dev/etherlink.hh:
dev/etherpkt.hh:
dev/ethertap.cc:
dev/ethertap.hh:
dev/simple_disk.cc:
dev/simple_disk.hh:
kern/tru64/tru64_syscalls.cc:
kern/tru64/tru64_syscalls.hh:
sim/debug.cc:
sim/eventq.cc:
sim/eventq.hh:
sim/main.cc:
sim/param.cc:
sim/param.hh:
sim/prog.cc:
sim/prog.hh:
sim/serialize.cc:
sim/serialize.hh:
sim/sim_events.cc:
sim/sim_events.hh:
sim/sim_object.cc:
sim/sim_object.hh:
sim/sim_time.cc:
sim/system.cc:
sim/system.hh:
sim/universe.cc:
test/circletest.cc:
test/cprintftest.cc:
test/initest.cc:
test/nmtest.cc:
test/offtest.cc:
test/paramtest.cc:
test/rangetest.cc:
test/stattest.cc:
test/strnumtest.cc:
test/symtest.cc:
test/tokentest.cc:
test/tracetest.cc:
util/tap/tap.cc:
    Make include paths explicit.

--HG--
extra : convert_revision : 941cbdc591fd4d3d1d9f095cd58fc23dd2d73840
2003-10-10 11:09:00 -07:00

479 lines
10 KiB
C++

/* $Id$ */
/* @file
* User Console Definitions
*/
#include <sys/ioctl.h>
#include <sys/termios.h>
#include <sys/types.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "base/misc.hh"
#include "targetarch/ev5.hh"
#include "dev/console.hh"
#include "base/socket.hh"
#include "base/trace.hh"
#include "mem/functional_mem/memory_control.hh"
using namespace std;
// check whether an int is pending
inline bool
IntPending(int status, int mask)
{ return (status & mask) != 0; }
inline bool
IntTransition(int ostaus, int omask, int nstatus, int nmask)
{ return IntPending(ostaus, omask) != IntPending(nstatus, nmask); }
////////////////////////////////////////////////////////////////////////
//
//
SimConsole::Event::Event(SimConsole *c, int fd, int e)
: PollEvent(fd, e), cons(c)
{
}
void
SimConsole::Event::process(int revent)
{
if (revent & POLLIN)
cons->data();
else if (revent & POLLNVAL)
cons->detach();
}
SimConsole::SimConsole(const string &name, const string &file, int num)
: SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL),
intr_status(0), intr_enable(0), intr(NULL)
{
if (!file.empty())
outfile = new ofstream(file.c_str());
if (outfile)
outfile->setf(ios::unitbuf);
}
SimConsole::~SimConsole()
{
close();
if (outfile)
delete outfile;
}
void
SimConsole::close()
{
if (in_fd != -1)
::close(in_fd);
if (out_fd != in_fd && out_fd != -1)
::close(out_fd);
}
void
SimConsole::attach(int in, int out, ConsoleListener *l)
{
in_fd = in;
out_fd = out;
listener = l;
event = new Event(this, in, POLLIN);
pollQueue.schedule(event);
stringstream stream;
ccprintf(stream, "==== Simplescalar slave console: Console %d ====",
number);
// we need an actual carriage return followed by a newline for the
// terminal
stream << "\r\n";
write((const uint8_t *)stream.str().c_str(), stream.str().size());
DPRINTFN("attach console %d\n", number);
txbuf.readall(out);
}
void
SimConsole::detach()
{
close();
in_fd = -1;
out_fd = -1;
pollQueue.remove(event);
if (listener) {
listener->add(this);
listener = NULL;
}
DPRINTFN("detach console %d\n", number);
}
void
SimConsole::data()
{
uint8_t buf[1024];
int len;
len = read(buf, sizeof(buf));
if (len) {
rxbuf.write((char *)buf, len);
raiseInt(ReceiveInterrupt);
}
}
size_t
SimConsole::read(uint8_t *buf, size_t len)
{
if (in_fd < 0)
panic("SimConsole(read): Console not properly attached.\n");
size_t ret;
do {
ret = ::read(in_fd, buf, len);
} while (ret == -1 && errno == EINTR);
if (ret < 0)
DPRINTFN("SimConsole(read): Read failed.\n");
if (ret <= 0) {
detach();
return 0;
}
return ret;
}
// Console output.
size_t
SimConsole::write(const uint8_t *buf, size_t len)
{
if (out_fd < 0)
panic("SimConsole(write): Console not properly attached.\n");
size_t ret;
for (;;) {
ret = ::write(out_fd, buf, len);
if (ret >= 0)
break;
if (errno != EINTR)
detach();
}
return ret;
}
///////////////////////////////////////////////////////////////////////
// ConfigureTerm turns off all character processing by the host OS so
// the launched OS can control it.
//
// We ignore anything except stdin; the sconsole program runs this
// same code on the ttys for the slave consoles before connecting.
//
void
SimConsole::configTerm()
{
struct termios ios;
if (isatty(out_fd)) {
if (tcgetattr(out_fd, &ios) < 0) {
panic( "tcgetattr\n");
}
ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
ios.c_oflag &= ~(OPOST);
ios.c_oflag &= (ONLCR);
ios.c_lflag &= ~(ISIG|ICANON|ECHO);
ios.c_cc[VMIN] = 1;
ios.c_cc[VTIME] = 0;
if (tcsetattr(out_fd, TCSANOW, &ios) < 0) {
panic( "tcsetattr\n");
}
}
}
///////////////////////////////////////////////////////////////////////
// console i/o
//
///////////////////////////////////////////////////////////////////////
//
// Console input.
// Returns -1 if there is no character pending, otherwise returns the
// char. Calling this function clears the input int (if no further
// chars are pending).
//
int
SimConsole::in()
{
if (rxbuf.empty()) {
clearInt(ReceiveInterrupt);
return -1;
}
char c;
rxbuf.read(&c, 1);
DPRINTF(Console, "in: \'%c\' %#02x status: %#x\n",
isprint(c) ? c : ' ', c, intr_status);
return c;
}
///////////////////////////////////////////////////////////////////////
//
// Console output.
// NOTE: this very rudimentary device generates a TX int as soon as
// a character is output, since it has unlimited TX buffer capacity.
//
// Console output.
// Uses sim_console_out to perform functionality similar to 'write'
void
SimConsole::out(char c)
{
txbuf.write(c);
if (out_fd >= 0)
write(c);
if (outfile)
outfile->write(&c, 1);
raiseInt(TransmitInterrupt);
DPRINTF(Console, "out: \'%c\' %#02x status: %#x\n",
isprint(c) ? c : ' ', (int)c, intr_status);
}
// Simple console output used by Alpha firmware (not by the OS) -
// outputs the character to console n, and doesn't raise any
// interrupts
void
SimConsole::simple(char c)
{
txbuf.write(c);
if (out_fd >= 0)
write(c);
if (outfile)
outfile->write(&c, 1);
DPRINTF(Console, "simple char: \'%c\' %#02x\n",
isprint(c) ? c : ' ', (int)c);
}
// Read the current interrupt status of this console.
int
SimConsole::intStatus()
{
#if 0
DPRINTF(Console, "interrupt %d status: %#x\n",
number, intr_status);
#endif
return intr_status;
}
int
SimConsole::clearInt(int i)
{
int old_status = intr_status;
intr_status &= ~i;
if (IntTransition(old_status, intr_enable, intr_status, intr_enable) &&
intr)
intr->clear(TheISA::INTLEVEL_IRQ0);
return old_status;
}
void
SimConsole::raiseInt(int i)
{
int old = intr_status;
intr_status |= i;
if (IntTransition(old, intr_enable, intr_status, intr_enable) && intr)
intr->post(TheISA::INTLEVEL_IRQ0);
}
void
SimConsole::initInt(IntrControl *i)
{
if (intr)
panic("Console has already been initialized.");
// note: intr_status and intr_enable will normally be 0, since
// cs is statically allocated. When restoring from a checkpoint,
// these fields will be set, so don't touch them here.
intr = i; // interrupt handler
}
// Set the interrupt enable bits.
void
SimConsole::setInt(int bits)
{
int old_enable;
if (bits & ~(TransmitInterrupt | ReceiveInterrupt))
panic("An interrupt was not set!");
old_enable = intr_enable;
intr_enable |= bits;
if (IntTransition(intr_status, old_enable, intr_status, intr_enable) &&
intr) {
if (IntPending(intr_status, intr_enable))
intr->post(TheISA::INTLEVEL_IRQ0);
else
intr->clear(TheISA::INTLEVEL_IRQ0);
}
}
void
SimConsole::serialize()
{
panic("Unimplemented");
}
void
SimConsole::unserialize(IniFile &db, const std::string &category,
ConfigNode *node)
{
panic("Unimplemented");
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
SimObjectParam<ConsoleListener *> listener;
SimObjectParam<IntrControl *> intr_control;
Param<string> output;
Param<int> number;
END_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole)
INIT_PARAM(listener, "console listener"),
INIT_PARAM(intr_control, "interrupt controller"),
INIT_PARAM_DFLT(output, "file to dump output to", ""),
INIT_PARAM_DFLT(number, "console number", 0)
END_INIT_SIM_OBJECT_PARAMS(SimConsole)
CREATE_SIM_OBJECT(SimConsole)
{
SimConsole *console = new SimConsole(getInstanceName(), output, number);
((ConsoleListener *)listener)->add(console);
((SimConsole *)console)->initInt(intr_control);
((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt |
SimConsole::ReceiveInterrupt);
return console;
}
REGISTER_SIM_OBJECT("SimConsole", SimConsole)
////////////////////////////////////////////////////////////////////////
//
//
ConsoleListener::ConsoleListener(const string &name)
: SimObject(name), event(NULL)
{}
ConsoleListener::~ConsoleListener()
{
if (event)
delete event;
}
void
ConsoleListener::Event::process(int revent)
{
listener->accept();
}
///////////////////////////////////////////////////////////////////////
// socket creation and console attach
//
void
ConsoleListener::listen(int port)
{
while (!listener.listen(port, true)) {
DPRINTF(Console, ": can't bind address console port %d inuse PID %d\n",
port, getpid());
port++;
}
cerr << "Listening for console connection on port " << port << endl;
event = new Event(this, listener.getfd(), POLLIN);
pollQueue.schedule(event);
}
void
ConsoleListener::add(SimConsole *cons)
{ ConsoleList.push_back(cons);}
void
ConsoleListener::accept()
{
if (!listener.islistening())
panic("%s: cannot accept a connection if we're not listening!",
name());
int sfd = listener.accept(true);
if (sfd != -1) {
iter_t i = ConsoleList.begin();
iter_t end = ConsoleList.end();
if (i == end) {
close(sfd);
} else {
(*i)->attach(sfd, this);
i = ConsoleList.erase(i);
}
}
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
Param<int> port;
END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
INIT_PARAM_DFLT(port, "listen port", 3456)
END_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
CREATE_SIM_OBJECT(ConsoleListener)
{
ConsoleListener *listener = new ConsoleListener(getInstanceName());
listener->listen(port);
return listener;
}
REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener)