From: Andreas Sandberg Date: Thu, 10 Dec 2015 10:35:23 +0000 (+0000) Subject: dev: Move storage devices to src/dev/storage/ X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8ec5fc66321549ebda555e7c16ddaf158b021d2b;p=gem5.git dev: Move storage devices to src/dev/storage/ Move the IDE controller and the disk implementations to src/dev/storage. --HG-- rename : src/dev/DiskImage.py => src/dev/storage/DiskImage.py rename : src/dev/Ide.py => src/dev/storage/Ide.py rename : src/dev/SimpleDisk.py => src/dev/storage/SimpleDisk.py rename : src/dev/disk_image.cc => src/dev/storage/disk_image.cc rename : src/dev/disk_image.hh => src/dev/storage/disk_image.hh rename : src/dev/ide_atareg.h => src/dev/storage/ide_atareg.h rename : src/dev/ide_ctrl.cc => src/dev/storage/ide_ctrl.cc rename : src/dev/ide_ctrl.hh => src/dev/storage/ide_ctrl.hh rename : src/dev/ide_disk.cc => src/dev/storage/ide_disk.cc rename : src/dev/ide_disk.hh => src/dev/storage/ide_disk.hh rename : src/dev/ide_wdcreg.h => src/dev/storage/ide_wdcreg.h rename : src/dev/simple_disk.cc => src/dev/storage/simple_disk.cc rename : src/dev/simple_disk.hh => src/dev/storage/simple_disk.hh --- diff --git a/src/dev/DiskImage.py b/src/dev/DiskImage.py deleted file mode 100644 index 38cc6e75d..000000000 --- a/src/dev/DiskImage.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 = "" diff --git a/src/dev/Ide.py b/src/dev/Ide.py deleted file mode 100644 index 4d3da1971..000000000 --- a/src/dev/Ide.py +++ /dev/null @@ -1,70 +0,0 @@ -# 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") diff --git a/src/dev/SConscript b/src/dev/SConscript index 85bf839ec..2f3ec5d17 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -40,40 +40,24 @@ if env['TARGET_ISA'] == 'null': 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' ]) diff --git a/src/dev/SimpleDisk.py b/src/dev/SimpleDisk.py deleted file mode 100644 index 88bf5dbfb..000000000 --- a/src/dev/SimpleDisk.py +++ /dev/null @@ -1,36 +0,0 @@ -# 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") diff --git a/src/dev/alpha/backdoor.cc b/src/dev/alpha/backdoor.cc index ec5765673..93bfedf9d 100644 --- a/src/dev/alpha/backdoor.cc +++ b/src/dev/alpha/backdoor.cc @@ -50,7 +50,7 @@ #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" diff --git a/src/dev/arm/ufs_device.hh b/src/dev/arm/ufs_device.hh index b0be55777..435d5f59f 100644 --- a/src/dev/arm/ufs_device.hh +++ b/src/dev/arm/ufs_device.hh @@ -152,7 +152,7 @@ #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" diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc deleted file mode 100644 index e4907853f..000000000 --- a/src/dev/disk_image.cc +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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 -#include -#include - -#include -#include -#include -#include - -#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 -void -SafeRead(ifstream &stream, T &data) -{ - SafeRead(stream, &data, sizeof(data)); -} - -template -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 -void -SafeWrite(ofstream &stream, const T &data) -{ - SafeWrite(stream, &data, sizeof(data)); -} - -template -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); -} diff --git a/src/dev/disk_image.hh b/src/dev/disk_image.hh deleted file mode 100644 index fa25fc770..000000000 --- a/src/dev/disk_image.hh +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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 -#include - -#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 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 -void SafeRead(std::ifstream &stream, T &data); - -template -void SafeReadSwap(std::ifstream &stream, T &data); - -void SafeWrite(std::ofstream &stream, const void *data, int count); - -template -void SafeWrite(std::ofstream &stream, const T &data); - -template -void SafeWriteSwap(std::ofstream &stream, const T &data); - -#endif // __DISK_IMAGE_HH__ diff --git a/src/dev/ide_atareg.h b/src/dev/ide_atareg.h deleted file mode 100644 index d19a75462..000000000 --- a/src/dev/ide_atareg.h +++ /dev/null @@ -1,290 +0,0 @@ -/* $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 -#elif defined(__sun) -#include -#else -#include -#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_ */ diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc deleted file mode 100644 index 3e6086265..000000000 --- a/src/dev/ide_ctrl.cc +++ /dev/null @@ -1,649 +0,0 @@ -/* - * 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 - -#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(deviceTiming); - break; - case UDMAControl: - pkt->set(udmaControl); - break; - case PrimaryTiming + 1: - pkt->set(bits(htole(primaryTiming), 15, 8)); - break; - case SecondaryTiming + 1: - pkt->set(bits(htole(secondaryTiming), 15, 8)); - break; - case IDEConfig: - pkt->set(bits(htole(ideConfig), 7, 0)); - break; - case IDEConfig + 1: - pkt->set(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()); - break; - case sizeof(uint16_t): - switch (offset) { - case UDMAControl: - pkt->set(udmaControl); - break; - case PrimaryTiming: - pkt->set(primaryTiming); - break; - case SecondaryTiming: - pkt->set(secondaryTiming); - break; - case UDMATiming: - pkt->set(udmaTiming); - break; - case IDEConfig: - pkt->set(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()); - break; - case sizeof(uint32_t): - switch (offset) { - case PrimaryTiming: - pkt->set(primaryTiming); - break; - case IDEConfig: - pkt->set(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()); - 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(); - break; - case UDMAControl: - udmaControl = pkt->get(); - break; - case IDEConfig: - replaceBits(ideConfig, 7, 0, pkt->get()); - break; - case IDEConfig + 1: - replaceBits(ideConfig, 15, 8, pkt->get()); - 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()); - break; - case sizeof(uint16_t): - switch (offset) { - case UDMAControl: - udmaControl = pkt->get(); - break; - case PrimaryTiming: - primaryTiming = pkt->get(); - break; - case SecondaryTiming: - secondaryTiming = pkt->get(); - break; - case UDMATiming: - udmaTiming = pkt->get(); - break; - case IDEConfig: - ideConfig = pkt->get(); - 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()); - break; - case sizeof(uint32_t): - switch (offset) { - case PrimaryTiming: - primaryTiming = pkt->get(); - break; - case IDEConfig: - ideConfig = pkt->get(); - 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(); - - 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(); - else if (pkt->getSize() == 2) - data = pkt->get(); - else - data = pkt->get(); - 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); -} diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh deleted file mode 100644 index c6c4beecc..000000000 --- a/src/dev/ide_ctrl.hh +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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_ diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc deleted file mode 100644 index 2c8dfceb1..000000000 --- a/src/dev/ide_disk.cc +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * 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 -#include -#include -#include - -#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); -} diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh deleted file mode 100644 index 45b0dd149..000000000 --- a/src/dev/ide_disk.hh +++ /dev/null @@ -1,373 +0,0 @@ -/* - * 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; - EventWrapper dmaTransferEvent; - - void doDmaDataRead(); - - void doDmaRead(); - ChunkGenerator *dmaReadCG; - friend class EventWrapper; - EventWrapper dmaReadWaitEvent; - - void doDmaDataWrite(); - - void doDmaWrite(); - ChunkGenerator *dmaWriteCG; - friend class EventWrapper; - EventWrapper dmaWriteWaitEvent; - - void dmaPrdReadDone(); - friend class EventWrapper; - EventWrapper dmaPrdReadEvent; - - void dmaReadDone(); - friend class EventWrapper; - EventWrapper dmaReadEvent; - - void dmaWriteDone(); - friend class EventWrapper; - EventWrapper 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__ diff --git a/src/dev/ide_wdcreg.h b/src/dev/ide_wdcreg.h deleted file mode 100644 index f6a59c9f2..000000000 --- a/src/dev/ide_wdcreg.h +++ /dev/null @@ -1,197 +0,0 @@ -/* $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_ */ diff --git a/src/dev/simple_disk.cc b/src/dev/simple_disk.cc deleted file mode 100644 index 26e8239bb..000000000 --- a/src/dev/simple_disk.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 -#include -#include -#include - -#include -#include - -#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); -} diff --git a/src/dev/simple_disk.hh b/src/dev/simple_disk.hh deleted file mode 100644 index 1a95bd59f..000000000 --- a/src/dev/simple_disk.hh +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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__ diff --git a/src/dev/sparc/iob.hh b/src/dev/sparc/iob.hh index 4772e8654..1de625eba 100644 --- a/src/dev/sparc/iob.hh +++ b/src/dev/sparc/iob.hh @@ -36,7 +36,6 @@ #ifndef __DEV_SPARC_IOB_HH__ #define __DEV_SPARC_IOB_HH__ -#include "dev/disk_image.hh" #include "dev/io_device.hh" #include "params/Iob.hh" diff --git a/src/dev/sparc/mm_disk.hh b/src/dev/sparc/mm_disk.hh index 6242ed943..2d551fe3f 100644 --- a/src/dev/sparc/mm_disk.hh +++ b/src/dev/sparc/mm_disk.hh @@ -36,8 +36,8 @@ #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 diff --git a/src/dev/storage/DiskImage.py b/src/dev/storage/DiskImage.py new file mode 100644 index 000000000..5a3bc54e1 --- /dev/null +++ b/src/dev/storage/DiskImage.py @@ -0,0 +1,48 @@ +# 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 = "" diff --git a/src/dev/storage/Ide.py b/src/dev/storage/Ide.py new file mode 100644 index 000000000..fc3f356f0 --- /dev/null +++ b/src/dev/storage/Ide.py @@ -0,0 +1,70 @@ +# 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") diff --git a/src/dev/storage/SConscript b/src/dev/storage/SConscript new file mode 100644 index 000000000..b5ddece04 --- /dev/null +++ b/src/dev/storage/SConscript @@ -0,0 +1,73 @@ +# -*- 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' ]) diff --git a/src/dev/storage/SimpleDisk.py b/src/dev/storage/SimpleDisk.py new file mode 100644 index 000000000..01b41ee0e --- /dev/null +++ b/src/dev/storage/SimpleDisk.py @@ -0,0 +1,37 @@ +# 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") diff --git a/src/dev/storage/disk_image.cc b/src/dev/storage/disk_image.cc new file mode 100644 index 000000000..24688f55a --- /dev/null +++ b/src/dev/storage/disk_image.cc @@ -0,0 +1,432 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include + +#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 +void +SafeRead(ifstream &stream, T &data) +{ + SafeRead(stream, &data, sizeof(data)); +} + +template +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 +void +SafeWrite(ofstream &stream, const T &data) +{ + SafeWrite(stream, &data, sizeof(data)); +} + +template +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); +} diff --git a/src/dev/storage/disk_image.hh b/src/dev/storage/disk_image.hh new file mode 100644 index 000000000..43e6adf5e --- /dev/null +++ b/src/dev/storage/disk_image.hh @@ -0,0 +1,157 @@ +/* + * 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 +#include + +#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 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 +void SafeRead(std::ifstream &stream, T &data); + +template +void SafeReadSwap(std::ifstream &stream, T &data); + +void SafeWrite(std::ofstream &stream, const void *data, int count); + +template +void SafeWrite(std::ofstream &stream, const T &data); + +template +void SafeWriteSwap(std::ofstream &stream, const T &data); + +#endif // __DEV_STORAGE_DISK_IMAGE_HH__ diff --git a/src/dev/storage/ide_atareg.h b/src/dev/storage/ide_atareg.h new file mode 100644 index 000000000..51c8aeccf --- /dev/null +++ b/src/dev/storage/ide_atareg.h @@ -0,0 +1,293 @@ +/* $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 + +#elif defined(__sun) +#include + +#else +#include + +#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_ */ diff --git a/src/dev/storage/ide_ctrl.cc b/src/dev/storage/ide_ctrl.cc new file mode 100644 index 000000000..feed9cfd2 --- /dev/null +++ b/src/dev/storage/ide_ctrl.cc @@ -0,0 +1,650 @@ +/* + * 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 + +#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(deviceTiming); + break; + case UDMAControl: + pkt->set(udmaControl); + break; + case PrimaryTiming + 1: + pkt->set(bits(htole(primaryTiming), 15, 8)); + break; + case SecondaryTiming + 1: + pkt->set(bits(htole(secondaryTiming), 15, 8)); + break; + case IDEConfig: + pkt->set(bits(htole(ideConfig), 7, 0)); + break; + case IDEConfig + 1: + pkt->set(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()); + break; + case sizeof(uint16_t): + switch (offset) { + case UDMAControl: + pkt->set(udmaControl); + break; + case PrimaryTiming: + pkt->set(primaryTiming); + break; + case SecondaryTiming: + pkt->set(secondaryTiming); + break; + case UDMATiming: + pkt->set(udmaTiming); + break; + case IDEConfig: + pkt->set(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()); + break; + case sizeof(uint32_t): + switch (offset) { + case PrimaryTiming: + pkt->set(primaryTiming); + break; + case IDEConfig: + pkt->set(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()); + 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(); + break; + case UDMAControl: + udmaControl = pkt->get(); + break; + case IDEConfig: + replaceBits(ideConfig, 7, 0, pkt->get()); + break; + case IDEConfig + 1: + replaceBits(ideConfig, 15, 8, pkt->get()); + 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()); + break; + case sizeof(uint16_t): + switch (offset) { + case UDMAControl: + udmaControl = pkt->get(); + break; + case PrimaryTiming: + primaryTiming = pkt->get(); + break; + case SecondaryTiming: + secondaryTiming = pkt->get(); + break; + case UDMATiming: + udmaTiming = pkt->get(); + break; + case IDEConfig: + ideConfig = pkt->get(); + 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()); + break; + case sizeof(uint32_t): + switch (offset) { + case PrimaryTiming: + primaryTiming = pkt->get(); + break; + case IDEConfig: + ideConfig = pkt->get(); + 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(); + + 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(); + else if (pkt->getSize() == 2) + data = pkt->get(); + else + data = pkt->get(); + 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); +} diff --git a/src/dev/storage/ide_ctrl.hh b/src/dev/storage/ide_ctrl.hh new file mode 100644 index 000000000..94a9c65e5 --- /dev/null +++ b/src/dev/storage/ide_ctrl.hh @@ -0,0 +1,159 @@ +/* + * 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_ diff --git a/src/dev/storage/ide_disk.cc b/src/dev/storage/ide_disk.cc new file mode 100644 index 000000000..4eefdbbd7 --- /dev/null +++ b/src/dev/storage/ide_disk.cc @@ -0,0 +1,1203 @@ +/* + * 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 +#include +#include +#include + +#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); +} diff --git a/src/dev/storage/ide_disk.hh b/src/dev/storage/ide_disk.hh new file mode 100644 index 000000000..9214599e9 --- /dev/null +++ b/src/dev/storage/ide_disk.hh @@ -0,0 +1,373 @@ +/* + * 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; + EventWrapper dmaTransferEvent; + + void doDmaDataRead(); + + void doDmaRead(); + ChunkGenerator *dmaReadCG; + friend class EventWrapper; + EventWrapper dmaReadWaitEvent; + + void doDmaDataWrite(); + + void doDmaWrite(); + ChunkGenerator *dmaWriteCG; + friend class EventWrapper; + EventWrapper dmaWriteWaitEvent; + + void dmaPrdReadDone(); + friend class EventWrapper; + EventWrapper dmaPrdReadEvent; + + void dmaReadDone(); + friend class EventWrapper; + EventWrapper dmaReadEvent; + + void dmaWriteDone(); + friend class EventWrapper; + EventWrapper 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__ diff --git a/src/dev/storage/ide_wdcreg.h b/src/dev/storage/ide_wdcreg.h new file mode 100644 index 000000000..f6a59c9f2 --- /dev/null +++ b/src/dev/storage/ide_wdcreg.h @@ -0,0 +1,197 @@ +/* $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_ */ diff --git a/src/dev/storage/simple_disk.cc b/src/dev/storage/simple_disk.cc new file mode 100644 index 000000000..49c001a00 --- /dev/null +++ b/src/dev/storage/simple_disk.cc @@ -0,0 +1,100 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +#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); +} diff --git a/src/dev/storage/simple_disk.hh b/src/dev/storage/simple_disk.hh new file mode 100644 index 000000000..2a3ff4986 --- /dev/null +++ b/src/dev/storage/simple_disk.hh @@ -0,0 +1,65 @@ +/* + * 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__ diff --git a/src/dev/virtio/block.hh b/src/dev/virtio/block.hh index bef29580b..fbbb51854 100644 --- a/src/dev/virtio/block.hh +++ b/src/dev/virtio/block.hh @@ -41,7 +41,7 @@ #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;