+++ /dev/null
-# Copyright (c) 2005-2007 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Nathan Binkert
-
-from m5.SimObject import SimObject
-from m5.params import *
-class DiskImage(SimObject):
- type = 'DiskImage'
- abstract = True
- cxx_header = "dev/disk_image.hh"
- image_file = Param.String("disk image file")
- read_only = Param.Bool(False, "read only image")
-
-class RawDiskImage(DiskImage):
- type = 'RawDiskImage'
- cxx_header = "dev/disk_image.hh"
-
-class CowDiskImage(DiskImage):
- type = 'CowDiskImage'
- cxx_header = "dev/disk_image.hh"
- child = Param.DiskImage(RawDiskImage(read_only=True),
- "child image")
- table_size = Param.Int(65536, "initial table size")
- image_file = ""
+++ /dev/null
-# Copyright (c) 2005-2007 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Nathan Binkert
-
-from m5.SimObject import SimObject
-from m5.params import *
-from PciDevice import PciDevice
-
-class IdeID(Enum): vals = ['master', 'slave']
-
-class IdeDisk(SimObject):
- type = 'IdeDisk'
- cxx_header = "dev/ide_disk.hh"
- delay = Param.Latency('1us', "Fixed disk delay in microseconds")
- driveID = Param.IdeID('master', "Drive ID")
- image = Param.DiskImage("Disk image")
-
-class IdeController(PciDevice):
- type = 'IdeController'
- cxx_header = "dev/ide_ctrl.hh"
- disks = VectorParam.IdeDisk("IDE disks attached to this controller")
-
- VendorID = 0x8086
- DeviceID = 0x7111
- Command = 0x0
- Status = 0x280
- Revision = 0x0
- ClassCode = 0x01
- SubClassCode = 0x01
- ProgIF = 0x85
- BAR0 = 0x00000001
- BAR1 = 0x00000001
- BAR2 = 0x00000001
- BAR3 = 0x00000001
- BAR4 = 0x00000001
- BAR5 = 0x00000001
- InterruptLine = 0x1f
- InterruptPin = 0x01
- BAR0Size = '8B'
- BAR1Size = '4B'
- BAR2Size = '8B'
- BAR3Size = '4B'
- BAR4Size = '16B'
-
- io_shift = Param.UInt32(0x0, "IO port shift");
- ctrl_offset = Param.UInt32(0x0, "IDE disk control offset")
Return()
SimObject('BadDevice.py')
-SimObject('DiskImage.py')
-SimObject('Ide.py')
SimObject('Platform.py')
-SimObject('SimpleDisk.py')
SimObject('Terminal.py')
SimObject('Uart.py')
Source('baddev.cc')
-Source('disk_image.cc')
Source('dma_device.cc')
-Source('ide_ctrl.cc')
-Source('ide_disk.cc')
Source('intel_8254_timer.cc')
Source('mc146818.cc')
Source('pixelpump.cc')
Source('platform.cc')
Source('ps2.cc')
-Source('simple_disk.cc')
Source('terminal.cc')
Source('uart.cc')
Source('uart8250.cc')
-DebugFlag('DiskImageRead')
-DebugFlag('DiskImageWrite')
DebugFlag('DMA')
-DebugFlag('IdeCtrl')
-DebugFlag('IdeDisk')
DebugFlag('Intel8254Timer')
DebugFlag('MC146818')
-DebugFlag('SimpleDisk')
-DebugFlag('SimpleDiskData')
DebugFlag('Terminal')
DebugFlag('TerminalVerbose')
DebugFlag('Uart')
-
-CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
-CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])
+++ /dev/null
-# Copyright (c) 2005-2007 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Nathan Binkert
-
-from m5.SimObject import SimObject
-from m5.params import *
-from m5.proxy import *
-class SimpleDisk(SimObject):
- type = 'SimpleDisk'
- cxx_header = "dev/simple_disk.hh"
- disk = Param.DiskImage("Disk Image")
- system = Param.System(Parent.any, "System Pointer")
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/platform.hh"
-#include "dev/simple_disk.hh"
+#include "dev/storage/simple_disk.hh"
#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "debug/UFSHostDevice.hh"
#include "dev/arm/abstract_nvm.hh"
#include "dev/arm/base_gic.hh"
-#include "dev/disk_image.hh"
+#include "dev/storage/disk_image.hh"
#include "dev/dma_device.hh"
#include "dev/io_device.hh"
#include "mem/packet.hh"
+++ /dev/null
-/*
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/** @file
- * Disk Image Definitions
- */
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <cerrno>
-#include <cstring>
-#include <fstream>
-#include <string>
-
-#include "base/callback.hh"
-#include "base/misc.hh"
-#include "base/trace.hh"
-#include "debug/DiskImageRead.hh"
-#include "debug/DiskImageWrite.hh"
-#include "dev/disk_image.hh"
-#include "sim/byteswap.hh"
-#include "sim/sim_exit.hh"
-
-using namespace std;
-
-////////////////////////////////////////////////////////////////////////
-//
-// Raw Disk image
-//
-RawDiskImage::RawDiskImage(const Params* p)
- : DiskImage(p), disk_size(0)
-{ open(p->image_file, p->read_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();
-}
-
-std::streampos
-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;
-}
-
-std::streampos
-RawDiskImage::read(uint8_t *data, std::streampos offset) const
-{
- if (!initialized)
- panic("RawDiskImage not initialized");
-
- if (!stream.is_open())
- panic("file not open!\n");
-
- stream.seekg(offset * SectorSize, ios::beg);
- if (!stream.good())
- panic("Could not seek to location in file");
-
- streampos 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;
-}
-
-std::streampos
-RawDiskImage::write(const uint8_t *data, std::streampos 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");
-
- stream.seekp(offset * SectorSize, ios::beg);
- if (!stream.good())
- panic("Could not seek to location in file");
-
- DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
- DDUMP(DiskImageWrite, data, SectorSize);
-
- streampos pos = stream.tellp();
- stream.write((const char *)data, SectorSize);
- return stream.tellp() - pos;
-}
-
-RawDiskImage *
-RawDiskImageParams::create()
-{
- return new RawDiskImage(this);
-}
-
-////////////////////////////////////////////////////////////////////////
-//
-// Copy on Write Disk image
-//
-const uint32_t CowDiskImage::VersionMajor = 1;
-const uint32_t CowDiskImage::VersionMinor = 0;
-
-class CowDiskCallback : public Callback
-{
- private:
- CowDiskImage *image;
-
- public:
- CowDiskCallback(CowDiskImage *i) : image(i) {}
- void process() { image->save(); delete this; }
-};
-
-CowDiskImage::CowDiskImage(const Params *p)
- : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
-{
- if (filename.empty()) {
- initSectorTable(p->table_size);
- } else {
- if (!open(filename)) {
- if (p->read_only)
- fatal("could not open read-only file");
- initSectorTable(p->table_size);
- }
-
- if (!p->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));
-}
-
-template<class T>
-void
-SafeReadSwap(ifstream &stream, T &data)
-{
- SafeRead(stream, &data, sizeof(data));
- data = letoh(data); //is this the proper byte order conversion?
-}
-
-bool
-CowDiskImage::open(const string &file)
-{
- ifstream stream(file.c_str());
- if (!stream.is_open())
- return false;
-
- if (stream.fail() || stream.bad())
- panic("Error opening %s", file);
-
- uint64_t magic;
- SafeRead(stream, magic);
-
- if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
- panic("Could not open %s: Invalid magic", file);
-
- uint32_t major, minor;
- SafeReadSwap(stream, major);
- SafeReadSwap(stream, minor);
-
- if (major != VersionMajor && minor != VersionMinor)
- panic("Could not open %s: invalid version %d.%d != %d.%d",
- file, major, minor, VersionMajor, VersionMinor);
-
- uint64_t sector_count;
- SafeReadSwap(stream, sector_count);
- table = new SectorTable(sector_count);
-
-
- for (uint64_t i = 0; i < sector_count; i++) {
- uint64_t offset;
- SafeReadSwap(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::initSectorTable(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));
-}
-
-template<class T>
-void
-SafeWriteSwap(ofstream &stream, const T &data)
-{
- T swappeddata = letoh(data); //is this the proper byte order conversion?
- SafeWrite(stream, &swappeddata, sizeof(data));
-}
-void
-CowDiskImage::save() const
-{
- save(filename);
-}
-
-void
-CowDiskImage::save(const string &file) const
-{
- if (!initialized)
- panic("RawDiskImage not initialized");
-
- ofstream stream(file.c_str());
- if (!stream.is_open() || stream.fail() || stream.bad())
- panic("Error opening %s", file);
-
- uint64_t magic;
- memcpy(&magic, "COWDISK!", sizeof(magic));
- SafeWrite(stream, magic);
-
- SafeWriteSwap(stream, (uint32_t)VersionMajor);
- SafeWriteSwap(stream, (uint32_t)VersionMinor);
- SafeWriteSwap(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");
-
- SafeWriteSwap(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;
- }
-}
-
-std::streampos
-CowDiskImage::size() const
-{ return child->size(); }
-
-std::streampos
-CowDiskImage::read(uint8_t *data, std::streampos 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;
- }
-}
-
-std::streampos
-CowDiskImage::write(const uint8_t *data, std::streampos 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;
-}
-
-void
-CowDiskImage::serialize(CheckpointOut &cp) const
-{
- string cowFilename = name() + ".cow";
- SERIALIZE_SCALAR(cowFilename);
- save(CheckpointIn::dir() + "/" + cowFilename);
-}
-
-void
-CowDiskImage::unserialize(CheckpointIn &cp)
-{
- string cowFilename;
- UNSERIALIZE_SCALAR(cowFilename);
- cowFilename = cp.cptDir + "/" + cowFilename;
- open(cowFilename);
-}
-
-CowDiskImage *
-CowDiskImageParams::create()
-{
- return new CowDiskImage(this);
-}
+++ /dev/null
-/*
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/** @file
- * Disk Image Interfaces
- */
-
-#ifndef __DISK_IMAGE_HH__
-#define __DISK_IMAGE_HH__
-
-#include <fstream>
-#include <unordered_map>
-
-#include "params/CowDiskImage.hh"
-#include "params/DiskImage.hh"
-#include "params/RawDiskImage.hh"
-#include "sim/sim_object.hh"
-
-#define SectorSize (512)
-
-/**
- * Basic interface for accessing a disk image.
- */
-class DiskImage : public SimObject
-{
- protected:
- bool initialized;
-
- public:
- typedef DiskImageParams Params;
- DiskImage(const Params *p) : SimObject(p), initialized(false) {}
- virtual ~DiskImage() {}
-
- virtual std::streampos size() const = 0;
-
- virtual std::streampos read(uint8_t *data,
- std::streampos offset) const = 0;
- virtual std::streampos write(const uint8_t *data,
- std::streampos offset) = 0;
-};
-
-/**
- * Specialization for accessing a raw disk image
- */
-class RawDiskImage : public DiskImage
-{
- protected:
- mutable std::fstream stream;
- std::string file;
- bool readonly;
- mutable std::streampos disk_size;
-
- public:
- typedef RawDiskImageParams Params;
- RawDiskImage(const Params *p);
- ~RawDiskImage();
-
- void close();
- void open(const std::string &filename, bool rd_only = false);
-
- virtual std::streampos size() const;
-
- virtual std::streampos read(uint8_t *data, std::streampos offset) const;
- virtual std::streampos write(const uint8_t *data, std::streampos 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 uint32_t VersionMajor;
- static const uint32_t VersionMinor;
-
- protected:
- struct Sector {
- uint8_t data[SectorSize];
- };
- typedef std::unordered_map<uint64_t, Sector *> SectorTable;
-
- protected:
- std::string filename;
- DiskImage *child;
- SectorTable *table;
-
- public:
- typedef CowDiskImageParams Params;
- CowDiskImage(const Params *p);
- ~CowDiskImage();
-
- void initSectorTable(int hash_size);
- bool open(const std::string &file);
- void save() const;
- void save(const std::string &file) const;
- void writeback();
-
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
-
- std::streampos size() const override;
-
- std::streampos read(uint8_t *data, std::streampos offset) const override;
- std::streampos write(const uint8_t *data, std::streampos offset) override;
-};
-
-void SafeRead(std::ifstream &stream, void *data, int count);
-
-template<class T>
-void SafeRead(std::ifstream &stream, T &data);
-
-template<class T>
-void SafeReadSwap(std::ifstream &stream, T &data);
-
-void SafeWrite(std::ofstream &stream, const void *data, int count);
-
-template<class T>
-void SafeWrite(std::ofstream &stream, const T &data);
-
-template<class T>
-void SafeWriteSwap(std::ofstream &stream, const T &data);
-
-#endif // __DISK_IMAGE_HH__
+++ /dev/null
-/* $OpenBSD: atareg.h,v 1.12 2004/09/24 07:15:22 grange Exp $ */
-/* $NetBSD: atareg.h,v 1.5 1999/01/18 20:06:24 bouyer Exp $ */
-
-/*
- * Copyright (c) 1998, 2001 Manuel Bouyer.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Manuel Bouyer.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _DEV_ATA_ATAREG_H_
-#define _DEV_ATA_ATAREG_H_
-
-#if defined(__linux__)
-#include <endian.h>
-#elif defined(__sun)
-#include <sys/isa_defs.h>
-#else
-#include <machine/endian.h>
-#endif
-
-#ifdef LITTLE_ENDIAN
-#define ATA_BYTE_ORDER LITTLE_ENDIAN
-#elif defined(BIG_ENDIAN)
-#define ATA_BYTE_ORDER BIG_ENDIAN
-#elif defined(_LITTLE_ENDIAN)
-#define ATA_BYTE_ORDER 1
-#define LITTLE_ENDIAN 1
-#elif defined(_BIG_ENDIAN)
-#define ATA_BYTE_ORDER 0
-#define LITTLE_ENDIAN 1
-#else
-#error "No endianess defined"
-#endif
-
-/*
- * Drive parameter structure for ATA/ATAPI.
- * Bit fields: WDC_* : common to ATA/ATAPI
- * ATA_* : ATA only
- * ATAPI_* : ATAPI only.
- */
-struct ataparams {
- /* drive info */
- uint16_t atap_config; /* 0: general configuration */
-#define WDC_CFG_ATAPI_MASK 0xc000
-#define WDC_CFG_ATAPI 0x8000
-#define ATA_CFG_REMOVABLE 0x0080
-#define ATA_CFG_FIXED 0x0040
-#define ATAPI_CFG_TYPE_MASK 0x1f00
-#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8)
-#define ATAPI_CFG_TYPE_DIRECT 0x00
-#define ATAPI_CFG_TYPE_SEQUENTIAL 0x01
-#define ATAPI_CFG_TYPE_CDROM 0x05
-#define ATAPI_CFG_TYPE_OPTICAL 0x07
-#define ATAPI_CFG_TYPE_NODEVICE 0x1F
-#define ATAPI_CFG_REMOV 0x0080
-#define ATAPI_CFG_DRQ_MASK 0x0060
-#define ATAPI_CFG_STD_DRQ 0x0000
-#define ATAPI_CFG_IRQ_DRQ 0x0020
-#define ATAPI_CFG_ACCEL_DRQ 0x0040
-#define ATAPI_CFG_CMD_MASK 0x0003
-#define ATAPI_CFG_CMD_12 0x0000
-#define ATAPI_CFG_CMD_16 0x0001
-/* words 1-9 are ATA only */
- uint16_t atap_cylinders; /* 1: # of non-removable cylinders */
- uint16_t __reserved1;
- uint16_t atap_heads; /* 3: # of heads */
- uint16_t __retired1[2]; /* 4-5: # of unform. bytes/track */
- uint16_t atap_sectors; /* 6: # of sectors */
- uint16_t __retired2[3];
-
- uint8_t atap_serial[20]; /* 10-19: serial number */
- uint16_t __retired3[2];
- uint16_t __obsolete1;
- uint8_t atap_revision[8]; /* 23-26: firmware revision */
- uint8_t atap_model[40]; /* 27-46: model number */
- uint16_t atap_multi; /* 47: maximum sectors per irq (ATA) */
- uint16_t __reserved2;
- uint8_t atap_vendor; /* 49: vendor */
- uint8_t atap_capabilities1; /* 49: capability flags */
-#define WDC_CAP_IORDY 0x0800
-#define WDC_CAP_IORDY_DSBL 0x0400
-#define WDC_CAP_LBA 0x0200
-#define WDC_CAP_DMA 0x0100
-#define ATA_CAP_STBY 0x2000
-#define ATAPI_CAP_INTERL_DMA 0x8000
-#define ATAPI_CAP_CMD_QUEUE 0x4000
-#define ATAPI_CAP_OVERLP 0x2000
-#define ATAPI_CAP_ATA_RST 0x1000
- uint16_t atap_capabilities2; /* 50: capability flags (ATA) */
-#if ATA_BYTE_ORDER == LITTLE_ENDIAN
- uint8_t __junk2;
- uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
- uint8_t __junk3;
- uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
-#else
- uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
- uint8_t __junk2;
- uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
- uint8_t __junk3;
-#endif
- uint16_t atap_extensions; /* 53: extensions supported */
-#define WDC_EXT_UDMA_MODES 0x0004
-#define WDC_EXT_MODES 0x0002
-#define WDC_EXT_GEOM 0x0001
-/* words 54-62 are ATA only */
- uint16_t atap_curcylinders; /* 54: current logical cylinders */
- uint16_t atap_curheads; /* 55: current logical heads */
- uint16_t atap_cursectors; /* 56: current logical sectors/tracks */
- uint16_t atap_curcapacity[2]; /* 57-58: current capacity */
- uint8_t atap_curmulti; /* 59: current multi-sector setting */
- uint8_t atap_curmulti_valid; /* 59: current multi-sector setting */
-#define WDC_MULTI_VALID 0x0100
-#define WDC_MULTI_MASK 0x00ff
- uint32_t atap_capacity; /* 60-61: total capacity (LBA only) */
- uint16_t __retired4;
-#if ATA_BYTE_ORDER == LITTLE_ENDIAN
- uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
- uint8_t atap_dmamode_act; /* multiword DMA mode active */
- uint8_t atap_piomode_supp; /* 64: PIO mode supported */
- uint8_t __junk4;
-#else
- uint8_t atap_dmamode_act; /* multiword DMA mode active */
- uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
- uint8_t __junk4;
- uint8_t atap_piomode_supp; /* 64: PIO mode supported */
-#endif
- uint16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */
- uint16_t atap_dmatiming_recom; /* 66: recommended DMA cycle time */
- uint16_t atap_piotiming; /* 67: mini PIO cycle time without FC */
- uint16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */
- uint16_t __reserved3[2];
-/* words 71-72 are ATAPI only */
- uint16_t atap_pkt_br; /* 71: time (ns) to bus release */
- uint16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */
- uint16_t __reserved4[2];
- uint16_t atap_queuedepth; /* 75: */
-#define WDC_QUEUE_DEPTH_MASK 0x1f
- uint16_t atap_sata_caps; /* 76: SATA capabilities */
-#define SATA_SIGNAL_GEN1 0x0002 /* SATA Gen-1 signaling speed */
-#define SATA_SIGNAL_GEN2 0x0004 /* SATA Gen-2 signaling speed */
-#define SATA_NATIVE_CMDQ 0x0100 /* native command queuing */
-#define SATA_HOST_PWR_MGMT 0x0200 /* power management (host) */
- uint16_t atap_sata_reserved; /* 77: reserved */
- uint16_t atap_sata_features_supp;/* 78: SATA features supported */
-#define SATA_NONZERO_OFFSETS 0x0002 /* non-zero buffer offsets */
-#define SATA_DMA_SETUP_AUTO 0x0004 /* DMA setup auto-activate */
-#define SATA_DRIVE_PWR_MGMT 0x0008 /* power management (device) */
- uint16_t atap_sata_features_en; /* 79: SATA features enabled */
- uint16_t atap_ata_major; /* 80: Major version number */
-#define WDC_VER_ATA1 0x0002
-#define WDC_VER_ATA2 0x0004
-#define WDC_VER_ATA3 0x0008
-#define WDC_VER_ATA4 0x0010
-#define WDC_VER_ATA5 0x0020
-#define WDC_VER_ATA6 0x0040
-#define WDC_VER_ATA7 0x0080
-#define WDC_VER_ATA8 0x0100
-#define WDC_VER_ATA9 0x0200
-#define WDC_VER_ATA10 0x0400
-#define WDC_VER_ATA11 0x0800
-#define WDC_VER_ATA12 0x1000
-#define WDC_VER_ATA13 0x2000
-#define WDC_VER_ATA14 0x4000
- uint16_t atap_ata_minor; /* 81: Minor version number */
- uint16_t atap_cmd_set1; /* 82: command set supported */
-#define WDC_CMD1_NOP 0x4000
-#define WDC_CMD1_RB 0x2000
-#define WDC_CMD1_WB 0x1000
-#define WDC_CMD1_HPA 0x0400
-#define WDC_CMD1_DVRST 0x0200
-#define WDC_CMD1_SRV 0x0100
-#define WDC_CMD1_RLSE 0x0080
-#define WDC_CMD1_AHEAD 0x0040
-#define WDC_CMD1_CACHE 0x0020
-#define WDC_CMD1_PKT 0x0010
-#define WDC_CMD1_PM 0x0008
-#define WDC_CMD1_REMOV 0x0004
-#define WDC_CMD1_SEC 0x0002
-#define WDC_CMD1_SMART 0x0001
- uint16_t atap_cmd_set2; /* 83: command set supported */
-#define ATAPI_CMD2_FCE 0x2000 /* Flush Cache Ext supported */
-#define ATAPI_CMD2_FC 0x1000 /* Flush Cache supported */
-#define ATAPI_CMD2_DCO 0x0800 /* Device Configuration Overlay supported */
-#define ATAPI_CMD2_48AD 0x0400 /* 48bit address supported */
-#define ATAPI_CMD2_AAM 0x0200 /* Automatic Acoustic Management supported */
-#define ATAPI_CMD2_SM 0x0100 /* Set Max security extension supported */
-#define ATAPI_CMD2_SF 0x0040 /* Set Features subcommand required */
-#define ATAPI_CMD2_PUIS 0x0020 /* Power up in standby supported */
-#define WDC_CMD2_RMSN 0x0010
-#define ATA_CMD2_APM 0x0008
-#define ATA_CMD2_CFA 0x0004
-#define ATA_CMD2_RWQ 0x0002
-#define WDC_CMD2_DM 0x0001 /* Download Microcode supported */
- uint16_t atap_cmd_ext; /* 84: command/features supp. ext. */
-#define ATAPI_CMDE_MSER 0x0004 /* Media serial number supported */
-#define ATAPI_CMDE_TEST 0x0002 /* SMART self-test supported */
-#define ATAPI_CMDE_SLOG 0x0001 /* SMART error logging supported */
- uint16_t atap_cmd1_en; /* 85: cmd/features enabled */
-/* bits are the same as atap_cmd_set1 */
- uint16_t atap_cmd2_en; /* 86: cmd/features enabled */
-/* bits are the same as atap_cmd_set2 */
- uint16_t atap_cmd_def; /* 87: cmd/features default */
-/* bits are NOT the same as atap_cmd_ext */
-#if ATA_BYTE_ORDER == LITTLE_ENDIAN
- uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
- uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
-#else
- uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
- uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
-#endif
-/* 89-92 are ATA-only */
- uint16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */
- uint16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */
- uint16_t atap_apm_val; /* 91: current APM value */
- uint16_t atap_mpasswd_rev; /* 92: Master Password revision */
- uint16_t atap_hwreset_res; /* 93: Hardware reset value */
-#define ATA_HWRES_CBLID 0x2000 /* CBLID above Vih */
-#define ATA_HWRES_D1_PDIAG 0x0800 /* Device 1 PDIAG detect OK */
-#define ATA_HWRES_D1_CSEL 0x0400 /* Device 1 used CSEL for address */
-#define ATA_HWRES_D1_JUMP 0x0200 /* Device 1 jumpered to address */
-#define ATA_HWRES_D0_SEL 0x0040 /* Device 0 responds when Dev 1 selected */
-#define ATA_HWRES_D0_DASP 0x0020 /* Device 0 DASP detect OK */
-#define ATA_HWRES_D0_PDIAG 0x0010 /* Device 0 PDIAG detect OK */
-#define ATA_HWRES_D0_DIAG 0x0008 /* Device 0 diag OK */
-#define ATA_HWRES_D0_CSEL 0x0004 /* Device 0 used CSEL for address */
-#define ATA_HWRES_D0_JUMP 0x0002 /* Device 0 jumpered to address */
-#if ATA_BYTE_ORDER == LITTLE_ENDIAN
- uint8_t atap_acoustic_val; /* 94: Current acoustic level */
- uint8_t atap_acoustic_def; /* recommended level */
-#else
- uint8_t atap_acoustic_def; /* recommended level */
- uint8_t atap_acoustic_val; /* 94: Current acoustic level */
-#endif
- uint16_t __reserved6[5]; /* 95-99: reserved */
- uint16_t atap_max_lba[4]; /* 100-103: Max. user LBA add */
- uint16_t __reserved7[23]; /* 104-126: reserved */
- uint16_t atap_rmsn_supp; /* 127: remov. media status notif. */
-#define WDC_RMSN_SUPP_MASK 0x0003
-#define WDC_RMSN_SUPP 0x0001
- uint16_t atap_sec_st; /* 128: security status */
-#define WDC_SEC_LEV_MAX 0x0100
-#define WDC_SEC_ESE_SUPP 0x0020
-#define WDC_SEC_EXP 0x0010
-#define WDC_SEC_FROZEN 0x0008
-#define WDC_SEC_LOCKED 0x0004
-#define WDC_SEC_EN 0x0002
-#define WDC_SEC_SUPP 0x0001
- uint16_t __reserved8[31]; /* 129-159: vendor specific */
- uint16_t atap_cfa_power; /* 160: CFA powermode */
-#define ATAPI_CFA_MAX_MASK 0x0FFF
-#define ATAPI_CFA_MODE1_DIS 0x1000 /* CFA Mode 1 Disabled */
-#define ATAPI_CFA_MODE1_REQ 0x2000 /* CFA Mode 1 Required */
-#define ATAPI_CFA_WORD160 0x8000 /* Word 160 supported */
- uint16_t __reserved9[15]; /* 161-175: reserved for CFA */
- uint8_t atap_media_serial[60]; /* 176-205: media serial number */
- uint16_t __reserved10[49]; /* 206-254: reserved */
-#if ATA_BYTE_ORDER == LITTLE_ENDIAN
- uint8_t atap_signature; /* 255: Signature */
- uint8_t atap_checksum; /* Checksum */
-#else
- uint8_t atap_checksum; /* Checksum */
- uint8_t atap_signature; /* 255: Signature */
-#endif
-};
-
-#undef ATA_BYTE_ORDER
-#endif /* !_DEV_ATA_ATAREG_H_ */
+++ /dev/null
-/*
- * Copyright (c) 2013 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder. You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andrew Schultz
- * Ali Saidi
- * Miguel Serrano
- */
-
-#include <string>
-
-#include "cpu/intr_control.hh"
-#include "debug/IdeCtrl.hh"
-#include "dev/ide_ctrl.hh"
-#include "dev/ide_disk.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "params/IdeController.hh"
-#include "sim/byteswap.hh"
-
-// clang complains about std::set being overloaded with Packet::set if
-// we open up the entire namespace std
-using std::string;
-
-// Bus master IDE registers
-enum BMIRegOffset {
- BMICommand = 0x0,
- BMIStatus = 0x2,
- BMIDescTablePtr = 0x4
-};
-
-// PCI config space registers
-enum ConfRegOffset {
- PrimaryTiming = 0x40,
- SecondaryTiming = 0x42,
- DeviceTiming = 0x44,
- UDMAControl = 0x48,
- UDMATiming = 0x4A,
- IDEConfig = 0x54
-};
-
-static const uint16_t timeRegWithDecodeEn = 0x8000;
-
-IdeController::Channel::Channel(
- string newName, Addr _cmdSize, Addr _ctrlSize) :
- _name(newName),
- cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
- master(NULL), slave(NULL), selected(NULL)
-{
- memset(&bmiRegs, 0, sizeof(bmiRegs));
- bmiRegs.status.dmaCap0 = 1;
- bmiRegs.status.dmaCap1 = 1;
-}
-
-IdeController::Channel::~Channel()
-{
-}
-
-IdeController::IdeController(Params *p)
- : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
- secondary(name() + ".secondary", BARSize[2], BARSize[3]),
- bmiAddr(0), bmiSize(BARSize[4]),
- primaryTiming(htole(timeRegWithDecodeEn)),
- secondaryTiming(htole(timeRegWithDecodeEn)),
- deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
- ioEnabled(false), bmEnabled(false),
- ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
-{
- if (params()->disks.size() > 3)
- panic("IDE controllers support a maximum of 4 devices attached!\n");
-
- // Assign the disks to channels
- int numDisks = params()->disks.size();
- if (numDisks > 0)
- primary.master = params()->disks[0];
- if (numDisks > 1)
- primary.slave = params()->disks[1];
- if (numDisks > 2)
- secondary.master = params()->disks[2];
- if (numDisks > 3)
- secondary.slave = params()->disks[3];
-
- for (int i = 0; i < params()->disks.size(); i++) {
- params()->disks[i]->setController(this);
- }
- primary.select(false);
- secondary.select(false);
-
- if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
- primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0];
- primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
- }
- if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
- secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2];
- secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
- }
-
- ioEnabled = (config.command & htole(PCI_CMD_IOSE));
- bmEnabled = (config.command & htole(PCI_CMD_BME));
-}
-
-bool
-IdeController::isDiskSelected(IdeDisk *diskPtr)
-{
- return (primary.selected == diskPtr || secondary.selected == diskPtr);
-}
-
-void
-IdeController::intrPost()
-{
- primary.bmiRegs.status.intStatus = 1;
- PciDevice::intrPost();
-}
-
-void
-IdeController::setDmaComplete(IdeDisk *disk)
-{
- Channel *channel;
- if (disk == primary.master || disk == primary.slave) {
- channel = &primary;
- } else if (disk == secondary.master || disk == secondary.slave) {
- channel = &secondary;
- } else {
- panic("Unable to find disk based on pointer %#x\n", disk);
- }
-
- channel->bmiRegs.command.startStop = 0;
- channel->bmiRegs.status.active = 0;
- channel->bmiRegs.status.intStatus = 1;
-}
-
-Tick
-IdeController::readConfig(PacketPtr pkt)
-{
- int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
- if (offset < PCI_DEVICE_SPECIFIC) {
- return PciDevice::readConfig(pkt);
- }
-
- switch (pkt->getSize()) {
- case sizeof(uint8_t):
- switch (offset) {
- case DeviceTiming:
- pkt->set<uint8_t>(deviceTiming);
- break;
- case UDMAControl:
- pkt->set<uint8_t>(udmaControl);
- break;
- case PrimaryTiming + 1:
- pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
- break;
- case SecondaryTiming + 1:
- pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
- break;
- case IDEConfig:
- pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
- break;
- case IDEConfig + 1:
- pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
- break;
- default:
- panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
- offset);
- }
- DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
- (uint32_t)pkt->get<uint8_t>());
- break;
- case sizeof(uint16_t):
- switch (offset) {
- case UDMAControl:
- pkt->set<uint16_t>(udmaControl);
- break;
- case PrimaryTiming:
- pkt->set<uint16_t>(primaryTiming);
- break;
- case SecondaryTiming:
- pkt->set<uint16_t>(secondaryTiming);
- break;
- case UDMATiming:
- pkt->set<uint16_t>(udmaTiming);
- break;
- case IDEConfig:
- pkt->set<uint16_t>(ideConfig);
- break;
- default:
- panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
- offset);
- }
- DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
- (uint32_t)pkt->get<uint16_t>());
- break;
- case sizeof(uint32_t):
- switch (offset) {
- case PrimaryTiming:
- pkt->set<uint32_t>(primaryTiming);
- break;
- case IDEConfig:
- pkt->set<uint32_t>(ideConfig);
- break;
- default:
- panic("No 32bit reads implemented for this device.");
- }
- DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
- (uint32_t)pkt->get<uint32_t>());
- break;
- default:
- panic("invalid access size(?) for PCI configspace!\n");
- }
- pkt->makeAtomicResponse();
- return configDelay;
-}
-
-
-Tick
-IdeController::writeConfig(PacketPtr pkt)
-{
- int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
- if (offset < PCI_DEVICE_SPECIFIC) {
- PciDevice::writeConfig(pkt);
- } else {
- switch (pkt->getSize()) {
- case sizeof(uint8_t):
- switch (offset) {
- case DeviceTiming:
- deviceTiming = pkt->get<uint8_t>();
- break;
- case UDMAControl:
- udmaControl = pkt->get<uint8_t>();
- break;
- case IDEConfig:
- replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
- break;
- case IDEConfig + 1:
- replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
- break;
- default:
- panic("Invalid PCI configuration write "
- "for size 1 offset: %#x!\n", offset);
- }
- DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
- offset, (uint32_t)pkt->get<uint8_t>());
- break;
- case sizeof(uint16_t):
- switch (offset) {
- case UDMAControl:
- udmaControl = pkt->get<uint16_t>();
- break;
- case PrimaryTiming:
- primaryTiming = pkt->get<uint16_t>();
- break;
- case SecondaryTiming:
- secondaryTiming = pkt->get<uint16_t>();
- break;
- case UDMATiming:
- udmaTiming = pkt->get<uint16_t>();
- break;
- case IDEConfig:
- ideConfig = pkt->get<uint16_t>();
- break;
- default:
- panic("Invalid PCI configuration write "
- "for size 2 offset: %#x!\n",
- offset);
- }
- DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
- offset, (uint32_t)pkt->get<uint16_t>());
- break;
- case sizeof(uint32_t):
- switch (offset) {
- case PrimaryTiming:
- primaryTiming = pkt->get<uint32_t>();
- break;
- case IDEConfig:
- ideConfig = pkt->get<uint32_t>();
- break;
- default:
- panic("Write of unimplemented PCI config. register: %x\n", offset);
- }
- break;
- default:
- panic("invalid access size(?) for PCI configspace!\n");
- }
- pkt->makeAtomicResponse();
- }
-
- /* Trap command register writes and enable IO/BM as appropriate as well as
- * BARs. */
- switch(offset) {
- case PCI0_BASE_ADDR0:
- if (BARAddrs[0] != 0)
- primary.cmdAddr = BARAddrs[0];
- break;
-
- case PCI0_BASE_ADDR1:
- if (BARAddrs[1] != 0)
- primary.ctrlAddr = BARAddrs[1];
- break;
-
- case PCI0_BASE_ADDR2:
- if (BARAddrs[2] != 0)
- secondary.cmdAddr = BARAddrs[2];
- break;
-
- case PCI0_BASE_ADDR3:
- if (BARAddrs[3] != 0)
- secondary.ctrlAddr = BARAddrs[3];
- break;
-
- case PCI0_BASE_ADDR4:
- if (BARAddrs[4] != 0)
- bmiAddr = BARAddrs[4];
- break;
-
- case PCI_COMMAND:
- DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
- ioEnabled = (config.command & htole(PCI_CMD_IOSE));
- bmEnabled = (config.command & htole(PCI_CMD_BME));
- break;
- }
- return configDelay;
-}
-
-void
-IdeController::Channel::accessCommand(Addr offset,
- int size, uint8_t *data, bool read)
-{
- const Addr SelectOffset = 6;
- const uint8_t SelectDevBit = 0x10;
-
- if (!read && offset == SelectOffset)
- select(*data & SelectDevBit);
-
- if (selected == NULL) {
- assert(size == sizeof(uint8_t));
- *data = 0;
- } else if (read) {
- selected->readCommand(offset, size, data);
- } else {
- selected->writeCommand(offset, size, data);
- }
-}
-
-void
-IdeController::Channel::accessControl(Addr offset,
- int size, uint8_t *data, bool read)
-{
- if (selected == NULL) {
- assert(size == sizeof(uint8_t));
- *data = 0;
- } else if (read) {
- selected->readControl(offset, size, data);
- } else {
- selected->writeControl(offset, size, data);
- }
-}
-
-void
-IdeController::Channel::accessBMI(Addr offset,
- int size, uint8_t *data, bool read)
-{
- assert(offset + size <= sizeof(BMIRegs));
- if (read) {
- memcpy(data, (uint8_t *)&bmiRegs + offset, size);
- } else {
- switch (offset) {
- case BMICommand:
- {
- if (size != sizeof(uint8_t))
- panic("Invalid BMIC write size: %x\n", size);
-
- BMICommandReg oldVal = bmiRegs.command;
- BMICommandReg newVal = *data;
-
- // if a DMA transfer is in progress, R/W control cannot change
- if (oldVal.startStop && oldVal.rw != newVal.rw)
- oldVal.rw = newVal.rw;
-
- if (oldVal.startStop != newVal.startStop) {
- if (selected == NULL)
- panic("DMA start for disk which does not exist\n");
-
- if (oldVal.startStop) {
- DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
- bmiRegs.status.active = 0;
-
- selected->abortDma();
- } else {
- DPRINTF(IdeCtrl, "Starting DMA transfer\n");
- bmiRegs.status.active = 1;
-
- selected->startDma(letoh(bmiRegs.bmidtp));
- }
- }
-
- bmiRegs.command = newVal;
- }
- break;
- case BMIStatus:
- {
- if (size != sizeof(uint8_t))
- panic("Invalid BMIS write size: %x\n", size);
-
- BMIStatusReg oldVal = bmiRegs.status;
- BMIStatusReg newVal = *data;
-
- // the BMIDEA bit is read only
- newVal.active = oldVal.active;
-
- // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
- if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
- newVal.intStatus = 0; // clear the interrupt?
- } else {
- // Assigning two bitunion fields to each other does not
- // work as intended, so we need to use this temporary variable
- // to get around the bug.
- uint8_t tmp = oldVal.intStatus;
- newVal.intStatus = tmp;
- }
- if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
- newVal.dmaError = 0;
- } else {
- uint8_t tmp = oldVal.dmaError;
- newVal.dmaError = tmp;
- }
-
- bmiRegs.status = newVal;
- }
- break;
- case BMIDescTablePtr:
- if (size != sizeof(uint32_t))
- panic("Invalid BMIDTP write size: %x\n", size);
- bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
- break;
- default:
- if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
- size != sizeof(uint32_t))
- panic("IDE controller write of invalid write size: %x\n", size);
- memcpy((uint8_t *)&bmiRegs + offset, data, size);
- }
- }
-}
-
-void
-IdeController::dispatchAccess(PacketPtr pkt, bool read)
-{
- if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
- panic("Bad IDE read size: %d\n", pkt->getSize());
-
- if (!ioEnabled) {
- pkt->makeAtomicResponse();
- DPRINTF(IdeCtrl, "io not enabled\n");
- return;
- }
-
- Addr addr = pkt->getAddr();
- int size = pkt->getSize();
- uint8_t *dataPtr = pkt->getPtr<uint8_t>();
-
- if (addr >= primary.cmdAddr &&
- addr < (primary.cmdAddr + primary.cmdSize)) {
- addr -= primary.cmdAddr;
- // linux may have shifted the address by ioShift,
- // here we shift it back, similarly for ctrlOffset.
- addr >>= ioShift;
- primary.accessCommand(addr, size, dataPtr, read);
- } else if (addr >= primary.ctrlAddr &&
- addr < (primary.ctrlAddr + primary.ctrlSize)) {
- addr -= primary.ctrlAddr;
- addr += ctrlOffset;
- primary.accessControl(addr, size, dataPtr, read);
- } else if (addr >= secondary.cmdAddr &&
- addr < (secondary.cmdAddr + secondary.cmdSize)) {
- addr -= secondary.cmdAddr;
- secondary.accessCommand(addr, size, dataPtr, read);
- } else if (addr >= secondary.ctrlAddr &&
- addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
- addr -= secondary.ctrlAddr;
- secondary.accessControl(addr, size, dataPtr, read);
- } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
- if (!read && !bmEnabled)
- return;
- addr -= bmiAddr;
- if (addr < sizeof(Channel::BMIRegs)) {
- primary.accessBMI(addr, size, dataPtr, read);
- } else {
- addr -= sizeof(Channel::BMIRegs);
- secondary.accessBMI(addr, size, dataPtr, read);
- }
- } else {
- panic("IDE controller access to invalid address: %#x\n", addr);
- }
-
-#ifndef NDEBUG
- uint32_t data;
- if (pkt->getSize() == 1)
- data = pkt->get<uint8_t>();
- else if (pkt->getSize() == 2)
- data = pkt->get<uint16_t>();
- else
- data = pkt->get<uint32_t>();
- DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
- read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
-#endif
-
- pkt->makeAtomicResponse();
-}
-
-Tick
-IdeController::read(PacketPtr pkt)
-{
- dispatchAccess(pkt, true);
- return pioDelay;
-}
-
-Tick
-IdeController::write(PacketPtr pkt)
-{
- dispatchAccess(pkt, false);
- return pioDelay;
-}
-
-void
-IdeController::serialize(CheckpointOut &cp) const
-{
- // Serialize the PciDevice base class
- PciDevice::serialize(cp);
-
- // Serialize channels
- primary.serialize("primary", cp);
- secondary.serialize("secondary", cp);
-
- // Serialize config registers
- SERIALIZE_SCALAR(primaryTiming);
- SERIALIZE_SCALAR(secondaryTiming);
- SERIALIZE_SCALAR(deviceTiming);
- SERIALIZE_SCALAR(udmaControl);
- SERIALIZE_SCALAR(udmaTiming);
- SERIALIZE_SCALAR(ideConfig);
-
- // Serialize internal state
- SERIALIZE_SCALAR(ioEnabled);
- SERIALIZE_SCALAR(bmEnabled);
- SERIALIZE_SCALAR(bmiAddr);
- SERIALIZE_SCALAR(bmiSize);
-}
-
-void
-IdeController::Channel::serialize(const std::string &base,
- CheckpointOut &cp) const
-{
- paramOut(cp, base + ".cmdAddr", cmdAddr);
- paramOut(cp, base + ".cmdSize", cmdSize);
- paramOut(cp, base + ".ctrlAddr", ctrlAddr);
- paramOut(cp, base + ".ctrlSize", ctrlSize);
- uint8_t command = bmiRegs.command;
- paramOut(cp, base + ".bmiRegs.command", command);
- paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
- uint8_t status = bmiRegs.status;
- paramOut(cp, base + ".bmiRegs.status", status);
- paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
- paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
- paramOut(cp, base + ".selectBit", selectBit);
-}
-
-void
-IdeController::unserialize(CheckpointIn &cp)
-{
- // Unserialize the PciDevice base class
- PciDevice::unserialize(cp);
-
- // Unserialize channels
- primary.unserialize("primary", cp);
- secondary.unserialize("secondary", cp);
-
- // Unserialize config registers
- UNSERIALIZE_SCALAR(primaryTiming);
- UNSERIALIZE_SCALAR(secondaryTiming);
- UNSERIALIZE_SCALAR(deviceTiming);
- UNSERIALIZE_SCALAR(udmaControl);
- UNSERIALIZE_SCALAR(udmaTiming);
- UNSERIALIZE_SCALAR(ideConfig);
-
- // Unserialize internal state
- UNSERIALIZE_SCALAR(ioEnabled);
- UNSERIALIZE_SCALAR(bmEnabled);
- UNSERIALIZE_SCALAR(bmiAddr);
- UNSERIALIZE_SCALAR(bmiSize);
-}
-
-void
-IdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp)
-{
- paramIn(cp, base + ".cmdAddr", cmdAddr);
- paramIn(cp, base + ".cmdSize", cmdSize);
- paramIn(cp, base + ".ctrlAddr", ctrlAddr);
- paramIn(cp, base + ".ctrlSize", ctrlSize);
- uint8_t command;
- paramIn(cp, base +".bmiRegs.command", command);
- bmiRegs.command = command;
- paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
- uint8_t status;
- paramIn(cp, base + ".bmiRegs.status", status);
- bmiRegs.status = status;
- paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
- paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
- paramIn(cp, base + ".selectBit", selectBit);
- select(selectBit);
-}
-
-IdeController *
-IdeControllerParams::create()
-{
- return new IdeController(this);
-}
+++ /dev/null
-/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andrew Schultz
- * Miguel Serrano
- */
-
-/** @file
- * Simple PCI IDE controller with bus mastering capability and UDMA
- * modeled after controller in the Intel PIIX4 chip
- */
-
-#ifndef __IDE_CTRL_HH__
-#define __IDE_CTRL_HH__
-
-#include "base/bitunion.hh"
-#include "dev/io_device.hh"
-#include "dev/pci/device.hh"
-#include "params/IdeController.hh"
-
-class IdeDisk;
-
-/**
- * Device model for an Intel PIIX4 IDE controller
- */
-
-class IdeController : public PciDevice
-{
- private:
- // Bus master IDE status register bit fields
- BitUnion8(BMIStatusReg)
- Bitfield<6> dmaCap0;
- Bitfield<5> dmaCap1;
- Bitfield<2> intStatus;
- Bitfield<1> dmaError;
- Bitfield<0> active;
- EndBitUnion(BMIStatusReg)
-
- BitUnion8(BMICommandReg)
- Bitfield<3> rw;
- Bitfield<0> startStop;
- EndBitUnion(BMICommandReg)
-
- struct Channel
- {
- std::string _name;
-
- const std::string
- name()
- {
- return _name;
- }
-
- /** Command and control block registers */
- Addr cmdAddr, cmdSize, ctrlAddr, ctrlSize;
-
- /** Registers used for bus master interface */
- struct BMIRegs
- {
- BMICommandReg command;
- uint8_t reserved0;
- BMIStatusReg status;
- uint8_t reserved1;
- uint32_t bmidtp;
- } bmiRegs;
-
- /** IDE disks connected to this controller */
- IdeDisk *master, *slave;
-
- /** Currently selected disk */
- IdeDisk *selected;
-
- bool selectBit;
-
- void
- select(bool selSlave)
- {
- selectBit = selSlave;
- selected = selectBit ? slave : master;
- }
-
- void accessCommand(Addr offset, int size, uint8_t *data, bool read);
- void accessControl(Addr offset, int size, uint8_t *data, bool read);
- void accessBMI(Addr offset, int size, uint8_t *data, bool read);
-
- Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize);
- ~Channel();
-
- void serialize(const std::string &base, std::ostream &os) const;
- void unserialize(const std::string &base, CheckpointIn &cp);
- };
-
- Channel primary;
- Channel secondary;
-
- /** Bus master interface (BMI) registers */
- Addr bmiAddr, bmiSize;
-
- /** Registers used in device specific PCI configuration */
- uint16_t primaryTiming, secondaryTiming;
- uint8_t deviceTiming;
- uint8_t udmaControl;
- uint16_t udmaTiming;
- uint16_t ideConfig;
-
- // Internal management variables
- bool ioEnabled;
- bool bmEnabled;
-
- uint32_t ioShift, ctrlOffset;
-
- void dispatchAccess(PacketPtr pkt, bool read);
-
- public:
- typedef IdeControllerParams Params;
- const Params *params() const { return (const Params *)_params; }
- IdeController(Params *p);
-
- /** See if a disk is selected based on its pointer */
- bool isDiskSelected(IdeDisk *diskPtr);
-
- void intrPost();
-
- Tick writeConfig(PacketPtr pkt) override;
- Tick readConfig(PacketPtr pkt) override;
-
- void setDmaComplete(IdeDisk *disk);
-
- Tick read(PacketPtr pkt) override;
- Tick write(PacketPtr pkt) override;
-
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
-};
-#endif // __IDE_CTRL_HH_
+++ /dev/null
-/*
- * Copyright (c) 2013 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder. You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andrew Schultz
- * Ali Saidi
- */
-
-/** @file
- * Device model implementation for an IDE disk
- */
-
-#include <cerrno>
-#include <cstring>
-#include <deque>
-#include <string>
-
-#include "arch/isa_traits.hh"
-#include "base/chunk_generator.hh"
-#include "base/cprintf.hh" // csprintf
-#include "base/trace.hh"
-#include "config/the_isa.hh"
-#include "debug/IdeDisk.hh"
-#include "dev/disk_image.hh"
-#include "dev/ide_ctrl.hh"
-#include "dev/ide_disk.hh"
-#include "sim/core.hh"
-#include "sim/sim_object.hh"
-
-using namespace std;
-using namespace TheISA;
-
-IdeDisk::IdeDisk(const Params *p)
- : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
- dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
- dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
- dmaReadEvent(this), dmaWriteEvent(this)
-{
- // Reset the device state
- reset(p->driveID);
-
- // fill out the drive ID structure
- memset(&driveID, 0, sizeof(struct ataparams));
-
- // Calculate LBA and C/H/S values
- uint16_t cylinders;
- uint8_t heads;
- uint8_t sectors;
-
- uint32_t lba_size = image->size();
- if (lba_size >= 16383*16*63) {
- cylinders = 16383;
- heads = 16;
- sectors = 63;
- } else {
- if (lba_size >= 63)
- sectors = 63;
- else if (lba_size == 0)
- panic("Bad IDE image size: 0\n");
- else
- sectors = lba_size;
-
- if ((lba_size / sectors) >= 16)
- heads = 16;
- else
- heads = (lba_size / sectors);
-
- cylinders = lba_size / (heads * sectors);
- }
-
- // Setup the model name
- strncpy((char *)driveID.atap_model, "5MI EDD si k",
- sizeof(driveID.atap_model));
- // Set the maximum multisector transfer size
- driveID.atap_multi = MAX_MULTSECT;
- // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
- driveID.atap_capabilities1 = 0x7;
- // UDMA support, EIDE support
- driveID.atap_extensions = 0x6;
- // Setup default C/H/S settings
- driveID.atap_cylinders = cylinders;
- driveID.atap_sectors = sectors;
- driveID.atap_heads = heads;
- // Setup the current multisector transfer size
- driveID.atap_curmulti = MAX_MULTSECT;
- driveID.atap_curmulti_valid = 0x1;
- // Number of sectors on disk
- driveID.atap_capacity = lba_size;
- // Multiword DMA mode 2 and below supported
- driveID.atap_dmamode_supp = 0x4;
- // Set PIO mode 4 and 3 supported
- driveID.atap_piomode_supp = 0x3;
- // Set DMA mode 4 and below supported
- driveID.atap_udmamode_supp = 0x1f;
- // Statically set hardware config word
- driveID.atap_hwreset_res = 0x4001;
-
- //arbitrary for now...
- driveID.atap_ata_major = WDC_VER_ATA7;
-}
-
-IdeDisk::~IdeDisk()
-{
- // destroy the data buffer
- delete [] dataBuffer;
-}
-
-void
-IdeDisk::reset(int id)
-{
- // initialize the data buffer and shadow registers
- dataBuffer = new uint8_t[MAX_DMA_SIZE];
-
- memset(dataBuffer, 0, MAX_DMA_SIZE);
- memset(&cmdReg, 0, sizeof(CommandReg_t));
- memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
-
- curPrdAddr = 0;
- curSector = 0;
- cmdBytes = 0;
- cmdBytesLeft = 0;
- drqBytesLeft = 0;
- dmaRead = false;
- intrPending = false;
- dmaAborted = false;
-
- // set the device state to idle
- dmaState = Dma_Idle;
-
- if (id == DEV0) {
- devState = Device_Idle_S;
- devID = DEV0;
- } else if (id == DEV1) {
- devState = Device_Idle_NS;
- devID = DEV1;
- } else {
- panic("Invalid device ID: %#x\n", id);
- }
-
- // set the device ready bit
- status = STATUS_DRDY_BIT;
-
- /* The error register must be set to 0x1 on start-up to
- indicate that no diagnostic error was detected */
- cmdReg.error = 0x1;
-}
-
-////
-// Utility functions
-////
-
-bool
-IdeDisk::isDEVSelect()
-{
- return ctrl->isDiskSelected(this);
-}
-
-Addr
-IdeDisk::pciToDma(Addr pciAddr)
-{
- if (ctrl)
- return ctrl->pciToDma(pciAddr);
- else
- panic("Access to unset controller!\n");
-}
-
-////
-// Device registers read/write
-////
-
-void
-IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
-{
- if (offset == DATA_OFFSET) {
- if (size == sizeof(uint16_t)) {
- *(uint16_t *)data = cmdReg.data;
- } else if (size == sizeof(uint32_t)) {
- *(uint16_t *)data = cmdReg.data;
- updateState(ACT_DATA_READ_SHORT);
- *((uint16_t *)data + 1) = cmdReg.data;
- } else {
- panic("Data read of unsupported size %d.\n", size);
- }
- updateState(ACT_DATA_READ_SHORT);
- return;
- }
- assert(size == sizeof(uint8_t));
- switch (offset) {
- case ERROR_OFFSET:
- *data = cmdReg.error;
- break;
- case NSECTOR_OFFSET:
- *data = cmdReg.sec_count;
- break;
- case SECTOR_OFFSET:
- *data = cmdReg.sec_num;
- break;
- case LCYL_OFFSET:
- *data = cmdReg.cyl_low;
- break;
- case HCYL_OFFSET:
- *data = cmdReg.cyl_high;
- break;
- case DRIVE_OFFSET:
- *data = cmdReg.drive;
- break;
- case STATUS_OFFSET:
- *data = status;
- updateState(ACT_STAT_READ);
- break;
- default:
- panic("Invalid IDE command register offset: %#x\n", offset);
- }
- DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
-}
-
-void
-IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
-{
- assert(size == sizeof(uint8_t));
- *data = status;
- if (offset != ALTSTAT_OFFSET)
- panic("Invalid IDE control register offset: %#x\n", offset);
- DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
-}
-
-void
-IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
-{
- if (offset == DATA_OFFSET) {
- if (size == sizeof(uint16_t)) {
- cmdReg.data = *(const uint16_t *)data;
- } else if (size == sizeof(uint32_t)) {
- cmdReg.data = *(const uint16_t *)data;
- updateState(ACT_DATA_WRITE_SHORT);
- cmdReg.data = *((const uint16_t *)data + 1);
- } else {
- panic("Data write of unsupported size %d.\n", size);
- }
- updateState(ACT_DATA_WRITE_SHORT);
- return;
- }
-
- assert(size == sizeof(uint8_t));
- switch (offset) {
- case FEATURES_OFFSET:
- break;
- case NSECTOR_OFFSET:
- cmdReg.sec_count = *data;
- break;
- case SECTOR_OFFSET:
- cmdReg.sec_num = *data;
- break;
- case LCYL_OFFSET:
- cmdReg.cyl_low = *data;
- break;
- case HCYL_OFFSET:
- cmdReg.cyl_high = *data;
- break;
- case DRIVE_OFFSET:
- cmdReg.drive = *data;
- updateState(ACT_SELECT_WRITE);
- break;
- case COMMAND_OFFSET:
- cmdReg.command = *data;
- updateState(ACT_CMD_WRITE);
- break;
- default:
- panic("Invalid IDE command register offset: %#x\n", offset);
- }
- DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
- (uint32_t)*data);
-}
-
-void
-IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
-{
- if (offset != CONTROL_OFFSET)
- panic("Invalid IDE control register offset: %#x\n", offset);
-
- if (*data & CONTROL_RST_BIT) {
- // force the device into the reset state
- devState = Device_Srst;
- updateState(ACT_SRST_SET);
- } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
- updateState(ACT_SRST_CLEAR);
- }
-
- nIENBit = *data & CONTROL_IEN_BIT;
-
- DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
- (uint32_t)*data);
-}
-
-////
-// Perform DMA transactions
-////
-
-void
-IdeDisk::doDmaTransfer()
-{
- if (dmaAborted) {
- DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
- updateState(ACT_CMD_ERROR);
- return;
- }
-
- if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
- panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
- dmaState, devState);
-
- if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
- schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
- return;
- } else
- ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
- (uint8_t*)&curPrd.entry);
-}
-
-void
-IdeDisk::dmaPrdReadDone()
-{
- if (dmaAborted) {
- DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
- updateState(ACT_CMD_ERROR);
- return;
- }
-
- DPRINTF(IdeDisk,
- "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
- curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
- curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
- curPrd.getEOT(), curSector);
-
- // the prd pointer has already been translated, so just do an increment
- curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
-
- if (dmaRead)
- doDmaDataRead();
- else
- doDmaDataWrite();
-}
-
-void
-IdeDisk::doDmaDataRead()
-{
- /** @todo we need to figure out what the delay actually will be */
- Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
-
- DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
- diskDelay, totalDiskDelay);
-
- schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
-}
-
-void
-IdeDisk::regStats()
-{
- using namespace Stats;
- dmaReadFullPages
- .name(name() + ".dma_read_full_pages")
- .desc("Number of full page size DMA reads (not PRD).")
- ;
- dmaReadBytes
- .name(name() + ".dma_read_bytes")
- .desc("Number of bytes transfered via DMA reads (not PRD).")
- ;
- dmaReadTxs
- .name(name() + ".dma_read_txs")
- .desc("Number of DMA read transactions (not PRD).")
- ;
-
- dmaWriteFullPages
- .name(name() + ".dma_write_full_pages")
- .desc("Number of full page size DMA writes.")
- ;
- dmaWriteBytes
- .name(name() + ".dma_write_bytes")
- .desc("Number of bytes transfered via DMA writes.")
- ;
- dmaWriteTxs
- .name(name() + ".dma_write_txs")
- .desc("Number of DMA write transactions.")
- ;
-}
-
-void
-IdeDisk::doDmaRead()
-{
- if (dmaAborted) {
- DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
- if (dmaReadCG)
- delete dmaReadCG;
- dmaReadCG = NULL;
- updateState(ACT_CMD_ERROR);
- return;
- }
-
- if (!dmaReadCG) {
- // clear out the data buffer
- memset(dataBuffer, 0, MAX_DMA_SIZE);
- dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
- curPrd.getByteCount(), TheISA::PageBytes);
-
- }
- if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
- schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
- return;
- } else if (!dmaReadCG->done()) {
- assert(dmaReadCG->complete() < MAX_DMA_SIZE);
- ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
- &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
- dmaReadBytes += dmaReadCG->size();
- dmaReadTxs++;
- if (dmaReadCG->size() == TheISA::PageBytes)
- dmaReadFullPages++;
- dmaReadCG->next();
- } else {
- assert(dmaReadCG->done());
- delete dmaReadCG;
- dmaReadCG = NULL;
- dmaReadDone();
- }
-}
-
-void
-IdeDisk::dmaReadDone()
-{
- uint32_t bytesWritten = 0;
-
- // write the data to the disk image
- for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
- bytesWritten += SectorSize) {
-
- cmdBytesLeft -= SectorSize;
- writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
- }
-
- // check for the EOT
- if (curPrd.getEOT()) {
- assert(cmdBytesLeft == 0);
- dmaState = Dma_Idle;
- updateState(ACT_DMA_DONE);
- } else {
- doDmaTransfer();
- }
-}
-
-void
-IdeDisk::doDmaDataWrite()
-{
- /** @todo we need to figure out what the delay actually will be */
- Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
- uint32_t bytesRead = 0;
-
- DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
- diskDelay, totalDiskDelay);
-
- memset(dataBuffer, 0, MAX_DMA_SIZE);
- assert(cmdBytesLeft <= MAX_DMA_SIZE);
- while (bytesRead < curPrd.getByteCount()) {
- readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
- bytesRead += SectorSize;
- cmdBytesLeft -= SectorSize;
- }
- DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
- bytesRead, cmdBytesLeft);
-
- schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
-}
-
-void
-IdeDisk::doDmaWrite()
-{
- if (dmaAborted) {
- DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
- if (dmaWriteCG)
- delete dmaWriteCG;
- dmaWriteCG = NULL;
- updateState(ACT_CMD_ERROR);
- return;
- }
- if (!dmaWriteCG) {
- // clear out the data buffer
- dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
- curPrd.getByteCount(), TheISA::PageBytes);
- }
- if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
- schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
- DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
- return;
- } else if (!dmaWriteCG->done()) {
- assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
- ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
- &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
- DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
- curPrd.getByteCount(), curPrd.getEOT());
- dmaWriteBytes += dmaWriteCG->size();
- dmaWriteTxs++;
- if (dmaWriteCG->size() == TheISA::PageBytes)
- dmaWriteFullPages++;
- dmaWriteCG->next();
- } else {
- DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
- curPrd.getByteCount(), curPrd.getEOT());
- assert(dmaWriteCG->done());
- delete dmaWriteCG;
- dmaWriteCG = NULL;
- dmaWriteDone();
- }
-}
-
-void
-IdeDisk::dmaWriteDone()
-{
- DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
- curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
- // check for the EOT
- if (curPrd.getEOT()) {
- assert(cmdBytesLeft == 0);
- dmaState = Dma_Idle;
- updateState(ACT_DMA_DONE);
- } else {
- doDmaTransfer();
- }
-}
-
-////
-// Disk utility routines
-///
-
-void
-IdeDisk::readDisk(uint32_t sector, uint8_t *data)
-{
- uint32_t bytesRead = image->read(data, sector);
-
- if (bytesRead != SectorSize)
- panic("Can't read from %s. Only %d of %d read. errno=%d\n",
- name(), bytesRead, SectorSize, errno);
-}
-
-void
-IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
-{
- uint32_t bytesWritten = image->write(data, sector);
-
- if (bytesWritten != SectorSize)
- panic("Can't write to %s. Only %d of %d written. errno=%d\n",
- name(), bytesWritten, SectorSize, errno);
-}
-
-////
-// Setup and handle commands
-////
-
-void
-IdeDisk::startDma(const uint32_t &prdTableBase)
-{
- if (dmaState != Dma_Start)
- panic("Inconsistent DMA state, should be in Dma_Start!\n");
-
- if (devState != Transfer_Data_Dma)
- panic("Inconsistent device state for DMA start!\n");
-
- // PRD base address is given by bits 31:2
- curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
-
- dmaState = Dma_Transfer;
-
- // schedule dma transfer (doDmaTransfer)
- schedule(dmaTransferEvent, curTick() + 1);
-}
-
-void
-IdeDisk::abortDma()
-{
- if (dmaState == Dma_Idle)
- panic("Inconsistent DMA state, should be Start or Transfer!");
-
- if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
- panic("Inconsistent device state, should be Transfer or Prepare!\n");
-
- updateState(ACT_CMD_ERROR);
-}
-
-void
-IdeDisk::startCommand()
-{
- DevAction_t action = ACT_NONE;
- uint32_t size = 0;
- dmaRead = false;
-
- // Decode commands
- switch (cmdReg.command) {
- // Supported non-data commands
- case WDSF_READ_NATIVE_MAX:
- size = (uint32_t)image->size() - 1;
- cmdReg.sec_num = (size & 0xff);
- cmdReg.cyl_low = ((size & 0xff00) >> 8);
- cmdReg.cyl_high = ((size & 0xff0000) >> 16);
- cmdReg.head = ((size & 0xf000000) >> 24);
-
- devState = Command_Execution;
- action = ACT_CMD_COMPLETE;
- break;
-
- case WDCC_RECAL:
- case WDCC_IDP:
- case WDCC_STANDBY_IMMED:
- case WDCC_FLUSHCACHE:
- case WDSF_VERIFY:
- case WDSF_SEEK:
- case SET_FEATURES:
- case WDCC_SETMULTI:
- case WDCC_IDLE:
- devState = Command_Execution;
- action = ACT_CMD_COMPLETE;
- break;
-
- // Supported PIO data-in commands
- case WDCC_IDENTIFY:
- cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
- devState = Prepare_Data_In;
- action = ACT_DATA_READY;
- break;
-
- case WDCC_READMULTI:
- case WDCC_READ:
- if (!(cmdReg.drive & DRIVE_LBA_BIT))
- panic("Attempt to perform CHS access, only supports LBA\n");
-
- if (cmdReg.sec_count == 0)
- cmdBytes = cmdBytesLeft = (256 * SectorSize);
- else
- cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
-
- curSector = getLBABase();
-
- /** @todo make this a scheduled event to simulate disk delay */
- devState = Prepare_Data_In;
- action = ACT_DATA_READY;
- break;
-
- // Supported PIO data-out commands
- case WDCC_WRITEMULTI:
- case WDCC_WRITE:
- if (!(cmdReg.drive & DRIVE_LBA_BIT))
- panic("Attempt to perform CHS access, only supports LBA\n");
-
- if (cmdReg.sec_count == 0)
- cmdBytes = cmdBytesLeft = (256 * SectorSize);
- else
- cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
- DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
- curSector = getLBABase();
-
- devState = Prepare_Data_Out;
- action = ACT_DATA_READY;
- break;
-
- // Supported DMA commands
- case WDCC_WRITEDMA:
- dmaRead = true; // a write to the disk is a DMA read from memory
- case WDCC_READDMA:
- if (!(cmdReg.drive & DRIVE_LBA_BIT))
- panic("Attempt to perform CHS access, only supports LBA\n");
-
- if (cmdReg.sec_count == 0)
- cmdBytes = cmdBytesLeft = (256 * SectorSize);
- else
- cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
- DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
-
- curSector = getLBABase();
-
- devState = Prepare_Data_Dma;
- action = ACT_DMA_READY;
- break;
-
- default:
- panic("Unsupported ATA command: %#x\n", cmdReg.command);
- }
-
- if (action != ACT_NONE) {
- // set the BSY bit
- status |= STATUS_BSY_BIT;
- // clear the DRQ bit
- status &= ~STATUS_DRQ_BIT;
- // clear the DF bit
- status &= ~STATUS_DF_BIT;
-
- updateState(action);
- }
-}
-
-////
-// Handle setting and clearing interrupts
-////
-
-void
-IdeDisk::intrPost()
-{
- DPRINTF(IdeDisk, "Posting Interrupt\n");
- if (intrPending)
- panic("Attempt to post an interrupt with one pending\n");
-
- intrPending = true;
-
- // talk to controller to set interrupt
- if (ctrl) {
- ctrl->intrPost();
- }
-}
-
-void
-IdeDisk::intrClear()
-{
- DPRINTF(IdeDisk, "Clearing Interrupt\n");
- if (!intrPending)
- panic("Attempt to clear a non-pending interrupt\n");
-
- intrPending = false;
-
- // talk to controller to clear interrupt
- if (ctrl)
- ctrl->intrClear();
-}
-
-////
-// Manage the device internal state machine
-////
-
-void
-IdeDisk::updateState(DevAction_t action)
-{
- switch (devState) {
- case Device_Srst:
- if (action == ACT_SRST_SET) {
- // set the BSY bit
- status |= STATUS_BSY_BIT;
- } else if (action == ACT_SRST_CLEAR) {
- // clear the BSY bit
- status &= ~STATUS_BSY_BIT;
-
- // reset the device state
- reset(devID);
- }
- break;
-
- case Device_Idle_S:
- if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
- devState = Device_Idle_NS;
- } else if (action == ACT_CMD_WRITE) {
- startCommand();
- }
-
- break;
-
- case Device_Idle_SI:
- if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
- devState = Device_Idle_NS;
- intrClear();
- } else if (action == ACT_STAT_READ || isIENSet()) {
- devState = Device_Idle_S;
- intrClear();
- } else if (action == ACT_CMD_WRITE) {
- intrClear();
- startCommand();
- }
-
- break;
-
- case Device_Idle_NS:
- if (action == ACT_SELECT_WRITE && isDEVSelect()) {
- if (!isIENSet() && intrPending) {
- devState = Device_Idle_SI;
- intrPost();
- }
- if (isIENSet() || !intrPending) {
- devState = Device_Idle_S;
- }
- }
- break;
-
- case Command_Execution:
- if (action == ACT_CMD_COMPLETE) {
- // clear the BSY bit
- setComplete();
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- }
- break;
-
- case Prepare_Data_In:
- if (action == ACT_CMD_ERROR) {
- // clear the BSY bit
- setComplete();
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- } else if (action == ACT_DATA_READY) {
- // clear the BSY bit
- status &= ~STATUS_BSY_BIT;
- // set the DRQ bit
- status |= STATUS_DRQ_BIT;
-
- // copy the data into the data buffer
- if (cmdReg.command == WDCC_IDENTIFY) {
- // Reset the drqBytes for this block
- drqBytesLeft = sizeof(struct ataparams);
-
- memcpy((void *)dataBuffer, (void *)&driveID,
- sizeof(struct ataparams));
- } else {
- // Reset the drqBytes for this block
- drqBytesLeft = SectorSize;
-
- readDisk(curSector++, dataBuffer);
- }
-
- // put the first two bytes into the data register
- memcpy((void *)&cmdReg.data, (void *)dataBuffer,
- sizeof(uint16_t));
-
- if (!isIENSet()) {
- devState = Data_Ready_INTRQ_In;
- intrPost();
- } else {
- devState = Transfer_Data_In;
- }
- }
- break;
-
- case Data_Ready_INTRQ_In:
- if (action == ACT_STAT_READ) {
- devState = Transfer_Data_In;
- intrClear();
- }
- break;
-
- case Transfer_Data_In:
- if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
- if (action == ACT_DATA_READ_BYTE) {
- panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
- } else {
- drqBytesLeft -= 2;
- cmdBytesLeft -= 2;
-
- // copy next short into data registers
- if (drqBytesLeft)
- memcpy((void *)&cmdReg.data,
- (void *)&dataBuffer[SectorSize - drqBytesLeft],
- sizeof(uint16_t));
- }
-
- if (drqBytesLeft == 0) {
- if (cmdBytesLeft == 0) {
- // Clear the BSY bit
- setComplete();
- devState = Device_Idle_S;
- } else {
- devState = Prepare_Data_In;
- // set the BSY_BIT
- status |= STATUS_BSY_BIT;
- // clear the DRQ_BIT
- status &= ~STATUS_DRQ_BIT;
-
- /** @todo change this to a scheduled event to simulate
- disk delay */
- updateState(ACT_DATA_READY);
- }
- }
- }
- break;
-
- case Prepare_Data_Out:
- if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
- // clear the BSY bit
- setComplete();
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
- // clear the BSY bit
- status &= ~STATUS_BSY_BIT;
- // set the DRQ bit
- status |= STATUS_DRQ_BIT;
-
- // clear the data buffer to get it ready for writes
- memset(dataBuffer, 0, MAX_DMA_SIZE);
-
- // reset the drqBytes for this block
- drqBytesLeft = SectorSize;
-
- if (cmdBytesLeft == cmdBytes || isIENSet()) {
- devState = Transfer_Data_Out;
- } else {
- devState = Data_Ready_INTRQ_Out;
- intrPost();
- }
- }
- break;
-
- case Data_Ready_INTRQ_Out:
- if (action == ACT_STAT_READ) {
- devState = Transfer_Data_Out;
- intrClear();
- }
- break;
-
- case Transfer_Data_Out:
- if (action == ACT_DATA_WRITE_BYTE ||
- action == ACT_DATA_WRITE_SHORT) {
-
- if (action == ACT_DATA_READ_BYTE) {
- panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
- } else {
- // copy the latest short into the data buffer
- memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
- (void *)&cmdReg.data,
- sizeof(uint16_t));
-
- drqBytesLeft -= 2;
- cmdBytesLeft -= 2;
- }
-
- if (drqBytesLeft == 0) {
- // copy the block to the disk
- writeDisk(curSector++, dataBuffer);
-
- // set the BSY bit
- status |= STATUS_BSY_BIT;
- // set the seek bit
- status |= STATUS_SEEK_BIT;
- // clear the DRQ bit
- status &= ~STATUS_DRQ_BIT;
-
- devState = Prepare_Data_Out;
-
- /** @todo change this to a scheduled event to simulate
- disk delay */
- updateState(ACT_DATA_READY);
- }
- }
- break;
-
- case Prepare_Data_Dma:
- if (action == ACT_CMD_ERROR) {
- // clear the BSY bit
- setComplete();
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- } else if (action == ACT_DMA_READY) {
- // clear the BSY bit
- status &= ~STATUS_BSY_BIT;
- // set the DRQ bit
- status |= STATUS_DRQ_BIT;
-
- devState = Transfer_Data_Dma;
-
- if (dmaState != Dma_Idle)
- panic("Inconsistent DMA state, should be Dma_Idle\n");
-
- dmaState = Dma_Start;
- // wait for the write to the DMA start bit
- }
- break;
-
- case Transfer_Data_Dma:
- if (action == ACT_CMD_ERROR) {
- dmaAborted = true;
- devState = Device_Dma_Abort;
- } else if (action == ACT_DMA_DONE) {
- // clear the BSY bit
- setComplete();
- // set the seek bit
- status |= STATUS_SEEK_BIT;
- // clear the controller state for DMA transfer
- ctrl->setDmaComplete(this);
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- }
- break;
-
- case Device_Dma_Abort:
- if (action == ACT_CMD_ERROR) {
- setComplete();
- status |= STATUS_SEEK_BIT;
- ctrl->setDmaComplete(this);
- dmaAborted = false;
- dmaState = Dma_Idle;
-
- if (!isIENSet()) {
- devState = Device_Idle_SI;
- intrPost();
- } else {
- devState = Device_Idle_S;
- }
- } else {
- DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
- }
- break;
-
- default:
- panic("Unknown IDE device state: %#x\n", devState);
- }
-}
-
-void
-IdeDisk::serialize(CheckpointOut &cp) const
-{
- // Check all outstanding events to see if they are scheduled
- // these are all mutually exclusive
- Tick reschedule = 0;
- Events_t event = None;
-
- int eventCount = 0;
-
- if (dmaTransferEvent.scheduled()) {
- reschedule = dmaTransferEvent.when();
- event = Transfer;
- eventCount++;
- }
- if (dmaReadWaitEvent.scheduled()) {
- reschedule = dmaReadWaitEvent.when();
- event = ReadWait;
- eventCount++;
- }
- if (dmaWriteWaitEvent.scheduled()) {
- reschedule = dmaWriteWaitEvent.when();
- event = WriteWait;
- eventCount++;
- }
- if (dmaPrdReadEvent.scheduled()) {
- reschedule = dmaPrdReadEvent.when();
- event = PrdRead;
- eventCount++;
- }
- if (dmaReadEvent.scheduled()) {
- reschedule = dmaReadEvent.when();
- event = DmaRead;
- eventCount++;
- }
- if (dmaWriteEvent.scheduled()) {
- reschedule = dmaWriteEvent.when();
- event = DmaWrite;
- eventCount++;
- }
-
- assert(eventCount <= 1);
-
- SERIALIZE_SCALAR(reschedule);
- SERIALIZE_ENUM(event);
-
- // Serialize device registers
- SERIALIZE_SCALAR(cmdReg.data);
- SERIALIZE_SCALAR(cmdReg.sec_count);
- SERIALIZE_SCALAR(cmdReg.sec_num);
- SERIALIZE_SCALAR(cmdReg.cyl_low);
- SERIALIZE_SCALAR(cmdReg.cyl_high);
- SERIALIZE_SCALAR(cmdReg.drive);
- SERIALIZE_SCALAR(cmdReg.command);
- SERIALIZE_SCALAR(status);
- SERIALIZE_SCALAR(nIENBit);
- SERIALIZE_SCALAR(devID);
-
- // Serialize the PRD related information
- SERIALIZE_SCALAR(curPrd.entry.baseAddr);
- SERIALIZE_SCALAR(curPrd.entry.byteCount);
- SERIALIZE_SCALAR(curPrd.entry.endOfTable);
- SERIALIZE_SCALAR(curPrdAddr);
-
- /** @todo need to serialized chunk generator stuff!! */
- // Serialize current transfer related information
- SERIALIZE_SCALAR(cmdBytesLeft);
- SERIALIZE_SCALAR(cmdBytes);
- SERIALIZE_SCALAR(drqBytesLeft);
- SERIALIZE_SCALAR(curSector);
- SERIALIZE_SCALAR(dmaRead);
- SERIALIZE_SCALAR(intrPending);
- SERIALIZE_SCALAR(dmaAborted);
- SERIALIZE_ENUM(devState);
- SERIALIZE_ENUM(dmaState);
- SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
-}
-
-void
-IdeDisk::unserialize(CheckpointIn &cp)
-{
- // Reschedule events that were outstanding
- // these are all mutually exclusive
- Tick reschedule = 0;
- Events_t event = None;
-
- UNSERIALIZE_SCALAR(reschedule);
- UNSERIALIZE_ENUM(event);
-
- switch (event) {
- case None : break;
- case Transfer : schedule(dmaTransferEvent, reschedule); break;
- case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
- case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
- case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
- case DmaRead : schedule(dmaReadEvent, reschedule); break;
- case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
- }
-
- // Unserialize device registers
- UNSERIALIZE_SCALAR(cmdReg.data);
- UNSERIALIZE_SCALAR(cmdReg.sec_count);
- UNSERIALIZE_SCALAR(cmdReg.sec_num);
- UNSERIALIZE_SCALAR(cmdReg.cyl_low);
- UNSERIALIZE_SCALAR(cmdReg.cyl_high);
- UNSERIALIZE_SCALAR(cmdReg.drive);
- UNSERIALIZE_SCALAR(cmdReg.command);
- UNSERIALIZE_SCALAR(status);
- UNSERIALIZE_SCALAR(nIENBit);
- UNSERIALIZE_SCALAR(devID);
-
- // Unserialize the PRD related information
- UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
- UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
- UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
- UNSERIALIZE_SCALAR(curPrdAddr);
-
- /** @todo need to serialized chunk generator stuff!! */
- // Unserialize current transfer related information
- UNSERIALIZE_SCALAR(cmdBytes);
- UNSERIALIZE_SCALAR(cmdBytesLeft);
- UNSERIALIZE_SCALAR(drqBytesLeft);
- UNSERIALIZE_SCALAR(curSector);
- UNSERIALIZE_SCALAR(dmaRead);
- UNSERIALIZE_SCALAR(intrPending);
- UNSERIALIZE_SCALAR(dmaAborted);
- UNSERIALIZE_ENUM(devState);
- UNSERIALIZE_ENUM(dmaState);
- UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
-}
-
-IdeDisk *
-IdeDiskParams::create()
-{
- return new IdeDisk(this);
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder. You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andrew Schultz
- */
-
-/** @file
- * Device model for an IDE disk
- */
-
-#ifndef __IDE_DISK_HH__
-#define __IDE_DISK_HH__
-
-#include "base/statistics.hh"
-#include "dev/disk_image.hh"
-#include "dev/ide_atareg.h"
-#include "dev/ide_ctrl.hh"
-#include "dev/ide_wdcreg.h"
-#include "dev/io_device.hh"
-#include "params/IdeDisk.hh"
-#include "sim/eventq.hh"
-
-class ChunkGenerator;
-
-#define DMA_BACKOFF_PERIOD 200
-
-#define MAX_DMA_SIZE 0x20000 // 128K
-#define MAX_SINGLE_DMA_SIZE 0x10000
-#define MAX_MULTSECT (128)
-
-#define PRD_BASE_MASK 0xfffffffe
-#define PRD_COUNT_MASK 0xfffe
-#define PRD_EOT_MASK 0x8000
-
-typedef struct PrdEntry {
- uint32_t baseAddr;
- uint16_t byteCount;
- uint16_t endOfTable;
-} PrdEntry_t;
-
-class PrdTableEntry {
- public:
- PrdEntry_t entry;
-
- uint32_t getBaseAddr()
- {
- return (entry.baseAddr & PRD_BASE_MASK);
- }
-
- uint32_t getByteCount()
- {
- return ((entry.byteCount == 0) ? MAX_SINGLE_DMA_SIZE :
- (entry.byteCount & PRD_COUNT_MASK));
- }
-
- uint16_t getEOT()
- {
- return (entry.endOfTable & PRD_EOT_MASK);
- }
-};
-
-#define DATA_OFFSET (0)
-#define ERROR_OFFSET (1)
-#define FEATURES_OFFSET (1)
-#define NSECTOR_OFFSET (2)
-#define SECTOR_OFFSET (3)
-#define LCYL_OFFSET (4)
-#define HCYL_OFFSET (5)
-#define SELECT_OFFSET (6)
-#define DRIVE_OFFSET (6)
-#define STATUS_OFFSET (7)
-#define COMMAND_OFFSET (7)
-
-#define CONTROL_OFFSET (2)
-#define ALTSTAT_OFFSET (2)
-
-#define SELECT_DEV_BIT 0x10
-#define CONTROL_RST_BIT 0x04
-#define CONTROL_IEN_BIT 0x02
-#define STATUS_BSY_BIT 0x80
-#define STATUS_DRDY_BIT 0x40
-#define STATUS_DRQ_BIT 0x08
-#define STATUS_SEEK_BIT 0x10
-#define STATUS_DF_BIT 0x20
-#define DRIVE_LBA_BIT 0x40
-
-#define DEV0 (0)
-#define DEV1 (1)
-
-typedef struct CommandReg {
- uint16_t data;
- uint8_t error;
- uint8_t sec_count;
- uint8_t sec_num;
- uint8_t cyl_low;
- uint8_t cyl_high;
- union {
- uint8_t drive;
- uint8_t head;
- };
- uint8_t command;
-} CommandReg_t;
-
-typedef enum Events {
- None = 0,
- Transfer,
- ReadWait,
- WriteWait,
- PrdRead,
- DmaRead,
- DmaWrite
-} Events_t;
-
-typedef enum DevAction {
- ACT_NONE = 0,
- ACT_CMD_WRITE,
- ACT_CMD_COMPLETE,
- ACT_CMD_ERROR,
- ACT_SELECT_WRITE,
- ACT_STAT_READ,
- ACT_DATA_READY,
- ACT_DATA_READ_BYTE,
- ACT_DATA_READ_SHORT,
- ACT_DATA_WRITE_BYTE,
- ACT_DATA_WRITE_SHORT,
- ACT_DMA_READY,
- ACT_DMA_DONE,
- ACT_SRST_SET,
- ACT_SRST_CLEAR
-} DevAction_t;
-
-typedef enum DevState {
- // Device idle
- Device_Idle_S = 0,
- Device_Idle_SI,
- Device_Idle_NS,
-
- // Software reset
- Device_Srst,
-
- // Non-data commands
- Command_Execution,
-
- // PIO data-in (data to host)
- Prepare_Data_In,
- Data_Ready_INTRQ_In,
- Transfer_Data_In,
-
- // PIO data-out (data from host)
- Prepare_Data_Out,
- Data_Ready_INTRQ_Out,
- Transfer_Data_Out,
-
- // DMA protocol
- Prepare_Data_Dma,
- Transfer_Data_Dma,
- Device_Dma_Abort
-} DevState_t;
-
-typedef enum DmaState {
- Dma_Idle = 0,
- Dma_Start,
- Dma_Transfer
-} DmaState_t;
-
-class IdeController;
-
-/**
- * IDE Disk device model
- */
-class IdeDisk : public SimObject
-{
- protected:
- /** The IDE controller for this disk. */
- IdeController *ctrl;
- /** The image that contains the data of this disk. */
- DiskImage *image;
-
- protected:
- /** The disk delay in microseconds. */
- int diskDelay;
-
- private:
- /** Drive identification structure for this disk */
- struct ataparams driveID;
- /** Data buffer for transfers */
- uint8_t *dataBuffer;
- /** Number of bytes in command data transfer */
- uint32_t cmdBytes;
- /** Number of bytes left in command data transfer */
- uint32_t cmdBytesLeft;
- /** Number of bytes left in DRQ block */
- uint32_t drqBytesLeft;
- /** Current sector in access */
- uint32_t curSector;
- /** Command block registers */
- CommandReg_t cmdReg;
- /** Status register */
- uint8_t status;
- /** Interrupt enable bit */
- bool nIENBit;
- /** Device state */
- DevState_t devState;
- /** Dma state */
- DmaState_t dmaState;
- /** Dma transaction is a read */
- bool dmaRead;
- /** PRD table base address */
- uint32_t curPrdAddr;
- /** PRD entry */
- PrdTableEntry curPrd;
- /** Device ID (master=0/slave=1) */
- int devID;
- /** Interrupt pending */
- bool intrPending;
- /** DMA Aborted */
- bool dmaAborted;
-
- Stats::Scalar dmaReadFullPages;
- Stats::Scalar dmaReadBytes;
- Stats::Scalar dmaReadTxs;
- Stats::Scalar dmaWriteFullPages;
- Stats::Scalar dmaWriteBytes;
- Stats::Scalar dmaWriteTxs;
-
- public:
- typedef IdeDiskParams Params;
- IdeDisk(const Params *p);
-
- /**
- * Delete the data buffer.
- */
- ~IdeDisk();
-
- /**
- * Reset the device state
- */
- void reset(int id);
-
- /**
- * Register Statistics
- */
- void regStats() override;
-
- /**
- * Set the controller for this device
- * @param c The IDE controller
- */
- void setController(IdeController *c) {
- if (ctrl) panic("Cannot change the controller once set!\n");
- ctrl = c;
- }
-
- // Device register read/write
- void readCommand(const Addr offset, int size, uint8_t *data);
- void readControl(const Addr offset, int size, uint8_t *data);
- void writeCommand(const Addr offset, int size, const uint8_t *data);
- void writeControl(const Addr offset, int size, const uint8_t *data);
-
- // Start/abort functions
- void startDma(const uint32_t &prdTableBase);
- void abortDma();
-
- private:
- void startCommand();
-
- // Interrupt management
- void intrPost();
- void intrClear();
-
- // DMA stuff
- void doDmaTransfer();
- friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
- EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
-
- void doDmaDataRead();
-
- void doDmaRead();
- ChunkGenerator *dmaReadCG;
- friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
- EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
-
- void doDmaDataWrite();
-
- void doDmaWrite();
- ChunkGenerator *dmaWriteCG;
- friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
- EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
-
- void dmaPrdReadDone();
- friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
- EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
-
- void dmaReadDone();
- friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
- EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
-
- void dmaWriteDone();
- friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
- EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
-
- // Disk image read/write
- void readDisk(uint32_t sector, uint8_t *data);
- void writeDisk(uint32_t sector, uint8_t *data);
-
- // State machine management
- void updateState(DevAction_t action);
-
- // Utility functions
- bool isBSYSet() { return (status & STATUS_BSY_BIT); }
- bool isIENSet() { return nIENBit; }
- bool isDEVSelect();
-
- void setComplete()
- {
- // clear out the status byte
- status = 0;
- // set the DRDY bit
- status |= STATUS_DRDY_BIT;
- // set the SEEK bit
- status |= STATUS_SEEK_BIT;
- }
-
- uint32_t getLBABase()
- {
- return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
- (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
- }
-
- inline Addr pciToDma(Addr pciAddr);
-
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
-};
-
-
-#endif // __IDE_DISK_HH__
+++ /dev/null
-/* $OpenBSD: wdcreg.h,v 1.13 2004/09/24 07:05:44 grange Exp $ */
-/* $NetBSD: wdcreg.h,v 1.22 1999/03/07 14:02:54 bouyer Exp $ */
-
-/*-
- * Copyright (c) 1991 The Regents of the University of California
- * All rights reserved
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- * @(#)wdreg.h 7.1 (Berkeley) 5/9/91
- */
-
-#ifndef _DEV_IC_WDCREG_H_
-#define _DEV_IC_WDCREG_H_
-
-/*
- * Controller register (wdr_ctlr)
- */
-#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */
-#define WDCTL_RST 0x04 /* reset the controller */
-#define WDCTL_IDS 0x02 /* disable controller interrupts */
-
-/*
- * Status bits.
- */
-#define WDCS_BSY 0x80 /* busy */
-#define WDCS_DRDY 0x40 /* drive ready */
-#define WDCS_DWF 0x20 /* drive write fault */
-#define WDCS_DSC 0x10 /* drive seek complete */
-#define WDCS_DRQ 0x08 /* data request */
-#define WDCS_CORR 0x04 /* corrected data */
-#define WDCS_IDX 0x02 /* index */
-#define WDCS_ERR 0x01 /* error */
-#define WDCS_BITS "\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR"
-
-/*
- * Error bits.
- */
-#define WDCE_BBK 0x80 /* bad block detected */
-#define WDCE_CRC 0x80 /* CRC error (Ultra-DMA only) */
-#define WDCE_UNC 0x40 /* uncorrectable data error */
-#define WDCE_MC 0x20 /* media changed */
-#define WDCE_IDNF 0x10 /* id not found */
-#define WDCE_MCR 0x08 /* media change requested */
-#define WDCE_ABRT 0x04 /* aborted command */
-#define WDCE_TK0NF 0x02 /* track 0 not found */
-#define WDCE_AMNF 0x01 /* address mark not found */
-
-/*
- * Commands for Disk Controller.
- */
-#define WDCC_NOP 0x00 /* NOP - Always fail with "aborted command" */
-#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
-
-#define WDCC_READ 0x20 /* disk read code */
-#define WDCC_WRITE 0x30 /* disk write code */
-#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
-#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
-
-#define WDCC_FORMAT 0x50 /* disk format code */
-#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
-#define WDCC_IDP 0x91 /* initialize drive parameters */
-
-#define WDCC_READMULTI 0xc4 /* read multiple */
-#define WDCC_WRITEMULTI 0xc5 /* write multiple */
-#define WDCC_SETMULTI 0xc6 /* set multiple mode */
-
-#define WDCC_READDMA 0xc8 /* read with DMA */
-#define WDCC_WRITEDMA 0xca /* write with DMA */
-
-#define WDCC_ACKMC 0xdb /* acknowledge media change */
-#define WDCC_LOCK 0xde /* lock drawer */
-#define WDCC_UNLOCK 0xdf /* unlock drawer */
-
-#define WDCC_FLUSHCACHE 0xe7 /* Flush cache */
-#define WDCC_IDENTIFY 0xec /* read parameters from controller */
-#define SET_FEATURES 0xef /* set features */
-
-#define WDCC_IDLE 0xe3 /* set idle timer & enter idle mode */
-#define WDCC_IDLE_IMMED 0xe1 /* enter idle mode */
-#define WDCC_SLEEP 0xe6 /* enter sleep mode */
-#define WDCC_STANDBY 0xe2 /* set standby timer & enter standby mode */
-#define WDCC_STANDBY_IMMED 0xe0 /* enter standby mode */
-#define WDCC_CHECK_PWR 0xe5 /* check power mode */
-
-#define WDCC_READ_EXT 0x24 /* read 48-bit addressing */
-#define WDCC_WRITE_EXT 0x34 /* write 48-bit addressing */
-
-#define WDCC_READMULTI_EXT 0x29 /* read multiple 48-bit addressing */
-#define WDCC_WRITEMULTI_EXT 0x39 /* write multiple 48-bit addressing */
-
-#define WDCC_READDMA_EXT 0x25 /* read 48-bit addressing with DMA */
-#define WDCC_WRITEDMA_EXT 0x35 /* write 48-bit addressing with DMA */
-
-#define WDCC_FLUSHCACHE_EXT 0xea /* 48-bit addressing flush cache */
-
-/* Subcommands for SET_FEATURES (features register ) */
-#define WDSF_8BIT_PIO_EN 0x01 /* Enable 8bit PIO (CFA featureset) */
-#define WDSF_EN_WR_CACHE 0x02
-#define WDSF_SET_MODE 0x03
-#define WDSF_REASSIGN_EN 0x04 /* Obsolete in ATA-6 */
-#define WDSF_APM_EN 0x05 /* Enable Adv. Power Management */
-#define WDSF_PUIS_EN 0x06 /* Enable Power-Up In Standby */
-#define WDSF_PUIS_SPINUP 0x07 /* Power-Up In Standby spin-up */
-#define WDSF_CFA_MODE1_EN 0x0A /* Enable CFA power mode 1 */
-#define WDSF_RMSN_DS 0x31 /* Disable Removable Media Status */
-#define WDSF_RETRY_DS 0x33 /* Obsolete in ATA-6 */
-#define WDSF_AAM_EN 0x42 /* Enable Autom. Acoustic Management */
-#define WDSF_SET_CACHE_SGMT 0x54 /* Obsolete in ATA-6 */
-#define WDSF_READAHEAD_DS 0x55 /* Disable read look-ahead */
-#define WDSF_RLSE_EN 0x5D /* Enable release interrupt */
-#define WDSF_SRV_EN 0x5E /* Enable SERVICE interrupt */
-#define WDSF_POD_DS 0x66
-#define WDSF_ECC_DS 0x77
-#define WDSF_8BIT_PIO_DS 0x81 /* Disable 8bit PIO (CFA featureset) */
-#define WDSF_WRITE_CACHE_DS 0x82
-#define WDSF_REASSIGN_DS 0x84
-#define WDSF_APM_DS 0x85 /* Disable Adv. Power Management */
-#define WDSF_PUIS_DS 0x86 /* Disable Power-Up In Standby */
-#define WDSF_ECC_EN 0x88
-#define WDSF_CFA_MODE1_DS 0x8A /* Disable CFA power mode 1 */
-#define WDSF_RMSN_EN 0x95 /* Enable Removable Media Status */
-#define WDSF_RETRY_EN 0x99 /* Obsolete in ATA-6 */
-#define WDSF_SET_CURRENT 0x9A /* Obsolete in ATA-6 */
-#define WDSF_READAHEAD_EN 0xAA
-#define WDSF_PREFETCH_SET 0xAB /* Obsolete in ATA-6 */
-#define WDSF_AAM_DS 0xC2 /* Disable Autom. Acoustic Management */
-#define WDSF_POD_EN 0xCC
-#define WDSF_RLSE_DS 0xDD /* Disable release interrupt */
-#define WDSF_SRV_DS 0xDE /* Disable SERVICE interrupt */
-#define WDSF_READ_NATIVE_MAX 0xF8
-#define WDSF_SEEK 0x70
-#define WDSF_VERIFY 0x40
-
-/* parameters uploaded to device/heads register */
-#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
-#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
-#define WDSD_LBA 0x40 /* logical block addressing */
-
-/* Commands for ATAPI devices */
-#define ATAPI_CHECK_POWER_MODE 0xe5
-#define ATAPI_EXEC_DRIVE_DIAGS 0x90
-#define ATAPI_IDLE_IMMEDIATE 0xe1
-#define ATAPI_NOP 0x00
-#define ATAPI_PKT_CMD 0xa0
-#define ATAPI_IDENTIFY_DEVICE 0xa1
-#define ATAPI_SOFT_RESET 0x08
-#define ATAPI_DEVICE_RESET 0x08 /* ATA/ATAPI-5 name for soft reset */
-#define ATAPI_SLEEP 0xe6
-#define ATAPI_STANDBY_IMMEDIATE 0xe0
-#define ATAPI_SMART 0xB0 /* SMART operations */
-#define ATAPI_SETMAX 0xF9 /* Set Max Address */
-#define ATAPI_WRITEEXT 0x34 /* Write sectors Ext */
-#define ATAPI_SETMAXEXT 0x37 /* Set Max Address Ext */
-#define ATAPI_WRITEMULTIEXT 0x39 /* Write Multi Ext */
-
-/* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */
-#define ATAPI_PKT_CMD_FTRE_DMA 0x01
-#define ATAPI_PKT_CMD_FTRE_OVL 0x02
-
-/* ireason */
-#define WDCI_CMD 0x01 /* command(1) or data(0) */
-#define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */
-#define WDCI_RELEASE 0x04 /* bus released until completion */
-
-#define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD)
-#define PHASE_DATAIN (WDCS_DRQ | WDCI_IN)
-#define PHASE_DATAOUT WDCS_DRQ
-#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
-#define PHASE_ABORTED 0
-
-#endif /* !_DEV_IC_WDCREG_H_ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Simple disk interface for the system console
- */
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <cstring>
-#include <string>
-
-#include "base/misc.hh"
-#include "base/trace.hh"
-#include "debug/SimpleDisk.hh"
-#include "debug/SimpleDiskData.hh"
-#include "dev/disk_image.hh"
-#include "dev/simple_disk.hh"
-#include "mem/port_proxy.hh"
-#include "sim/system.hh"
-
-using namespace std;
-
-SimpleDisk::SimpleDisk(const Params *p)
- : SimObject(p), system(p->system), image(p->disk)
-{}
-
-SimpleDisk::~SimpleDisk()
-{}
-
-
-void
-SimpleDisk::read(Addr addr, baddr_t block, int count) const
-{
- uint8_t *data = new uint8_t[SectorSize * 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);
-
- system->physProxy.writeBlob(addr, data, count);
-
- DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count);
- DDUMP(SimpleDiskData, data, count);
-
- delete [] data;
-}
-
-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
-}
-
-SimpleDisk *
-SimpleDiskParams::create()
-{
- return new SimpleDisk(this);
-}
+++ /dev/null
-/*
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Simple disk interface for the system console
- */
-
-#ifndef __DEV_SIMPLE_DISK_HH__
-#define __DEV_SIMPLE_DISK_HH__
-
-#include "params/SimpleDisk.hh"
-#include "sim/sim_object.hh"
-
-class DiskImage;
-class System;
-
-/*
- * Trivial interface to a disk image used by the System Console
- */
-class SimpleDisk : public SimObject
-{
- public:
- typedef uint64_t baddr_t;
-
- protected:
- System *system;
- DiskImage *image;
-
- public:
- typedef SimpleDiskParams Params;
- SimpleDisk(const Params *p);
- ~SimpleDisk();
-
- void read(Addr addr, baddr_t block, int count) const;
- void write(Addr addr, baddr_t block, int count);
-};
-
-#endif // __DEV_SIMPLE_DISK_HH__
#ifndef __DEV_SPARC_IOB_HH__
#define __DEV_SPARC_IOB_HH__
-#include "dev/disk_image.hh"
#include "dev/io_device.hh"
#include "params/Iob.hh"
#ifndef __DEV_SPARC_MM_DISK_HH__
#define __DEV_SPARC_MM_DISK_HH__
-#include "dev/disk_image.hh"
#include "dev/io_device.hh"
+#include "dev/storage/disk_image.hh"
#include "params/MmDisk.hh"
class MmDisk : public BasicPioDevice
--- /dev/null
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+from m5.SimObject import SimObject
+from m5.params import *
+class DiskImage(SimObject):
+ type = 'DiskImage'
+ abstract = True
+ cxx_header = "dev/storage/disk_image.hh"
+ image_file = Param.String("disk image file")
+ read_only = Param.Bool(False, "read only image")
+
+class RawDiskImage(DiskImage):
+ type = 'RawDiskImage'
+ cxx_header = "dev/storage/disk_image.hh"
+
+class CowDiskImage(DiskImage):
+ type = 'CowDiskImage'
+ cxx_header = "dev/storage/disk_image.hh"
+ child = Param.DiskImage(RawDiskImage(read_only=True),
+ "child image")
+ table_size = Param.Int(65536, "initial table size")
+ image_file = ""
--- /dev/null
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+from m5.SimObject import SimObject
+from m5.params import *
+from PciDevice import PciDevice
+
+class IdeID(Enum): vals = ['master', 'slave']
+
+class IdeDisk(SimObject):
+ type = 'IdeDisk'
+ cxx_header = "dev/storage/ide_disk.hh"
+ delay = Param.Latency('1us', "Fixed disk delay in microseconds")
+ driveID = Param.IdeID('master', "Drive ID")
+ image = Param.DiskImage("Disk image")
+
+class IdeController(PciDevice):
+ type = 'IdeController'
+ cxx_header = "dev/storage/ide_ctrl.hh"
+ disks = VectorParam.IdeDisk("IDE disks attached to this controller")
+
+ VendorID = 0x8086
+ DeviceID = 0x7111
+ Command = 0x0
+ Status = 0x280
+ Revision = 0x0
+ ClassCode = 0x01
+ SubClassCode = 0x01
+ ProgIF = 0x85
+ BAR0 = 0x00000001
+ BAR1 = 0x00000001
+ BAR2 = 0x00000001
+ BAR3 = 0x00000001
+ BAR4 = 0x00000001
+ BAR5 = 0x00000001
+ InterruptLine = 0x1f
+ InterruptPin = 0x01
+ BAR0Size = '8B'
+ BAR1Size = '4B'
+ BAR2Size = '8B'
+ BAR3Size = '4B'
+ BAR4Size = '16B'
+
+ io_shift = Param.UInt32(0x0, "IO port shift");
+ ctrl_offset = Param.UInt32(0x0, "IDE disk control offset")
--- /dev/null
+# -*- mode:python -*-
+
+# Copyright (c) 2015 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Steve Reinhardt
+# Gabe Black
+# Andreas Sandberg
+
+Import('*')
+
+if env['TARGET_ISA'] == 'null':
+ Return()
+
+# Controllers
+SimObject('Ide.py')
+
+Source('ide_ctrl.cc')
+Source('ide_disk.cc')
+
+DebugFlag('IdeCtrl')
+DebugFlag('IdeDisk')
+
+# Disk models
+SimObject('DiskImage.py')
+SimObject('SimpleDisk.py')
+
+Source('disk_image.cc')
+Source('simple_disk.cc')
+
+DebugFlag('DiskImageRead')
+DebugFlag('DiskImageWrite')
+DebugFlag('SimpleDisk')
+DebugFlag('SimpleDiskData')
+
+
+CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
+CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])
--- /dev/null
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+
+class SimpleDisk(SimObject):
+ type = 'SimpleDisk'
+ cxx_header = "dev/storage/simple_disk.hh"
+ disk = Param.DiskImage("Disk Image")
+ system = Param.System(Parent.any, "System Pointer")
--- /dev/null
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/** @file
+ * Disk Image Definitions
+ */
+
+#include "dev/storage/disk_image.hh"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+#include <string>
+
+#include "base/callback.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/DiskImageRead.hh"
+#include "debug/DiskImageWrite.hh"
+#include "sim/byteswap.hh"
+#include "sim/sim_exit.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Raw Disk image
+//
+RawDiskImage::RawDiskImage(const Params* p)
+ : DiskImage(p), disk_size(0)
+{ open(p->image_file, p->read_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();
+}
+
+std::streampos
+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;
+}
+
+std::streampos
+RawDiskImage::read(uint8_t *data, std::streampos offset) const
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ if (!stream.is_open())
+ panic("file not open!\n");
+
+ stream.seekg(offset * SectorSize, ios::beg);
+ if (!stream.good())
+ panic("Could not seek to location in file");
+
+ streampos 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;
+}
+
+std::streampos
+RawDiskImage::write(const uint8_t *data, std::streampos 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");
+
+ stream.seekp(offset * SectorSize, ios::beg);
+ if (!stream.good())
+ panic("Could not seek to location in file");
+
+ DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
+ DDUMP(DiskImageWrite, data, SectorSize);
+
+ streampos pos = stream.tellp();
+ stream.write((const char *)data, SectorSize);
+ return stream.tellp() - pos;
+}
+
+RawDiskImage *
+RawDiskImageParams::create()
+{
+ return new RawDiskImage(this);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Copy on Write Disk image
+//
+const uint32_t CowDiskImage::VersionMajor = 1;
+const uint32_t CowDiskImage::VersionMinor = 0;
+
+class CowDiskCallback : public Callback
+{
+ private:
+ CowDiskImage *image;
+
+ public:
+ CowDiskCallback(CowDiskImage *i) : image(i) {}
+ void process() { image->save(); delete this; }
+};
+
+CowDiskImage::CowDiskImage(const Params *p)
+ : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
+{
+ if (filename.empty()) {
+ initSectorTable(p->table_size);
+ } else {
+ if (!open(filename)) {
+ if (p->read_only)
+ fatal("could not open read-only file");
+ initSectorTable(p->table_size);
+ }
+
+ if (!p->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));
+}
+
+template<class T>
+void
+SafeReadSwap(ifstream &stream, T &data)
+{
+ SafeRead(stream, &data, sizeof(data));
+ data = letoh(data); //is this the proper byte order conversion?
+}
+
+bool
+CowDiskImage::open(const string &file)
+{
+ ifstream stream(file.c_str());
+ if (!stream.is_open())
+ return false;
+
+ if (stream.fail() || stream.bad())
+ panic("Error opening %s", file);
+
+ uint64_t magic;
+ SafeRead(stream, magic);
+
+ if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
+ panic("Could not open %s: Invalid magic", file);
+
+ uint32_t major, minor;
+ SafeReadSwap(stream, major);
+ SafeReadSwap(stream, minor);
+
+ if (major != VersionMajor && minor != VersionMinor)
+ panic("Could not open %s: invalid version %d.%d != %d.%d",
+ file, major, minor, VersionMajor, VersionMinor);
+
+ uint64_t sector_count;
+ SafeReadSwap(stream, sector_count);
+ table = new SectorTable(sector_count);
+
+
+ for (uint64_t i = 0; i < sector_count; i++) {
+ uint64_t offset;
+ SafeReadSwap(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::initSectorTable(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));
+}
+
+template<class T>
+void
+SafeWriteSwap(ofstream &stream, const T &data)
+{
+ T swappeddata = letoh(data); //is this the proper byte order conversion?
+ SafeWrite(stream, &swappeddata, sizeof(data));
+}
+void
+CowDiskImage::save() const
+{
+ save(filename);
+}
+
+void
+CowDiskImage::save(const string &file) const
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ ofstream stream(file.c_str());
+ if (!stream.is_open() || stream.fail() || stream.bad())
+ panic("Error opening %s", file);
+
+ uint64_t magic;
+ memcpy(&magic, "COWDISK!", sizeof(magic));
+ SafeWrite(stream, magic);
+
+ SafeWriteSwap(stream, (uint32_t)VersionMajor);
+ SafeWriteSwap(stream, (uint32_t)VersionMinor);
+ SafeWriteSwap(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");
+
+ SafeWriteSwap(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;
+ }
+}
+
+std::streampos
+CowDiskImage::size() const
+{ return child->size(); }
+
+std::streampos
+CowDiskImage::read(uint8_t *data, std::streampos 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;
+ }
+}
+
+std::streampos
+CowDiskImage::write(const uint8_t *data, std::streampos 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;
+}
+
+void
+CowDiskImage::serialize(CheckpointOut &cp) const
+{
+ string cowFilename = name() + ".cow";
+ SERIALIZE_SCALAR(cowFilename);
+ save(CheckpointIn::dir() + "/" + cowFilename);
+}
+
+void
+CowDiskImage::unserialize(CheckpointIn &cp)
+{
+ string cowFilename;
+ UNSERIALIZE_SCALAR(cowFilename);
+ cowFilename = cp.cptDir + "/" + cowFilename;
+ open(cowFilename);
+}
+
+CowDiskImage *
+CowDiskImageParams::create()
+{
+ return new CowDiskImage(this);
+}
--- /dev/null
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/** @file
+ * Disk Image Interfaces
+ */
+
+#ifndef __DEV_STORAGE_DISK_IMAGE_HH__
+#define __DEV_STORAGE_DISK_IMAGE_HH__
+
+#include <fstream>
+#include <unordered_map>
+
+#include "params/CowDiskImage.hh"
+#include "params/DiskImage.hh"
+#include "params/RawDiskImage.hh"
+#include "sim/sim_object.hh"
+
+#define SectorSize (512)
+
+/**
+ * Basic interface for accessing a disk image.
+ */
+class DiskImage : public SimObject
+{
+ protected:
+ bool initialized;
+
+ public:
+ typedef DiskImageParams Params;
+ DiskImage(const Params *p) : SimObject(p), initialized(false) {}
+ virtual ~DiskImage() {}
+
+ virtual std::streampos size() const = 0;
+
+ virtual std::streampos read(uint8_t *data,
+ std::streampos offset) const = 0;
+ virtual std::streampos write(const uint8_t *data,
+ std::streampos offset) = 0;
+};
+
+/**
+ * Specialization for accessing a raw disk image
+ */
+class RawDiskImage : public DiskImage
+{
+ protected:
+ mutable std::fstream stream;
+ std::string file;
+ bool readonly;
+ mutable std::streampos disk_size;
+
+ public:
+ typedef RawDiskImageParams Params;
+ RawDiskImage(const Params *p);
+ ~RawDiskImage();
+
+ void close();
+ void open(const std::string &filename, bool rd_only = false);
+
+ virtual std::streampos size() const;
+
+ virtual std::streampos read(uint8_t *data, std::streampos offset) const;
+ virtual std::streampos write(const uint8_t *data, std::streampos 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 uint32_t VersionMajor;
+ static const uint32_t VersionMinor;
+
+ protected:
+ struct Sector {
+ uint8_t data[SectorSize];
+ };
+ typedef std::unordered_map<uint64_t, Sector *> SectorTable;
+
+ protected:
+ std::string filename;
+ DiskImage *child;
+ SectorTable *table;
+
+ public:
+ typedef CowDiskImageParams Params;
+ CowDiskImage(const Params *p);
+ ~CowDiskImage();
+
+ void initSectorTable(int hash_size);
+ bool open(const std::string &file);
+ void save() const;
+ void save(const std::string &file) const;
+ void writeback();
+
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+
+ std::streampos size() const override;
+
+ std::streampos read(uint8_t *data, std::streampos offset) const override;
+ std::streampos write(const uint8_t *data, std::streampos offset) override;
+};
+
+void SafeRead(std::ifstream &stream, void *data, int count);
+
+template<class T>
+void SafeRead(std::ifstream &stream, T &data);
+
+template<class T>
+void SafeReadSwap(std::ifstream &stream, T &data);
+
+void SafeWrite(std::ofstream &stream, const void *data, int count);
+
+template<class T>
+void SafeWrite(std::ofstream &stream, const T &data);
+
+template<class T>
+void SafeWriteSwap(std::ofstream &stream, const T &data);
+
+#endif // __DEV_STORAGE_DISK_IMAGE_HH__
--- /dev/null
+/* $OpenBSD: atareg.h,v 1.12 2004/09/24 07:15:22 grange Exp $ */
+/* $NetBSD: atareg.h,v 1.5 1999/01/18 20:06:24 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1998, 2001 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _DEV_ATA_ATAREG_H_
+#define _DEV_ATA_ATAREG_H_
+
+#if defined(__linux__)
+#include <endian.h>
+
+#elif defined(__sun)
+#include <sys/isa_defs.h>
+
+#else
+#include <machine/endian.h>
+
+#endif
+
+#ifdef LITTLE_ENDIAN
+#define ATA_BYTE_ORDER LITTLE_ENDIAN
+#elif defined(BIG_ENDIAN)
+#define ATA_BYTE_ORDER BIG_ENDIAN
+#elif defined(_LITTLE_ENDIAN)
+#define ATA_BYTE_ORDER 1
+#define LITTLE_ENDIAN 1
+#elif defined(_BIG_ENDIAN)
+#define ATA_BYTE_ORDER 0
+#define LITTLE_ENDIAN 1
+#else
+#error "No endianess defined"
+#endif
+
+/*
+ * Drive parameter structure for ATA/ATAPI.
+ * Bit fields: WDC_* : common to ATA/ATAPI
+ * ATA_* : ATA only
+ * ATAPI_* : ATAPI only.
+ */
+struct ataparams {
+ /* drive info */
+ uint16_t atap_config; /* 0: general configuration */
+#define WDC_CFG_ATAPI_MASK 0xc000
+#define WDC_CFG_ATAPI 0x8000
+#define ATA_CFG_REMOVABLE 0x0080
+#define ATA_CFG_FIXED 0x0040
+#define ATAPI_CFG_TYPE_MASK 0x1f00
+#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8)
+#define ATAPI_CFG_TYPE_DIRECT 0x00
+#define ATAPI_CFG_TYPE_SEQUENTIAL 0x01
+#define ATAPI_CFG_TYPE_CDROM 0x05
+#define ATAPI_CFG_TYPE_OPTICAL 0x07
+#define ATAPI_CFG_TYPE_NODEVICE 0x1F
+#define ATAPI_CFG_REMOV 0x0080
+#define ATAPI_CFG_DRQ_MASK 0x0060
+#define ATAPI_CFG_STD_DRQ 0x0000
+#define ATAPI_CFG_IRQ_DRQ 0x0020
+#define ATAPI_CFG_ACCEL_DRQ 0x0040
+#define ATAPI_CFG_CMD_MASK 0x0003
+#define ATAPI_CFG_CMD_12 0x0000
+#define ATAPI_CFG_CMD_16 0x0001
+/* words 1-9 are ATA only */
+ uint16_t atap_cylinders; /* 1: # of non-removable cylinders */
+ uint16_t __reserved1;
+ uint16_t atap_heads; /* 3: # of heads */
+ uint16_t __retired1[2]; /* 4-5: # of unform. bytes/track */
+ uint16_t atap_sectors; /* 6: # of sectors */
+ uint16_t __retired2[3];
+
+ uint8_t atap_serial[20]; /* 10-19: serial number */
+ uint16_t __retired3[2];
+ uint16_t __obsolete1;
+ uint8_t atap_revision[8]; /* 23-26: firmware revision */
+ uint8_t atap_model[40]; /* 27-46: model number */
+ uint16_t atap_multi; /* 47: maximum sectors per irq (ATA) */
+ uint16_t __reserved2;
+ uint8_t atap_vendor; /* 49: vendor */
+ uint8_t atap_capabilities1; /* 49: capability flags */
+#define WDC_CAP_IORDY 0x0800
+#define WDC_CAP_IORDY_DSBL 0x0400
+#define WDC_CAP_LBA 0x0200
+#define WDC_CAP_DMA 0x0100
+#define ATA_CAP_STBY 0x2000
+#define ATAPI_CAP_INTERL_DMA 0x8000
+#define ATAPI_CAP_CMD_QUEUE 0x4000
+#define ATAPI_CAP_OVERLP 0x2000
+#define ATAPI_CAP_ATA_RST 0x1000
+ uint16_t atap_capabilities2; /* 50: capability flags (ATA) */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t __junk2;
+ uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
+ uint8_t __junk3;
+ uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
+#else
+ uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
+ uint8_t __junk2;
+ uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
+ uint8_t __junk3;
+#endif
+ uint16_t atap_extensions; /* 53: extensions supported */
+#define WDC_EXT_UDMA_MODES 0x0004
+#define WDC_EXT_MODES 0x0002
+#define WDC_EXT_GEOM 0x0001
+/* words 54-62 are ATA only */
+ uint16_t atap_curcylinders; /* 54: current logical cylinders */
+ uint16_t atap_curheads; /* 55: current logical heads */
+ uint16_t atap_cursectors; /* 56: current logical sectors/tracks */
+ uint16_t atap_curcapacity[2]; /* 57-58: current capacity */
+ uint8_t atap_curmulti; /* 59: current multi-sector setting */
+ uint8_t atap_curmulti_valid; /* 59: current multi-sector setting */
+#define WDC_MULTI_VALID 0x0100
+#define WDC_MULTI_MASK 0x00ff
+ uint32_t atap_capacity; /* 60-61: total capacity (LBA only) */
+ uint16_t __retired4;
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
+ uint8_t atap_dmamode_act; /* multiword DMA mode active */
+ uint8_t atap_piomode_supp; /* 64: PIO mode supported */
+ uint8_t __junk4;
+#else
+ uint8_t atap_dmamode_act; /* multiword DMA mode active */
+ uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
+ uint8_t __junk4;
+ uint8_t atap_piomode_supp; /* 64: PIO mode supported */
+#endif
+ uint16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */
+ uint16_t atap_dmatiming_recom; /* 66: recommended DMA cycle time */
+ uint16_t atap_piotiming; /* 67: mini PIO cycle time without FC */
+ uint16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */
+ uint16_t __reserved3[2];
+/* words 71-72 are ATAPI only */
+ uint16_t atap_pkt_br; /* 71: time (ns) to bus release */
+ uint16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */
+ uint16_t __reserved4[2];
+ uint16_t atap_queuedepth; /* 75: */
+#define WDC_QUEUE_DEPTH_MASK 0x1f
+ uint16_t atap_sata_caps; /* 76: SATA capabilities */
+#define SATA_SIGNAL_GEN1 0x0002 /* SATA Gen-1 signaling speed */
+#define SATA_SIGNAL_GEN2 0x0004 /* SATA Gen-2 signaling speed */
+#define SATA_NATIVE_CMDQ 0x0100 /* native command queuing */
+#define SATA_HOST_PWR_MGMT 0x0200 /* power management (host) */
+ uint16_t atap_sata_reserved; /* 77: reserved */
+ uint16_t atap_sata_features_supp;/* 78: SATA features supported */
+#define SATA_NONZERO_OFFSETS 0x0002 /* non-zero buffer offsets */
+#define SATA_DMA_SETUP_AUTO 0x0004 /* DMA setup auto-activate */
+#define SATA_DRIVE_PWR_MGMT 0x0008 /* power management (device) */
+ uint16_t atap_sata_features_en; /* 79: SATA features enabled */
+ uint16_t atap_ata_major; /* 80: Major version number */
+#define WDC_VER_ATA1 0x0002
+#define WDC_VER_ATA2 0x0004
+#define WDC_VER_ATA3 0x0008
+#define WDC_VER_ATA4 0x0010
+#define WDC_VER_ATA5 0x0020
+#define WDC_VER_ATA6 0x0040
+#define WDC_VER_ATA7 0x0080
+#define WDC_VER_ATA8 0x0100
+#define WDC_VER_ATA9 0x0200
+#define WDC_VER_ATA10 0x0400
+#define WDC_VER_ATA11 0x0800
+#define WDC_VER_ATA12 0x1000
+#define WDC_VER_ATA13 0x2000
+#define WDC_VER_ATA14 0x4000
+ uint16_t atap_ata_minor; /* 81: Minor version number */
+ uint16_t atap_cmd_set1; /* 82: command set supported */
+#define WDC_CMD1_NOP 0x4000
+#define WDC_CMD1_RB 0x2000
+#define WDC_CMD1_WB 0x1000
+#define WDC_CMD1_HPA 0x0400
+#define WDC_CMD1_DVRST 0x0200
+#define WDC_CMD1_SRV 0x0100
+#define WDC_CMD1_RLSE 0x0080
+#define WDC_CMD1_AHEAD 0x0040
+#define WDC_CMD1_CACHE 0x0020
+#define WDC_CMD1_PKT 0x0010
+#define WDC_CMD1_PM 0x0008
+#define WDC_CMD1_REMOV 0x0004
+#define WDC_CMD1_SEC 0x0002
+#define WDC_CMD1_SMART 0x0001
+ uint16_t atap_cmd_set2; /* 83: command set supported */
+#define ATAPI_CMD2_FCE 0x2000 /* Flush Cache Ext supported */
+#define ATAPI_CMD2_FC 0x1000 /* Flush Cache supported */
+#define ATAPI_CMD2_DCO 0x0800 /* Device Configuration Overlay supported */
+#define ATAPI_CMD2_48AD 0x0400 /* 48bit address supported */
+#define ATAPI_CMD2_AAM 0x0200 /* Automatic Acoustic Management supported */
+#define ATAPI_CMD2_SM 0x0100 /* Set Max security extension supported */
+#define ATAPI_CMD2_SF 0x0040 /* Set Features subcommand required */
+#define ATAPI_CMD2_PUIS 0x0020 /* Power up in standby supported */
+#define WDC_CMD2_RMSN 0x0010
+#define ATA_CMD2_APM 0x0008
+#define ATA_CMD2_CFA 0x0004
+#define ATA_CMD2_RWQ 0x0002
+#define WDC_CMD2_DM 0x0001 /* Download Microcode supported */
+ uint16_t atap_cmd_ext; /* 84: command/features supp. ext. */
+#define ATAPI_CMDE_MSER 0x0004 /* Media serial number supported */
+#define ATAPI_CMDE_TEST 0x0002 /* SMART self-test supported */
+#define ATAPI_CMDE_SLOG 0x0001 /* SMART error logging supported */
+ uint16_t atap_cmd1_en; /* 85: cmd/features enabled */
+/* bits are the same as atap_cmd_set1 */
+ uint16_t atap_cmd2_en; /* 86: cmd/features enabled */
+/* bits are the same as atap_cmd_set2 */
+ uint16_t atap_cmd_def; /* 87: cmd/features default */
+/* bits are NOT the same as atap_cmd_ext */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
+ uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
+#else
+ uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
+ uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
+#endif
+/* 89-92 are ATA-only */
+ uint16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */
+ uint16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */
+ uint16_t atap_apm_val; /* 91: current APM value */
+ uint16_t atap_mpasswd_rev; /* 92: Master Password revision */
+ uint16_t atap_hwreset_res; /* 93: Hardware reset value */
+#define ATA_HWRES_CBLID 0x2000 /* CBLID above Vih */
+#define ATA_HWRES_D1_PDIAG 0x0800 /* Device 1 PDIAG detect OK */
+#define ATA_HWRES_D1_CSEL 0x0400 /* Device 1 used CSEL for address */
+#define ATA_HWRES_D1_JUMP 0x0200 /* Device 1 jumpered to address */
+#define ATA_HWRES_D0_SEL 0x0040 /* Device 0 responds when Dev 1 selected */
+#define ATA_HWRES_D0_DASP 0x0020 /* Device 0 DASP detect OK */
+#define ATA_HWRES_D0_PDIAG 0x0010 /* Device 0 PDIAG detect OK */
+#define ATA_HWRES_D0_DIAG 0x0008 /* Device 0 diag OK */
+#define ATA_HWRES_D0_CSEL 0x0004 /* Device 0 used CSEL for address */
+#define ATA_HWRES_D0_JUMP 0x0002 /* Device 0 jumpered to address */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_acoustic_val; /* 94: Current acoustic level */
+ uint8_t atap_acoustic_def; /* recommended level */
+#else
+ uint8_t atap_acoustic_def; /* recommended level */
+ uint8_t atap_acoustic_val; /* 94: Current acoustic level */
+#endif
+ uint16_t __reserved6[5]; /* 95-99: reserved */
+ uint16_t atap_max_lba[4]; /* 100-103: Max. user LBA add */
+ uint16_t __reserved7[23]; /* 104-126: reserved */
+ uint16_t atap_rmsn_supp; /* 127: remov. media status notif. */
+#define WDC_RMSN_SUPP_MASK 0x0003
+#define WDC_RMSN_SUPP 0x0001
+ uint16_t atap_sec_st; /* 128: security status */
+#define WDC_SEC_LEV_MAX 0x0100
+#define WDC_SEC_ESE_SUPP 0x0020
+#define WDC_SEC_EXP 0x0010
+#define WDC_SEC_FROZEN 0x0008
+#define WDC_SEC_LOCKED 0x0004
+#define WDC_SEC_EN 0x0002
+#define WDC_SEC_SUPP 0x0001
+ uint16_t __reserved8[31]; /* 129-159: vendor specific */
+ uint16_t atap_cfa_power; /* 160: CFA powermode */
+#define ATAPI_CFA_MAX_MASK 0x0FFF
+#define ATAPI_CFA_MODE1_DIS 0x1000 /* CFA Mode 1 Disabled */
+#define ATAPI_CFA_MODE1_REQ 0x2000 /* CFA Mode 1 Required */
+#define ATAPI_CFA_WORD160 0x8000 /* Word 160 supported */
+ uint16_t __reserved9[15]; /* 161-175: reserved for CFA */
+ uint8_t atap_media_serial[60]; /* 176-205: media serial number */
+ uint16_t __reserved10[49]; /* 206-254: reserved */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_signature; /* 255: Signature */
+ uint8_t atap_checksum; /* Checksum */
+#else
+ uint8_t atap_checksum; /* Checksum */
+ uint8_t atap_signature; /* 255: Signature */
+#endif
+};
+
+#undef ATA_BYTE_ORDER
+#endif /* !_DEV_ATA_ATAREG_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andrew Schultz
+ * Ali Saidi
+ * Miguel Serrano
+ */
+
+#include "dev/storage/ide_ctrl.hh"
+
+#include <string>
+
+#include "cpu/intr_control.hh"
+#include "debug/IdeCtrl.hh"
+#include "dev/storage/ide_disk.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/IdeController.hh"
+#include "sim/byteswap.hh"
+
+// clang complains about std::set being overloaded with Packet::set if
+// we open up the entire namespace std
+using std::string;
+
+// Bus master IDE registers
+enum BMIRegOffset {
+ BMICommand = 0x0,
+ BMIStatus = 0x2,
+ BMIDescTablePtr = 0x4
+};
+
+// PCI config space registers
+enum ConfRegOffset {
+ PrimaryTiming = 0x40,
+ SecondaryTiming = 0x42,
+ DeviceTiming = 0x44,
+ UDMAControl = 0x48,
+ UDMATiming = 0x4A,
+ IDEConfig = 0x54
+};
+
+static const uint16_t timeRegWithDecodeEn = 0x8000;
+
+IdeController::Channel::Channel(
+ string newName, Addr _cmdSize, Addr _ctrlSize) :
+ _name(newName),
+ cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
+ master(NULL), slave(NULL), selected(NULL)
+{
+ memset(&bmiRegs, 0, sizeof(bmiRegs));
+ bmiRegs.status.dmaCap0 = 1;
+ bmiRegs.status.dmaCap1 = 1;
+}
+
+IdeController::Channel::~Channel()
+{
+}
+
+IdeController::IdeController(Params *p)
+ : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
+ secondary(name() + ".secondary", BARSize[2], BARSize[3]),
+ bmiAddr(0), bmiSize(BARSize[4]),
+ primaryTiming(htole(timeRegWithDecodeEn)),
+ secondaryTiming(htole(timeRegWithDecodeEn)),
+ deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
+ ioEnabled(false), bmEnabled(false),
+ ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
+{
+ if (params()->disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
+
+ // Assign the disks to channels
+ int numDisks = params()->disks.size();
+ if (numDisks > 0)
+ primary.master = params()->disks[0];
+ if (numDisks > 1)
+ primary.slave = params()->disks[1];
+ if (numDisks > 2)
+ secondary.master = params()->disks[2];
+ if (numDisks > 3)
+ secondary.slave = params()->disks[3];
+
+ for (int i = 0; i < params()->disks.size(); i++) {
+ params()->disks[i]->setController(this);
+ }
+ primary.select(false);
+ secondary.select(false);
+
+ if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
+ primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0];
+ primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
+ }
+ if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
+ secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2];
+ secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
+ }
+
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
+}
+
+bool
+IdeController::isDiskSelected(IdeDisk *diskPtr)
+{
+ return (primary.selected == diskPtr || secondary.selected == diskPtr);
+}
+
+void
+IdeController::intrPost()
+{
+ primary.bmiRegs.status.intStatus = 1;
+ PciDevice::intrPost();
+}
+
+void
+IdeController::setDmaComplete(IdeDisk *disk)
+{
+ Channel *channel;
+ if (disk == primary.master || disk == primary.slave) {
+ channel = &primary;
+ } else if (disk == secondary.master || disk == secondary.slave) {
+ channel = &secondary;
+ } else {
+ panic("Unable to find disk based on pointer %#x\n", disk);
+ }
+
+ channel->bmiRegs.command.startStop = 0;
+ channel->bmiRegs.status.active = 0;
+ channel->bmiRegs.status.intStatus = 1;
+}
+
+Tick
+IdeController::readConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ return PciDevice::readConfig(pkt);
+ }
+
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ switch (offset) {
+ case DeviceTiming:
+ pkt->set<uint8_t>(deviceTiming);
+ break;
+ case UDMAControl:
+ pkt->set<uint8_t>(udmaControl);
+ break;
+ case PrimaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
+ break;
+ case SecondaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
+ break;
+ case IDEConfig:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
+ break;
+ case IDEConfig + 1:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ switch (offset) {
+ case UDMAControl:
+ pkt->set<uint16_t>(udmaControl);
+ break;
+ case PrimaryTiming:
+ pkt->set<uint16_t>(primaryTiming);
+ break;
+ case SecondaryTiming:
+ pkt->set<uint16_t>(secondaryTiming);
+ break;
+ case UDMATiming:
+ pkt->set<uint16_t>(udmaTiming);
+ break;
+ case IDEConfig:
+ pkt->set<uint16_t>(ideConfig);
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ switch (offset) {
+ case PrimaryTiming:
+ pkt->set<uint32_t>(primaryTiming);
+ break;
+ case IDEConfig:
+ pkt->set<uint32_t>(ideConfig);
+ break;
+ default:
+ panic("No 32bit reads implemented for this device.");
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint32_t>());
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ return configDelay;
+}
+
+
+Tick
+IdeController::writeConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDevice::writeConfig(pkt);
+ } else {
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ switch (offset) {
+ case DeviceTiming:
+ deviceTiming = pkt->get<uint8_t>();
+ break;
+ case UDMAControl:
+ udmaControl = pkt->get<uint8_t>();
+ break;
+ case IDEConfig:
+ replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
+ break;
+ case IDEConfig + 1:
+ replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
+ break;
+ default:
+ panic("Invalid PCI configuration write "
+ "for size 1 offset: %#x!\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
+ offset, (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ switch (offset) {
+ case UDMAControl:
+ udmaControl = pkt->get<uint16_t>();
+ break;
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint16_t>();
+ break;
+ case SecondaryTiming:
+ secondaryTiming = pkt->get<uint16_t>();
+ break;
+ case UDMATiming:
+ udmaTiming = pkt->get<uint16_t>();
+ break;
+ case IDEConfig:
+ ideConfig = pkt->get<uint16_t>();
+ break;
+ default:
+ panic("Invalid PCI configuration write "
+ "for size 2 offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
+ offset, (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ switch (offset) {
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint32_t>();
+ break;
+ case IDEConfig:
+ ideConfig = pkt->get<uint32_t>();
+ break;
+ default:
+ panic("Write of unimplemented PCI config. register: %x\n", offset);
+ }
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ }
+
+ /* Trap command register writes and enable IO/BM as appropriate as well as
+ * BARs. */
+ switch(offset) {
+ case PCI0_BASE_ADDR0:
+ if (BARAddrs[0] != 0)
+ primary.cmdAddr = BARAddrs[0];
+ break;
+
+ case PCI0_BASE_ADDR1:
+ if (BARAddrs[1] != 0)
+ primary.ctrlAddr = BARAddrs[1];
+ break;
+
+ case PCI0_BASE_ADDR2:
+ if (BARAddrs[2] != 0)
+ secondary.cmdAddr = BARAddrs[2];
+ break;
+
+ case PCI0_BASE_ADDR3:
+ if (BARAddrs[3] != 0)
+ secondary.ctrlAddr = BARAddrs[3];
+ break;
+
+ case PCI0_BASE_ADDR4:
+ if (BARAddrs[4] != 0)
+ bmiAddr = BARAddrs[4];
+ break;
+
+ case PCI_COMMAND:
+ DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
+ break;
+ }
+ return configDelay;
+}
+
+void
+IdeController::Channel::accessCommand(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ const Addr SelectOffset = 6;
+ const uint8_t SelectDevBit = 0x10;
+
+ if (!read && offset == SelectOffset)
+ select(*data & SelectDevBit);
+
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readCommand(offset, size, data);
+ } else {
+ selected->writeCommand(offset, size, data);
+ }
+}
+
+void
+IdeController::Channel::accessControl(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readControl(offset, size, data);
+ } else {
+ selected->writeControl(offset, size, data);
+ }
+}
+
+void
+IdeController::Channel::accessBMI(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ assert(offset + size <= sizeof(BMIRegs));
+ if (read) {
+ memcpy(data, (uint8_t *)&bmiRegs + offset, size);
+ } else {
+ switch (offset) {
+ case BMICommand:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", size);
+
+ BMICommandReg oldVal = bmiRegs.command;
+ BMICommandReg newVal = *data;
+
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal.startStop && oldVal.rw != newVal.rw)
+ oldVal.rw = newVal.rw;
+
+ if (oldVal.startStop != newVal.startStop) {
+ if (selected == NULL)
+ panic("DMA start for disk which does not exist\n");
+
+ if (oldVal.startStop) {
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+ bmiRegs.status.active = 0;
+
+ selected->abortDma();
+ } else {
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ bmiRegs.status.active = 1;
+
+ selected->startDma(letoh(bmiRegs.bmidtp));
+ }
+ }
+
+ bmiRegs.command = newVal;
+ }
+ break;
+ case BMIStatus:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIS write size: %x\n", size);
+
+ BMIStatusReg oldVal = bmiRegs.status;
+ BMIStatusReg newVal = *data;
+
+ // the BMIDEA bit is read only
+ newVal.active = oldVal.active;
+
+ // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
+ if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
+ newVal.intStatus = 0; // clear the interrupt?
+ } else {
+ // Assigning two bitunion fields to each other does not
+ // work as intended, so we need to use this temporary variable
+ // to get around the bug.
+ uint8_t tmp = oldVal.intStatus;
+ newVal.intStatus = tmp;
+ }
+ if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
+ newVal.dmaError = 0;
+ } else {
+ uint8_t tmp = oldVal.dmaError;
+ newVal.dmaError = tmp;
+ }
+
+ bmiRegs.status = newVal;
+ }
+ break;
+ case BMIDescTablePtr:
+ if (size != sizeof(uint32_t))
+ panic("Invalid BMIDTP write size: %x\n", size);
+ bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
+ break;
+ default:
+ if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
+ size != sizeof(uint32_t))
+ panic("IDE controller write of invalid write size: %x\n", size);
+ memcpy((uint8_t *)&bmiRegs + offset, data, size);
+ }
+ }
+}
+
+void
+IdeController::dispatchAccess(PacketPtr pkt, bool read)
+{
+ if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
+ panic("Bad IDE read size: %d\n", pkt->getSize());
+
+ if (!ioEnabled) {
+ pkt->makeAtomicResponse();
+ DPRINTF(IdeCtrl, "io not enabled\n");
+ return;
+ }
+
+ Addr addr = pkt->getAddr();
+ int size = pkt->getSize();
+ uint8_t *dataPtr = pkt->getPtr<uint8_t>();
+
+ if (addr >= primary.cmdAddr &&
+ addr < (primary.cmdAddr + primary.cmdSize)) {
+ addr -= primary.cmdAddr;
+ // linux may have shifted the address by ioShift,
+ // here we shift it back, similarly for ctrlOffset.
+ addr >>= ioShift;
+ primary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= primary.ctrlAddr &&
+ addr < (primary.ctrlAddr + primary.ctrlSize)) {
+ addr -= primary.ctrlAddr;
+ addr += ctrlOffset;
+ primary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= secondary.cmdAddr &&
+ addr < (secondary.cmdAddr + secondary.cmdSize)) {
+ addr -= secondary.cmdAddr;
+ secondary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= secondary.ctrlAddr &&
+ addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
+ addr -= secondary.ctrlAddr;
+ secondary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
+ if (!read && !bmEnabled)
+ return;
+ addr -= bmiAddr;
+ if (addr < sizeof(Channel::BMIRegs)) {
+ primary.accessBMI(addr, size, dataPtr, read);
+ } else {
+ addr -= sizeof(Channel::BMIRegs);
+ secondary.accessBMI(addr, size, dataPtr, read);
+ }
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
+ }
+
+#ifndef NDEBUG
+ uint32_t data;
+ if (pkt->getSize() == 1)
+ data = pkt->get<uint8_t>();
+ else if (pkt->getSize() == 2)
+ data = pkt->get<uint16_t>();
+ else
+ data = pkt->get<uint32_t>();
+ DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
+ read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
+#endif
+
+ pkt->makeAtomicResponse();
+}
+
+Tick
+IdeController::read(PacketPtr pkt)
+{
+ dispatchAccess(pkt, true);
+ return pioDelay;
+}
+
+Tick
+IdeController::write(PacketPtr pkt)
+{
+ dispatchAccess(pkt, false);
+ return pioDelay;
+}
+
+void
+IdeController::serialize(CheckpointOut &cp) const
+{
+ // Serialize the PciDevice base class
+ PciDevice::serialize(cp);
+
+ // Serialize channels
+ primary.serialize("primary", cp);
+ secondary.serialize("secondary", cp);
+
+ // Serialize config registers
+ SERIALIZE_SCALAR(primaryTiming);
+ SERIALIZE_SCALAR(secondaryTiming);
+ SERIALIZE_SCALAR(deviceTiming);
+ SERIALIZE_SCALAR(udmaControl);
+ SERIALIZE_SCALAR(udmaTiming);
+ SERIALIZE_SCALAR(ideConfig);
+
+ // Serialize internal state
+ SERIALIZE_SCALAR(ioEnabled);
+ SERIALIZE_SCALAR(bmEnabled);
+ SERIALIZE_SCALAR(bmiAddr);
+ SERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::serialize(const std::string &base,
+ CheckpointOut &cp) const
+{
+ paramOut(cp, base + ".cmdAddr", cmdAddr);
+ paramOut(cp, base + ".cmdSize", cmdSize);
+ paramOut(cp, base + ".ctrlAddr", ctrlAddr);
+ paramOut(cp, base + ".ctrlSize", ctrlSize);
+ uint8_t command = bmiRegs.command;
+ paramOut(cp, base + ".bmiRegs.command", command);
+ paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status = bmiRegs.status;
+ paramOut(cp, base + ".bmiRegs.status", status);
+ paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramOut(cp, base + ".selectBit", selectBit);
+}
+
+void
+IdeController::unserialize(CheckpointIn &cp)
+{
+ // Unserialize the PciDevice base class
+ PciDevice::unserialize(cp);
+
+ // Unserialize channels
+ primary.unserialize("primary", cp);
+ secondary.unserialize("secondary", cp);
+
+ // Unserialize config registers
+ UNSERIALIZE_SCALAR(primaryTiming);
+ UNSERIALIZE_SCALAR(secondaryTiming);
+ UNSERIALIZE_SCALAR(deviceTiming);
+ UNSERIALIZE_SCALAR(udmaControl);
+ UNSERIALIZE_SCALAR(udmaTiming);
+ UNSERIALIZE_SCALAR(ideConfig);
+
+ // Unserialize internal state
+ UNSERIALIZE_SCALAR(ioEnabled);
+ UNSERIALIZE_SCALAR(bmEnabled);
+ UNSERIALIZE_SCALAR(bmiAddr);
+ UNSERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp)
+{
+ paramIn(cp, base + ".cmdAddr", cmdAddr);
+ paramIn(cp, base + ".cmdSize", cmdSize);
+ paramIn(cp, base + ".ctrlAddr", ctrlAddr);
+ paramIn(cp, base + ".ctrlSize", ctrlSize);
+ uint8_t command;
+ paramIn(cp, base +".bmiRegs.command", command);
+ bmiRegs.command = command;
+ paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status;
+ paramIn(cp, base + ".bmiRegs.status", status);
+ bmiRegs.status = status;
+ paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramIn(cp, base + ".selectBit", selectBit);
+ select(selectBit);
+}
+
+IdeController *
+IdeControllerParams::create()
+{
+ return new IdeController(this);
+}
--- /dev/null
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andrew Schultz
+ * Miguel Serrano
+ */
+
+/** @file
+ * Simple PCI IDE controller with bus mastering capability and UDMA
+ * modeled after controller in the Intel PIIX4 chip
+ */
+
+#ifndef __DEV_STORAGE_IDE_CTRL_HH__
+#define __DEV_STORAGE_IDE_CTRL_HH__
+
+#include "base/bitunion.hh"
+#include "dev/io_device.hh"
+#include "dev/pci/device.hh"
+#include "params/IdeController.hh"
+
+class IdeDisk;
+
+/**
+ * Device model for an Intel PIIX4 IDE controller
+ */
+
+class IdeController : public PciDevice
+{
+ private:
+ // Bus master IDE status register bit fields
+ BitUnion8(BMIStatusReg)
+ Bitfield<6> dmaCap0;
+ Bitfield<5> dmaCap1;
+ Bitfield<2> intStatus;
+ Bitfield<1> dmaError;
+ Bitfield<0> active;
+ EndBitUnion(BMIStatusReg)
+
+ BitUnion8(BMICommandReg)
+ Bitfield<3> rw;
+ Bitfield<0> startStop;
+ EndBitUnion(BMICommandReg)
+
+ struct Channel
+ {
+ std::string _name;
+
+ const std::string
+ name()
+ {
+ return _name;
+ }
+
+ /** Command and control block registers */
+ Addr cmdAddr, cmdSize, ctrlAddr, ctrlSize;
+
+ /** Registers used for bus master interface */
+ struct BMIRegs
+ {
+ BMICommandReg command;
+ uint8_t reserved0;
+ BMIStatusReg status;
+ uint8_t reserved1;
+ uint32_t bmidtp;
+ } bmiRegs;
+
+ /** IDE disks connected to this controller */
+ IdeDisk *master, *slave;
+
+ /** Currently selected disk */
+ IdeDisk *selected;
+
+ bool selectBit;
+
+ void
+ select(bool selSlave)
+ {
+ selectBit = selSlave;
+ selected = selectBit ? slave : master;
+ }
+
+ void accessCommand(Addr offset, int size, uint8_t *data, bool read);
+ void accessControl(Addr offset, int size, uint8_t *data, bool read);
+ void accessBMI(Addr offset, int size, uint8_t *data, bool read);
+
+ Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize);
+ ~Channel();
+
+ void serialize(const std::string &base, std::ostream &os) const;
+ void unserialize(const std::string &base, CheckpointIn &cp);
+ };
+
+ Channel primary;
+ Channel secondary;
+
+ /** Bus master interface (BMI) registers */
+ Addr bmiAddr, bmiSize;
+
+ /** Registers used in device specific PCI configuration */
+ uint16_t primaryTiming, secondaryTiming;
+ uint8_t deviceTiming;
+ uint8_t udmaControl;
+ uint16_t udmaTiming;
+ uint16_t ideConfig;
+
+ // Internal management variables
+ bool ioEnabled;
+ bool bmEnabled;
+
+ uint32_t ioShift, ctrlOffset;
+
+ void dispatchAccess(PacketPtr pkt, bool read);
+
+ public:
+ typedef IdeControllerParams Params;
+ const Params *params() const { return (const Params *)_params; }
+ IdeController(Params *p);
+
+ /** See if a disk is selected based on its pointer */
+ bool isDiskSelected(IdeDisk *diskPtr);
+
+ void intrPost();
+
+ Tick writeConfig(PacketPtr pkt) override;
+ Tick readConfig(PacketPtr pkt) override;
+
+ void setDmaComplete(IdeDisk *disk);
+
+ Tick read(PacketPtr pkt) override;
+ Tick write(PacketPtr pkt) override;
+
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+};
+#endif // __DEV_STORAGE_IDE_CTRL_HH_
--- /dev/null
+/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andrew Schultz
+ * Ali Saidi
+ */
+
+/** @file
+ * Device model implementation for an IDE disk
+ */
+
+#include "dev/storage/ide_disk.hh"
+
+#include <cerrno>
+#include <cstring>
+#include <deque>
+#include <string>
+
+#include "arch/isa_traits.hh"
+#include "base/chunk_generator.hh"
+#include "base/cprintf.hh" // csprintf
+#include "base/trace.hh"
+#include "config/the_isa.hh"
+#include "debug/IdeDisk.hh"
+#include "dev/storage/disk_image.hh"
+#include "dev/storage/ide_ctrl.hh"
+#include "sim/core.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+using namespace TheISA;
+
+IdeDisk::IdeDisk(const Params *p)
+ : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
+ dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
+ dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
+ dmaReadEvent(this), dmaWriteEvent(this)
+{
+ // Reset the device state
+ reset(p->driveID);
+
+ // fill out the drive ID structure
+ memset(&driveID, 0, sizeof(struct ataparams));
+
+ // Calculate LBA and C/H/S values
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
+
+ uint32_t lba_size = image->size();
+ if (lba_size >= 16383*16*63) {
+ cylinders = 16383;
+ heads = 16;
+ sectors = 63;
+ } else {
+ if (lba_size >= 63)
+ sectors = 63;
+ else if (lba_size == 0)
+ panic("Bad IDE image size: 0\n");
+ else
+ sectors = lba_size;
+
+ if ((lba_size / sectors) >= 16)
+ heads = 16;
+ else
+ heads = (lba_size / sectors);
+
+ cylinders = lba_size / (heads * sectors);
+ }
+
+ // Setup the model name
+ strncpy((char *)driveID.atap_model, "5MI EDD si k",
+ sizeof(driveID.atap_model));
+ // Set the maximum multisector transfer size
+ driveID.atap_multi = MAX_MULTSECT;
+ // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
+ driveID.atap_capabilities1 = 0x7;
+ // UDMA support, EIDE support
+ driveID.atap_extensions = 0x6;
+ // Setup default C/H/S settings
+ driveID.atap_cylinders = cylinders;
+ driveID.atap_sectors = sectors;
+ driveID.atap_heads = heads;
+ // Setup the current multisector transfer size
+ driveID.atap_curmulti = MAX_MULTSECT;
+ driveID.atap_curmulti_valid = 0x1;
+ // Number of sectors on disk
+ driveID.atap_capacity = lba_size;
+ // Multiword DMA mode 2 and below supported
+ driveID.atap_dmamode_supp = 0x4;
+ // Set PIO mode 4 and 3 supported
+ driveID.atap_piomode_supp = 0x3;
+ // Set DMA mode 4 and below supported
+ driveID.atap_udmamode_supp = 0x1f;
+ // Statically set hardware config word
+ driveID.atap_hwreset_res = 0x4001;
+
+ //arbitrary for now...
+ driveID.atap_ata_major = WDC_VER_ATA7;
+}
+
+IdeDisk::~IdeDisk()
+{
+ // destroy the data buffer
+ delete [] dataBuffer;
+}
+
+void
+IdeDisk::reset(int id)
+{
+ // initialize the data buffer and shadow registers
+ dataBuffer = new uint8_t[MAX_DMA_SIZE];
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ memset(&cmdReg, 0, sizeof(CommandReg_t));
+ memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
+
+ curPrdAddr = 0;
+ curSector = 0;
+ cmdBytes = 0;
+ cmdBytesLeft = 0;
+ drqBytesLeft = 0;
+ dmaRead = false;
+ intrPending = false;
+ dmaAborted = false;
+
+ // set the device state to idle
+ dmaState = Dma_Idle;
+
+ if (id == DEV0) {
+ devState = Device_Idle_S;
+ devID = DEV0;
+ } else if (id == DEV1) {
+ devState = Device_Idle_NS;
+ devID = DEV1;
+ } else {
+ panic("Invalid device ID: %#x\n", id);
+ }
+
+ // set the device ready bit
+ status = STATUS_DRDY_BIT;
+
+ /* The error register must be set to 0x1 on start-up to
+ indicate that no diagnostic error was detected */
+ cmdReg.error = 0x1;
+}
+
+////
+// Utility functions
+////
+
+bool
+IdeDisk::isDEVSelect()
+{
+ return ctrl->isDiskSelected(this);
+}
+
+Addr
+IdeDisk::pciToDma(Addr pciAddr)
+{
+ if (ctrl)
+ return ctrl->pciToDma(pciAddr);
+ else
+ panic("Access to unset controller!\n");
+}
+
+////
+// Device registers read/write
+////
+
+void
+IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
+{
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ } else if (size == sizeof(uint32_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ updateState(ACT_DATA_READ_SHORT);
+ *((uint16_t *)data + 1) = cmdReg.data;
+ } else {
+ panic("Data read of unsupported size %d.\n", size);
+ }
+ updateState(ACT_DATA_READ_SHORT);
+ return;
+ }
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case ERROR_OFFSET:
+ *data = cmdReg.error;
+ break;
+ case NSECTOR_OFFSET:
+ *data = cmdReg.sec_count;
+ break;
+ case SECTOR_OFFSET:
+ *data = cmdReg.sec_num;
+ break;
+ case LCYL_OFFSET:
+ *data = cmdReg.cyl_low;
+ break;
+ case HCYL_OFFSET:
+ *data = cmdReg.cyl_high;
+ break;
+ case DRIVE_OFFSET:
+ *data = cmdReg.drive;
+ break;
+ case STATUS_OFFSET:
+ *data = status;
+ updateState(ACT_STAT_READ);
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
+ }
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
+}
+
+void
+IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
+{
+ assert(size == sizeof(uint8_t));
+ *data = status;
+ if (offset != ALTSTAT_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
+}
+
+void
+IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ } else if (size == sizeof(uint32_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ updateState(ACT_DATA_WRITE_SHORT);
+ cmdReg.data = *((const uint16_t *)data + 1);
+ } else {
+ panic("Data write of unsupported size %d.\n", size);
+ }
+ updateState(ACT_DATA_WRITE_SHORT);
+ return;
+ }
+
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case FEATURES_OFFSET:
+ break;
+ case NSECTOR_OFFSET:
+ cmdReg.sec_count = *data;
+ break;
+ case SECTOR_OFFSET:
+ cmdReg.sec_num = *data;
+ break;
+ case LCYL_OFFSET:
+ cmdReg.cyl_low = *data;
+ break;
+ case HCYL_OFFSET:
+ cmdReg.cyl_high = *data;
+ break;
+ case DRIVE_OFFSET:
+ cmdReg.drive = *data;
+ updateState(ACT_SELECT_WRITE);
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ updateState(ACT_CMD_WRITE);
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
+ }
+ DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+}
+
+void
+IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset != CONTROL_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ updateState(ACT_SRST_SET);
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
+ updateState(ACT_SRST_CLEAR);
+ }
+
+ nIENBit = *data & CONTROL_IEN_BIT;
+
+ DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+}
+
+////
+// Perform DMA transactions
+////
+
+void
+IdeDisk::doDmaTransfer()
+{
+ if (dmaAborted) {
+ DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
+ updateState(ACT_CMD_ERROR);
+ return;
+ }
+
+ if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
+ panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
+ dmaState, devState);
+
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
+ schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
+ return;
+ } else
+ ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
+ (uint8_t*)&curPrd.entry);
+}
+
+void
+IdeDisk::dmaPrdReadDone()
+{
+ if (dmaAborted) {
+ DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
+ updateState(ACT_CMD_ERROR);
+ return;
+ }
+
+ DPRINTF(IdeDisk,
+ "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
+ curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
+ curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
+ curPrd.getEOT(), curSector);
+
+ // the prd pointer has already been translated, so just do an increment
+ curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
+
+ if (dmaRead)
+ doDmaDataRead();
+ else
+ doDmaDataWrite();
+}
+
+void
+IdeDisk::doDmaDataRead()
+{
+ /** @todo we need to figure out what the delay actually will be */
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+
+ DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
+ diskDelay, totalDiskDelay);
+
+ schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
+}
+
+void
+IdeDisk::regStats()
+{
+ using namespace Stats;
+ dmaReadFullPages
+ .name(name() + ".dma_read_full_pages")
+ .desc("Number of full page size DMA reads (not PRD).")
+ ;
+ dmaReadBytes
+ .name(name() + ".dma_read_bytes")
+ .desc("Number of bytes transfered via DMA reads (not PRD).")
+ ;
+ dmaReadTxs
+ .name(name() + ".dma_read_txs")
+ .desc("Number of DMA read transactions (not PRD).")
+ ;
+
+ dmaWriteFullPages
+ .name(name() + ".dma_write_full_pages")
+ .desc("Number of full page size DMA writes.")
+ ;
+ dmaWriteBytes
+ .name(name() + ".dma_write_bytes")
+ .desc("Number of bytes transfered via DMA writes.")
+ ;
+ dmaWriteTxs
+ .name(name() + ".dma_write_txs")
+ .desc("Number of DMA write transactions.")
+ ;
+}
+
+void
+IdeDisk::doDmaRead()
+{
+ if (dmaAborted) {
+ DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
+ if (dmaReadCG)
+ delete dmaReadCG;
+ dmaReadCG = NULL;
+ updateState(ACT_CMD_ERROR);
+ return;
+ }
+
+ if (!dmaReadCG) {
+ // clear out the data buffer
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
+ curPrd.getByteCount(), TheISA::PageBytes);
+
+ }
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
+ schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
+ return;
+ } else if (!dmaReadCG->done()) {
+ assert(dmaReadCG->complete() < MAX_DMA_SIZE);
+ ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
+ &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
+ dmaReadBytes += dmaReadCG->size();
+ dmaReadTxs++;
+ if (dmaReadCG->size() == TheISA::PageBytes)
+ dmaReadFullPages++;
+ dmaReadCG->next();
+ } else {
+ assert(dmaReadCG->done());
+ delete dmaReadCG;
+ dmaReadCG = NULL;
+ dmaReadDone();
+ }
+}
+
+void
+IdeDisk::dmaReadDone()
+{
+ uint32_t bytesWritten = 0;
+
+ // write the data to the disk image
+ for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
+ bytesWritten += SectorSize) {
+
+ cmdBytesLeft -= SectorSize;
+ writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+ }
+
+ // check for the EOT
+ if (curPrd.getEOT()) {
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+void
+IdeDisk::doDmaDataWrite()
+{
+ /** @todo we need to figure out what the delay actually will be */
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+ uint32_t bytesRead = 0;
+
+ DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
+ diskDelay, totalDiskDelay);
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ assert(cmdBytesLeft <= MAX_DMA_SIZE);
+ while (bytesRead < curPrd.getByteCount()) {
+ readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
+ bytesRead += SectorSize;
+ cmdBytesLeft -= SectorSize;
+ }
+ DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
+ bytesRead, cmdBytesLeft);
+
+ schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
+}
+
+void
+IdeDisk::doDmaWrite()
+{
+ if (dmaAborted) {
+ DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
+ if (dmaWriteCG)
+ delete dmaWriteCG;
+ dmaWriteCG = NULL;
+ updateState(ACT_CMD_ERROR);
+ return;
+ }
+ if (!dmaWriteCG) {
+ // clear out the data buffer
+ dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
+ curPrd.getByteCount(), TheISA::PageBytes);
+ }
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
+ schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
+ DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
+ return;
+ } else if (!dmaWriteCG->done()) {
+ assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
+ ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
+ &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
+ DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
+ curPrd.getByteCount(), curPrd.getEOT());
+ dmaWriteBytes += dmaWriteCG->size();
+ dmaWriteTxs++;
+ if (dmaWriteCG->size() == TheISA::PageBytes)
+ dmaWriteFullPages++;
+ dmaWriteCG->next();
+ } else {
+ DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
+ curPrd.getByteCount(), curPrd.getEOT());
+ assert(dmaWriteCG->done());
+ delete dmaWriteCG;
+ dmaWriteCG = NULL;
+ dmaWriteDone();
+ }
+}
+
+void
+IdeDisk::dmaWriteDone()
+{
+ DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
+ curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
+ // check for the EOT
+ if (curPrd.getEOT()) {
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+////
+// Disk utility routines
+///
+
+void
+IdeDisk::readDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesRead = image->read(data, sector);
+
+ if (bytesRead != SectorSize)
+ panic("Can't read from %s. Only %d of %d read. errno=%d\n",
+ name(), bytesRead, SectorSize, errno);
+}
+
+void
+IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesWritten = image->write(data, sector);
+
+ if (bytesWritten != SectorSize)
+ panic("Can't write to %s. Only %d of %d written. errno=%d\n",
+ name(), bytesWritten, SectorSize, errno);
+}
+
+////
+// Setup and handle commands
+////
+
+void
+IdeDisk::startDma(const uint32_t &prdTableBase)
+{
+ if (dmaState != Dma_Start)
+ panic("Inconsistent DMA state, should be in Dma_Start!\n");
+
+ if (devState != Transfer_Data_Dma)
+ panic("Inconsistent device state for DMA start!\n");
+
+ // PRD base address is given by bits 31:2
+ curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
+
+ dmaState = Dma_Transfer;
+
+ // schedule dma transfer (doDmaTransfer)
+ schedule(dmaTransferEvent, curTick() + 1);
+}
+
+void
+IdeDisk::abortDma()
+{
+ if (dmaState == Dma_Idle)
+ panic("Inconsistent DMA state, should be Start or Transfer!");
+
+ if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
+ panic("Inconsistent device state, should be Transfer or Prepare!\n");
+
+ updateState(ACT_CMD_ERROR);
+}
+
+void
+IdeDisk::startCommand()
+{
+ DevAction_t action = ACT_NONE;
+ uint32_t size = 0;
+ dmaRead = false;
+
+ // Decode commands
+ switch (cmdReg.command) {
+ // Supported non-data commands
+ case WDSF_READ_NATIVE_MAX:
+ size = (uint32_t)image->size() - 1;
+ cmdReg.sec_num = (size & 0xff);
+ cmdReg.cyl_low = ((size & 0xff00) >> 8);
+ cmdReg.cyl_high = ((size & 0xff0000) >> 16);
+ cmdReg.head = ((size & 0xf000000) >> 24);
+
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ case WDCC_RECAL:
+ case WDCC_IDP:
+ case WDCC_STANDBY_IMMED:
+ case WDCC_FLUSHCACHE:
+ case WDSF_VERIFY:
+ case WDSF_SEEK:
+ case SET_FEATURES:
+ case WDCC_SETMULTI:
+ case WDCC_IDLE:
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ // Supported PIO data-in commands
+ case WDCC_IDENTIFY:
+ cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ case WDCC_READMULTI:
+ case WDCC_READ:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ /** @todo make this a scheduled event to simulate disk delay */
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported PIO data-out commands
+ case WDCC_WRITEMULTI:
+ case WDCC_WRITE:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+ DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Out;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported DMA commands
+ case WDCC_WRITEDMA:
+ dmaRead = true; // a write to the disk is a DMA read from memory
+ case WDCC_READDMA:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+ DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
+
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Dma;
+ action = ACT_DMA_READY;
+ break;
+
+ default:
+ panic("Unsupported ATA command: %#x\n", cmdReg.command);
+ }
+
+ if (action != ACT_NONE) {
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ // clear the DRQ bit
+ status &= ~STATUS_DRQ_BIT;
+ // clear the DF bit
+ status &= ~STATUS_DF_BIT;
+
+ updateState(action);
+ }
+}
+
+////
+// Handle setting and clearing interrupts
+////
+
+void
+IdeDisk::intrPost()
+{
+ DPRINTF(IdeDisk, "Posting Interrupt\n");
+ if (intrPending)
+ panic("Attempt to post an interrupt with one pending\n");
+
+ intrPending = true;
+
+ // talk to controller to set interrupt
+ if (ctrl) {
+ ctrl->intrPost();
+ }
+}
+
+void
+IdeDisk::intrClear()
+{
+ DPRINTF(IdeDisk, "Clearing Interrupt\n");
+ if (!intrPending)
+ panic("Attempt to clear a non-pending interrupt\n");
+
+ intrPending = false;
+
+ // talk to controller to clear interrupt
+ if (ctrl)
+ ctrl->intrClear();
+}
+
+////
+// Manage the device internal state machine
+////
+
+void
+IdeDisk::updateState(DevAction_t action)
+{
+ switch (devState) {
+ case Device_Srst:
+ if (action == ACT_SRST_SET) {
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ } else if (action == ACT_SRST_CLEAR) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+
+ // reset the device state
+ reset(devID);
+ }
+ break;
+
+ case Device_Idle_S:
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
+ devState = Device_Idle_NS;
+ } else if (action == ACT_CMD_WRITE) {
+ startCommand();
+ }
+
+ break;
+
+ case Device_Idle_SI:
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
+ devState = Device_Idle_NS;
+ intrClear();
+ } else if (action == ACT_STAT_READ || isIENSet()) {
+ devState = Device_Idle_S;
+ intrClear();
+ } else if (action == ACT_CMD_WRITE) {
+ intrClear();
+ startCommand();
+ }
+
+ break;
+
+ case Device_Idle_NS:
+ if (action == ACT_SELECT_WRITE && isDEVSelect()) {
+ if (!isIENSet() && intrPending) {
+ devState = Device_Idle_SI;
+ intrPost();
+ }
+ if (isIENSet() || !intrPending) {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Command_Execution:
+ if (action == ACT_CMD_COMPLETE) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Prepare_Data_In:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DATA_READY) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ // copy the data into the data buffer
+ if (cmdReg.command == WDCC_IDENTIFY) {
+ // Reset the drqBytes for this block
+ drqBytesLeft = sizeof(struct ataparams);
+
+ memcpy((void *)dataBuffer, (void *)&driveID,
+ sizeof(struct ataparams));
+ } else {
+ // Reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ readDisk(curSector++, dataBuffer);
+ }
+
+ // put the first two bytes into the data register
+ memcpy((void *)&cmdReg.data, (void *)dataBuffer,
+ sizeof(uint16_t));
+
+ if (!isIENSet()) {
+ devState = Data_Ready_INTRQ_In;
+ intrPost();
+ } else {
+ devState = Transfer_Data_In;
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_In:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_In;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_In:
+ if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+
+ // copy next short into data registers
+ if (drqBytesLeft)
+ memcpy((void *)&cmdReg.data,
+ (void *)&dataBuffer[SectorSize - drqBytesLeft],
+ sizeof(uint16_t));
+ }
+
+ if (drqBytesLeft == 0) {
+ if (cmdBytesLeft == 0) {
+ // Clear the BSY bit
+ setComplete();
+ devState = Device_Idle_S;
+ } else {
+ devState = Prepare_Data_In;
+ // set the BSY_BIT
+ status |= STATUS_BSY_BIT;
+ // clear the DRQ_BIT
+ status &= ~STATUS_DRQ_BIT;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ }
+ break;
+
+ case Prepare_Data_Out:
+ if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ // clear the data buffer to get it ready for writes
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ // reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ if (cmdBytesLeft == cmdBytes || isIENSet()) {
+ devState = Transfer_Data_Out;
+ } else {
+ devState = Data_Ready_INTRQ_Out;
+ intrPost();
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_Out:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_Out;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_Out:
+ if (action == ACT_DATA_WRITE_BYTE ||
+ action == ACT_DATA_WRITE_SHORT) {
+
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ // copy the latest short into the data buffer
+ memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
+ (void *)&cmdReg.data,
+ sizeof(uint16_t));
+
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+ }
+
+ if (drqBytesLeft == 0) {
+ // copy the block to the disk
+ writeDisk(curSector++, dataBuffer);
+
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ // set the seek bit
+ status |= STATUS_SEEK_BIT;
+ // clear the DRQ bit
+ status &= ~STATUS_DRQ_BIT;
+
+ devState = Prepare_Data_Out;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ break;
+
+ case Prepare_Data_Dma:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DMA_READY) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ devState = Transfer_Data_Dma;
+
+ if (dmaState != Dma_Idle)
+ panic("Inconsistent DMA state, should be Dma_Idle\n");
+
+ dmaState = Dma_Start;
+ // wait for the write to the DMA start bit
+ }
+ break;
+
+ case Transfer_Data_Dma:
+ if (action == ACT_CMD_ERROR) {
+ dmaAborted = true;
+ devState = Device_Dma_Abort;
+ } else if (action == ACT_DMA_DONE) {
+ // clear the BSY bit
+ setComplete();
+ // set the seek bit
+ status |= STATUS_SEEK_BIT;
+ // clear the controller state for DMA transfer
+ ctrl->setDmaComplete(this);
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Device_Dma_Abort:
+ if (action == ACT_CMD_ERROR) {
+ setComplete();
+ status |= STATUS_SEEK_BIT;
+ ctrl->setDmaComplete(this);
+ dmaAborted = false;
+ dmaState = Dma_Idle;
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else {
+ DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
+ }
+ break;
+
+ default:
+ panic("Unknown IDE device state: %#x\n", devState);
+ }
+}
+
+void
+IdeDisk::serialize(CheckpointOut &cp) const
+{
+ // Check all outstanding events to see if they are scheduled
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ int eventCount = 0;
+
+ if (dmaTransferEvent.scheduled()) {
+ reschedule = dmaTransferEvent.when();
+ event = Transfer;
+ eventCount++;
+ }
+ if (dmaReadWaitEvent.scheduled()) {
+ reschedule = dmaReadWaitEvent.when();
+ event = ReadWait;
+ eventCount++;
+ }
+ if (dmaWriteWaitEvent.scheduled()) {
+ reschedule = dmaWriteWaitEvent.when();
+ event = WriteWait;
+ eventCount++;
+ }
+ if (dmaPrdReadEvent.scheduled()) {
+ reschedule = dmaPrdReadEvent.when();
+ event = PrdRead;
+ eventCount++;
+ }
+ if (dmaReadEvent.scheduled()) {
+ reschedule = dmaReadEvent.when();
+ event = DmaRead;
+ eventCount++;
+ }
+ if (dmaWriteEvent.scheduled()) {
+ reschedule = dmaWriteEvent.when();
+ event = DmaWrite;
+ eventCount++;
+ }
+
+ assert(eventCount <= 1);
+
+ SERIALIZE_SCALAR(reschedule);
+ SERIALIZE_ENUM(event);
+
+ // Serialize device registers
+ SERIALIZE_SCALAR(cmdReg.data);
+ SERIALIZE_SCALAR(cmdReg.sec_count);
+ SERIALIZE_SCALAR(cmdReg.sec_num);
+ SERIALIZE_SCALAR(cmdReg.cyl_low);
+ SERIALIZE_SCALAR(cmdReg.cyl_high);
+ SERIALIZE_SCALAR(cmdReg.drive);
+ SERIALIZE_SCALAR(cmdReg.command);
+ SERIALIZE_SCALAR(status);
+ SERIALIZE_SCALAR(nIENBit);
+ SERIALIZE_SCALAR(devID);
+
+ // Serialize the PRD related information
+ SERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ SERIALIZE_SCALAR(curPrd.entry.byteCount);
+ SERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ SERIALIZE_SCALAR(curPrdAddr);
+
+ /** @todo need to serialized chunk generator stuff!! */
+ // Serialize current transfer related information
+ SERIALIZE_SCALAR(cmdBytesLeft);
+ SERIALIZE_SCALAR(cmdBytes);
+ SERIALIZE_SCALAR(drqBytesLeft);
+ SERIALIZE_SCALAR(curSector);
+ SERIALIZE_SCALAR(dmaRead);
+ SERIALIZE_SCALAR(intrPending);
+ SERIALIZE_SCALAR(dmaAborted);
+ SERIALIZE_ENUM(devState);
+ SERIALIZE_ENUM(dmaState);
+ SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+void
+IdeDisk::unserialize(CheckpointIn &cp)
+{
+ // Reschedule events that were outstanding
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ UNSERIALIZE_SCALAR(reschedule);
+ UNSERIALIZE_ENUM(event);
+
+ switch (event) {
+ case None : break;
+ case Transfer : schedule(dmaTransferEvent, reschedule); break;
+ case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
+ case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
+ case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
+ case DmaRead : schedule(dmaReadEvent, reschedule); break;
+ case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
+ }
+
+ // Unserialize device registers
+ UNSERIALIZE_SCALAR(cmdReg.data);
+ UNSERIALIZE_SCALAR(cmdReg.sec_count);
+ UNSERIALIZE_SCALAR(cmdReg.sec_num);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_low);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_high);
+ UNSERIALIZE_SCALAR(cmdReg.drive);
+ UNSERIALIZE_SCALAR(cmdReg.command);
+ UNSERIALIZE_SCALAR(status);
+ UNSERIALIZE_SCALAR(nIENBit);
+ UNSERIALIZE_SCALAR(devID);
+
+ // Unserialize the PRD related information
+ UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
+ UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ UNSERIALIZE_SCALAR(curPrdAddr);
+
+ /** @todo need to serialized chunk generator stuff!! */
+ // Unserialize current transfer related information
+ UNSERIALIZE_SCALAR(cmdBytes);
+ UNSERIALIZE_SCALAR(cmdBytesLeft);
+ UNSERIALIZE_SCALAR(drqBytesLeft);
+ UNSERIALIZE_SCALAR(curSector);
+ UNSERIALIZE_SCALAR(dmaRead);
+ UNSERIALIZE_SCALAR(intrPending);
+ UNSERIALIZE_SCALAR(dmaAborted);
+ UNSERIALIZE_ENUM(devState);
+ UNSERIALIZE_ENUM(dmaState);
+ UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+IdeDisk *
+IdeDiskParams::create()
+{
+ return new IdeDisk(this);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andrew Schultz
+ */
+
+/** @file
+ * Device model for an IDE disk
+ */
+
+#ifndef __DEV_STORAGE_IDE_DISK_HH__
+#define __DEV_STORAGE_IDE_DISK_HH__
+
+#include "base/statistics.hh"
+#include "dev/io_device.hh"
+#include "dev/storage/disk_image.hh"
+#include "dev/storage/ide_atareg.h"
+#include "dev/storage/ide_ctrl.hh"
+#include "dev/storage/ide_wdcreg.h"
+#include "params/IdeDisk.hh"
+#include "sim/eventq.hh"
+
+class ChunkGenerator;
+
+#define DMA_BACKOFF_PERIOD 200
+
+#define MAX_DMA_SIZE 0x20000 // 128K
+#define MAX_SINGLE_DMA_SIZE 0x10000
+#define MAX_MULTSECT (128)
+
+#define PRD_BASE_MASK 0xfffffffe
+#define PRD_COUNT_MASK 0xfffe
+#define PRD_EOT_MASK 0x8000
+
+typedef struct PrdEntry {
+ uint32_t baseAddr;
+ uint16_t byteCount;
+ uint16_t endOfTable;
+} PrdEntry_t;
+
+class PrdTableEntry {
+ public:
+ PrdEntry_t entry;
+
+ uint32_t getBaseAddr()
+ {
+ return (entry.baseAddr & PRD_BASE_MASK);
+ }
+
+ uint32_t getByteCount()
+ {
+ return ((entry.byteCount == 0) ? MAX_SINGLE_DMA_SIZE :
+ (entry.byteCount & PRD_COUNT_MASK));
+ }
+
+ uint16_t getEOT()
+ {
+ return (entry.endOfTable & PRD_EOT_MASK);
+ }
+};
+
+#define DATA_OFFSET (0)
+#define ERROR_OFFSET (1)
+#define FEATURES_OFFSET (1)
+#define NSECTOR_OFFSET (2)
+#define SECTOR_OFFSET (3)
+#define LCYL_OFFSET (4)
+#define HCYL_OFFSET (5)
+#define SELECT_OFFSET (6)
+#define DRIVE_OFFSET (6)
+#define STATUS_OFFSET (7)
+#define COMMAND_OFFSET (7)
+
+#define CONTROL_OFFSET (2)
+#define ALTSTAT_OFFSET (2)
+
+#define SELECT_DEV_BIT 0x10
+#define CONTROL_RST_BIT 0x04
+#define CONTROL_IEN_BIT 0x02
+#define STATUS_BSY_BIT 0x80
+#define STATUS_DRDY_BIT 0x40
+#define STATUS_DRQ_BIT 0x08
+#define STATUS_SEEK_BIT 0x10
+#define STATUS_DF_BIT 0x20
+#define DRIVE_LBA_BIT 0x40
+
+#define DEV0 (0)
+#define DEV1 (1)
+
+typedef struct CommandReg {
+ uint16_t data;
+ uint8_t error;
+ uint8_t sec_count;
+ uint8_t sec_num;
+ uint8_t cyl_low;
+ uint8_t cyl_high;
+ union {
+ uint8_t drive;
+ uint8_t head;
+ };
+ uint8_t command;
+} CommandReg_t;
+
+typedef enum Events {
+ None = 0,
+ Transfer,
+ ReadWait,
+ WriteWait,
+ PrdRead,
+ DmaRead,
+ DmaWrite
+} Events_t;
+
+typedef enum DevAction {
+ ACT_NONE = 0,
+ ACT_CMD_WRITE,
+ ACT_CMD_COMPLETE,
+ ACT_CMD_ERROR,
+ ACT_SELECT_WRITE,
+ ACT_STAT_READ,
+ ACT_DATA_READY,
+ ACT_DATA_READ_BYTE,
+ ACT_DATA_READ_SHORT,
+ ACT_DATA_WRITE_BYTE,
+ ACT_DATA_WRITE_SHORT,
+ ACT_DMA_READY,
+ ACT_DMA_DONE,
+ ACT_SRST_SET,
+ ACT_SRST_CLEAR
+} DevAction_t;
+
+typedef enum DevState {
+ // Device idle
+ Device_Idle_S = 0,
+ Device_Idle_SI,
+ Device_Idle_NS,
+
+ // Software reset
+ Device_Srst,
+
+ // Non-data commands
+ Command_Execution,
+
+ // PIO data-in (data to host)
+ Prepare_Data_In,
+ Data_Ready_INTRQ_In,
+ Transfer_Data_In,
+
+ // PIO data-out (data from host)
+ Prepare_Data_Out,
+ Data_Ready_INTRQ_Out,
+ Transfer_Data_Out,
+
+ // DMA protocol
+ Prepare_Data_Dma,
+ Transfer_Data_Dma,
+ Device_Dma_Abort
+} DevState_t;
+
+typedef enum DmaState {
+ Dma_Idle = 0,
+ Dma_Start,
+ Dma_Transfer
+} DmaState_t;
+
+class IdeController;
+
+/**
+ * IDE Disk device model
+ */
+class IdeDisk : public SimObject
+{
+ protected:
+ /** The IDE controller for this disk. */
+ IdeController *ctrl;
+ /** The image that contains the data of this disk. */
+ DiskImage *image;
+
+ protected:
+ /** The disk delay in microseconds. */
+ int diskDelay;
+
+ private:
+ /** Drive identification structure for this disk */
+ struct ataparams driveID;
+ /** Data buffer for transfers */
+ uint8_t *dataBuffer;
+ /** Number of bytes in command data transfer */
+ uint32_t cmdBytes;
+ /** Number of bytes left in command data transfer */
+ uint32_t cmdBytesLeft;
+ /** Number of bytes left in DRQ block */
+ uint32_t drqBytesLeft;
+ /** Current sector in access */
+ uint32_t curSector;
+ /** Command block registers */
+ CommandReg_t cmdReg;
+ /** Status register */
+ uint8_t status;
+ /** Interrupt enable bit */
+ bool nIENBit;
+ /** Device state */
+ DevState_t devState;
+ /** Dma state */
+ DmaState_t dmaState;
+ /** Dma transaction is a read */
+ bool dmaRead;
+ /** PRD table base address */
+ uint32_t curPrdAddr;
+ /** PRD entry */
+ PrdTableEntry curPrd;
+ /** Device ID (master=0/slave=1) */
+ int devID;
+ /** Interrupt pending */
+ bool intrPending;
+ /** DMA Aborted */
+ bool dmaAborted;
+
+ Stats::Scalar dmaReadFullPages;
+ Stats::Scalar dmaReadBytes;
+ Stats::Scalar dmaReadTxs;
+ Stats::Scalar dmaWriteFullPages;
+ Stats::Scalar dmaWriteBytes;
+ Stats::Scalar dmaWriteTxs;
+
+ public:
+ typedef IdeDiskParams Params;
+ IdeDisk(const Params *p);
+
+ /**
+ * Delete the data buffer.
+ */
+ ~IdeDisk();
+
+ /**
+ * Reset the device state
+ */
+ void reset(int id);
+
+ /**
+ * Register Statistics
+ */
+ void regStats() override;
+
+ /**
+ * Set the controller for this device
+ * @param c The IDE controller
+ */
+ void setController(IdeController *c) {
+ if (ctrl) panic("Cannot change the controller once set!\n");
+ ctrl = c;
+ }
+
+ // Device register read/write
+ void readCommand(const Addr offset, int size, uint8_t *data);
+ void readControl(const Addr offset, int size, uint8_t *data);
+ void writeCommand(const Addr offset, int size, const uint8_t *data);
+ void writeControl(const Addr offset, int size, const uint8_t *data);
+
+ // Start/abort functions
+ void startDma(const uint32_t &prdTableBase);
+ void abortDma();
+
+ private:
+ void startCommand();
+
+ // Interrupt management
+ void intrPost();
+ void intrClear();
+
+ // DMA stuff
+ void doDmaTransfer();
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
+
+ void doDmaDataRead();
+
+ void doDmaRead();
+ ChunkGenerator *dmaReadCG;
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
+
+ void doDmaDataWrite();
+
+ void doDmaWrite();
+ ChunkGenerator *dmaWriteCG;
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
+
+ void dmaPrdReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
+
+ void dmaReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
+
+ void dmaWriteDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
+
+ // Disk image read/write
+ void readDisk(uint32_t sector, uint8_t *data);
+ void writeDisk(uint32_t sector, uint8_t *data);
+
+ // State machine management
+ void updateState(DevAction_t action);
+
+ // Utility functions
+ bool isBSYSet() { return (status & STATUS_BSY_BIT); }
+ bool isIENSet() { return nIENBit; }
+ bool isDEVSelect();
+
+ void setComplete()
+ {
+ // clear out the status byte
+ status = 0;
+ // set the DRDY bit
+ status |= STATUS_DRDY_BIT;
+ // set the SEEK bit
+ status |= STATUS_SEEK_BIT;
+ }
+
+ uint32_t getLBABase()
+ {
+ return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
+ (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
+ }
+
+ inline Addr pciToDma(Addr pciAddr);
+
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+};
+
+
+#endif // __DEV_STORAGE_IDE_DISK_HH__
--- /dev/null
+/* $OpenBSD: wdcreg.h,v 1.13 2004/09/24 07:05:44 grange Exp $ */
+/* $NetBSD: wdcreg.h,v 1.22 1999/03/07 14:02:54 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California
+ * All rights reserved
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)wdreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+#ifndef _DEV_IC_WDCREG_H_
+#define _DEV_IC_WDCREG_H_
+
+/*
+ * Controller register (wdr_ctlr)
+ */
+#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x04 /* reset the controller */
+#define WDCTL_IDS 0x02 /* disable controller interrupts */
+
+/*
+ * Status bits.
+ */
+#define WDCS_BSY 0x80 /* busy */
+#define WDCS_DRDY 0x40 /* drive ready */
+#define WDCS_DWF 0x20 /* drive write fault */
+#define WDCS_DSC 0x10 /* drive seek complete */
+#define WDCS_DRQ 0x08 /* data request */
+#define WDCS_CORR 0x04 /* corrected data */
+#define WDCS_IDX 0x02 /* index */
+#define WDCS_ERR 0x01 /* error */
+#define WDCS_BITS "\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR"
+
+/*
+ * Error bits.
+ */
+#define WDCE_BBK 0x80 /* bad block detected */
+#define WDCE_CRC 0x80 /* CRC error (Ultra-DMA only) */
+#define WDCE_UNC 0x40 /* uncorrectable data error */
+#define WDCE_MC 0x20 /* media changed */
+#define WDCE_IDNF 0x10 /* id not found */
+#define WDCE_MCR 0x08 /* media change requested */
+#define WDCE_ABRT 0x04 /* aborted command */
+#define WDCE_TK0NF 0x02 /* track 0 not found */
+#define WDCE_AMNF 0x01 /* address mark not found */
+
+/*
+ * Commands for Disk Controller.
+ */
+#define WDCC_NOP 0x00 /* NOP - Always fail with "aborted command" */
+#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
+
+#define WDCC_READ 0x20 /* disk read code */
+#define WDCC_WRITE 0x30 /* disk write code */
+#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
+#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
+
+#define WDCC_FORMAT 0x50 /* disk format code */
+#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
+#define WDCC_IDP 0x91 /* initialize drive parameters */
+
+#define WDCC_READMULTI 0xc4 /* read multiple */
+#define WDCC_WRITEMULTI 0xc5 /* write multiple */
+#define WDCC_SETMULTI 0xc6 /* set multiple mode */
+
+#define WDCC_READDMA 0xc8 /* read with DMA */
+#define WDCC_WRITEDMA 0xca /* write with DMA */
+
+#define WDCC_ACKMC 0xdb /* acknowledge media change */
+#define WDCC_LOCK 0xde /* lock drawer */
+#define WDCC_UNLOCK 0xdf /* unlock drawer */
+
+#define WDCC_FLUSHCACHE 0xe7 /* Flush cache */
+#define WDCC_IDENTIFY 0xec /* read parameters from controller */
+#define SET_FEATURES 0xef /* set features */
+
+#define WDCC_IDLE 0xe3 /* set idle timer & enter idle mode */
+#define WDCC_IDLE_IMMED 0xe1 /* enter idle mode */
+#define WDCC_SLEEP 0xe6 /* enter sleep mode */
+#define WDCC_STANDBY 0xe2 /* set standby timer & enter standby mode */
+#define WDCC_STANDBY_IMMED 0xe0 /* enter standby mode */
+#define WDCC_CHECK_PWR 0xe5 /* check power mode */
+
+#define WDCC_READ_EXT 0x24 /* read 48-bit addressing */
+#define WDCC_WRITE_EXT 0x34 /* write 48-bit addressing */
+
+#define WDCC_READMULTI_EXT 0x29 /* read multiple 48-bit addressing */
+#define WDCC_WRITEMULTI_EXT 0x39 /* write multiple 48-bit addressing */
+
+#define WDCC_READDMA_EXT 0x25 /* read 48-bit addressing with DMA */
+#define WDCC_WRITEDMA_EXT 0x35 /* write 48-bit addressing with DMA */
+
+#define WDCC_FLUSHCACHE_EXT 0xea /* 48-bit addressing flush cache */
+
+/* Subcommands for SET_FEATURES (features register ) */
+#define WDSF_8BIT_PIO_EN 0x01 /* Enable 8bit PIO (CFA featureset) */
+#define WDSF_EN_WR_CACHE 0x02
+#define WDSF_SET_MODE 0x03
+#define WDSF_REASSIGN_EN 0x04 /* Obsolete in ATA-6 */
+#define WDSF_APM_EN 0x05 /* Enable Adv. Power Management */
+#define WDSF_PUIS_EN 0x06 /* Enable Power-Up In Standby */
+#define WDSF_PUIS_SPINUP 0x07 /* Power-Up In Standby spin-up */
+#define WDSF_CFA_MODE1_EN 0x0A /* Enable CFA power mode 1 */
+#define WDSF_RMSN_DS 0x31 /* Disable Removable Media Status */
+#define WDSF_RETRY_DS 0x33 /* Obsolete in ATA-6 */
+#define WDSF_AAM_EN 0x42 /* Enable Autom. Acoustic Management */
+#define WDSF_SET_CACHE_SGMT 0x54 /* Obsolete in ATA-6 */
+#define WDSF_READAHEAD_DS 0x55 /* Disable read look-ahead */
+#define WDSF_RLSE_EN 0x5D /* Enable release interrupt */
+#define WDSF_SRV_EN 0x5E /* Enable SERVICE interrupt */
+#define WDSF_POD_DS 0x66
+#define WDSF_ECC_DS 0x77
+#define WDSF_8BIT_PIO_DS 0x81 /* Disable 8bit PIO (CFA featureset) */
+#define WDSF_WRITE_CACHE_DS 0x82
+#define WDSF_REASSIGN_DS 0x84
+#define WDSF_APM_DS 0x85 /* Disable Adv. Power Management */
+#define WDSF_PUIS_DS 0x86 /* Disable Power-Up In Standby */
+#define WDSF_ECC_EN 0x88
+#define WDSF_CFA_MODE1_DS 0x8A /* Disable CFA power mode 1 */
+#define WDSF_RMSN_EN 0x95 /* Enable Removable Media Status */
+#define WDSF_RETRY_EN 0x99 /* Obsolete in ATA-6 */
+#define WDSF_SET_CURRENT 0x9A /* Obsolete in ATA-6 */
+#define WDSF_READAHEAD_EN 0xAA
+#define WDSF_PREFETCH_SET 0xAB /* Obsolete in ATA-6 */
+#define WDSF_AAM_DS 0xC2 /* Disable Autom. Acoustic Management */
+#define WDSF_POD_EN 0xCC
+#define WDSF_RLSE_DS 0xDD /* Disable release interrupt */
+#define WDSF_SRV_DS 0xDE /* Disable SERVICE interrupt */
+#define WDSF_READ_NATIVE_MAX 0xF8
+#define WDSF_SEEK 0x70
+#define WDSF_VERIFY 0x40
+
+/* parameters uploaded to device/heads register */
+#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
+#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
+#define WDSD_LBA 0x40 /* logical block addressing */
+
+/* Commands for ATAPI devices */
+#define ATAPI_CHECK_POWER_MODE 0xe5
+#define ATAPI_EXEC_DRIVE_DIAGS 0x90
+#define ATAPI_IDLE_IMMEDIATE 0xe1
+#define ATAPI_NOP 0x00
+#define ATAPI_PKT_CMD 0xa0
+#define ATAPI_IDENTIFY_DEVICE 0xa1
+#define ATAPI_SOFT_RESET 0x08
+#define ATAPI_DEVICE_RESET 0x08 /* ATA/ATAPI-5 name for soft reset */
+#define ATAPI_SLEEP 0xe6
+#define ATAPI_STANDBY_IMMEDIATE 0xe0
+#define ATAPI_SMART 0xB0 /* SMART operations */
+#define ATAPI_SETMAX 0xF9 /* Set Max Address */
+#define ATAPI_WRITEEXT 0x34 /* Write sectors Ext */
+#define ATAPI_SETMAXEXT 0x37 /* Set Max Address Ext */
+#define ATAPI_WRITEMULTIEXT 0x39 /* Write Multi Ext */
+
+/* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */
+#define ATAPI_PKT_CMD_FTRE_DMA 0x01
+#define ATAPI_PKT_CMD_FTRE_OVL 0x02
+
+/* ireason */
+#define WDCI_CMD 0x01 /* command(1) or data(0) */
+#define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */
+#define WDCI_RELEASE 0x04 /* bus released until completion */
+
+#define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD)
+#define PHASE_DATAIN (WDCS_DRQ | WDCI_IN)
+#define PHASE_DATAOUT WDCS_DRQ
+#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
+#define PHASE_ABORTED 0
+
+#endif /* !_DEV_IC_WDCREG_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#include "dev/storage/simple_disk.hh"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/SimpleDisk.hh"
+#include "debug/SimpleDiskData.hh"
+#include "dev/storage/disk_image.hh"
+#include "mem/port_proxy.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+SimpleDisk::SimpleDisk(const Params *p)
+ : SimObject(p), system(p->system), image(p->disk)
+{}
+
+SimpleDisk::~SimpleDisk()
+{}
+
+
+void
+SimpleDisk::read(Addr addr, baddr_t block, int count) const
+{
+ uint8_t *data = new uint8_t[SectorSize * 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);
+
+ system->physProxy.writeBlob(addr, data, count);
+
+ DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count);
+ DDUMP(SimpleDiskData, data, count);
+
+ delete [] data;
+}
+
+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
+}
+
+SimpleDisk *
+SimpleDiskParams::create()
+{
+ return new SimpleDisk(this);
+}
--- /dev/null
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#ifndef __DEV_STORAGE_SIMPLE_DISK_HH__
+#define __DEV_STORAGE_SIMPLE_DISK_HH__
+
+#include "params/SimpleDisk.hh"
+#include "sim/sim_object.hh"
+
+class DiskImage;
+class System;
+
+/*
+ * Trivial interface to a disk image used by the System Console
+ */
+class SimpleDisk : public SimObject
+{
+ public:
+ typedef uint64_t baddr_t;
+
+ protected:
+ System *system;
+ DiskImage *image;
+
+ public:
+ typedef SimpleDiskParams Params;
+ SimpleDisk(const Params *p);
+ ~SimpleDisk();
+
+ void read(Addr addr, baddr_t block, int count) const;
+ void write(Addr addr, baddr_t block, int count);
+};
+
+#endif // __DEV_STORAGE_SIMPLE_DISK_HH__
#define __DEV_VIRTIO_BLOCK_HH__
#include "dev/virtio/base.hh"
-#include "dev/disk_image.hh"
+#include "dev/storage/disk_image.hh"
#include "dev/terminal.hh"
struct VirtIOBlockParams;