diff options
Diffstat (limited to 'dev')
-rw-r--r-- | dev/alpha_access.h | 79 | ||||
-rw-r--r-- | dev/alpha_console.cc | 273 | ||||
-rw-r--r-- | dev/alpha_console.hh | 108 | ||||
-rw-r--r-- | dev/console.cc | 478 | ||||
-rw-r--r-- | dev/console.hh | 147 | ||||
-rw-r--r-- | dev/disk_image.cc | 427 | ||||
-rw-r--r-- | dev/disk_image.hh | 130 | ||||
-rw-r--r-- | dev/etherbus.cc | 128 | ||||
-rw-r--r-- | dev/etherbus.hh | 79 | ||||
-rw-r--r-- | dev/etherdump.cc | 138 | ||||
-rw-r--r-- | dev/etherdump.hh | 60 | ||||
-rw-r--r-- | dev/etherint.cc | 44 | ||||
-rw-r--r-- | dev/etherint.hh | 63 | ||||
-rw-r--r-- | dev/etherlink.cc | 148 | ||||
-rw-r--r-- | dev/etherlink.hh | 123 | ||||
-rw-r--r-- | dev/etherpkt.hh | 65 | ||||
-rw-r--r-- | dev/ethertap.cc | 295 | ||||
-rw-r--r-- | dev/ethertap.hh | 101 | ||||
-rw-r--r-- | dev/pcireg.h | 175 | ||||
-rw-r--r-- | dev/simple_disk.cc | 108 | ||||
-rw-r--r-- | dev/simple_disk.hh | 60 |
21 files changed, 3229 insertions, 0 deletions
diff --git a/dev/alpha_access.h b/dev/alpha_access.h new file mode 100644 index 000000000..ef33633e5 --- /dev/null +++ b/dev/alpha_access.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003 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. + */ + +#ifndef __ALPHA_ACCESS_H__ +#define __ALPHA_ACCESS_H__ + +/* @file + * System Console Memory Mapped Register Definition + */ + +#define ALPHA_ACCESS_VERSION (1291+1) /* CH++*/ + +#ifdef CONSOLE +typedef uint32 UINT32; +typedef uint64 UINT64; +#else +typedef uint32_t UINT32; +typedef uint64_t UINT64; +#endif + +// This structure hacked up from simos +struct AlphaAccess +{ + UINT32 last_offset; // 00: must be first field + UINT32 version; // 04: + UINT32 numCPUs; // 08: + UINT32 align0; // 0C: Placeholder for alignment + UINT64 mem_size; // 10: + UINT64 cpuClock; // 18: MHz + UINT32 intrClockFrequency; // 20: Hz + UINT32 align1; // 24: Placeholder for alignment + + // Loaded kernel + UINT64 kernStart; // 28: + UINT64 kernEnd; // 30: + UINT64 entryPoint; // 38: + + // console disk stuff + UINT64 diskUnit; // 40: + UINT64 diskCount; // 48: + UINT64 diskPAddr; // 50: + UINT64 diskBlock; // 58: + UINT64 diskOperation; // 60: + + // console simple output stuff + UINT64 outputChar; // 68: + + // MP boot + UINT64 bootStrapImpure; // 70: + UINT32 bootStrapCPU; // 78: + UINT32 align2; // 7C: Dummy placeholder for alignment +}; + +#endif // __ALPHA_ACCESS_H__ diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc new file mode 100644 index 000000000..6a1e2b169 --- /dev/null +++ b/dev/alpha_console.cc @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * System Console Definition + */ + +#include <stddef.h> +#include <stdio.h> + +#include <string> + +#include "alpha_console.hh" +#include "base_cpu.hh" +#include "console.hh" +#include "exec_context.hh" +#include "memory_control.hh" +#include "simple_disk.hh" +#include "tlaser_clock.hh" +#include "system.hh" +#include "trace.hh" +#include "inifile.hh" +#include "str.hh" // for to_number() + +using namespace std; + +AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, + SimpleDisk *d, int size, System *system, + BaseCPU *cpu, TlaserClock *clock, int num_cpus, + Addr addr, Addr mask, MemoryController *mmu) + : MmapDevice(name, addr, mask, mmu), disk(d), console(cons) +{ + consoleData = new uint8_t[size]; + memset(consoleData, 0, size); + + alphaAccess->last_offset = size - 1; + alphaAccess->kernStart = system->getKernelStart(); + alphaAccess->kernEnd = system->getKernelEnd(); + alphaAccess->entryPoint = system->getKernelEntry(); + + alphaAccess->version = ALPHA_ACCESS_VERSION; + alphaAccess->numCPUs = num_cpus; + alphaAccess->mem_size = system->physmem->getSize(); + alphaAccess->cpuClock = cpu->getFreq() / 1000000; + alphaAccess->intrClockFrequency = clock->frequency(); + + alphaAccess->diskUnit = 1; +} + +Fault +AlphaConsole::read(MemReqPtr req, uint8_t *data) +{ + memset(data, 0, req->size); + + if (req->size == sizeof(uint32_t)) { + Addr daddr = req->paddr & addr_mask; + *(uint32_t *)data = *(uint32_t *)(consoleData + daddr); + +#if 0 + DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", + daddr, *(uint32_t *)data); +#endif + } + + return No_Fault; +} + +Fault +AlphaConsole::write(MemReqPtr req, const uint8_t *data) +{ + uint64_t val; + + switch (req->size) { + case sizeof(uint32_t): + val = *(uint32_t *)data; + break; + case sizeof(uint64_t): + val = *(uint64_t *)data; + break; + default: + return Machine_Check_Fault; + } + + Addr paddr = req->paddr & addr_mask; + + if (paddr == offsetof(AlphaAccess, diskUnit)) { + alphaAccess->diskUnit = val; + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, diskCount)) { + alphaAccess->diskCount = val; + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, diskPAddr)) { + alphaAccess->diskPAddr = val; + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, diskBlock)) { + alphaAccess->diskBlock = val; + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, diskOperation)) { + if (val == 0x13) + disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock, + alphaAccess->diskCount); + else + panic("Invalid disk operation!"); + + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, outputChar)) { + console->simple((char)(val & 0xff)); + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, bootStrapImpure)) { + alphaAccess->bootStrapImpure = val; + return No_Fault; + } + + if (paddr == offsetof(AlphaAccess, bootStrapCPU)) { + warn("%d: Trying to launch another CPU!", curTick); + int cpu = val; + assert(cpu > 0 && "Must not access primary cpu"); + + ExecContext *other_xc = req->xc->system->xc_array[cpu]; + other_xc->regs.intRegFile[16] = cpu; + other_xc->regs.ipr[TheISA::IPR_PALtemp16] = cpu; + other_xc->regs.intRegFile[0] = cpu; + other_xc->regs.intRegFile[30] = alphaAccess->bootStrapImpure; + other_xc->setStatus(ExecContext::Active); //Start the cpu + return No_Fault; + } + + return No_Fault; +} + +void +AlphaConsole::serialize() +{ + nameOut(); + // assumes full AlphaAccess size + // might have unnecessary fields here + paramOut("last_offset",alphaAccess->last_offset); + paramOut("version",alphaAccess->version); + paramOut("numCPUs",alphaAccess->numCPUs); + paramOut("mem_size",alphaAccess->mem_size); + paramOut("cpuClock",alphaAccess->cpuClock); + paramOut("intrClockFrequency",alphaAccess->intrClockFrequency); + paramOut("kernStart",alphaAccess->kernStart); + paramOut("kernEnd",alphaAccess->kernEnd); + paramOut("entryPoint",alphaAccess->entryPoint); + paramOut("diskUnit",alphaAccess->diskUnit); + paramOut("diskCount",alphaAccess->diskCount); + paramOut("diskPAddr",alphaAccess->diskPAddr); + paramOut("diskBlock",alphaAccess->diskBlock); + paramOut("diskOperation",alphaAccess->diskOperation); + paramOut("outputChar",alphaAccess->outputChar); + paramOut("bootStrapImpure",alphaAccess->bootStrapImpure); + paramOut("bootStrapCPU",alphaAccess->bootStrapCPU); +} + +void +AlphaConsole::unserialize(IniFile &db, const std::string &category, + ConfigNode *node) +{ + string data; + db.findDefault(category,"last_offset",data); + to_number(data,alphaAccess->last_offset); + db.findDefault(category,"version",data); + to_number(data,alphaAccess->version); + db.findDefault(category,"numCPUs",data); + to_number(data,alphaAccess->numCPUs); + db.findDefault(category,"mem_size",data); + to_number(data,alphaAccess->mem_size); + db.findDefault(category,"cpuClock",data); + to_number(data,alphaAccess->cpuClock); + db.findDefault(category,"intrClockFrequency",data); + to_number(data,alphaAccess->intrClockFrequency); + db.findDefault(category,"kernStart",data); + to_number(data,alphaAccess->kernStart); + db.findDefault(category,"kernEnd",data); + to_number(data,alphaAccess->kernEnd); + db.findDefault(category,"entryPoint",data); + to_number(data,alphaAccess->entryPoint); + db.findDefault(category,"diskUnit",data); + to_number(data,alphaAccess->diskUnit); + db.findDefault(category,"diskCount",data); + to_number(data,alphaAccess->diskCount); + db.findDefault(category,"diskPAddr",data); + to_number(data,alphaAccess->diskPAddr); + db.findDefault(category,"diskBlock",data); + to_number(data,alphaAccess->diskBlock); + db.findDefault(category,"diskOperation",data); + to_number(data,alphaAccess->diskOperation); + db.findDefault(category,"outputChar",data); + to_number(data,alphaAccess->outputChar); + db.findDefault(category,"bootStrapImpure",data); + to_number(data,alphaAccess->bootStrapImpure); + db.findDefault(category,"bootStrapCPU",data); + to_number(data,alphaAccess->bootStrapCPU); + +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + + SimObjectParam<SimConsole *> sim_console; + SimObjectParam<SimpleDisk *> disk; + Param<int> size; + Param<int> num_cpus; + SimObjectParam<MemoryController *> mmu; + Param<Addr> addr; + Param<Addr> mask; + SimObjectParam<System *> system; + SimObjectParam<BaseCPU *> cpu; + SimObjectParam<TlaserClock *> clock; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + + INIT_PARAM(sim_console, "The Simulator Console"), + INIT_PARAM(disk, "Simple Disk"), + INIT_PARAM_DFLT(size, "AlphaConsole size", sizeof(AlphaAccess)), + INIT_PARAM_DFLT(num_cpus, "Number of CPU's", 1), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(addr, "Device Address"), + INIT_PARAM(mask, "Address Mask"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu, "Processor"), + INIT_PARAM(clock, "Turbolaser Clock") + +END_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + +CREATE_SIM_OBJECT(AlphaConsole) +{ + return new AlphaConsole(getInstanceName(), sim_console, + disk, size, system, + cpu, clock, num_cpus, + addr, mask, mmu); +} + +REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole) diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh new file mode 100644 index 000000000..518f5fccb --- /dev/null +++ b/dev/alpha_console.hh @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * System Console Interface + */ + +#ifndef __ALPHA_CONSOLE_HH__ +#define __ALPHA_CONSOLE_HH__ + +#include "host.hh" +#include "alpha_access.h" +#include "mmap_device.hh" + +class BaseCPU; +class SimConsole; +class System; +class TlaserClock; +class SimpleDisk; + +/* + * Memory mapped interface to the system console. This device + * represents a shared data region between the OS Kernel and the + * System Console. + * + * The system console is a small standalone program that is initially + * run when the system boots. It contains the necessary code to + * access the boot disk, to read/write from the console, and to pass + * boot parameters to the kernel. + * + * This version of the system console is very different from the one + * that would be found in a real system. Many of the functions use + * some sort of backdoor to get their job done. For example, reading + * from the boot device on a real system would require a minimal + * device driver to access the disk controller, but since we have a + * simulator here, we are able to bypass the disk controller and + * access the disk image directly. There are also some things like + * reading the kernel off the disk image into memory that are normally + * taken care of by the console that are now taken care of by the + * simulator. + * + * These shortcuts are acceptable since the system console is + * primarily used doing boot before the kernel has loaded its device + * drivers. + */ +class AlphaConsole : public MmapDevice +{ + protected: + union { + AlphaAccess *alphaAccess; + uint8_t *consoleData; + }; + + /** the disk must be accessed from the console */ + SimpleDisk *disk; + + /** the system console (the terminal) is accessable from the console */ + SimConsole *console; + + public: + /** Standard Constructor */ + AlphaConsole(const std::string &name, SimConsole *cons, + SimpleDisk *d, int size, + System *system, BaseCPU *cpu, + TlaserClock *clock, int num_cpus, + Addr addr, Addr mask, MemoryController *mmu); + + public: + /** + * memory mapped reads and writes + */ + virtual Fault read(MemReqPtr req, uint8_t *data); + virtual Fault write(MemReqPtr req, const uint8_t *data); + + /** + * standard serialization routines for checkpointing + */ + virtual void serialize(); + virtual void unserialize(IniFile &db, const std::string &category, + ConfigNode *node); +}; + +#endif // __ALPHA_CONSOLE_HH__ diff --git a/dev/console.cc b/dev/console.cc new file mode 100644 index 000000000..8141a6508 --- /dev/null +++ b/dev/console.cc @@ -0,0 +1,478 @@ +/* $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 "misc.hh" +#include "ev5.hh" + +#include "console.hh" +#include "socket.hh" +#include "trace.hh" +#include "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) diff --git a/dev/console.hh b/dev/console.hh new file mode 100644 index 000000000..092e6ea53 --- /dev/null +++ b/dev/console.hh @@ -0,0 +1,147 @@ +/* $Id$ */ + +/* @file + * User Console Interface + */ + +#ifndef __CONSOLE_HH__ +#define __CONSOLE_HH__ + +#include <iostream> + +#include "circlebuf.hh" +#include "intr_control.hh" +#include "pollevent.hh" +#include "socket.hh" +#include "sim_object.hh" + +class ConsoleListener; +class SimConsole : public SimObject +{ + protected: + class Event : public PollEvent + { + protected: + SimConsole *cons; + + public: + Event(SimConsole *c, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + int number; + int in_fd; + int out_fd; + + protected: + ConsoleListener *listener; + + public: + SimConsole(const std::string &name, const std::string &file, int num); + ~SimConsole(); + + protected: + CircleBuf txbuf; + CircleBuf rxbuf; + std::ostream *outfile; + + public: + /////////////////////// + // Terminal Interface + + void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } + void attach(int in, int out, ConsoleListener *l = NULL); + void detach(); + + void data(); + + void close(); + 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 configTerm(); + + protected: + // interrupt status/enable + int intr_status; + int intr_enable; + + // interrupt handle + IntrControl *intr; + + public: + ///////////////// + // OS interface + + // Input a character from the console. Returns the character (if + // any) or -1 if there is no character pending on this console. If + // no further characters are pending, the (input) interrupt is + // cleared. + int in(); + + // Output a character to the console. This never fails, as this + // device doesn't model finite buffering capacity. + void out(char c); + void simple(char c); + + enum { + TransmitInterrupt = 1, + ReceiveInterrupt = 2 + }; + + // Read the current interrupt status of this console. + int intStatus(); + + // Set the interrupt enable bits. + int clearInt(int i); + void raiseInt(int i); + + void initInt(IntrControl *i); + void setInt(int bits); + + virtual void serialize(); + virtual void unserialize(IniFile &db, const std::string &category, + ConfigNode *node); +}; + +class ConsoleListener : public SimObject +{ + protected: + class Event : public PollEvent + { + protected: + ConsoleListener *listener; + + public: + Event(ConsoleListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + void process(int revent); + }; + + friend class Event; + Event *event; + + typedef std::list<SimConsole *> list_t; + typedef list_t::iterator iter_t; + list_t ConsoleList; + + protected: + ListenSocket listener; + + public: + ConsoleListener(const std::string &name); + ~ConsoleListener(); + + void add(SimConsole *cons); + + void accept(); + void listen(int port); +}; + +#endif // __CONSOLE_HH__ diff --git a/dev/disk_image.cc b/dev/disk_image.cc new file mode 100644 index 000000000..17a7f3e9d --- /dev/null +++ b/dev/disk_image.cc @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Disk Image Definitions + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <cstdio> +#include <fstream> +#include <string> + +#include "disk_image.hh" +#include "misc.hh" +#include "trace.hh" +#include "sim_exit.hh" +#include "callback.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// Raw Disk image +// +RawDiskImage::RawDiskImage(const string &name, const string &filename, + bool rd_only) + : DiskImage(name), disk_size(0) +{ open(filename, rd_only); } + +RawDiskImage::~RawDiskImage() +{ close(); } + +void +RawDiskImage::open(const string &filename, bool rd_only) +{ + if (!filename.empty()) { + initialized = true; + readonly = rd_only; + file = filename; + + ios::openmode mode = ios::in | ios::binary; + if (!readonly) + mode |= ios::out; + stream.open(file.c_str(), mode); + if (!stream.is_open()) + panic("Error opening %s", filename); + } +} + +void +RawDiskImage::close() +{ + stream.close(); +} + +off_t +RawDiskImage::size() const +{ + if (disk_size == 0) { + if (!stream.is_open()) + panic("file not open!\n"); + stream.seekg(0, ios::end); + disk_size = stream.tellg(); + } + + return disk_size / SectorSize; +} + +off_t +RawDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekg(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + off_t pos = stream.tellg(); + stream.read((char *)data, SectorSize); + + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + + return stream.tellg() - pos; +} + +off_t +RawDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (readonly) + panic("Cannot write to a read only disk image"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekp(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + off_t pos = stream.tellp(); + stream.write((const char *)data, SectorSize); + return stream.tellp() - pos; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + + Param<string> image_file; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + INIT_PARAM(image_file, "disk image file"), + INIT_PARAM_DFLT(read_only, "read only image", false) + +END_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + +CREATE_SIM_OBJECT(RawDiskImage) +{ + return new RawDiskImage(getInstanceName(), image_file, read_only); +} + +REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) + +//////////////////////////////////////////////////////////////////////// +// +// Copy on Write Disk image +// +const int CowDiskImage::VersionMajor = 1; +const int CowDiskImage::VersionMinor = 0; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) + : DiskImage(name), child(kid), table(NULL) +{ init(hash_size); } + +class CowDiskCallback : public Callback +{ + private: + CowDiskImage *image; + + public: + CowDiskCallback(CowDiskImage *i) : image(i) {} + void process() { image->save(); delete this; } +}; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, + const string &file, bool read_only) + : DiskImage(name), filename(file), child(kid), table(NULL) +{ + if (!open()) { + assert(!read_only && "why have a non-existent read only file?"); + init(hash_size); + } + + if (!read_only) + registerExitCallback(new CowDiskCallback(this)); +} + +CowDiskImage::~CowDiskImage() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + +void +SafeRead(ifstream &stream, void *data, int count) +{ + stream.read((char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeRead(ifstream &stream, T &data) +{ SafeRead(stream, &data, sizeof(data)); } + +bool +CowDiskImage::open() +{ + ifstream stream(filename.c_str()); + if (!stream.is_open()) + return false; + + if (stream.fail() || stream.bad()) + panic("Error opening %s", filename); + + uint64_t magic; + SafeRead(stream, magic); + + if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) + panic("Could not open %s: Invalid magic", filename); + + uint32_t major, minor; + SafeRead(stream, major); + SafeRead(stream, minor); + + if (major != VersionMajor && minor != VersionMinor) + panic("Could not open %s: invalid version %d.%d != %d.%d", + filename, major, minor, VersionMajor, VersionMinor); + + uint64_t sector_count; + SafeRead(stream, sector_count); + table = new SectorTable(sector_count); + + + for (uint64_t i = 0; i < sector_count; i++) { + uint64_t offset; + SafeRead(stream, offset); + + Sector *sector = new Sector; + SafeRead(stream, sector, sizeof(Sector)); + + assert(table->find(offset) == table->end()); + (*table)[offset] = sector; + } + + stream.close(); + + initialized = true; + return true; +} + +void +CowDiskImage::init(int hash_size) +{ + table = new SectorTable(hash_size); + + initialized = true; +} + +void +SafeWrite(ofstream &stream, const void *data, int count) +{ + stream.write((const char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeWrite(ofstream &stream, const T &data) +{ SafeWrite(stream, &data, sizeof(data)); } + +void +CowDiskImage::save() +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + ofstream stream(filename.c_str()); + if (!stream.is_open() || stream.fail() || stream.bad()) + panic("Error opening %s", filename); + + uint64_t magic; + memcpy(&magic, "COWDISK!", sizeof(magic)); + SafeWrite(stream, magic); + + SafeWrite(stream, (uint32_t)VersionMajor); + SafeWrite(stream, (uint32_t)VersionMinor); + SafeWrite(stream, (uint64_t)table->size()); + + uint64_t size = table->size(); + SectorTable::iterator iter = table->begin(); + SectorTable::iterator end = table->end(); + + for (uint64_t i = 0; i < size; i++) { + if (iter == end) + panic("Incorrect Table Size during save of COW disk image"); + + SafeWrite(stream, (uint64_t)(*iter).first); + SafeWrite(stream, (*iter).second->data, sizeof(Sector)); + ++iter; + } + + stream.close(); +} + +void +CowDiskImage::writeback() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + child->write((*i).second->data, (*i).first); + ++i; + } +} + +off_t +CowDiskImage::size() const +{ return child->size(); } + +off_t +CowDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("CowDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::const_iterator i = table->find(offset); + if (i == table->end()) + return child->read(data, offset); + else { + memcpy(data, (*i).second->data, SectorSize); + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + return SectorSize; + } +} + +off_t +CowDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::iterator i = table->find(offset); + if (i == table->end()) { + Sector *sector = new Sector; + memcpy(sector, data, SectorSize); + table->insert(make_pair(offset, sector)); + } else { + memcpy((*i).second->data, data, SectorSize); + } + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + return SectorSize; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + + SimObjectParam<DiskImage *> child; + Param<string> image_file; + Param<int> table_size; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + INIT_PARAM(child, "child image"), + INIT_PARAM_DFLT(image_file, "disk image file", ""), + INIT_PARAM_DFLT(table_size, "initial table size", 65536), + INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", + true) + +END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + +CREATE_SIM_OBJECT(CowDiskImage) +{ + if (((string)image_file).empty()) + return new CowDiskImage(getInstanceName(), child, table_size); + else + return new CowDiskImage(getInstanceName(), child, table_size, + image_file, read_only); +} + +REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) diff --git a/dev/disk_image.hh b/dev/disk_image.hh new file mode 100644 index 000000000..2cfa1490a --- /dev/null +++ b/dev/disk_image.hh @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Disk Image Interfaces + */ + +#ifndef __DISK_IMAGE_HH__ +#define __DISK_IMAGE_HH__ + +#include <fstream> + +#include "hashmap.hh" +#include "sim_object.hh" + +#define SectorSize (512) + +/* + * Basic interface for accessing a disk image. + */ +class DiskImage : public SimObject +{ + protected: + bool initialized; + + public: + DiskImage(const std::string &name) : SimObject(name), initialized(false) {} + virtual ~DiskImage() {} + + virtual off_t size() const = 0; + + virtual off_t read(uint8_t *data, off_t offset) const = 0; + virtual off_t write(const uint8_t *data, off_t offset) = 0; +}; + +/* + * Specialization for accessing a raw disk image + */ +class RawDiskImage : public DiskImage +{ + protected: + mutable std::fstream stream; + std::string file; + bool readonly; + mutable off_t disk_size; + + public: + RawDiskImage(const std::string &name, const std::string &filename, + bool rd_only); + ~RawDiskImage(); + + void close(); + void open(const std::string &filename, bool rd_only = false); + + virtual off_t size() const; + + virtual off_t read(uint8_t *data, off_t offset) const; + virtual off_t write(const uint8_t *data, off_t offset); +}; + +/* + * Specialization for accessing a copy-on-write disk image layer. + * A copy-on-write(COW) layer must be stacked on top of another disk + * image layer this layer can be another CowDiskImage, or a + * RawDiskImage. + * + * This object is designed to provide a mechanism for persistant + * changes to a main disk image, or to provide a place for temporary + * changes to the image to take place that later may be thrown away. + */ +class CowDiskImage : public DiskImage +{ + public: + static const int VersionMajor; + static const int VersionMinor; + + protected: + struct Sector { + uint8_t data[SectorSize]; + }; + typedef m5::hash_map<uint64_t, Sector *> SectorTable; + + protected: + std::string filename; + DiskImage *child; + SectorTable *table; + + public: + CowDiskImage(const std::string &name, DiskImage *kid, int hash_size); + CowDiskImage(const std::string &name, DiskImage *kid, int hash_size, + const std::string &filename, bool read_only); + ~CowDiskImage(); + + void init(int hash_size); + bool open(); + void save(); + void writeback(); + + virtual off_t size() const; + + virtual off_t read(uint8_t *data, off_t offset) const; + virtual off_t write(const uint8_t *data, off_t offset); +}; + +#endif // __DISK_IMAGE_HH__ diff --git a/dev/etherbus.cc b/dev/etherbus.cc new file mode 100644 index 000000000..fa5a62208 --- /dev/null +++ b/dev/etherbus.cc @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#include <deque> +#include <string> +#include <vector> + +#include <math.h> + +#include "etherbus.hh" +#include "etherdump.hh" +#include "etherint.hh" +#include "etherpkt.hh" +#include "trace.hh" +#include "universe.hh" + +using namespace std; + +EtherBus::EtherBus(const string &name, double rate, bool loop, + EtherDump *packet_dump) + : SimObject(name), ticks_per_byte(rate), loopback(loop), + event(&mainEventQueue, this), + sender(0), dump(packet_dump) +{ } + +void +EtherBus::txDone() +{ + devlist_t::iterator i = devlist.begin(); + devlist_t::iterator end = devlist.end(); + + DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + + while (i != end) { + if (loopback || *i != sender) + (*i)->sendPacket(packet); + ++i; + } + + sender->sendDone(); + + if (dump) + dump->dump(packet); + + sender = 0; + packet = 0; +} + +void +EtherBus::reg(EtherInt *dev) +{ devlist.push_back(dev); } + +bool +EtherBus::send(EtherInt *sndr, PacketPtr pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick); + return false; + } + + DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + sender = sndr; + int delay = (int)ceil(((double)pkt->length * ticks_per_byte) + 1.0); + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticks_per_byte); + event.schedule(curTick + delay); + + return true; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + + Param<bool> loopback; + Param<int> speed; + SimObjectParam<EtherDump *> packet_dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus) + + INIT_PARAM_DFLT(loopback, + "send the packet back to the interface from which it came", + true), + INIT_PARAM_DFLT(speed, "bus speed in bits per second", 100000000), + INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL) + +END_INIT_SIM_OBJECT_PARAMS(EtherBus) + +CREATE_SIM_OBJECT(EtherBus) +{ + double rate = ((double)ticksPerSecond * 8.0) / (double)speed; + return new EtherBus(getInstanceName(), rate, loopback, packet_dump); +} + +REGISTER_SIM_OBJECT("EtherBus", EtherBus) diff --git a/dev/etherbus.hh b/dev/etherbus.hh new file mode 100644 index 000000000..f64aa45e1 --- /dev/null +++ b/dev/etherbus.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#ifndef __ETHERBUS_H__ +#define __ETHERBUS_H__ + +#include "eventq.hh" +#include "etherpkt.hh" +#include "sim_object.hh" + +class EtherDump; +class EtherInt; +class EtherBus : public SimObject +{ + protected: + typedef std::list<EtherInt *> devlist_t; + devlist_t devlist; + double ticks_per_byte; + bool loopback; + + protected: + class DoneEvent : public Event + { + protected: + EtherBus *bus; + + public: + DoneEvent(EventQueue *q, EtherBus *b) + : Event(q), bus(b) {} + virtual void process() { bus->txDone(); } + virtual const char *description() { return "ethernet bus completion"; } + }; + + DoneEvent event; + PacketPtr packet; + EtherInt *sender; + EtherDump *dump; + + public: + EtherBus(const std::string &name, double ticks_per_byte, bool loopback, + EtherDump *dump); + virtual ~EtherBus() {} + + void txDone(); + void reg(EtherInt *dev); + bool busy() const { return (bool)packet; } + bool send(EtherInt *sender, PacketPtr packet); +}; + +#endif // __ETHERBUS_H__ diff --git a/dev/etherdump.cc b/dev/etherdump.cc new file mode 100644 index 000000000..034db86aa --- /dev/null +++ b/dev/etherdump.cc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#include <sys/time.h> + +#include <string> + +#include "universe.hh" +#include "etherdump.hh" +#include "universe.hh" + +using std::string; + +EtherDump::EtherDump(const string &name, const string &file) + : SimObject(name) +{ + if (!file.empty()) { + stream.open(file.c_str()); + if (stream.is_open()) + init(); + } +} + +#define DLT_EN10MB 1 // Ethernet (10Mb) +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +struct pcap_file_header { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; // gmt to local correction + uint32_t sigfigs; // accuracy of timestamps + uint32_t snaplen; // max length saved portion of each pkt + uint32_t linktype; // data link type (DLT_*) +}; + +struct pcap_pkthdr { + struct timeval ts; // time stamp + uint32_t caplen; // length of portion present + uint32_t len; // length this packet (off wire) +}; + +void +EtherDump::init() +{ + curtime = time(NULL); + s_freq = ticksPerSecond; + us_freq = ticksPerSecond / ULL(1000000); + + struct pcap_file_header hdr; + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + + hdr.thiszone = -5 * 3600; + hdr.snaplen = 1500; + hdr.sigfigs = 0; + hdr.linktype = DLT_EN10MB; + + stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + + /* + * output an empty packet with the current time so that we know + * when the simulation began. This allows us to correlate packets + * to sim_cycles. + */ + pcap_pkthdr pkthdr; + pkthdr.ts.tv_sec = curtime; + pkthdr.ts.tv_usec = 0; + pkthdr.caplen = 0; + pkthdr.len = 0; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + + stream.flush(); +} + +void +EtherDump::dumpPacket(PacketPtr packet) +{ + pcap_pkthdr pkthdr; + pkthdr.ts.tv_sec = curtime + (curTick / s_freq); + pkthdr.ts.tv_usec = (curTick / us_freq) % ULL(1000000); + pkthdr.caplen = packet->length; + pkthdr.len = packet->length; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream.write(reinterpret_cast<char *>(packet->data), packet->length); + stream.flush(); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + + Param<string> file; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) + + INIT_PARAM_DFLT(file, "file to dump packets to", "") + +END_INIT_SIM_OBJECT_PARAMS(EtherDump) + +CREATE_SIM_OBJECT(EtherDump) +{ + return new EtherDump(getInstanceName(), file); +} + +REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/dev/etherdump.hh b/dev/etherdump.hh new file mode 100644 index 000000000..87824c470 --- /dev/null +++ b/dev/etherdump.hh @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#ifndef __ETHERDUMP_H__ +#define __ETHERDUMP_H__ + +#include <fstream> +#include "etherpkt.hh" +#include "sim_object.hh" + +/* + * Simple object for creating a simple pcap style packet trace + */ +class EtherDump : public SimObject +{ + private: + std::ofstream stream; + void dumpPacket(PacketPtr packet); + void init(); + + Tick curtime; + Tick s_freq; + Tick us_freq; + + public: + EtherDump(const std::string &name, const std::string &file); + + inline void dump(PacketPtr pkt) { if (stream.is_open()) dumpPacket(pkt); } +}; + +#endif // __ETHERDUMP_H__ diff --git a/dev/etherint.cc b/dev/etherint.cc new file mode 100644 index 000000000..51b18c6aa --- /dev/null +++ b/dev/etherint.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003 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. + */ + +#include "etherint.hh" +#include "misc.hh" +#include "sim_object.hh" + +void +EtherInt::setPeer(EtherInt *p) +{ + if (peer && peer != p) + panic("You cannot change the peer once it is set.\n" + "Current peer=%s Desired peer=%s", peer->name(), p->name()); + + peer = p; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("EtherInt", EtherInt) + diff --git a/dev/etherint.hh b/dev/etherint.hh new file mode 100644 index 000000000..00e291fc9 --- /dev/null +++ b/dev/etherint.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Class representing the actual interface between two ethernet + * components. + */ + +#ifndef __ETHERINT_HH__ +#define __ETHERINT_HH__ + +#include <string> + +#include "etherpkt.hh" +#include "sim_object.hh" + +/* + * Class representing the actual interface between two ethernet + * components. These components are intended to attach to another + * ethernet interface on one side and whatever device on the other. + */ +class EtherInt : public SimObject +{ + protected: + EtherInt *peer; + + public: + EtherInt(const std::string &name) : SimObject(name), peer(NULL) {} + virtual ~EtherInt() {} + + void setPeer(EtherInt *p); + virtual bool recvPacket(PacketPtr packet) = 0; + void recvDone() { peer->sendDone(); } + bool sendPacket(PacketPtr packet) { return peer->recvPacket(packet); } + virtual void sendDone() = 0; +}; + +#endif // __ETHERINT_HH__ diff --git a/dev/etherlink.cc b/dev/etherlink.cc new file mode 100644 index 000000000..1d3578e58 --- /dev/null +++ b/dev/etherlink.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#include <deque> +#include <string> +#include <vector> + +#include <math.h> + +#include "etherlink.hh" +#include "etherdump.hh" +#include "etherint.hh" +#include "etherpkt.hh" +#include "trace.hh" +#include "universe.hh" + +using namespace std; + +EtherLink::EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2, + Tick speed, EtherDump *dump) + : SimObject(name) +{ + double rate = ((double)ticksPerSecond * 8.0) / (double)speed; + + link1 = new Link(name + ".link1", rate, dump); + link2 = new Link(name + ".link2", rate, dump); + + int1 = new Interface(name + ".int1", link1, link2); + int2 = new Interface(name + ".int2", link2, link1); + + int1->setPeer(i1); + i1->setPeer(int1); + int2->setPeer(i2); + i2->setPeer(int2); +} + +EtherLink::~EtherLink() +{ + delete link1; + delete link2; + + delete int1; + delete int2; +} + +EtherLink::Interface::Interface(const std::string &name, Link *tx, Link *rx) + : EtherInt(name), txlink(tx) +{ + tx->setTxInt(this); + rx->setRxInt(this); +} + +EtherLink::Link::Link(const std::string &name, double rate, EtherDump *d) + : Serializeable(name), txint(NULL), rxint(NULL), ticks_per_byte(rate), + dump(d), event(&mainEventQueue, this) +{} + +void +EtherLink::Link::txDone() +{ + rxint->sendPacket(packet); + + if (dump) + dump->dump(packet); + + DPRINTF(Ethernet, "EtherLink packet received: len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + + packet = 0; + assert(!busy()); + + txint->sendDone(); +} + +bool +EtherLink::Link::transmit(PacketPtr pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "EtherLink packet not sent, link busy\n"); + return false; + } + + DPRINTF(Ethernet, "EtherLink packet sent: len=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + int delay = (int)ceil(((double)pkt->length * ticks_per_byte) + 1.0); + DPRINTF(Ethernet, "EtherLink scheduling packet: delay=%d, (rate=%f)\n", + delay, ticks_per_byte); + event.schedule(curTick + delay); + + return true; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + + SimObjectParam<EtherInt *> interface1; + SimObjectParam<EtherInt *> interface2; + Param<int> link_speed; + SimObjectParam<EtherDump *> packet_dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) + + INIT_PARAM(interface1, "interface 1"), + INIT_PARAM(interface2, "interface 2"), + INIT_PARAM_DFLT(link_speed, "link speed in bits per second", 100000000), + INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL) + +END_INIT_SIM_OBJECT_PARAMS(EtherLink) + +CREATE_SIM_OBJECT(EtherLink) +{ + return new EtherLink(getInstanceName(), interface1, interface2, link_speed, + packet_dump); +} + +REGISTER_SIM_OBJECT("EtherLink", EtherLink) diff --git a/dev/etherlink.hh b/dev/etherlink.hh new file mode 100644 index 000000000..b88d80420 --- /dev/null +++ b/dev/etherlink.hh @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#ifndef __ETHERLINK_HH__ +#define __ETHERLINK_HH__ + +#include "host.hh" +#include "eventq.hh" +#include "etherint.hh" +#include "etherpkt.hh" +#include "sim_object.hh" + +class EtherDump; + +/* + * Model for a fixed bandwidth full duplex ethernet link + */ +class EtherLink : public SimObject +{ + protected: + class Interface; + + /* + * Model for a single uni-directional link + */ + class Link : public Serializeable { + protected: + Interface *txint; + Interface *rxint; + + double ticks_per_byte; + EtherDump *dump; + + protected: + /* + * Transfer is complete + */ + class DoneEvent : public Event + { + protected: + Link *link; + + public: + DoneEvent(EventQueue *q, Link *l) + : Event(q), link(l) {} + virtual void process() { link->txDone(); } + virtual const char *description() + { return "ethernet link completion"; } + }; + + friend class DoneEvent; + DoneEvent event; + PacketPtr packet; + + void txDone(); + + public: + Link(const std::string &name, double rate, EtherDump *dump); + ~Link() {} + + bool busy() const { return (bool)packet; } + bool transmit(PacketPtr packet); + + void setTxInt(Interface *i) { assert(!txint); txint = i; } + void setRxInt(Interface *i) { assert(!rxint); rxint = i; } + }; + + /* + * Interface at each end of the link + */ + class Interface : public EtherInt + { + private: + Link *txlink; + + public: + Interface(const std::string &name, Link *txlink, Link *rxlink); + bool recvPacket(PacketPtr packet) { return txlink->transmit(packet); } + void sendDone() { } + }; + + Link *link1; + Link *link2; + + EtherInt *int1; + EtherInt *int2; + + public: + EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2, + Tick speed, EtherDump *dump); + virtual ~EtherLink(); +}; + +#endif // __ETHERLINK_HH__ diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh new file mode 100644 index 000000000..4927cc779 --- /dev/null +++ b/dev/etherpkt.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Reference counted class containing ethernet packet data + */ + +#ifndef __ETHERPKT_HH__ +#define __ETHERPKT_HH__ + +#include <memory> + +#include "host.hh" + +#include "refcnt.hh" + +/* + * Reference counted class containing ethernet packet data + */ +class EtherPacket : public RefCounted +{ + public: + uint8_t *data; + int length; + + public: + EtherPacket() : data(NULL), length(0) {} + EtherPacket(std::auto_ptr<uint8_t> d, int l) + : data(d.release()), length(l) {} + ~EtherPacket() { if (data) delete [] data; } + + public: + bool IsUnicast() { return data[0] == 0x00; } + bool IsMulticast() { return data[0] == 0x01; } + bool IsBroadcast() { return data[0] == 0xff; } +}; + +typedef RefCountingPtr<EtherPacket> PacketPtr; + +#endif // __ETHERPKT_HH__ diff --git a/dev/ethertap.cc b/dev/ethertap.cc new file mode 100644 index 000000000..6643cab30 --- /dev/null +++ b/dev/ethertap.cc @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#if defined(__OpenBSD__) +#include <sys/param.h> +#endif +#include <netinet/in.h> + +#include <unistd.h> + +#include <deque> +#include <string> + +#include "etherdump.hh" +#include "etherint.hh" +#include "etherpkt.hh" +#include "ethertap.hh" +#include "pollevent.hh" +#include "socket.hh" +#include "trace.hh" +#include "misc.hh" + +using namespace std; + +/** + */ +class TapListener +{ + protected: + /** + */ + class Event : public PollEvent + { + protected: + TapListener *listener; + + public: + Event(TapListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + + virtual void process(int revent) { listener->accept(); } + }; + + friend class Event; + Event *event; + + protected: + ListenSocket listener; + EtherTap *tap; + int port; + + public: + TapListener(EtherTap *t, int p) + : event(NULL), tap(t), port(p) {} + ~TapListener() { if (event) delete event; } + + void accept(); + void listen(); +}; + +void +TapListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); + port++; + } + + ccprintf(cerr, "Listening for tap connection on port %d\n", port); + event = new Event(this, listener.getfd(), POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +TapListener::accept() +{ + if (!listener.islistening()) + panic("TapListener(accept): cannot accept if we're not listening!"); + + int sfd = listener.accept(true); + if (sfd != -1) + tap->attach(sfd); +} + +/** + */ +class TapEvent : public PollEvent +{ + protected: + EtherTap *tap; + + public: + TapEvent(EtherTap *_tap, int fd, int e) + : PollEvent(fd, e), tap(_tap) {} + virtual void process(int revent) { tap->process(revent); } +}; + +EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) + : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), + txEvent(this) +{ + buffer = new char[buflen]; + listener = new TapListener(this, port); + listener->listen(); +} + +EtherTap::~EtherTap() +{ + if (event) + delete event; + if (buffer) + delete [] buffer; + + delete listener; +} + +void +EtherTap::attach(int fd) +{ + if (socket != -1) + close(fd); + + buffer_offset = 0; + data_len = 0; + socket = fd; + DPRINTF(Ethernet, "EtherTap attached\n"); + event = new TapEvent(this, socket, POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +EtherTap::detach() +{ + DPRINTF(Ethernet, "EtherTap detached\n"); + delete event; + close(socket); + socket = -1; +} + +bool +EtherTap::recvPacket(PacketPtr packet) +{ + if (dump) + dump->dump(packet); + + DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + u_int32_t len = htonl(packet->length); + write(socket, &len, sizeof(len)); + write(socket, packet->data, packet->length); + + recvDone(); + + return true; +} + +void +EtherTap::sendDone() +{} + +void +EtherTap::process(int revent) +{ + if (revent & POLLERR) { + detach(); + return; + } + + char *data = buffer + sizeof(u_int32_t); + if (!(revent & POLLIN)) + return; + + if (buffer_offset < data_len + sizeof(u_int32_t)) { + int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); + if (len == 0) { + detach(); + return; + } + + buffer_offset += len; + + if (data_len == 0) + data_len = ntohl(*(u_int32_t *)buffer); + + DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " + "data_len=%d\n", len, buffer_offset, data_len); + } + + while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { + PacketPtr packet; + packet = new EtherPacket; + packet->data = new uint8_t[data_len]; + packet->length = data_len; + memcpy(packet->data, data, data_len); + + buffer_offset -= data_len + sizeof(u_int32_t); + assert(buffer_offset >= 0); + if (buffer_offset > 0) { + memmove(buffer, data + data_len, buffer_offset); + data_len = ntohl(*(u_int32_t *)buffer); + } else + data_len = 0; + + DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + if (!sendPacket(packet)) { + DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); + packetBuffer.push(packet); + if (!txEvent.scheduled()) + txEvent.schedule(curTick + 1000); + } else if (dump) + dump->dump(packet); + } +} + +void +EtherTap::retransmit() +{ + if (packetBuffer.empty()) + return; + + PacketPtr packet = packetBuffer.front(); + if (sendPacket(packet)) { + if (dump) + dump->dump(packet); + DPRINTF(Ethernet, "EtherTap retransmit\n"); + packetBuffer.front() = NULL; + packetBuffer.pop(); + } + + if (!packetBuffer.empty() && !txEvent.scheduled()) + txEvent.schedule(curTick + 1000); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<EtherDump *> packet_dump; + Param<uint16_t> port; + Param<uint16_t> bufsz; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL), + INIT_PARAM_DFLT(port, "tap port", 3500), + INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) + +END_INIT_SIM_OBJECT_PARAMS(EtherTap) + + +CREATE_SIM_OBJECT(EtherTap) +{ + EtherTap *tap = new EtherTap(getInstanceName(), packet_dump, port, bufsz); + + if (peer) { + tap->setPeer(peer); + peer->setPeer(tap); + } + + return tap; +} + +REGISTER_SIM_OBJECT("EtherTap", EtherTap) diff --git a/dev/ethertap.hh b/dev/ethertap.hh new file mode 100644 index 000000000..434df47b0 --- /dev/null +++ b/dev/ethertap.hh @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#ifndef __ETHERTAP_HH__ +#define __ETHERTAP_HH__ + +#include <queue> +#include <string> + +#include "etherint.hh" +#include "etherpkt.hh" +#include "eventq.hh" +#include "pollevent.hh" +#include "sim_object.hh" + +/* + * Interface to connect a simulated ethernet device to the real world + */ +class EtherTap : public EtherInt +{ + protected: + friend class TapEvent; + TapEvent *event; + + protected: + friend class TapListener; + TapListener *listener; + int socket; + char *buffer; + int buflen; + int32_t buffer_offset; + int32_t data_len; + + EtherDump *dump; + + void attach(int fd); + void detach(); + + protected: + std::string device; + std::queue<PacketPtr> packetBuffer; + + void process(int revent); + void enqueue(EtherPacket *packet); + void retransmit(); + + /* + */ + class TxEvent : public Event + { + protected: + EtherTap *tap; + + public: + TxEvent(EtherTap *_tap) + : Event(&mainEventQueue), tap(_tap) {} + void process() { tap->retransmit(); } + virtual const char *description() { return "retransmit event"; } + }; + + friend class TxEvent; + TxEvent txEvent; + + public: + EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); + virtual ~EtherTap(); + + virtual bool recvPacket(PacketPtr packet); + virtual void sendDone(); +}; + +#endif // __ETHERTAP_HH__ diff --git a/dev/pcireg.h b/dev/pcireg.h new file mode 100644 index 000000000..2921c30be --- /dev/null +++ b/dev/pcireg.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Device register definitions for a device's PCI config space + */ + +#ifndef __PCIREG_H__ +#define __PCIREG_H__ + +#include <sys/types.h> + +union PCIConfig { + uint8_t data[64]; + + struct hdr { + uint16_t vendor; + uint16_t device; + uint16_t command; + uint16_t status; + uint8_t revision; + uint8_t progIF; + uint8_t subClassCode; + uint8_t classCode; + uint8_t cacheLineSize; + uint8_t latencyTimer; + uint8_t headerType; + uint8_t bist; + + union { + struct { + uint32_t baseAddr0; + uint32_t baseAddr1; + uint32_t baseAddr2; + uint32_t baseAddr3; + uint32_t baseAddr4; + uint32_t baseAddr5; + uint32_t cardbusCIS; + uint16_t subsystemVendorID; + uint16_t subsystemID; + uint32_t expansionROM; + uint32_t reserved0; + uint32_t reserved1; + uint8_t interruptLine; + uint8_t interruptPin; + uint8_t minimumGrant; + uint8_t maximumLatency; + } pci0; + + struct { + uint32_t baseAddr0; + uint32_t baseAddr1; + uint8_t priBusNum; + uint8_t secBusNum; + uint8_t subBusNum; + uint8_t secLatency; + uint8_t ioBase; + uint8_t minimumGrantioLimit; + uint16_t secStatus; + uint16_t memBase; + uint16_t memLimit; + uint16_t prefetchMemBase; + uint16_t prefetchMemLimit; + uint32_t prfBaseUpper32; + uint32_t prfLimitUpper32; + uint16_t ioBaseUpper16; + uint16_t ioLimitUpper16; + uint32_t reserved0; + uint32_t expansionROM; + uint8_t interruptLine; + uint8_t interruptPin; + uint16_t bridgeControl; + } pci1; + }; + } hdr; +}; + +// Common PCI offsets +#define PCI_VENDOR_ID 0x00 // Vendor ID ro +#define PCI_DEVICE_ID 0x02 // Device ID ro +#define PCI_COMMAND 0x04 // Command rw +#define PCI_STATUS 0x06 // Status rw +#define PCI_REVISION_ID 0x08 // Revision ID ro +#define PCI_CLASS_CODE 0x09 // Class Code ro +#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro +#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro +#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+ +#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+ +#define PCI_HEADER_TYPE 0x0E // Header Type ro +#define PCI_BIST 0x0F // Built in self test rw + +// Type 0 PCI offsets +#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw +#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw +#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw +#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw +#define PCI0_CIS 0x28 // CardBus CIS Pointer ro +#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro +#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro +#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw +#define PCI0_RESERVED0 0x34 +#define PCI0_RESERVED1 0x38 +#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw +#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro +#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro +#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro + +// Type 1 PCI offsets +#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw +#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw +#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw +#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+ +#define PCI1_IO_BASE 0x1C // I/O Base rw +#define PCI1_IO_LIMIT 0x1D // I/O Limit rw +#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw +#define PCI1_MEM_BASE 0x20 // Memory Base rw +#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw +#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw +#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw +#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw +#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw +#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw +#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw +#define PCI1_RESERVED 0x34 // Reserved ro +#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw +#define PCI1_INTR_LINE 0x3C // Interrupt Line rw +#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro +#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw + +// Device specific offsets +#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes + +// Some Vendor IDs +#define PCI_VENDOR_DEC 0x1011 +#define PCI_VENDOR_NCR 0x101A +#define PCI_VENDOR_QLOGIC 0x1077 +#define PCI_VENDOR_SIMOS 0x1291 + +// Some Product IDs +#define PCI_PRODUCT_DEC_PZA 0x0008 +#define PCI_PRODUCT_NCR_810 0x0001 +#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 +#define PCI_PRODUCT_SIMOS_SIMOS 0x1291 +#define PCI_PRODUCT_SIMOS_ETHER 0x1292 + +#endif // __PCIREG_H__ diff --git a/dev/simple_disk.cc b/dev/simple_disk.cc new file mode 100644 index 000000000..25645db5f --- /dev/null +++ b/dev/simple_disk.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Simple disk interface for the system console + */ + +#include <string> + +#include <sys/types.h> +#include <sys/uio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include "disk_image.hh" +#include "misc.hh" +#include "physical_memory.hh" +#include "simple_disk.hh" +#include "trace.hh" + +using namespace std; + +SimpleDisk::SimpleDisk(const string &name, PhysicalMemory *pmem, + DiskImage *img) + : SimObject(name), physmem(pmem), image(img) +{} + +SimpleDisk::~SimpleDisk() +{} + + +void +SimpleDisk::read(Addr addr, baddr_t block, int count) const +{ + uint8_t *data = physmem->dma_addr(addr, count); + if (!data) + panic("dma out of range! read addr=%#x count=%d\n", addr, count); + + if (count & (SectorSize - 1)) + panic("Not reading a multiple of a sector (count = %d)", count); + + for (int i = 0, j = 0; i < count; i += SectorSize, j++) + image->read(data + i, block + j); + + DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count); + DDUMP(SimpleDiskData, data, count); +} + +void +SimpleDisk::write(Addr addr, baddr_t block, int count) +{ + panic("unimplemented!\n"); + +#if 0 + uint8_t *data = physmem->dma_addr(addr, count); + if (!data) + panic("dma out of range! write addr=%#x count=%d\n", addr, count); + + image->write(data, block, count); +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + + SimObjectParam<PhysicalMemory *> physmem; + SimObjectParam<DiskImage *> disk; + +END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + + INIT_PARAM(physmem, "Physical Memory"), + INIT_PARAM(disk, "Disk Image") + +END_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + +CREATE_SIM_OBJECT(SimpleDisk) +{ + return new SimpleDisk(getInstanceName(), physmem, disk); +} + +REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk) diff --git a/dev/simple_disk.hh b/dev/simple_disk.hh new file mode 100644 index 000000000..bf684950d --- /dev/null +++ b/dev/simple_disk.hh @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 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. + */ + +/* @file + * Simple disk interface for the system console + */ + +#ifndef __SIMPLE_DISK_HH__ +#define __SIMPLE_DISK_HH__ + +#include "physical_memory.hh" +#include "sim_object.hh" + +class DiskImage; + +/* + * Trivial interface to a disk image used by the System Console + */ +class SimpleDisk : public SimObject +{ +public: + typedef uint64_t baddr_t; + +protected: + PhysicalMemory *physmem; + DiskImage *image; + +public: + SimpleDisk(const std::string &name, PhysicalMemory *pmem, DiskImage *img); + ~SimpleDisk(); + + void read(Addr addr, baddr_t block, int count) const; + void write(Addr addr, baddr_t block, int count); +}; +#endif // __SIMPLE_DISK_HH__ |