summaryrefslogtreecommitdiff
path: root/dev
diff options
context:
space:
mode:
Diffstat (limited to 'dev')
-rw-r--r--dev/alpha_access.h79
-rw-r--r--dev/alpha_console.cc273
-rw-r--r--dev/alpha_console.hh108
-rw-r--r--dev/console.cc478
-rw-r--r--dev/console.hh147
-rw-r--r--dev/disk_image.cc427
-rw-r--r--dev/disk_image.hh130
-rw-r--r--dev/etherbus.cc128
-rw-r--r--dev/etherbus.hh79
-rw-r--r--dev/etherdump.cc138
-rw-r--r--dev/etherdump.hh60
-rw-r--r--dev/etherint.cc44
-rw-r--r--dev/etherint.hh63
-rw-r--r--dev/etherlink.cc148
-rw-r--r--dev/etherlink.hh123
-rw-r--r--dev/etherpkt.hh65
-rw-r--r--dev/ethertap.cc295
-rw-r--r--dev/ethertap.hh101
-rw-r--r--dev/pcireg.h175
-rw-r--r--dev/simple_disk.cc108
-rw-r--r--dev/simple_disk.hh60
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__