diff options
author | Andreas Sandberg <andreas.sandberg@arm.com> | 2017-07-20 11:58:06 +0100 |
---|---|---|
committer | Andreas Sandberg <andreas.sandberg@arm.com> | 2017-11-08 20:04:53 +0000 |
commit | 20de3bb759a36dbffed10adae2159e376b7cb68c (patch) | |
tree | 8984162e7204528cd5297e5514a4e6deda4536a3 /src/dev/serial | |
parent | 74d3f8a1765869765b542fd91114628a62947ba9 (diff) | |
download | gem5-20de3bb759a36dbffed10adae2159e376b7cb68c.tar.xz |
dev: Move generic serial devices to src/dev/serial
Change-Id: I104227fc460f8b561e7375b329a541c1fce881b2
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/4291
Reviewed-by: Gabe Black <gabeblack@google.com>
Diffstat (limited to 'src/dev/serial')
-rw-r--r-- | src/dev/serial/SConscript | 59 | ||||
-rw-r--r-- | src/dev/serial/Serial.py | 48 | ||||
-rw-r--r-- | src/dev/serial/Terminal.py | 40 | ||||
-rw-r--r-- | src/dev/serial/Uart.py | 43 | ||||
-rw-r--r-- | src/dev/serial/serial.cc | 95 | ||||
-rw-r--r-- | src/dev/serial/serial.hh | 158 | ||||
-rw-r--r-- | src/dev/serial/terminal.cc | 345 | ||||
-rw-r--r-- | src/dev/serial/terminal.hh | 141 | ||||
-rw-r--r-- | src/dev/serial/uart.cc | 46 | ||||
-rw-r--r-- | src/dev/serial/uart.hh | 80 | ||||
-rw-r--r-- | src/dev/serial/uart8250.cc | 326 | ||||
-rw-r--r-- | src/dev/serial/uart8250.hh | 111 |
12 files changed, 1492 insertions, 0 deletions
diff --git a/src/dev/serial/SConscript b/src/dev/serial/SConscript new file mode 100644 index 000000000..b9f13f54b --- /dev/null +++ b/src/dev/serial/SConscript @@ -0,0 +1,59 @@ +# -*- mode:python -*- + +# Copyright (c) 2017 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Andreas Sandberg + +Import('*') + +if env['TARGET_ISA'] == 'null': + Return() + +SimObject('Serial.py') +SimObject('Terminal.py') +SimObject('Uart.py') + +Source('serial.cc') +Source('terminal.cc') +Source('uart.cc') +Source('uart8250.cc') + +DebugFlag('Terminal') +DebugFlag('TerminalVerbose') +DebugFlag('Uart') diff --git a/src/dev/serial/Serial.py b/src/dev/serial/Serial.py new file mode 100644 index 000000000..3f62ef37f --- /dev/null +++ b/src/dev/serial/Serial.py @@ -0,0 +1,48 @@ +# Copyright (c) 2014, 2017 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Andreas Sandberg + +from m5.params import * +from m5.SimObject import SimObject + +class SerialDevice(SimObject): + type = 'SerialDevice' + abstract = True + cxx_header = "dev/serial/serial.hh" + +class SerialNullDevice(SerialDevice): + type = 'SerialNullDevice' + cxx_header = "dev/serial/serial.hh" diff --git a/src/dev/serial/Terminal.py b/src/dev/serial/Terminal.py new file mode 100644 index 000000000..863c4871c --- /dev/null +++ b/src/dev/serial/Terminal.py @@ -0,0 +1,40 @@ +# Copyright (c) 2005-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from m5.SimObject import SimObject +from m5.params import * +from m5.proxy import * +from Serial import SerialDevice + +class Terminal(SerialDevice): + type = 'Terminal' + cxx_header = "dev/serial/terminal.hh" + intr_control = Param.IntrControl(Parent.any, "interrupt controller") + port = Param.TcpPort(3456, "listen port") + number = Param.Int(0, "terminal number") + output = Param.Bool(True, "Enable output dump to file") diff --git a/src/dev/serial/Uart.py b/src/dev/serial/Uart.py new file mode 100644 index 000000000..53337059b --- /dev/null +++ b/src/dev/serial/Uart.py @@ -0,0 +1,43 @@ +# Copyright (c) 2005-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from Serial import SerialDevice + +class Uart(BasicPioDevice): + type = 'Uart' + abstract = True + cxx_header = "dev/serial/uart.hh" + platform = Param.Platform(Parent.any, "Platform this device is part of.") + device = Param.SerialDevice(Parent.any, "The terminal") + +class Uart8250(Uart): + type = 'Uart8250' + cxx_header = "dev/serial/uart8250.hh" diff --git a/src/dev/serial/serial.cc b/src/dev/serial/serial.cc new file mode 100644 index 000000000..873366860 --- /dev/null +++ b/src/dev/serial/serial.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "dev/serial/serial.hh" + +#include "base/misc.hh" +#include "params/SerialDevice.hh" +#include "params/SerialNullDevice.hh" + +SerialDevice::SerialDevice(const SerialDeviceParams *p) + : SimObject(p), interfaceCallback(nullptr) +{ +} + +SerialDevice::~SerialDevice() +{ +} + +void +SerialDevice::regInterfaceCallback(Callback *c) +{ + // This can happen if the user has connected multiple UARTs to the + // same terminal. In that case, each of them tries to register + // callbacks. + if (interfaceCallback) + fatal("A UART has already been associated with this device.\n"); + interfaceCallback = c; +} + +void +SerialDevice::notifyInterface() +{ + assert(dataAvailable()); + // Registering a callback is optional. + if (interfaceCallback) + interfaceCallback->process(); +} + + + + +SerialNullDevice::SerialNullDevice(const SerialNullDeviceParams *p) + : SerialDevice(p) +{ +} + +uint8_t +SerialNullDevice::readData() +{ + panic("SerialNullDevice does not have pending data.\n"); +} + + + +SerialNullDevice * +SerialNullDeviceParams::create() +{ + return new SerialNullDevice(this); +} diff --git a/src/dev/serial/serial.hh b/src/dev/serial/serial.hh new file mode 100644 index 000000000..230ecaa74 --- /dev/null +++ b/src/dev/serial/serial.hh @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014, 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#ifndef __DEV_SERIAL_HH__ +#define __DEV_SERIAL_HH__ + +#include "base/callback.hh" +#include "sim/sim_object.hh" + +struct SerialDeviceParams; +struct SerialNullDeviceParams; + +/** + * Base class for serial devices such as terminals. + * + * This class provides a unified interface that all serial (RS232 or + * similar) devices must implement. A device can be wired to exactly + * one host serial interface (serial port model). + * + * SerialDevices are passive devices that are <i>driven</i> by the + * serial interface using the writeData(c) (the interface sends a + * character) and readData() (the interface reads a character) + * methods. Serial devices need to override these methods to + * communicate with the host interface layer. + * + * To implement basic flow control, serial devices must implement the + * dataAvailable() method. This method returns true if a valid + * character can be read using the readData() method. When data + * becomes available, the serial device must call the + * notifyInterface() method to send a callback to the interface layer. + * + * To send a character (host to device), the interface layer calls + * writeData(char) to send a character to the serial device. + * + * To read a character (device to host), the interface layer calls + * dataAvailable() to determine if there is a character pending. If + * there is data available, it immediately calls readData() to get the + * character. The receive loop in the serial device typically looks + * like this: + * + * \code{.cc} + * while (device.dataAvailable()) { + * printf("%c", (int)device.readData()); + * } + * \endcode + * + * To avoid polling, the interface layer may register a data available + * callback using the regInterfaceCallback() method. The device uses + * this callback to notify the interface layer whenever there is new + * data pending. Note that devices will normally only notify the + * interface layer when there is a state transition in the + * device. E.g., the dataAvailable() transitions from false to + * true. This means that there can be multiple pending characters when + * the interface layer receives the callback. + */ +class SerialDevice : public SimObject +{ + public: + SerialDevice(const SerialDeviceParams *p); + ~SerialDevice(); + + public: // Serial device API (UART->Device) + /** + * Register a data available callback into the host interface layer. + * + * Serial devices need to call the underlying host interface layer + * to inform it of state change such as pending data that can be + * read from the device by the interface layer using the readData() + * method. The interface layer may use this method to register a + * callback that informs it of pending data. + * + * @param c Callback instance from interface layer. + */ + void regInterfaceCallback(Callback *c); + + /** + * Check if there is pending data from the serial device. + * + * @return true if there is data pending that can be read using + * the readData() method. + */ + virtual bool dataAvailable() const = 0; + + /** + * Transmit a character from the host interface to the device. + * + * @param c Received data. + */ + virtual void writeData(uint8_t c) = 0; + + /** + * Read a character from the device. + * + * @return Character from the device's output buffer, undefined if + * no data is pending. + */ + virtual uint8_t readData() = 0; + + protected: + /** Notify the host interface of pending data. */ + void notifyInterface(); + + private: + /** Currently regisxtered host interface layer callback */ + Callback *interfaceCallback; +}; + +/** + * Dummy serial device that discards all data sent to it. + */ +class SerialNullDevice : public SerialDevice +{ + public: + SerialNullDevice(const SerialNullDeviceParams *p); + + public: + bool dataAvailable() const override { return false; } + void writeData(uint8_t c) override {}; + uint8_t readData() override; +}; + +#endif // __DEV_SERIAL_HH__ diff --git a/src/dev/serial/terminal.cc b/src/dev/serial/terminal.cc new file mode 100644 index 000000000..7230698d3 --- /dev/null +++ b/src/dev/serial/terminal.cc @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Ali Saidi + */ + +/* @file + * Implements the user interface to a serial terminal + */ + +#include <sys/ioctl.h> + +#if defined(__FreeBSD__) +#include <termios.h> + +#else +#include <sys/termios.h> + +#endif +#include "dev/serial/terminal.hh" + +#include <poll.h> +#include <unistd.h> + +#include <cctype> +#include <cerrno> +#include <fstream> +#include <iostream> +#include <sstream> +#include <string> + +#include "base/atomicio.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "debug/Terminal.hh" +#include "debug/TerminalVerbose.hh" +#include "dev/platform.hh" +#include "dev/serial/uart.hh" + +using namespace std; + + +/* + * Poll event for the listen socket + */ +Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e) + : PollEvent(fd, e), term(t) +{ +} + +void +Terminal::ListenEvent::process(int revent) +{ + term->accept(); +} + +/* + * Poll event for the data socket + */ +Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e) + : PollEvent(fd, e), term(t) +{ +} + +void +Terminal::DataEvent::process(int revent) +{ + // As a consequence of being called from the PollQueue, we might + // have been called from a different thread. Migrate to "our" + // thread. + EventQueue::ScopedMigration migrate(term->eventQueue()); + + if (revent & POLLIN) + term->data(); + else if (revent & POLLNVAL) + term->detach(); +} + +/* + * Terminal code + */ +Terminal::Terminal(const Params *p) + : SerialDevice(p), listenEvent(NULL), dataEvent(NULL), + number(p->number), data_fd(-1), txbuf(16384), rxbuf(16384), + outfile(p->output ? simout.findOrCreate(p->name) : NULL) +#if TRACING_ON == 1 + , linebuf(16384) +#endif +{ + if (outfile) + outfile->stream()->setf(ios::unitbuf); + + if (p->port) + listen(p->port); +} + +Terminal::~Terminal() +{ + if (data_fd != -1) + ::close(data_fd); + + if (listenEvent) + delete listenEvent; + + if (dataEvent) + delete dataEvent; +} + + +/////////////////////////////////////////////////////////////////////// +// socket creation and terminal attach +// + +void +Terminal::listen(int port) +{ + if (ListenSocket::allDisabled()) { + warn_once("Sockets disabled, not accepting terminal connections"); + return; + } + + while (!listener.listen(port, true)) { + DPRINTF(Terminal, + ": can't bind address terminal port %d inuse PID %d\n", + port, getpid()); + port++; + } + + int p1, p2; + p2 = name().rfind('.') - 1; + p1 = name().rfind('.', p2); + ccprintf(cerr, "Listening for %s connection on port %d\n", + name().substr(p1+1,p2-p1), port); + + listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); + pollQueue.schedule(listenEvent); +} + +void +Terminal::accept() +{ + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); + + int fd = listener.accept(true); + if (data_fd != -1) { + char message[] = "terminal already attached!\n"; + atomic_write(fd, message, sizeof(message)); + ::close(fd); + return; + } + + data_fd = fd; + dataEvent = new DataEvent(this, data_fd, POLLIN); + pollQueue.schedule(dataEvent); + + stringstream stream; + ccprintf(stream, "==== m5 slave terminal: Terminal %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 terminal %d\n", number); + char buf[1024]; + for (size_t i = 0; i < txbuf.size(); i += sizeof(buf)) { + const size_t chunk_len(std::min(txbuf.size() - i, sizeof(buf))); + txbuf.peek(buf, i, chunk_len); + write((const uint8_t *)buf, chunk_len); + } +} + +void +Terminal::detach() +{ + if (data_fd != -1) { + ::close(data_fd); + data_fd = -1; + } + + pollQueue.remove(dataEvent); + delete dataEvent; + dataEvent = NULL; + + DPRINTFN("detach terminal %d\n", number); +} + +void +Terminal::data() +{ + uint8_t buf[1024]; + int len; + + len = read(buf, sizeof(buf)); + if (len) { + rxbuf.write((char *)buf, len); + notifyInterface(); + } +} + +size_t +Terminal::read(uint8_t *buf, size_t len) +{ + if (data_fd < 0) + panic("Terminal not properly attached.\n"); + + ssize_t ret; + do { + ret = ::read(data_fd, buf, len); + } while (ret == -1 && errno == EINTR); + + + if (ret < 0) + DPRINTFN("Read failed.\n"); + + if (ret <= 0) { + detach(); + return 0; + } + + return ret; +} + +// Terminal output. +size_t +Terminal::write(const uint8_t *buf, size_t len) +{ + if (data_fd < 0) + panic("Terminal not properly attached.\n"); + + ssize_t ret = atomic_write(data_fd, buf, len); + if (ret < len) + detach(); + + return ret; +} + +#define MORE_PENDING (ULL(1) << 61) +#define RECEIVE_SUCCESS (ULL(0) << 62) +#define RECEIVE_NONE (ULL(2) << 62) +#define RECEIVE_ERROR (ULL(3) << 62) + +uint8_t +Terminal::readData() +{ + uint8_t c; + + assert(!rxbuf.empty()); + rxbuf.read((char *)&c, 1); + + DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n", + isprint(c) ? c : ' ', c, !rxbuf.empty()); + + return c; +} + +uint64_t +Terminal::console_in() +{ + uint64_t value; + + if (dataAvailable()) { + value = RECEIVE_SUCCESS | readData(); + if (!rxbuf.empty()) + value |= MORE_PENDING; + } else { + value = RECEIVE_NONE; + } + + DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value); + + return value; +} + +void +Terminal::writeData(uint8_t c) +{ +#if TRACING_ON == 1 + if (DTRACE(Terminal)) { + static char last = '\0'; + + if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) { + if (c == '\n' || c == '\r') { + int size = linebuf.size(); + char *buffer = new char[size + 1]; + linebuf.read(buffer, size); + buffer[size] = '\0'; + DPRINTF(Terminal, "%s\n", buffer); + delete [] buffer; + } else { + linebuf.write(&c, 1); + } + } + + last = c; + } +#endif + + txbuf.write(&c, 1); + + if (data_fd >= 0) + write(c); + + if (outfile) + outfile->stream()->put((char)c); + + DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n", + isprint(c) ? c : ' ', (int)c); + +} + +Terminal * +TerminalParams::create() +{ + return new Terminal(this); +} diff --git a/src/dev/serial/terminal.hh b/src/dev/serial/terminal.hh new file mode 100644 index 000000000..48bfc0771 --- /dev/null +++ b/src/dev/serial/terminal.hh @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Ali Saidi + */ + +/* @file + * User Terminal Interface + */ + +#ifndef __DEV_TERMINAL_HH__ +#define __DEV_TERMINAL_HH__ + +#include <iostream> + +#include "base/callback.hh" +#include "base/circlebuf.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "cpu/intr_control.hh" +#include "dev/serial/serial.hh" +#include "params/Terminal.hh" +#include "sim/sim_object.hh" + +class OutputStream; +class TerminalListener; + +class Terminal : public SerialDevice +{ + protected: + class ListenEvent : public PollEvent + { + protected: + Terminal *term; + + public: + ListenEvent(Terminal *t, int fd, int e); + void process(int revent); + }; + + friend class ListenEvent; + ListenEvent *listenEvent; + + class DataEvent : public PollEvent + { + protected: + Terminal *term; + + public: + DataEvent(Terminal *t, int fd, int e); + void process(int revent); + }; + + friend class DataEvent; + DataEvent *dataEvent; + + protected: + int number; + int data_fd; + + public: + typedef TerminalParams Params; + Terminal(const Params *p); + ~Terminal(); + + protected: + ListenSocket listener; + + void listen(int port); + void accept(); + + protected: + CircleBuf<char> txbuf; + CircleBuf<char> rxbuf; + OutputStream *outfile; +#if TRACING_ON == 1 + CircleBuf<char> linebuf; +#endif + + public: + /////////////////////// + // Terminal Interface + + void data(); + + void read(uint8_t &c) { read(&c, 1); } + size_t read(uint8_t *buf, size_t len); + void write(uint8_t c) { write(&c, 1); } + size_t write(const uint8_t *buf, size_t len); + void detach(); + + public: // SerialDevice interface + uint8_t readData() override; + void writeData(uint8_t c) override; + bool dataAvailable() const override { return !rxbuf.empty(); } + + public: + ///////////////// + // OS interface + + // get a character from the terminal in the console specific format + // corresponds to GETC: + // retval<63:61> + // 000: success: character received + // 001: success: character received, more pending + // 100: failure: no character ready + // 110: failure: character received with error + // 111: failure: character received with error, more pending + // retval<31:0> + // character read from console + // + // Interrupts are cleared when the buffer is empty. + uint64_t console_in(); +}; + +#endif // __DEV_TERMINAL_HH__ diff --git a/src/dev/serial/uart.cc b/src/dev/serial/uart.cc new file mode 100644 index 000000000..3a4c13c43 --- /dev/null +++ b/src/dev/serial/uart.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * Implements a base class for UARTs + */ + +#include "dev/serial/uart.hh" + +Uart::Uart(const Params *p, Addr pio_size) + : BasicPioDevice(p, pio_size), + platform(p->platform), device(p->device), + callbackDataAvail(this) +{ + status = 0; + + // setup serial device callbacks + device->regInterfaceCallback(&callbackDataAvail); +} diff --git a/src/dev/serial/uart.hh b/src/dev/serial/uart.hh new file mode 100644 index 000000000..04e9ec2e0 --- /dev/null +++ b/src/dev/serial/uart.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * Base class for UART + */ + +#ifndef __UART_HH__ +#define __UART_HH__ + +#include "base/callback.hh" +#include "dev/io_device.hh" +#include "dev/serial/serial.hh" +#include "params/Uart.hh" + +class Platform; + +const int RX_INT = 0x1; +const int TX_INT = 0x2; + +class Uart : public BasicPioDevice +{ + protected: + int status; + Platform *platform; + SerialDevice *device; + + public: + typedef UartParams Params; + Uart(const Params *p, Addr pio_size); + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable() = 0; + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + bool intStatus() { return status ? true : false; } + + protected: + MakeCallback<Uart, &Uart::dataAvailable> callbackDataAvail; +}; + +#endif // __UART_HH__ diff --git a/src/dev/serial/uart8250.cc b/src/dev/serial/uart8250.cc new file mode 100644 index 000000000..43300f5e8 --- /dev/null +++ b/src/dev/serial/uart8250.cc @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * Implements a 8250 UART + */ + +#include "dev/serial/uart8250.hh" + +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/trace.hh" +#include "config/the_isa.hh" +#include "debug/Uart.hh" +#include "dev/platform.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +using namespace std; +using namespace TheISA; + +void +Uart8250::processIntrEvent(int intrBit) +{ + if (intrBit & IER) { + DPRINTF(Uart, "UART InterEvent, interrupting\n"); + platform->postConsoleInt(); + status |= intrBit; + lastTxInt = curTick(); + } + else + DPRINTF(Uart, "UART InterEvent, not interrupting\n"); + +} + +/* The linux serial driver (8250.c about line 1182) loops reading from + * the device until the device reports it has no more data to + * read. After a maximum of 255 iterations the code prints "serial8250 + * too much work for irq X," and breaks out of the loop. Since the + * simulated system is so much slower than the actual system, if a + * user is typing on the keyboard it is very easy for them to provide + * input at a fast enough rate to not allow the loop to exit and thus + * the error to be printed. This magic number provides a delay between + * the time the UART receives a character to send to the simulated + * system and the time it actually notifies the system it has a + * character to send to alleviate this problem. --Ali + */ +void +Uart8250::scheduleIntr(Event *event) +{ + static const Tick interval = 225 * SimClock::Int::ns; + DPRINTF(Uart, "Scheduling IER interrupt for %s, at cycle %lld\n", + event->name(), curTick() + interval); + if (!event->scheduled()) + schedule(event, curTick() + interval); + else + reschedule(event, curTick() + interval); +} + + +Uart8250::Uart8250(const Params *p) + : Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0), + txIntrEvent([this]{ processIntrEvent(TX_INT); }, "TX"), + rxIntrEvent([this]{ processIntrEvent(RX_INT); }, "RX") +{ +} + +Tick +Uart8250::read(PacketPtr pkt) +{ + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Uart, " read register %#x\n", daddr); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // read byte + if (device->dataAvailable()) + pkt->set(device->readData()); + else { + pkt->set((uint8_t)0); + // A limited amount of these are ok. + DPRINTF(Uart, "empty read of RX register\n"); + } + status &= ~RX_INT; + platform->clearConsoleInt(); + + if (device->dataAvailable() && (IER & UART_IER_RDI)) + scheduleIntr(&rxIntrEvent); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + pkt->set(IER); + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // Intr Identification Register (IIR) + DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); + + if (status & RX_INT) /* Rx data interrupt has a higher priority */ + pkt->set(IIR_RXID); + else if (status & TX_INT) { + pkt->set(IIR_TXID); + //Tx interrupts are cleared on IIR reads + status &= ~TX_INT; + } else + pkt->set(IIR_NOPEND); + + break; + case 0x3: // Line Control Register (LCR) + pkt->set(LCR); + break; + case 0x4: // Modem Control Register (MCR) + pkt->set(MCR); + break; + case 0x5: // Line Status Register (LSR) + uint8_t lsr; + lsr = 0; + // check if there are any bytes to be read + if (device->dataAvailable()) + lsr = UART_LSR_DR; + lsr |= UART_LSR_TEMT | UART_LSR_THRE; + pkt->set(lsr); + break; + case 0x6: // Modem Status Register (MSR) + pkt->set((uint8_t)0); + break; + case 0x7: // Scratch Register (SCR) + pkt->set((uint8_t)0); // doesn't exist with at 8250. + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } +/* uint32_t d32 = *data; + DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32); +*/ + pkt->makeAtomicResponse(); + return pioDelay; +} + +Tick +Uart8250::write(PacketPtr pkt) +{ + + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>()); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // write byte + device->writeData(pkt->get<uint8_t>()); + platform->clearConsoleInt(); + status &= ~TX_INT; + if (UART_IER_THRI & IER) + scheduleIntr(&txIntrEvent); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + IER = pkt->get<uint8_t>(); + if (UART_IER_THRI & IER) + { + DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); + if (curTick() - lastTxInt > 225 * SimClock::Int::ns) { + DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n", + curTick(), lastTxInt); + txIntrEvent.process(); + } else { + DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n", + curTick(), lastTxInt); + scheduleIntr(&txIntrEvent); + } + } + else + { + DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); + if (txIntrEvent.scheduled()) + deschedule(txIntrEvent); + if (status & TX_INT) + platform->clearConsoleInt(); + status &= ~TX_INT; + } + + if ((UART_IER_RDI & IER) && device->dataAvailable()) { + DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); + scheduleIntr(&rxIntrEvent); + } else { + DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); + if (rxIntrEvent.scheduled()) + deschedule(rxIntrEvent); + if (status & RX_INT) + platform->clearConsoleInt(); + status &= ~RX_INT; + } + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // FIFO Control Register (FCR) + break; + case 0x3: // Line Control Register (LCR) + LCR = pkt->get<uint8_t>(); + break; + case 0x4: // Modem Control Register (MCR) + if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A)) + MCR = 0x9A; + break; + case 0x7: // Scratch Register (SCR) + // We are emulating a 8250 so we don't have a scratch reg + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + pkt->makeAtomicResponse(); + return pioDelay; +} + +void +Uart8250::dataAvailable() +{ + // if the kernel wants an interrupt when we have data + if (IER & UART_IER_RDI) + { + platform->postConsoleInt(); + status |= RX_INT; + } + +} + +AddrRangeList +Uart8250::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(RangeSize(pioAddr, pioSize)); + return ranges; +} + +void +Uart8250::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(IER); + SERIALIZE_SCALAR(DLAB); + SERIALIZE_SCALAR(LCR); + SERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + if (rxIntrEvent.scheduled()) + rxintrwhen = rxIntrEvent.when(); + else + rxintrwhen = 0; + Tick txintrwhen; + if (txIntrEvent.scheduled()) + txintrwhen = txIntrEvent.when(); + else + txintrwhen = 0; + SERIALIZE_SCALAR(rxintrwhen); + SERIALIZE_SCALAR(txintrwhen); +} + +void +Uart8250::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(IER); + UNSERIALIZE_SCALAR(DLAB); + UNSERIALIZE_SCALAR(LCR); + UNSERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + Tick txintrwhen; + UNSERIALIZE_SCALAR(rxintrwhen); + UNSERIALIZE_SCALAR(txintrwhen); + if (rxintrwhen != 0) + schedule(rxIntrEvent, rxintrwhen); + if (txintrwhen != 0) + schedule(txIntrEvent, txintrwhen); +} + +Uart8250 * +Uart8250Params::create() +{ + return new Uart8250(this); +} diff --git a/src/dev/serial/uart8250.hh b/src/dev/serial/uart8250.hh new file mode 100644 index 000000000..585fbb21e --- /dev/null +++ b/src/dev/serial/uart8250.hh @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * Defines a 8250 UART + */ + +#ifndef __DEV_UART8250_HH__ +#define __DEV_UART8250_HH__ + +#include "dev/io_device.hh" +#include "dev/serial/uart.hh" +#include "params/Uart8250.hh" + +/* UART8250 Interrupt ID Register + * bit 0 Interrupt Pending 0 = true, 1 = false + * bit 2:1 ID of highest priority interrupt + * bit 7:3 zeroes + */ +const uint8_t IIR_NOPEND = 0x1; + +// Interrupt IDs +const uint8_t IIR_MODEM = 0x00; /* Modem Status (lowest priority) */ +const uint8_t IIR_TXID = 0x02; /* Tx Data */ +const uint8_t IIR_RXID = 0x04; /* Rx Data */ +const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/ + +const uint8_t UART_IER_RDI = 0x01; +const uint8_t UART_IER_THRI = 0x02; +const uint8_t UART_IER_RLSI = 0x04; + + +const uint8_t UART_LSR_TEMT = 0x40; +const uint8_t UART_LSR_THRE = 0x20; +const uint8_t UART_LSR_DR = 0x01; + +const uint8_t UART_MCR_LOOP = 0x10; + + +class Terminal; +class Platform; + +class Uart8250 : public Uart +{ + protected: + uint8_t IER, DLAB, LCR, MCR; + Tick lastTxInt; + + void processIntrEvent(int intrBit); + void scheduleIntr(Event *event); + + EventFunctionWrapper txIntrEvent; + EventFunctionWrapper rxIntrEvent; + + public: + typedef Uart8250Params Params; + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + Uart8250(const Params *p); + + Tick read(PacketPtr pkt) override; + Tick write(PacketPtr pkt) override; + AddrRangeList getAddrRanges() const override; + + /** + * Inform the uart that there is data available. + */ + void dataAvailable() override; + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + virtual bool intStatus() { return status ? true : false; } + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; +}; + +#endif // __TSUNAMI_UART_HH__ |